Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Make the (V)LDR/(V)STR instructions support negative offsets. This fi…
…xes 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
  • Loading branch information
Sonicadvance1 committed Mar 6, 2013
1 parent 2095641 commit d6558e1
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 136 deletions.
58 changes: 33 additions & 25 deletions Source/Core/Common/Src/ArmEmitter.cpp
Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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)
Expand Down
44 changes: 22 additions & 22 deletions Source/Core/Common/Src/ArmEmitter.h
Expand Up @@ -208,7 +208,7 @@ class Operand2
Value = base;
Type = TYPE_IMMSREG;
}
const u32 GetData()
u32 GetData()
{
switch(Type)
{
Expand All @@ -225,45 +225,45 @@ class Operand2
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
Expand All @@ -273,32 +273,32 @@ class Operand2
_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);
Expand Down Expand Up @@ -337,7 +337,7 @@ class ARMXEmitter
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);
Expand Down Expand Up @@ -467,16 +467,16 @@ class ARMXEmitter
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, ...);

Expand All @@ -499,8 +499,8 @@ class ARMXEmitter
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);
Expand Down
13 changes: 6 additions & 7 deletions Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp
Expand Up @@ -100,7 +100,7 @@ void JitArm::HLEFunction(UGeckoInstruction _inst)
MOVI2R(R1, _inst.hex);
QuickCallFunction(R14, (void*)&HLE::Execute);
ARMReg rA = gpr.GetReg();
LDR(rA, R9, STRUCT_OFF(PowerPC::ppcState, npc));
LDR(rA, R9, PPCSTATE_OFF(PowerPC::ppcState, npc));
WriteExitDestInR(rA);
}

Expand Down Expand Up @@ -161,7 +161,7 @@ void JitArm::DoDownCount()
}
void JitArm::WriteExitDestInR(ARMReg Reg)
{
STR(R9, Reg, STRUCT_OFF(PowerPC::ppcState, pc));
STR(R9, Reg, PPCSTATE_OFF(PowerPC::ppcState, pc));
Cleanup();
DoDownCount();
MOVI2R(Reg, (u32)asm_routines.dispatcher);
Expand All @@ -170,7 +170,7 @@ void JitArm::WriteExitDestInR(ARMReg Reg)
}
void JitArm::WriteRfiExitDestInR(ARMReg Reg)
{
STR(R9, Reg, STRUCT_OFF(PowerPC::ppcState, pc));
STR(R9, Reg, PPCSTATE_OFF(PowerPC::ppcState, pc));
Cleanup();
DoDownCount();

Expand Down Expand Up @@ -209,7 +209,7 @@ void JitArm::WriteExit(u32 destination, int exit_num)
{
ARMReg A = gpr.GetReg(false);
MOVI2R(A, destination);
STR(R9, A, STRUCT_OFF(PowerPC::ppcState, pc));
STR(R9, A, PPCSTATE_OFF(PowerPC::ppcState, pc));
MOVI2R(A, (u32)asm_routines.dispatcher);
B(A);
}
Expand Down Expand Up @@ -303,7 +303,6 @@ void JitArm::Break(UGeckoInstruction inst)
const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b)
{
int blockSize = code_buf->GetSize();

// Memory exception on instruction fetch
bool memory_exception = false;

Expand Down Expand Up @@ -382,10 +381,10 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
ARMReg C = gpr.GetReg();
Operand2 Shift(2, 10); // 1 << 13
MOVI2R(C, js.blockStart); // R3
LDR(A, R9, STRUCT_OFF(PowerPC::ppcState, msr));
LDR(A, R9, PPCSTATE_OFF(PowerPC::ppcState, msr));
TST(A, Shift);
FixupBranch b1 = B_CC(CC_NEQ);
STR(R9, C, STRUCT_OFF(PowerPC::ppcState, pc));
STR(R9, C, PPCSTATE_OFF(PowerPC::ppcState, pc));
MOVI2R(A, (u32)asm_routines.fpException);
B(A);
SetJumpTarget(b1);
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/JitArm32/Jit.h
Expand Up @@ -47,7 +47,7 @@
if (Core::g_CoreStartupParameter.bJITOff || \
Core::g_CoreStartupParameter.bJIT##type##Off) \
{Default(inst); return;}

#define PPCSTATE_OFF(str, elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0]))
class JitArm : public JitBase, public ArmGen::ARMXCodeBlock
{
private:
Expand Down
3 changes: 1 addition & 2 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArmCache.cpp
Expand Up @@ -36,10 +36,9 @@ using namespace ArmGen;
void JitArmBlockCache::WriteDestroyBlock(const u8* location, u32 address)
{
ARMXEmitter emit((u8 *)location);
emit.MOVI2R(R10, (u32)&PC);
emit.MOVI2R(R11, address);
emit.MOVI2R(R12, (u32)jit->GetAsmRoutines()->dispatcher);
emit.STR(R10, R11);
emit.STR(R9, R11, PPCSTATE_OFF(PowerPC::ppcState, pc));
emit.B(R12);
}

Expand Down

0 comments on commit d6558e1

Please sign in to comment.