#include "arm7.h" #include "mem.h" #define C_CORE #define DEV_VERSION //#define CPUReadHalfWordQuick(addr) arm_ReadMem16(addr & 0x7FFFFF) #define CPUReadMemoryQuick(addr) arm_ReadMem32(addr & ARAM_MASK) #define CPUReadByte arm_ReadMem8 #define CPUReadMemory arm_ReadMem32 #define CPUReadHalfWord arm_ReadMem16 #define CPUReadHalfWordSigned(addr) ((s16)arm_ReadMem16(addr)) #define CPUWriteMemory arm_WriteMem32 #define CPUWriteHalfWord arm_WriteMem16 #define CPUWriteByte arm_WriteMem8 #define reg arm_Reg #define armNextPC arm_ArmNextPC #define CPUUpdateTicksAccesint(a) 1 #define CPUUpdateTicksAccessSeq32(a) 1 #define CPUUpdateTicksAccesshort(a) 1 #define CPUUpdateTicksAccess32(a) 1 #define CPUUpdateTicksAccess16(a) 1 enum { R13_IRQ=18, R14_IRQ=19, SPSR_IRQ =20, R13_USR=26, R14_USR=27, R13_SVC=28, R14_SVC=29, SPSR_SVC =30, R13_ABT=31, R14_ABT=32, SPSR_ABT =33, R13_UND=34, R14_UND=35, SPSR_UND =36, R8_FIQ= 37, R9_FIQ= 38, R10_FIQ=39, R11_FIQ=40, R12_FIQ=41, R13_FIQ=42, R14_FIQ=43, SPSR_FIQ =44, }; #ifdef XENON typedef union { struct { u8 B3; u8 B2; u8 B1; u8 B0; } B; struct { u16 W1; u16 W0; } W; u32 I; } reg_pair; #else typedef union { struct { u8 B0; u8 B1; u8 B2; u8 B3; } B; struct { u16 W0; u16 W1; } W; u32 I; } reg_pair; #endif //bool arm_FiqPending; -- not used , i use the input directly :) //bool arm_IrqPending; u32 arm_ArmNextPC; reg_pair arm_Reg[45]; void CPUSwap(u32 *a, u32 *b) { u32 c = *b; *b = *a; *a = c; } bool C_OUT; bool N_FLAG; bool Z_FLAG; bool C_FLAG; bool V_FLAG; bool armIrqEnable; bool armFiqEnable; //bool armState; int armMode; bool Arm7Enabled=false; BYTE cpuBitsSet[256]; u16 IE; u16 IF; u16 IME; int cpuSavedTicks; int* extCpuLoopTicks = NULL; int* extClockTicks = NULL; int* extTicks = NULL; bool intState = false; bool stopState = false; bool holdState = false; #define CPU_BREAK_LOOP \ cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks;\ *extCpuLoopTicks = *extClockTicks; #define CPU_BREAK_LOOP_2 \ cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks;\ *extCpuLoopTicks = *extClockTicks;\ *extTicks = *extClockTicks; void CPUSwitchMode(int mode, bool saveState, bool breakLoop=true); void CPUUpdateCPSR(); void CPUUpdateFlags(bool breakLoop = true); void CPUSoftwareInterrupt(int comment); void CPUUndefinedException(); void CPUInterrupt(); void CPUFiq(); //void CreateTables(); void arm_Init() { //CreateTables(); arm_Reset(); int i; for(i = 0; i < 256; i++) { int count = 0; int j; for(j = 0; j < 8; j++) if(i & (1 << j)) count++; cpuBitsSet[i] = count; } } void CPUSwitchMode(int mode, bool saveState, bool breakLoop) { CPUUpdateCPSR(); switch(armMode) { case 0x10: case 0x1F: reg[R13_USR].I = reg[13].I; reg[R14_USR].I = reg[14].I; reg[17].I = reg[16].I; break; case 0x11: CPUSwap(®[R8_FIQ].I, ®[8].I); CPUSwap(®[R9_FIQ].I, ®[9].I); CPUSwap(®[R10_FIQ].I, ®[10].I); CPUSwap(®[R11_FIQ].I, ®[11].I); CPUSwap(®[R12_FIQ].I, ®[12].I); reg[R13_FIQ].I = reg[13].I; reg[R14_FIQ].I = reg[14].I; reg[SPSR_FIQ].I = reg[17].I; break; case 0x12: reg[R13_IRQ].I = reg[13].I; reg[R14_IRQ].I = reg[14].I; reg[SPSR_IRQ].I = reg[17].I; break; case 0x13: reg[R13_SVC].I = reg[13].I; reg[R14_SVC].I = reg[14].I; reg[SPSR_SVC].I = reg[17].I; break; case 0x17: reg[R13_ABT].I = reg[13].I; reg[R14_ABT].I = reg[14].I; reg[SPSR_ABT].I = reg[17].I; break; case 0x1b: reg[R13_UND].I = reg[13].I; reg[R14_UND].I = reg[14].I; reg[SPSR_UND].I = reg[17].I; break; } u32 CPSR = reg[16].I; u32 SPSR = reg[17].I; switch(mode) { case 0x10: case 0x1F: reg[13].I = reg[R13_USR].I; reg[14].I = reg[R14_USR].I; reg[16].I = SPSR; break; case 0x11: CPUSwap(®[8].I, ®[R8_FIQ].I); CPUSwap(®[9].I, ®[R9_FIQ].I); CPUSwap(®[10].I, ®[R10_FIQ].I); CPUSwap(®[11].I, ®[R11_FIQ].I); CPUSwap(®[12].I, ®[R12_FIQ].I); reg[13].I = reg[R13_FIQ].I; reg[14].I = reg[R14_FIQ].I; if(saveState) reg[17].I = CPSR; else reg[17].I = reg[SPSR_FIQ].I; break; case 0x12: reg[13].I = reg[R13_IRQ].I; reg[14].I = reg[R14_IRQ].I; reg[16].I = SPSR; if(saveState) reg[17].I = CPSR; else reg[17].I = reg[SPSR_IRQ].I; break; case 0x13: reg[13].I = reg[R13_SVC].I; reg[14].I = reg[R14_SVC].I; reg[16].I = SPSR; if(saveState) reg[17].I = CPSR; else reg[17].I = reg[SPSR_SVC].I; break; case 0x17: reg[13].I = reg[R13_ABT].I; reg[14].I = reg[R14_ABT].I; reg[16].I = SPSR; if(saveState) reg[17].I = CPSR; else reg[17].I = reg[SPSR_ABT].I; break; case 0x1b: reg[13].I = reg[R13_UND].I; reg[14].I = reg[R14_UND].I; reg[16].I = SPSR; if(saveState) reg[17].I = CPSR; else reg[17].I = reg[SPSR_UND].I; break; default: printf("Unsupported ARM mode %02x\n", mode); //gli die("Arm error.."); break; } armMode = mode; CPUUpdateFlags(breakLoop); CPUUpdateCPSR(); } void CPUUpdateCPSR() { u32 CPSR = reg[16].I & 0x40; if(N_FLAG) CPSR |= 0x80000000; if(Z_FLAG) CPSR |= 0x40000000; if(C_FLAG) CPSR |= 0x20000000; if(V_FLAG) CPSR |= 0x10000000; /*if(!armState) CPSR |= 0x00000020;*/ if (!armFiqEnable) CPSR |= 0x40; if(!armIrqEnable) CPSR |= 0x80; CPSR |= (armMode & 0x1F); reg[16].I = CPSR; } void CPUUpdateFlags(bool breakLoop) { u32 CPSR = reg[16].I; N_FLAG = (CPSR & 0x80000000) ? true: false; Z_FLAG = (CPSR & 0x40000000) ? true: false; C_FLAG = (CPSR & 0x20000000) ? true: false; V_FLAG = (CPSR & 0x10000000) ? true: false; //armState = (CPSR & 0x20) ? false : true; armIrqEnable = (CPSR & 0x80) ? false : true; armFiqEnable = (CPSR & 0x40) ? false : true; if(breakLoop) { if(armIrqEnable && (IF & IE) && (IME & 1)) { CPU_BREAK_LOOP_2; } } } void CPUSoftwareInterrupt(int comment) { u32 PC = reg[15].I; //bool savedArmState = armState; CPUSwitchMode(0x13, true, false); reg[14].I = PC - 4; reg[15].I = 0x08; armIrqEnable = false; armNextPC = 0x08; reg[15].I += 4; } void CPUUndefinedException() { u32 PC = reg[15].I; CPUSwitchMode(0x1b, true, false); reg[14].I = PC - 4; reg[15].I = 0x04; armIrqEnable = false; armNextPC = 0x04; reg[15].I += 4; } void arm_Reset() { Arm7Enabled = false; // clean registers memset(&arm_Reg[0], 0, sizeof(arm_Reg)); IE = 0x0000; IF = 0x0000; IME = 0x0000; armMode = 0x1F; reg[13].I = 0x03007F00; reg[15].I = 0x0000000; reg[16].I = 0x00000000; reg[R13_IRQ].I = 0x03007FA0; reg[R13_SVC].I = 0x03007FE0; armIrqEnable = true; armFiqEnable = false; //armState = true; C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; // disable FIQ reg[16].I |= 0x40; CPUUpdateCPSR(); armNextPC = reg[15].I; reg[15].I += 4; //arm_FiqPending = false; } void CPUInterrupt() { u32 PC = reg[15].I; //bool savedState = armState; CPUSwitchMode(0x12, true, false); reg[14].I = PC; //if(!savedState) // reg[14].I += 2; reg[15].I = 0x18; //armState = true; armIrqEnable = false; armNextPC = reg[15].I; reg[15].I += 4; } void CPUFiq() { u32 PC = reg[15].I; //bool savedState = armState; CPUSwitchMode(0x11, true, false); reg[14].I = PC; //if(!savedState) // reg[14].I += 2; reg[15].I = 0x1c; //armState = true; armIrqEnable = false; armFiqEnable = false; armNextPC = reg[15].I; reg[15].I += 4; } /* --Seems like aica has 3 interrupt controllers actualy (damn lazy sega ..) The "normal" one (the one that exists on scsp) , one to emulate the 68k intc , and , of course , the arm7 one The output of the sci* bits is input to the e68k , and the output of e68k is inputed into the FIQ pin on arm7 */ #ifdef _MUDFLAP __attribute__ ((optimize("O0"))) #endif void arm_Run(u32 CycleCount) { if (!Arm7Enabled) return; u32 clockTicks=0; while (clockTicks