aboutsummaryrefslogtreecommitdiff
path: root/src/ARM.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ARM.h')
-rw-r--r--src/ARM.h369
1 files changed, 252 insertions, 117 deletions
diff --git a/src/ARM.h b/src/ARM.h
index f06cb7f..5ecb818 100644
--- a/src/ARM.h
+++ b/src/ARM.h
@@ -19,24 +19,29 @@
#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();
+
+ virtual void DoSavestate(Savestate* file);
void SetClockShift(u32 shift)
{
@@ -44,9 +49,9 @@ public:
ClockDiffMask = (1<<shift) - 1;
}
- void DoSavestate(Savestate* file);
+ virtual void CalculateTimings() = 0;
- void JumpTo(u32 addr, bool restorecpsr = false);
+ virtual void JumpTo(u32 addr, bool restorecpsr = false) = 0;
void RestoreCPSR();
void Halt(u32 halt)
@@ -55,6 +60,7 @@ public:
Halted = halt;
}
+ // TODO: is this actually used??
void CheckIRQ()
{
if (!(NDS::IME[Num] & 0x1)) return;
@@ -64,7 +70,7 @@ public:
}
}
- s32 Execute();
+ virtual s32 Execute() = 0;
bool CheckCondition(u32 code)
{
@@ -102,167 +108,296 @@ public:
void SetupCodeMem(u32 addr);
- u16 CodeRead16(u32 addr)
- {
- Cycles += Waitstates[0][(addr>>24)&0xF];
+ virtual bool DataRead8(u32 addr, u32* val, u32 flags) = 0;
+ virtual bool DataRead16(u32 addr, u32* val, u32 flags) = 0;
+ virtual bool DataRead32(u32 addr, u32* val, u32 flags) = 0;
+ virtual bool DataWrite8(u32 addr, u8 val, u32 flags) = 0;
+ virtual bool DataWrite16(u32 addr, u16 val, u32 flags) = 0;
+ virtual bool DataWrite32(u32 addr, u32 val, u32 flags) = 0;
- if (CodeMem.Mem) return *(u16*)&CodeMem.Mem[addr & CodeMem.Mask];
+ virtual void AddCycles_C() = 0;
+ virtual void AddCycles_CI(s32 num) = 0;
+ virtual void AddCycles_CDI() = 0;
+ virtual void AddCycles_CD() = 0;
- u16 val;
- // TODO eventually: on ARM9, THUMB opcodes are prefetched with 32bit reads
- // probably not worth going through the trouble. we can probably just simulate
- // the timing quirks resulting from this. or not.
- if (!Num)
- {
- if (!CP15::HandleCodeRead16(addr, &val))
- val = NDS::ARM9Read16(addr);
- }
- else
- val = NDS::ARM7Read16(addr);
- return val;
+ u32 Num;
+
+ // shift relative to system clock
+ // 0=33MHz 1=66MHz 2=133MHz
+ u32 ClockShift;
+ u32 ClockDiffMask;
+
+ s32 Cycles;
+ s32 CyclesToRun;
+ u32 Halted;
+
+ int CodeRegion;
+
+ int 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 CalculateTimings();
+
+ void JumpTo(u32 addr, bool restorecpsr = false);
+
+ s32 Execute();
+
+ // all code accesses are forced nonseq 32bit
+ u32 CodeRead32(u32 addr);
+
+ bool DataRead8(u32 addr, u32* val, u32 flags);
+ bool DataRead16(u32 addr, u32* val, u32 flags);
+ bool DataRead32(u32 addr, u32* val, u32 flags);
+ bool DataWrite8(u32 addr, u8 val, u32 flags);
+ bool DataWrite16(u32 addr, u16 val, u32 flags);
+ bool DataWrite32(u32 addr, u32 val, u32 flags);
+
+ void AddCycles_C()
+ {
+ // code only. always nonseq 32-bit for ARM9.
+ Cycles += NDS::ARM9MemTimings[CodeRegion][2];
}
- u32 CodeRead32(u32 addr)
+ void AddCycles_CI(s32 num)
{
- Cycles += Waitstates[1][(addr>>24)&0xF];
+ // code+internal
+ Cycles += NDS::ARM9MemTimings[CodeRegion][2] + num;
+ }
- if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask];
+ void AddCycles_CDI()
+ {
+ // LDR/LDM cycles. ARM9 seems to skip the internal cycle there.
+ // TODO: ITCM data fetches shouldn't be parallelized, they say
+ s32 numC = NDS::ARM9MemTimings[CodeRegion][2];
+ s32 numD = DataCycles;
- u32 val;
- if (!Num)
- {
- if (!CP15::HandleCodeRead32(addr, &val))
- val = NDS::ARM9Read32(addr);
- }
+ if (DataRegion != CodeRegion)
+ Cycles += std::max(numC + numD - 6, std::max(numC, numD));
else
- val = NDS::ARM7Read32(addr);
+ Cycles += numC + numD;
+ }
+
+ void AddCycles_CD()
+ {
+ // TODO: ITCM data fetches shouldn't be parallelized, they say
+ s32 numC = NDS::ARM9MemTimings[CodeRegion][2];
+ 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 CP15Write(u32 id, u32 val);
+ u32 CP15Read(u32 id);
+
+ u32 CP15Control;
- return val;
+ u32 DTCMSetting, ITCMSetting;
+
+ u8 ITCM[0x8000];
+ u32 ITCMSize;
+ u8 DTCM[0x4000];
+ u32 DTCMBase, DTCMSize;
+};
+
+class ARMv4 : public ARM
+{
+public:
+ ARMv4();
+
+ void CalculateTimings();
+
+ void JumpTo(u32 addr, bool restorecpsr = false);
+
+ s32 Execute();
+
+ u16 CodeRead16(u32 addr)
+ {
+ u32 ret;
+ CodeRegion = NDS::ARM7Read16(addr, &ret);
+ return ret;
}
+ u32 CodeRead32(u32 addr)
+ {
+ u32 ret;
+ CodeRegion = NDS::ARM7Read32(addr, &ret);
+ return ret;
+ }
- u8 DataRead8(u32 addr, u32 forceuser=0)
+ bool DataRead8(u32 addr, u32* val, u32 flags)
{
- u8 val;
- if (!Num)
- {
- if (!CP15::HandleDataRead8(addr, &val, forceuser))
- val = NDS::ARM9Read8(addr);
- }
+ DataRegion = NDS::ARM7Read8(addr, val);
+ if (flags & RWFlags_Nonseq)
+ DataCycles = NDS::ARM7MemTimings[DataRegion][0];
else
- val = NDS::ARM7Read8(addr);
+ DataCycles += NDS::ARM7MemTimings[DataRegion][1];
- Cycles += Waitstates[2][(addr>>24)&0xF];
- return val;
+ return true;
}
- u16 DataRead16(u32 addr, u32 forceuser=0)
+ bool DataRead16(u32 addr, u32* val, u32 flags)
{
- u16 val;
addr &= ~1;
- if (!Num)
- {
- if (!CP15::HandleDataRead16(addr, &val, forceuser))
- val = NDS::ARM9Read16(addr);
- }
+
+ DataRegion = NDS::ARM7Read16(addr, val);
+ if (flags & RWFlags_Nonseq)
+ DataCycles = NDS::ARM7MemTimings[DataRegion][0];
else
- val = NDS::ARM7Read16(addr);
+ DataCycles += NDS::ARM7MemTimings[DataRegion][1];
- Cycles += Waitstates[2][(addr>>24)&0xF];
- return val;
+ return true;
}
- u32 DataRead32(u32 addr, u32 forceuser=0)
+ bool DataRead32(u32 addr, u32* val, u32 flags)
{
- u32 val;
addr &= ~3;
- if (!Num)
- {
- if (!CP15::HandleDataRead32(addr, &val, forceuser))
- val = NDS::ARM9Read32(addr);
- }
+
+ DataRegion = NDS::ARM7Read32(addr, val);
+ if (flags & RWFlags_Nonseq)
+ DataCycles = NDS::ARM7MemTimings[DataRegion][2];
else
- val = NDS::ARM7Read32(addr);
+ DataCycles += NDS::ARM7MemTimings[DataRegion][3];
- Cycles += Waitstates[3][(addr>>24)&0xF];
- return val;
+ return true;
}
- void DataWrite8(u32 addr, u8 val, u32 forceuser=0)
+ bool DataWrite8(u32 addr, u8 val, u32 flags)
{
- if (!Num)
- {
- if (!CP15::HandleDataWrite8(addr, val, forceuser))
- NDS::ARM9Write8(addr, val);
- }
+ DataRegion = NDS::ARM7Write8(addr, val);
+ if (flags & RWFlags_Nonseq)
+ DataCycles = NDS::ARM7MemTimings[DataRegion][0];
else
- NDS::ARM7Write8(addr, val);
+ DataCycles += NDS::ARM7MemTimings[DataRegion][1];
- Cycles += Waitstates[2][(addr>>24)&0xF];
+ return true;
}
- void DataWrite16(u32 addr, u16 val, u32 forceuser=0)
+ bool DataWrite16(u32 addr, u16 val, u32 flags)
{
addr &= ~1;
- if (!Num)
- {
- if (!CP15::HandleDataWrite16(addr, val, forceuser))
- NDS::ARM9Write16(addr, val);
- }
+
+ DataRegion = NDS::ARM7Write16(addr, val);
+ if (flags & RWFlags_Nonseq)
+ DataCycles = NDS::ARM7MemTimings[DataRegion][0];
else
- NDS::ARM7Write16(addr, val);
+ DataCycles += NDS::ARM7MemTimings[DataRegion][1];
- Cycles += Waitstates[2][(addr>>24)&0xF];
+ return true;
}
- void DataWrite32(u32 addr, u32 val, u32 forceuser=0)
+ bool DataWrite32(u32 addr, u32 val, u32 flags)
{
addr &= ~3;
- if (!Num)
- {
- if (!CP15::HandleDataWrite32(addr, val, forceuser))
- NDS::ARM9Write32(addr, val);
- }
+
+ DataRegion = NDS::ARM7Write32(addr, val);
+ if (flags & RWFlags_Nonseq)
+ DataCycles = NDS::ARM7MemTimings[DataRegion][2];
else
- NDS::ARM7Write32(addr, val);
+ DataCycles += NDS::ARM7MemTimings[DataRegion][3];
- Cycles += Waitstates[3][(addr>>24)&0xF];
+ return true;
}
- u32 Num;
-
- // shift relative to system clock
- // 0=33MHz 1=66MHz 2=133MHz
- u32 ClockShift;
- u32 ClockDiffMask;
-
- // waitstates:
- // 0=code16 1=code32 2=data16 3=data32
- // TODO eventually: nonsequential waitstates
- // TODO NOT MAKE THIS A FUCKING GROSS HACK!!!!!!
- s32 Waitstates[4][16];
+ void AddCycles_C()
+ {
+ // code only. this code fetch is sequential.
+ Cycles += NDS::ARM7MemTimings[CodeRegion][(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[CodeRegion][(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[CodeRegion][(CPSR&0x20)?0:2];
+ s32 numD = DataCycles;
- u32 ExceptionBase;
+ if (DataRegion == NDS::Region7_MainRAM)
+ {
+ if (CodeRegion == NDS::Region7_MainRAM)
+ Cycles += numC + numD;
+ else
+ {
+ numC++;
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ }
+ else if (CodeRegion == NDS::Region7_MainRAM)
+ {
+ numD++;
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ else
+ {
+ Cycles += numC + numD + 1;
+ }
+ }
- NDS::MemRegion CodeMem;
+ void AddCycles_CD()
+ {
+ // TODO: max gain should be 5c when writing to mainRAM
+ s32 numC = NDS::ARM7MemTimings[CodeRegion][(CPSR&0x20)?0:2];
+ s32 numD = DataCycles;
- static u32 ConditionTable[16];
+ if (DataRegion == NDS::Region7_MainRAM)
+ {
+ if (CodeRegion == NDS::Region7_MainRAM)
+ Cycles += numC + numD;
+ else
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ else if (CodeRegion == NDS::Region7_MainRAM)
+ {
+ Cycles += std::max(numC + numD - 3, std::max(numC, numD));
+ }
+ else
+ {
+ Cycles += numC + numD;
+ }
+ }
};
namespace ARMInterpreter