diff options
Diffstat (limited to 'src/ARM.h')
-rw-r--r-- | src/ARM.h | 399 |
1 files changed, 286 insertions, 113 deletions
@@ -19,28 +19,36 @@ #ifndef ARM_H #define ARM_H +#include <algorithm> + #include "types.h" #include "NDS.h" -#include "CP15.h" - -// lame -#define C_S(x) x -#define C_N(x) x -#define C_I(x) x #define ROR(x, n) (((x) >> (n)) | ((x) << (32-(n)))) +enum +{ + RWFlags_Nonseq = (1<<5), + RWFlags_ForceUser = (1<<21), +}; + class ARM { public: ARM(u32 num); ~ARM(); // destroy shit - void Reset(); + virtual void Reset(); - void DoSavestate(Savestate* file); + virtual void DoSavestate(Savestate* file); - void JumpTo(u32 addr, bool restorecpsr = false); + void SetClockShift(u32 shift) + { + ClockShift = shift; + ClockDiffMask = (1<<shift) - 1; + } + + virtual void JumpTo(u32 addr, bool restorecpsr = false) = 0; void RestoreCPSR(); void Halt(u32 halt) @@ -49,6 +57,7 @@ public: Halted = halt; } + // TODO: is this actually used?? void CheckIRQ() { if (!(NDS::IME[Num] & 0x1)) return; @@ -58,7 +67,7 @@ public: } } - s32 Execute(); + virtual s32 Execute() = 0; bool CheckCondition(u32 code) { @@ -93,154 +102,318 @@ public: void TriggerIRQ(); + void SetupCodeMem(u32 addr); - u16 CodeRead16(u32 addr) + + virtual void DataRead8(u32 addr, u32* val) = 0; + virtual void DataRead16(u32 addr, u32* val) = 0; + virtual void DataRead32(u32 addr, u32* val) = 0; + virtual void DataRead32S(u32 addr, u32* val) = 0; + virtual void DataWrite8(u32 addr, u8 val) = 0; + virtual void DataWrite16(u32 addr, u16 val) = 0; + virtual void DataWrite32(u32 addr, u32 val) = 0; + virtual void DataWrite32S(u32 addr, u32 val) = 0; + + virtual void AddCycles_C() = 0; + virtual void AddCycles_CI(s32 numI) = 0; + virtual void AddCycles_CDI() = 0; + virtual void AddCycles_CD() = 0; + + + u32 Num; + + // shift relative to system clock + // 0=33MHz 1=66MHz 2=133MHz + u32 ClockShift; + u32 ClockDiffMask; + + s32 Cycles; + s32 CyclesToRun; + u32 Halted; + + u32 CodeRegion; + s32 CodeCycles; + + u32 DataRegion; + s32 DataCycles; + + u32 R[16]; // heh + u32 CPSR; + u32 R_FIQ[8]; // holding SPSR too + u32 R_SVC[3]; + u32 R_ABT[3]; + u32 R_IRQ[3]; + u32 R_UND[3]; + u32 CurInstr; + u32 NextInstr[2]; + + u32 ExceptionBase; + + NDS::MemRegion CodeMem; + + static u32 ConditionTable[16]; +}; + +class ARMv5 : public ARM +{ +public: + ARMv5(); + + void Reset(); + + void DoSavestate(Savestate* file); + + void UpdateRegionTimings(u32 addrstart, u32 addrend); + + void JumpTo(u32 addr, bool restorecpsr = false); + + void PrefetchAbort(); + void DataAbort(); + + s32 Execute(); + + // all code accesses are forced nonseq 32bit + u32 CodeRead32(u32 addr); + + void DataRead8(u32 addr, u32* val); + void DataRead16(u32 addr, u32* val); + void DataRead32(u32 addr, u32* val); + void DataRead32S(u32 addr, u32* val); + void DataWrite8(u32 addr, u8 val); + void DataWrite16(u32 addr, u16 val); + void DataWrite32(u32 addr, u32 val); + void DataWrite32S(u32 addr, u32 val); + + void AddCycles_C() { - u16 val; - // TODO eventually: on ARM9, THUMB opcodes are prefetched with 32bit reads - if (!Num) - { - if (!CP15::HandleCodeRead16(addr, &val)) - val = NDS::ARM9Read16(addr); - } - else - val = NDS::ARM7Read16(addr); + // code only. always nonseq 32-bit for ARM9. + s32 numC = (R[15] & 0x2) ? 0 : CodeCycles; + Cycles += numC; + } - Cycles += Waitstates[0][(addr>>24)&0xF]; - return val; + void AddCycles_CI(s32 numI) + { + // code+internal + s32 numC = (R[15] & 0x2) ? 0 : CodeCycles; + Cycles += numC + numI; } - u32 CodeRead32(u32 addr) + void AddCycles_CDI() { - u32 val; - if (!Num) - { - if (!CP15::HandleCodeRead32(addr, &val)) - val = NDS::ARM9Read32(addr); - } - else - val = NDS::ARM7Read32(addr); + // LDR/LDM cycles. ARM9 seems to skip the internal cycle there. + // TODO: ITCM data fetches shouldn't be parallelized, they say + s32 numC = (R[15] & 0x2) ? 0 : CodeCycles; + s32 numD = DataCycles; + + //if (DataRegion != CodeRegion) + Cycles += std::max(numC + numD - 6, std::max(numC, numD)); + //else + // Cycles += numC + numD; + } - Cycles += Waitstates[1][(addr>>24)&0xF]; - return val; + void AddCycles_CD() + { + // TODO: ITCM data fetches shouldn't be parallelized, they say + s32 numC = (R[15] & 0x2) ? 0 : CodeCycles; + s32 numD = DataCycles; + + //if (DataRegion != CodeRegion) + Cycles += std::max(numC + numD - 6, std::max(numC, numD)); + //else + // Cycles += numC + numD; } + void GetCodeMemRegion(u32 addr, NDS::MemRegion* region); + + void CP15Reset(); + void CP15DoSavestate(Savestate* file); + + void UpdateDTCMSetting(); + void UpdateITCMSetting(); + + void UpdatePURegions(); + + void CP15Write(u32 id, u32 val); + u32 CP15Read(u32 id); + + u32 CP15Control; + + u32 DTCMSetting, ITCMSetting; + + u8 ITCM[0x8000]; + u32 ITCMSize; + u8 DTCM[0x4000]; + u32 DTCMBase, DTCMSize; + + u32 PU_CodeCacheable; + u32 PU_DataCacheable; + u32 PU_DataCacheWrite; + + u32 PU_CodeRW; + u32 PU_DataRW; + + u32 PU_Region[8]; + + // 0=dataR 1=dataW 2=codeR 4=datacache 5=datawrite 6=codecache + u8 PU_PrivMap[0x100000]; + u8 PU_UserMap[0x100000]; + + // games operate under system mode, generally + #define PU_Map PU_PrivMap - u8 DataRead8(u32 addr, u32 forceuser=0) + // code/16N/32N/32S + u8 MemTimings[0x100000][4]; + + s32 RegionCodeCycles; +}; + +class ARMv4 : public ARM +{ +public: + ARMv4(); + + void JumpTo(u32 addr, bool restorecpsr = false); + + s32 Execute(); + + u16 CodeRead16(u32 addr) { - u8 val; - if (!Num) - { - if (!CP15::HandleDataRead8(addr, &val, forceuser)) - val = NDS::ARM9Read8(addr); - } - else - val = NDS::ARM7Read8(addr); + return NDS::ARM7Read16(addr); + } - Cycles += Waitstates[2][(addr>>24)&0xF]; - return val; + u32 CodeRead32(u32 addr) + { + return NDS::ARM7Read32(addr); + } + + void DataRead8(u32 addr, u32* val) + { + *val = NDS::ARM7Read8(addr); + DataRegion = addr >> 24; + DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } - u16 DataRead16(u32 addr, u32 forceuser=0) + void DataRead16(u32 addr, u32* val) { - u16 val; addr &= ~1; - if (!Num) - { - if (!CP15::HandleDataRead16(addr, &val, forceuser)) - val = NDS::ARM9Read16(addr); - } - else - val = NDS::ARM7Read16(addr); - Cycles += Waitstates[2][(addr>>24)&0xF]; - return val; + *val = NDS::ARM7Read16(addr); + DataRegion = addr >> 24; + DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } - u32 DataRead32(u32 addr, u32 forceuser=0) + void DataRead32(u32 addr, u32* val) { - u32 val; addr &= ~3; - if (!Num) - { - if (!CP15::HandleDataRead32(addr, &val, forceuser)) - val = NDS::ARM9Read32(addr); - } - else - val = NDS::ARM7Read32(addr); - Cycles += Waitstates[3][(addr>>24)&0xF]; - return val; + *val = NDS::ARM7Read32(addr); + DataRegion = addr >> 24; + DataCycles = NDS::ARM7MemTimings[DataRegion][2]; } - void DataWrite8(u32 addr, u8 val, u32 forceuser=0) + void DataRead32S(u32 addr, u32* val) { - if (!Num) - { - if (!CP15::HandleDataWrite8(addr, val, forceuser)) - NDS::ARM9Write8(addr, val); - } - else - NDS::ARM7Write8(addr, val); + addr &= ~3; - Cycles += Waitstates[2][(addr>>24)&0xF]; + *val = NDS::ARM7Read32(addr); + DataCycles += NDS::ARM7MemTimings[DataRegion][3]; } - void DataWrite16(u32 addr, u16 val, u32 forceuser=0) + void DataWrite8(u32 addr, u8 val) + { + NDS::ARM7Write8(addr, val); + DataRegion = addr >> 24; + DataCycles = NDS::ARM7MemTimings[DataRegion][0]; + } + + void DataWrite16(u32 addr, u16 val) { addr &= ~1; - if (!Num) - { - if (!CP15::HandleDataWrite16(addr, val, forceuser)) - NDS::ARM9Write16(addr, val); - } - else - NDS::ARM7Write16(addr, val); - Cycles += Waitstates[2][(addr>>24)&0xF]; + NDS::ARM7Write16(addr, val); + DataRegion = addr >> 24; + DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } - void DataWrite32(u32 addr, u32 val, u32 forceuser=0) + void DataWrite32(u32 addr, u32 val) { addr &= ~3; - if (!Num) - { - if (!CP15::HandleDataWrite32(addr, val, forceuser)) - NDS::ARM9Write32(addr, val); - } - else - NDS::ARM7Write32(addr, val); - Cycles += Waitstates[3][(addr>>24)&0xF]; + NDS::ARM7Write32(addr, val); + DataRegion = addr >> 24; + DataCycles = NDS::ARM7MemTimings[DataRegion][2]; } + void DataWrite32S(u32 addr, u32 val) + { + addr &= ~3; + + NDS::ARM7Write32(addr, val); + DataCycles += NDS::ARM7MemTimings[DataRegion][3]; + } - u32 Num; - // waitstates: - // 0=code16 1=code32 2=data16 3=data32 - // TODO eventually: nonsequential waitstates - s32 Waitstates[4][16]; + void AddCycles_C() + { + // code only. this code fetch is sequential. + Cycles += NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?1:3]; + } - s32 Cycles; - s32 CyclesToRun; - u32 Halted; + void AddCycles_CI(s32 num) + { + // code+internal. results in a nonseq code fetch. + Cycles += NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2] + num; + } - u32 R[16]; // heh - u32 CPSR; - u32 R_FIQ[8]; // holding SPSR too - u32 R_SVC[3]; - u32 R_ABT[3]; - u32 R_IRQ[3]; - u32 R_UND[3]; - u32 CurInstr; - u32 NextInstr[2]; + void AddCycles_CDI() + { + // LDR/LDM cycles. + s32 numC = NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2]; + s32 numD = DataCycles; - u32 ExceptionBase; + if (DataRegion == 0x02) // mainRAM + { + if (CodeRegion == 0x02) + Cycles += numC + numD; + else + { + numC++; + Cycles += std::max(numC + numD - 3, std::max(numC, numD)); + } + } + else if (CodeRegion == 0x02) + { + numD++; + Cycles += std::max(numC + numD - 3, std::max(numC, numD)); + } + else + { + Cycles += numC + numD + 1; + } + } - static u32 ConditionTable[16]; + void AddCycles_CD() + { + // TODO: max gain should be 5c when writing to mainRAM + s32 numC = NDS::ARM7MemTimings[CodeCycles][(CPSR&0x20)?0:2]; + s32 numD = DataCycles; - u32 debug; + if (DataRegion == 0x02) + { + if (CodeRegion == 0x02) + Cycles += numC + numD; + else + Cycles += std::max(numC + numD - 3, std::max(numC, numD)); + } + else if (CodeRegion == 0x02) + { + Cycles += std::max(numC + numD - 3, std::max(numC, numD)); + } + else + { + Cycles += numC + numD; + } + } }; namespace ARMInterpreter |