mirror of
https://github.com/gligli/nulldc-360.git
synced 2025-04-02 11:11:56 -04:00
442 lines
No EOL
8.3 KiB
C++
442 lines
No EOL
8.3 KiB
C++
#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<CycleCount)
|
|
{
|
|
if (armFiqEnable && e68k_out)
|
|
{
|
|
CPUFiq();
|
|
}
|
|
|
|
#include "arm-new.h"
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void arm_SetEnabled(bool enabled)
|
|
{
|
|
if(!Arm7Enabled && enabled)
|
|
arm_Reset();
|
|
|
|
Arm7Enabled=enabled;
|
|
} |