mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-30 01:29:42 -06:00
Make the (V)LDR/(V)STR instructions support negative offsets. This fixes a bug where Arm Jit couldn't load the top 33 FPRs. Also makes it so the core can access all GPRs, FPRs, and SPRs in ppcState. This increases VPS 15-20 on SSBM intro movie on ODROIDX
This commit is contained in:
@ -533,15 +533,15 @@ void ARMXEmitter::MRS (ARMReg dest)
|
||||
Write32(condition | (16 << 20) | (15 << 16) | (dest << 12));
|
||||
}
|
||||
|
||||
void ARMXEmitter::WriteStoreOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2)
|
||||
void ARMXEmitter::WriteStoreOp(u32 op, ARMReg dest, ARMReg src, s16 op2)
|
||||
{
|
||||
if (op2.GetData() == 0) // set the preindex bit, but not the W bit!
|
||||
Write32(condition | 0x01800000 | (op << 20) | (dest << 16) | (src << 12) | op2.Imm12());
|
||||
else
|
||||
Write32(condition | (op << 20) | (3 << 23) | (dest << 16) | (src << 12) | op2.Imm12());
|
||||
bool Index = op2 != 0 ? true : false;
|
||||
bool Add = op2 >= 0 ? true : false;
|
||||
u32 imm = abs(op2);
|
||||
Write32(condition | (op << 20) | (Index << 24) | (Add << 23) | (dest << 16) | (src << 12) | imm);
|
||||
}
|
||||
void ARMXEmitter::STR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x40, dest, src, op);}
|
||||
void ARMXEmitter::STRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x44, dest, src, op);}
|
||||
void ARMXEmitter::STR (ARMReg dest, ARMReg src, s16 op) { WriteStoreOp(0x40, dest, src, op);}
|
||||
void ARMXEmitter::STRB(ARMReg dest, ARMReg src, s16 op) { WriteStoreOp(0x44, dest, src, op);}
|
||||
void ARMXEmitter::STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add)
|
||||
{
|
||||
Write32(condition | (0x60 << 20) | (Index << 24) | (Add << 23) | (dest << 16) | (base << 12) | offset);
|
||||
@ -564,13 +564,13 @@ void ARMXEmitter::SVC(Operand2 op)
|
||||
Write32(condition | (0x0F << 24) | op.Imm24());
|
||||
}
|
||||
|
||||
void ARMXEmitter::LDR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x41, src, dest, op);}
|
||||
void ARMXEmitter::LDR (ARMReg dest, ARMReg src, s16 op) { WriteStoreOp(0x41, src, dest, op);}
|
||||
void ARMXEmitter::LDRH(ARMReg dest, ARMReg src, Operand2 op)
|
||||
{
|
||||
u8 Imm = op.Imm8();
|
||||
Write32(condition | (0x05 << 20) | (src << 16) | (dest << 12) | ((Imm >> 4) << 8) | (0xB << 4) | (Imm & 0x0F));
|
||||
}
|
||||
void ARMXEmitter::LDRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x45, src, dest, op);}
|
||||
void ARMXEmitter::LDRB(ARMReg dest, ARMReg src, s16 op) { WriteStoreOp(0x45, src, dest, op);}
|
||||
|
||||
void ARMXEmitter::LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add)
|
||||
{
|
||||
@ -661,14 +661,18 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
|
||||
// VFP Specific
|
||||
|
||||
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, u16 offset)
|
||||
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR");
|
||||
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR");
|
||||
_assert_msg_(DYNA_REC, (offset & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough");
|
||||
|
||||
if (offset & 0xC03) {
|
||||
ERROR_LOG(DYNA_REC, "VLDR: Bad offset %08x", offset);
|
||||
bool Add = offset >= 0 ? true : false;
|
||||
u32 imm = abs(offset);
|
||||
|
||||
_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough");
|
||||
|
||||
if (imm & 0xC03) {
|
||||
ERROR_LOG(DYNA_REC, "VLDR: Bad offset %08x", imm);
|
||||
}
|
||||
|
||||
bool single_reg = Dest < D0;
|
||||
@ -677,24 +681,28 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, u16 offset)
|
||||
|
||||
if (single_reg)
|
||||
{
|
||||
Write32(NO_COND | (0x1B << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \
|
||||
| ((Dest & 0x1E) << 11) | (10 << 8) | (offset >> 2));
|
||||
Write32(NO_COND | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \
|
||||
| ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Write32(NO_COND | (0x1B << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \
|
||||
| ((Dest & 0xF) << 12) | (11 << 8) | (offset >> 2));
|
||||
Write32(NO_COND | (0xD << 24) | (Add << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \
|
||||
| ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2));
|
||||
}
|
||||
}
|
||||
void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, u16 offset)
|
||||
void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset)
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR");
|
||||
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR");
|
||||
_assert_msg_(DYNA_REC, (offset & 0xC03) == 0, "VSTR: Offset needs to be word aligned");
|
||||
|
||||
if (offset & 0xC03) {
|
||||
ERROR_LOG(DYNA_REC, "VSTR: Bad offset %08x", offset);
|
||||
bool Add = offset >= 0 ? true : false;
|
||||
u32 imm = abs(offset);
|
||||
|
||||
_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough");
|
||||
|
||||
if (imm & 0xC03) {
|
||||
ERROR_LOG(DYNA_REC, "VSTR: Bad offset %08x", imm);
|
||||
}
|
||||
|
||||
bool single_reg = Src < D0;
|
||||
@ -703,14 +711,14 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, u16 offset)
|
||||
|
||||
if (single_reg)
|
||||
{
|
||||
Write32(NO_COND | (0x1B << 23) | ((Src & 0x1) << 22) | (Base << 16) \
|
||||
| ((Src & 0x1E) << 11) | (10 << 8) | (offset >> 2));
|
||||
Write32(NO_COND | (0xD << 24) | (Add << 23) | ((Src & 0x1) << 22) | (Base << 16) \
|
||||
| ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Write32(NO_COND | (0x1B << 23) | ((Src & 0x10) << 18) | (Base << 16) \
|
||||
| ((Src & 0xF) << 12) | (11 << 8) | (offset >> 2));
|
||||
Write32(NO_COND | (0xD << 24) | (Add << 23) | ((Src & 0x10) << 18) | (Base << 16) \
|
||||
| ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2));
|
||||
}
|
||||
}
|
||||
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm)
|
||||
|
@ -208,7 +208,7 @@ public:
|
||||
Value = base;
|
||||
Type = TYPE_IMMSREG;
|
||||
}
|
||||
const u32 GetData()
|
||||
u32 GetData()
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
@ -225,45 +225,45 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const u32 IMMSR() // IMM shifted register
|
||||
u32 IMMSR() // IMM shifted register
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
|
||||
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
|
||||
}
|
||||
const u32 RSR() // Register shifted register
|
||||
u32 RSR() // Register shifted register
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Type == TYPE_RSR, "RSR must be RSR Of Course");
|
||||
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
|
||||
}
|
||||
const u32 Rm()
|
||||
u32 Rm()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, Type == TYPE_REG, "Rm must be with Reg");
|
||||
return Value;
|
||||
}
|
||||
|
||||
const u32 Imm5()
|
||||
u32 Imm5()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm5 not IMM value");
|
||||
return ((Value & 0x0000001F) << 7);
|
||||
}
|
||||
const u32 Imm8()
|
||||
u32 Imm8()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
|
||||
return Value & 0xFF;
|
||||
}
|
||||
const u32 Imm8Rot() // IMM8 with Rotation
|
||||
u32 Imm8Rot() // IMM8 with Rotation
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
|
||||
_assert_msg_(DYNA_REC, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
|
||||
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
|
||||
}
|
||||
const u32 Imm12()
|
||||
u32 Imm12()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12 not IMM");
|
||||
return (Value & 0x00000FFF);
|
||||
}
|
||||
|
||||
const u32 Imm12Mod()
|
||||
u32 Imm12Mod()
|
||||
{
|
||||
// This is a IMM12 with the top four bits being rotation and the
|
||||
// bottom eight being a IMM. This is for instructions that need to
|
||||
@ -273,32 +273,32 @@ public:
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12Mod not IMM");
|
||||
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
|
||||
}
|
||||
const u32 Imm16()
|
||||
u32 Imm16()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
|
||||
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
|
||||
}
|
||||
const u32 Imm16Low()
|
||||
u32 Imm16Low()
|
||||
{
|
||||
return Imm16();
|
||||
}
|
||||
const u32 Imm16High() // Returns high 16bits
|
||||
u32 Imm16High() // Returns high 16bits
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
|
||||
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
|
||||
}
|
||||
const u32 Imm24()
|
||||
u32 Imm24()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
|
||||
return (Value & 0x0FFFFFFF);
|
||||
}
|
||||
// NEON and ASIMD specific
|
||||
const u32 Imm8ASIMD()
|
||||
u32 Imm8ASIMD()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8ASIMD not IMM");
|
||||
return ((Value & 0x80) << 17) | ((Value & 0x70) << 12) | (Value & 0xF);
|
||||
}
|
||||
const u32 Imm8VFP()
|
||||
u32 Imm8VFP()
|
||||
{
|
||||
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8VFP not IMM");
|
||||
return ((Value & 0xF0) << 12) | (Value & 0xF);
|
||||
@ -337,7 +337,7 @@ private:
|
||||
u8 *lastCacheFlushEnd;
|
||||
u32 condition;
|
||||
|
||||
void WriteStoreOp(u32 op, ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void WriteStoreOp(u32 op, ARMReg dest, ARMReg src, s16 op2);
|
||||
void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList);
|
||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
|
||||
@ -467,16 +467,16 @@ public:
|
||||
void MRS (ARMReg dest);
|
||||
|
||||
// Memory load/store operations
|
||||
void LDR (ARMReg dest, ARMReg src, Operand2 op2 = 0);
|
||||
void LDR (ARMReg dest, ARMReg src, s16 op2 = 0);
|
||||
// Offset adds to the base register in LDR
|
||||
void LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
|
||||
void LDRH(ARMReg dest, ARMReg src, Operand2 op = 0);
|
||||
void LDRB(ARMReg dest, ARMReg src, Operand2 op2 = 0);
|
||||
void STR (ARMReg dest, ARMReg src, Operand2 op2 = 0);
|
||||
void LDRB(ARMReg dest, ARMReg src, s16 op2 = 0);
|
||||
void STR (ARMReg dest, ARMReg src, s16 op2 = 0);
|
||||
// Offset adds on to the destination register in STR
|
||||
void STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
|
||||
|
||||
void STRB(ARMReg dest, ARMReg src, Operand2 op2 = 0);
|
||||
void STRB(ARMReg dest, ARMReg src, s16 op2 = 0);
|
||||
void STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
|
||||
void LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
|
||||
|
||||
@ -499,8 +499,8 @@ public:
|
||||
void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
|
||||
// VFP Only
|
||||
void VLDR(ARMReg Dest, ARMReg Base, u16 offset);
|
||||
void VSTR(ARMReg Src, ARMReg Base, u16 offset);
|
||||
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
|
||||
void VSTR(ARMReg Src, ARMReg Base, s16 offset);
|
||||
void VCMP(ARMReg Vd, ARMReg Vm);
|
||||
// Compares against zero
|
||||
void VCMP(ARMReg Vd);
|
||||
|
Reference in New Issue
Block a user