flycast/core/hw/arm7/arm7.cpp

410 lines
7.7 KiB
C++
Raw Normal View History

2018-09-20 17:48:46 +00:00
#include "arm7.h"
2013-12-19 17:10:14 +00:00
#include "arm_mem.h"
#include "arm7_rec.h"
2013-12-19 17:10:14 +00:00
namespace aica::arm
{
#define CPUReadMemoryQuick(addr) (*(u32*)&aica_ram[(addr) & ARAM_MASK])
2023-01-30 12:21:43 +00:00
#define CPUReadByte readMem<u8>
#define CPUReadMemory readMem<u32>
#define CPUReadHalfWord readMem<u16>
#define CPUReadHalfWordSigned(addr) ((s16)readMem<u16>(addr))
2013-12-19 17:10:14 +00:00
2023-01-30 12:21:43 +00:00
#define CPUWriteMemory writeMem<u32>
#define CPUWriteHalfWord writeMem<u16>
#define CPUWriteByte writeMem<u8>
2013-12-19 17:10:14 +00:00
#define reg arm_Reg
#define armNextPC reg[R15_ARM_NEXT].I
#define CPUUpdateTicksAccessSeq32(a) 1
#define CPUUpdateTicksAccess32(a) 1
#define CPUUpdateTicksAccess16(a) 1
2020-02-19 22:20:32 +00:00
alignas(8) reg_pair arm_Reg[RN_ARM_REG_COUNT];
2013-12-19 17:10:14 +00:00
static void CPUSwap(u32 *a, u32 *b)
2013-12-19 17:10:14 +00:00
{
u32 c = *b;
*b = *a;
*a = c;
}
#define N_FLAG (reg[RN_PSR_FLAGS].FLG.N)
#define Z_FLAG (reg[RN_PSR_FLAGS].FLG.Z)
#define C_FLAG (reg[RN_PSR_FLAGS].FLG.C)
#define V_FLAG (reg[RN_PSR_FLAGS].FLG.V)
bool armIrqEnable;
bool armFiqEnable;
int armMode;
2019-07-25 19:34:43 +00:00
bool Arm7Enabled = false;
2013-12-19 17:10:14 +00:00
static u8 cpuBitsSet[256];
2013-12-19 17:10:14 +00:00
static void CPUSwitchMode(int mode, bool saveState);
static void CPUUpdateFlags();
static void CPUSoftwareInterrupt(int comment);
static void CPUUndefinedException();
2013-12-19 17:10:14 +00:00
2019-07-25 19:34:43 +00:00
//
// ARM7 interpreter
//
2021-09-02 15:51:23 +00:00
int arm7ClockTicks;
#if FEAT_AREC == DYNAREC_NONE
static void runInterpreter(u32 CycleCount)
2013-12-19 17:10:14 +00:00
{
if (!Arm7Enabled)
return;
2013-12-19 17:10:14 +00:00
2021-09-02 15:51:23 +00:00
arm7ClockTicks -= CycleCount;
while (arm7ClockTicks < 0)
2013-12-19 17:10:14 +00:00
{
if (reg[INTR_PEND].I)
CPUFiq();
reg[15].I = armNextPC + 8;
2021-09-02 15:51:23 +00:00
int& clockTicks = arm7ClockTicks;
2013-12-19 17:10:14 +00:00
#include "arm-new.h"
}
}
void avoidRaceCondition()
{
2021-09-02 15:51:23 +00:00
arm7ClockTicks = std::min(arm7ClockTicks, -50);
}
void run(u32 samples)
{
for (u32 i = 0; i < samples; i++)
2019-07-25 19:34:43 +00:00
{
runInterpreter(ARM_CYCLES_PER_SAMPLE);
timeStep();
2019-07-25 19:34:43 +00:00
}
}
#endif
2013-12-19 17:10:14 +00:00
void init()
2013-12-19 17:10:14 +00:00
{
#if FEAT_AREC != DYNAREC_NONE
recompiler::init();
2013-12-19 17:10:14 +00:00
#endif
reset();
for (std::size_t i = 0; i < std::size(cpuBitsSet); i++)
2013-12-19 17:10:14 +00:00
{
int count = 0;
for (int j = 0; j < 8; j++)
if (i & (1 << j))
2013-12-19 17:10:14 +00:00
count++;
2013-12-19 17:10:14 +00:00
cpuBitsSet[i] = count;
}
}
void term()
{
#if FEAT_AREC != DYNAREC_NONE
recompiler::term();
#endif
}
static void CPUSwitchMode(int mode, bool saveState)
2013-12-19 17:10:14 +00:00
{
CPUUpdateCPSR();
switch(armMode)
{
2013-12-19 17:10:14 +00:00
case 0x10:
case 0x1F:
reg[R13_USR].I = reg[13].I;
reg[R14_USR].I = reg[14].I;
reg[RN_SPSR].I = reg[RN_CPSR].I;
2013-12-19 17:10:14 +00:00
break;
case 0x11:
CPUSwap(&reg[R8_FIQ].I, &reg[8].I);
CPUSwap(&reg[R9_FIQ].I, &reg[9].I);
CPUSwap(&reg[R10_FIQ].I, &reg[10].I);
CPUSwap(&reg[R11_FIQ].I, &reg[11].I);
CPUSwap(&reg[R12_FIQ].I, &reg[12].I);
reg[R13_FIQ].I = reg[13].I;
reg[R14_FIQ].I = reg[14].I;
reg[SPSR_FIQ].I = reg[RN_SPSR].I;
2013-12-19 17:10:14 +00:00
break;
case 0x12:
reg[R13_IRQ].I = reg[13].I;
reg[R14_IRQ].I = reg[14].I;
reg[SPSR_IRQ].I = reg[RN_SPSR].I;
2013-12-19 17:10:14 +00:00
break;
case 0x13:
reg[R13_SVC].I = reg[13].I;
reg[R14_SVC].I = reg[14].I;
reg[SPSR_SVC].I = reg[RN_SPSR].I;
2013-12-19 17:10:14 +00:00
break;
case 0x17:
reg[R13_ABT].I = reg[13].I;
reg[R14_ABT].I = reg[14].I;
reg[SPSR_ABT].I = reg[RN_SPSR].I;
2013-12-19 17:10:14 +00:00
break;
case 0x1b:
reg[R13_UND].I = reg[13].I;
reg[R14_UND].I = reg[14].I;
reg[SPSR_UND].I = reg[RN_SPSR].I;
2013-12-19 17:10:14 +00:00
break;
}
u32 CPSR = reg[RN_CPSR].I;
u32 SPSR = reg[RN_SPSR].I;
2013-12-19 17:10:14 +00:00
switch(mode)
{
2013-12-19 17:10:14 +00:00
case 0x10:
case 0x1F:
reg[13].I = reg[R13_USR].I;
reg[14].I = reg[R14_USR].I;
reg[RN_CPSR].I = SPSR;
2013-12-19 17:10:14 +00:00
break;
case 0x11:
CPUSwap(&reg[8].I, &reg[R8_FIQ].I);
CPUSwap(&reg[9].I, &reg[R9_FIQ].I);
CPUSwap(&reg[10].I, &reg[R10_FIQ].I);
CPUSwap(&reg[11].I, &reg[R11_FIQ].I);
CPUSwap(&reg[12].I, &reg[R12_FIQ].I);
reg[13].I = reg[R13_FIQ].I;
reg[14].I = reg[R14_FIQ].I;
if(saveState)
reg[RN_SPSR].I = CPSR;
2013-12-19 17:10:14 +00:00
else
reg[RN_SPSR].I = reg[SPSR_FIQ].I;
2013-12-19 17:10:14 +00:00
break;
case 0x12:
reg[13].I = reg[R13_IRQ].I;
reg[14].I = reg[R14_IRQ].I;
reg[RN_CPSR].I = SPSR;
2013-12-19 17:10:14 +00:00
if(saveState)
reg[RN_SPSR].I = CPSR;
2013-12-19 17:10:14 +00:00
else
reg[RN_SPSR].I = reg[SPSR_IRQ].I;
2013-12-19 17:10:14 +00:00
break;
case 0x13:
reg[13].I = reg[R13_SVC].I;
reg[14].I = reg[R14_SVC].I;
reg[RN_CPSR].I = SPSR;
2013-12-19 17:10:14 +00:00
if(saveState)
reg[RN_SPSR].I = CPSR;
2013-12-19 17:10:14 +00:00
else
reg[RN_SPSR].I = reg[SPSR_SVC].I;
2013-12-19 17:10:14 +00:00
break;
case 0x17:
reg[13].I = reg[R13_ABT].I;
reg[14].I = reg[R14_ABT].I;
reg[RN_CPSR].I = SPSR;
2013-12-19 17:10:14 +00:00
if(saveState)
reg[RN_SPSR].I = CPSR;
2013-12-19 17:10:14 +00:00
else
reg[RN_SPSR].I = reg[SPSR_ABT].I;
break;
2013-12-19 17:10:14 +00:00
case 0x1b:
reg[13].I = reg[R13_UND].I;
reg[14].I = reg[R14_UND].I;
reg[RN_CPSR].I = SPSR;
2013-12-19 17:10:14 +00:00
if(saveState)
reg[RN_SPSR].I = CPSR;
2013-12-19 17:10:14 +00:00
else
reg[RN_SPSR].I = reg[SPSR_UND].I;
break;
2013-12-19 17:10:14 +00:00
default:
// An illegal mode causes the processor to enter an unrecoverable state
2019-06-30 20:09:32 +00:00
ERROR_LOG(AICA_ARM, "Unsupported ARM mode %02x", mode);
Arm7Enabled = false;
2013-12-19 17:10:14 +00:00
break;
}
armMode = mode;
CPUUpdateFlags();
CPUUpdateCPSR();
}
void CPUUpdateCPSR()
{
reg_pair CPSR;
CPSR.I = reg[RN_CPSR].I & 0x40;
CPSR.PSR.NZCV = reg[RN_PSR_FLAGS].FLG.NZCV;
2013-12-19 17:10:14 +00:00
if (!armFiqEnable)
CPSR.I |= 0x40;
if(!armIrqEnable)
CPSR.I |= 0x80;
CPSR.PSR.M = armMode;
2013-12-19 17:10:14 +00:00
reg[RN_CPSR].I = CPSR.I;
2013-12-19 17:10:14 +00:00
}
static void CPUUpdateFlags()
2013-12-19 17:10:14 +00:00
{
u32 CPSR = reg[RN_CPSR].I;
2013-12-19 17:10:14 +00:00
reg[RN_PSR_FLAGS].FLG.NZCV = reg[RN_CPSR].PSR.NZCV;
2013-12-19 17:10:14 +00:00
armIrqEnable = (CPSR & 0x80) ? false : true;
armFiqEnable = (CPSR & 0x40) ? false : true;
update_armintc();
}
static void CPUSoftwareInterrupt(int comment)
2013-12-19 17:10:14 +00:00
{
u32 PC = reg[R15_ARM_NEXT].I+4;
CPUSwitchMode(0x13, true);
2013-12-19 17:10:14 +00:00
reg[14].I = PC;
armIrqEnable = false;
armNextPC = 0x08;
}
static void CPUUndefinedException()
2013-12-19 17:10:14 +00:00
{
2019-06-30 20:09:32 +00:00
WARN_LOG(AICA_ARM, "arm7: CPUUndefinedException(). SOMETHING WENT WRONG");
2013-12-19 17:10:14 +00:00
u32 PC = reg[R15_ARM_NEXT].I+4;
CPUSwitchMode(0x1b, true);
2013-12-19 17:10:14 +00:00
reg[14].I = PC;
armIrqEnable = false;
armNextPC = 0x04;
}
void reset()
2013-12-19 17:10:14 +00:00
{
INFO_LOG(AICA_ARM, "AICA ARM Reset");
#if FEAT_AREC != DYNAREC_NONE
recompiler::flush();
2013-12-19 17:10:14 +00:00
#endif
2019-07-10 15:25:11 +00:00
aica_interr = false;
aica_reg_L = 0;
e68k_out = false;
e68k_reg_L = 0;
e68k_reg_M = 0;
2013-12-19 17:10:14 +00:00
Arm7Enabled = false;
// clean registers
memset(&arm_Reg[0], 0, sizeof(arm_Reg));
armMode = 0x13;
2013-12-19 17:10:14 +00:00
reg[13].I = 0x03007F00;
reg[15].I = 0x0000000;
reg[RN_CPSR].I = 0x00000000;
2013-12-19 17:10:14 +00:00
reg[R13_IRQ].I = 0x03007FA0;
reg[R13_SVC].I = 0x03007FE0;
armIrqEnable = true;
armFiqEnable = false;
update_armintc();
C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
// disable FIQ
reg[RN_CPSR].I |= 0x40;
2013-12-19 17:10:14 +00:00
CPUUpdateCPSR();
armNextPC = reg[15].I;
reg[15].I += 4;
}
void CPUFiq()
{
u32 PC = reg[R15_ARM_NEXT].I+4;
CPUSwitchMode(0x11, true);
2013-12-19 17:10:14 +00:00
reg[14].I = PC;
armIrqEnable = false;
armFiqEnable = false;
update_armintc();
armNextPC = 0x1c;
}
/*
--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
*/
void enable(bool enabled)
2013-12-19 17:10:14 +00:00
{
if(!Arm7Enabled && enabled)
reset();
2013-12-19 17:10:14 +00:00
Arm7Enabled=enabled;
}
void update_armintc()
{
reg[INTR_PEND].I=e68k_out && armFiqEnable;
}
2019-07-25 19:34:43 +00:00
#if FEAT_AREC != DYNAREC_NONE
//
// Used by ARM7 Recompiler
2019-07-25 19:34:43 +00:00
//
2021-03-02 19:10:25 +00:00
namespace recompiler {
//Emulate a single arm op, passed in opcode
void DYNACALL interpret(u32 opcode)
{
u32 clockTicks = 0;
#define NO_OPCODE_READ
#include "arm-new.h"
#undef NO_OPCODE_READ
reg[CYCL_CNT].I -= clockTicks;
}
2013-12-19 17:10:14 +00:00
template<u32 Pd>
void DYNACALL MSR_do(u32 v)
{
if (Pd)
{
if(armMode > 0x10 && armMode < 0x1f) /* !=0x10 ?*/
{
reg[RN_SPSR].I = (reg[RN_SPSR].I & 0x00FFFF00) | (v & 0xFF0000FF);
2013-12-19 17:10:14 +00:00
}
}
else
{
CPUUpdateCPSR();
u32 newValue = reg[RN_CPSR].I;
2013-12-19 17:10:14 +00:00
if(armMode > 0x10)
{
newValue = (newValue & 0xFFFFFF00) | (v & 0x000000FF);
}
newValue = (newValue & 0x00FFFFFF) | (v & 0xFF000000);
newValue |= 0x10;
if(armMode > 0x10)
{
CPUSwitchMode(newValue & 0x1f, false);
}
reg[RN_CPSR].I = newValue;
2013-12-19 17:10:14 +00:00
CPUUpdateFlags();
}
}
template void DYNACALL MSR_do<0>(u32 v);
template void DYNACALL MSR_do<1>(u32 v);
2013-12-19 17:10:14 +00:00
} // namespace recompiler
2019-07-25 19:34:43 +00:00
#endif // FEAT_AREC != DYNAREC_NONE
2021-01-29 10:39:00 +00:00
} // namespace aica::arm