mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
[ARM] Add support for IMMs to the GPR reg cache. Not yet using it since it doesn't quite work
This commit is contained in:
parent
f485d96b0b
commit
f2e43f47a4
@ -48,13 +48,8 @@ void JitArm::Init()
|
||||
AllocCodeSpace(CODE_SIZE);
|
||||
blocks.Init();
|
||||
asm_routines.Init();
|
||||
// TODO: Investigate why the register cache crashes when only doing Init with
|
||||
// the pointer to this. Seems for some reason it doesn't set the emitter pointer
|
||||
// In the class for some reason?
|
||||
gpr.Init(this);
|
||||
gpr.SetEmitter(this);
|
||||
fpr.Init(this);
|
||||
fpr.SetEmitter(this);
|
||||
jo.enableBlocklink = true;
|
||||
jo.optimizeGatherPipe = false;
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ void JitArm::mtspr(UGeckoInstruction inst)
|
||||
JITDISABLE(SystemRegisters)
|
||||
|
||||
u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
ARMReg RD = gpr.R(inst.RD);
|
||||
|
||||
switch (iIndex)
|
||||
{
|
||||
@ -70,6 +69,7 @@ void JitArm::mtspr(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
// OK, this is easy.
|
||||
ARMReg RD = gpr.R(inst.RD);
|
||||
STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4);
|
||||
}
|
||||
void JitArm::mftb(UGeckoInstruction inst)
|
||||
@ -115,7 +115,6 @@ void JitArm::mfmsr(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(SystemRegisters)
|
||||
Default(inst); return;
|
||||
|
||||
LDR(gpr.R(inst.RD), R9, PPCSTATE_OFF(msr));
|
||||
}
|
||||
|
@ -28,13 +28,7 @@ void ArmRegCache::Init(ARMXEmitter *emitter)
|
||||
emit = emitter;
|
||||
ARMReg *PPCRegs = GetPPCAllocationOrder(NUMPPCREG);
|
||||
ARMReg *Regs = GetAllocationOrder(NUMARMREG);
|
||||
for(u8 a = 0; a < 32; ++a)
|
||||
{
|
||||
// This gives us the memory locations of the gpr registers so we can
|
||||
// load them.
|
||||
regs[a].location = (u8*)&PowerPC::ppcState.gpr[a];
|
||||
regs[a].UsesLeft = 0;
|
||||
}
|
||||
|
||||
for(u8 a = 0; a < NUMPPCREG; ++a)
|
||||
{
|
||||
ArmCRegs[a].PPCReg = 33;
|
||||
@ -49,14 +43,8 @@ void ArmRegCache::Init(ARMXEmitter *emitter)
|
||||
}
|
||||
void ArmRegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||
{
|
||||
for(u8 a = 0; a < NUMPPCREG; ++a)
|
||||
{
|
||||
ArmCRegs[a].PPCReg = 33;
|
||||
ArmCRegs[a].LastLoad = 0;
|
||||
}
|
||||
for(u8 a = 0; a < 32; ++a)
|
||||
regs[a].UsesLeft = stats.GetTotalNumAccesses(a);
|
||||
}
|
||||
|
||||
ARMReg *ArmRegCache::GetPPCAllocationOrder(int &count)
|
||||
{
|
||||
// This will return us the allocation order of the registers we can use on
|
||||
@ -94,16 +82,7 @@ ARMReg ArmRegCache::GetReg(bool AutoLock)
|
||||
_assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb");
|
||||
return R0;
|
||||
}
|
||||
void ArmRegCache::Lock(ARMReg Reg)
|
||||
{
|
||||
for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum)
|
||||
if(ArmRegs[RegNum].Reg == Reg)
|
||||
{
|
||||
_assert_msg_(_DYNA_REC, ArmRegs[RegNum].free, "This register is already locked");
|
||||
ArmRegs[RegNum].free = false;
|
||||
}
|
||||
_assert_msg_(_DYNA_REC, false, "Register %d can't be used with lock", Reg);
|
||||
}
|
||||
|
||||
void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3)
|
||||
{
|
||||
for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum)
|
||||
@ -118,51 +97,115 @@ void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3)
|
||||
if( R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3) ArmRegs[RegNum].free = true;
|
||||
}
|
||||
}
|
||||
|
||||
ARMReg ArmRegCache::R(u32 preg)
|
||||
u32 ArmRegCache::GetLeastUsedRegister(bool increment)
|
||||
{
|
||||
u32 HighestUsed = 0;
|
||||
u8 Num = 0;
|
||||
u8 lastRegIndex = 0;
|
||||
for(u8 a = 0; a < NUMPPCREG; ++a){
|
||||
++ArmCRegs[a].LastLoad;
|
||||
if (increment)
|
||||
++ArmCRegs[a].LastLoad;
|
||||
if (ArmCRegs[a].LastLoad > HighestUsed)
|
||||
{
|
||||
HighestUsed = ArmCRegs[a].LastLoad;
|
||||
Num = a;
|
||||
lastRegIndex = a;
|
||||
}
|
||||
}
|
||||
// Check if already Loaded
|
||||
for(u8 a = 0; a < NUMPPCREG; ++a)
|
||||
if (ArmCRegs[a].PPCReg == preg)
|
||||
{
|
||||
ArmCRegs[a].LastLoad = 0;
|
||||
return ArmCRegs[a].Reg;
|
||||
}
|
||||
// Check if we have a free register
|
||||
return lastRegIndex;
|
||||
}
|
||||
bool ArmRegCache::FindFreeRegister(u32 ®index)
|
||||
{
|
||||
for (u8 a = 0; a < NUMPPCREG; ++a)
|
||||
if (ArmCRegs[a].PPCReg == 33)
|
||||
{
|
||||
emit->LDR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
|
||||
ArmCRegs[a].PPCReg = preg;
|
||||
ArmCRegs[a].LastLoad = 0;
|
||||
return ArmCRegs[a].Reg;
|
||||
regindex = a;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ARMReg ArmRegCache::R(u32 preg)
|
||||
{
|
||||
if (regs[preg].GetType() == REG_IMM)
|
||||
{
|
||||
return BindToRegister(preg);
|
||||
//asm ("bkpt #1;");
|
||||
}
|
||||
u32 lastRegIndex = GetLeastUsedRegister(true);
|
||||
|
||||
// Check if already Loaded
|
||||
if(regs[preg].GetType() == REG_REG)
|
||||
{
|
||||
u8 a = regs[preg].GetRegIndex();
|
||||
ArmCRegs[a].LastLoad = 0;
|
||||
return ArmCRegs[a].Reg;
|
||||
}
|
||||
|
||||
// Check if we have a free register
|
||||
u32 regindex;
|
||||
if (FindFreeRegister(regindex))
|
||||
{
|
||||
emit->LDR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
|
||||
ArmCRegs[regindex].PPCReg = preg;
|
||||
ArmCRegs[regindex].LastLoad = 0;
|
||||
|
||||
regs[preg].LoadToReg(regindex);
|
||||
return ArmCRegs[regindex].Reg;
|
||||
}
|
||||
|
||||
// Alright, we couldn't get a free space, dump that least used register
|
||||
emit->STR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[Num].PPCReg * 4);
|
||||
emit->LDR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
|
||||
ArmCRegs[Num].PPCReg = preg;
|
||||
ArmCRegs[Num].LastLoad = 0;
|
||||
return ArmCRegs[Num].Reg;
|
||||
emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4);
|
||||
emit->LDR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
|
||||
|
||||
regs[ArmCRegs[lastRegIndex].PPCReg].Flush();
|
||||
|
||||
ArmCRegs[lastRegIndex].PPCReg = preg;
|
||||
ArmCRegs[lastRegIndex].LastLoad = 0;
|
||||
|
||||
regs[preg].LoadToReg(lastRegIndex);
|
||||
|
||||
return ArmCRegs[lastRegIndex].Reg;
|
||||
}
|
||||
|
||||
ARMReg ArmRegCache::BindToRegister(u32 preg)
|
||||
{
|
||||
_assert_msg_(DYNA_REC, regs[preg].GetType() == REG_IMM, "Can't BindToRegister with a REG");
|
||||
u32 lastRegIndex = GetLeastUsedRegister(false);
|
||||
u32 freeRegIndex;
|
||||
if (FindFreeRegister(freeRegIndex))
|
||||
{
|
||||
emit->MOVI2R(ArmCRegs[freeRegIndex].Reg, regs[preg].GetImm());
|
||||
ArmCRegs[freeRegIndex].PPCReg = preg;
|
||||
ArmCRegs[freeRegIndex].LastLoad = 0;
|
||||
regs[preg].LoadToReg(freeRegIndex);
|
||||
return ArmCRegs[freeRegIndex].Reg;
|
||||
}
|
||||
else
|
||||
{
|
||||
emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4);
|
||||
emit->MOVI2R(ArmCRegs[lastRegIndex].Reg, regs[preg].GetImm());
|
||||
ArmCRegs[lastRegIndex].PPCReg = preg;
|
||||
ArmCRegs[lastRegIndex].LastLoad = 0;
|
||||
regs[preg].LoadToReg(lastRegIndex);
|
||||
return ArmCRegs[lastRegIndex].Reg;
|
||||
}
|
||||
}
|
||||
|
||||
void ArmRegCache::Flush()
|
||||
{
|
||||
for(u8 a = 0; a < NUMPPCREG; ++a)
|
||||
if (ArmCRegs[a].PPCReg != 33)
|
||||
for (u8 a = 0; a < 32; ++a)
|
||||
{
|
||||
if (regs[a].GetType() == REG_IMM)
|
||||
BindToRegister(a);
|
||||
if (regs[a].GetType() == REG_REG)
|
||||
{
|
||||
emit->STR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[a].PPCReg * 4);
|
||||
ArmCRegs[a].PPCReg = 33;
|
||||
ArmCRegs[a].LastLoad = 0;
|
||||
u32 regindex = regs[a].GetRegIndex();
|
||||
emit->STR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + a * 4);
|
||||
ArmCRegs[regindex].PPCReg = 33;
|
||||
ArmCRegs[regindex].LastLoad = 0;
|
||||
|
||||
}
|
||||
|
||||
regs[a].Flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,61 @@ using namespace ArmGen;
|
||||
// it
|
||||
// So we have R14, R12, R11, R10 to work with instructions
|
||||
|
||||
struct PPCCachedReg
|
||||
enum RegType
|
||||
{
|
||||
const u8 *location;
|
||||
u32 UsesLeft;
|
||||
REG_NOTLOADED = 0,
|
||||
REG_REG,
|
||||
REG_IMM,
|
||||
};
|
||||
|
||||
class OpArg
|
||||
{
|
||||
private:
|
||||
class Reg{
|
||||
public:
|
||||
RegType m_type;
|
||||
u8 m_reg; // index to register
|
||||
u32 m_value;
|
||||
Reg()
|
||||
{
|
||||
m_type = REG_NOTLOADED;
|
||||
m_reg = 33;
|
||||
m_value = 0;
|
||||
}
|
||||
} Reg;
|
||||
|
||||
public:
|
||||
OpArg(){}
|
||||
|
||||
RegType GetType()
|
||||
{
|
||||
return Reg.m_type;
|
||||
}
|
||||
|
||||
u8 GetRegIndex()
|
||||
{
|
||||
return Reg.m_reg;
|
||||
}
|
||||
u32 GetImm()
|
||||
{
|
||||
return Reg.m_value;
|
||||
}
|
||||
void LoadToReg(u8 reg)
|
||||
{
|
||||
Reg.m_type = REG_REG;
|
||||
Reg.m_reg = reg;
|
||||
}
|
||||
void LoadToImm(u32 imm)
|
||||
{
|
||||
Reg.m_type = REG_IMM;
|
||||
Reg.m_value = imm;
|
||||
}
|
||||
void Flush()
|
||||
{
|
||||
Reg.m_type = REG_NOTLOADED;
|
||||
}
|
||||
};
|
||||
|
||||
struct JRCPPC
|
||||
{
|
||||
u32 PPCReg; // Tied to which PPC Register
|
||||
@ -55,7 +105,7 @@ struct JRCReg
|
||||
class ArmRegCache
|
||||
{
|
||||
private:
|
||||
PPCCachedReg regs[32];
|
||||
OpArg regs[32];
|
||||
JRCPPC ArmCRegs[ARMREGS];
|
||||
JRCReg ArmRegs[ARMREGS]; // Four registers remaining
|
||||
|
||||
@ -64,7 +114,9 @@ private:
|
||||
|
||||
ARMReg *GetAllocationOrder(int &count);
|
||||
ARMReg *GetPPCAllocationOrder(int &count);
|
||||
|
||||
|
||||
u32 GetLeastUsedRegister(bool increment);
|
||||
bool FindFreeRegister(u32 ®index);
|
||||
protected:
|
||||
ARMXEmitter *emit;
|
||||
|
||||
@ -74,16 +126,16 @@ public:
|
||||
|
||||
void Init(ARMXEmitter *emitter);
|
||||
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||
|
||||
void SetEmitter(ARMXEmitter *emitter) {emit = emitter;}
|
||||
|
||||
ARMReg GetReg(bool AutoLock = true); // Return a ARM register we can use.
|
||||
void Lock(ARMReg reg);
|
||||
void Unlock(ARMReg R0, ARMReg R1 = INVALID_REG, ARMReg R2 = INVALID_REG, ARMReg R3 =
|
||||
INVALID_REG);
|
||||
void Flush();
|
||||
ARMReg R(u32 preg); // Returns a cached register
|
||||
|
||||
bool IsImm(u32 preg) { return regs[preg].GetType() == REG_IMM; }
|
||||
u32 GetImm(u32 preg) { return regs[preg].GetImm(); }
|
||||
void SetImmediate(u32 preg, u32 imm) { regs[preg].LoadToImm(imm); }
|
||||
ARMReg BindToRegister(u32 preg);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user