Merge pull request #2891 from Sonicadvance1/aarch64_implement_crxxx

[AArch64] Implement the cr instructions
This commit is contained in:
Markus Wick 2015-08-23 00:44:47 +02:00
commit 8b881a6c34
3 changed files with 215 additions and 8 deletions

View File

@ -112,6 +112,7 @@ public:
void mfspr(UGeckoInstruction inst);
void mftb(UGeckoInstruction inst);
void mtspr(UGeckoInstruction inst);
void crXXX(UGeckoInstruction inst);
// LoadStore
void lXX(UGeckoInstruction inst);

View File

@ -373,3 +373,209 @@ void JitArm64::mtspr(UGeckoInstruction inst)
ARM64Reg RD = gpr.R(inst.RD);
STR(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(spr) + iIndex * 4);
}
void JitArm64::crXXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITSystemRegistersOff);
// Special case: crclr
if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 193)
{
// Clear CR field bit
int field = inst.CRBD >> 2;
int bit = 3 - (inst.CRBD & 3);
ARM64Reg WA = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);
LDR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
switch (bit)
{
case CR_SO_BIT:
AND(XA, XA, 64 - 62, 62, true); // XA & ~(1<<61)
break;
case CR_EQ_BIT:
ORR(XA, XA, 0, 0, true); // XA | 1<<0
break;
case CR_GT_BIT:
ORR(XA, XA, 64 - 63, 0, true); // XA | 1<<63
break;
case CR_LT_BIT:
AND(XA, XA, 64 - 63, 62, true); // XA & ~(1<<62)
break;
}
STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
gpr.Unlock(WA);
return;
}
// Special case: crset
if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289)
{
// SetCRFieldBit
int field = inst.CRBD >> 2;
int bit = 3 - (inst.CRBD & 3);
ARM64Reg WA = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);
LDR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
if (bit != CR_GT_BIT)
{
ARM64Reg WB = gpr.GetReg();
ARM64Reg XB = EncodeRegTo64(WB);
ORR(XB, XA, 64 - 63, 0, true); // XA | 1<<63
CMP(XA, ZR);
CSEL(XA, XA, XB, CC_NEQ);
gpr.Unlock(WB);
}
switch (bit)
{
case CR_SO_BIT:
ORR(XA, XA, 64 - 61, 0, true); // XA | 1<<61
break;
case CR_EQ_BIT:
AND(XA, XA, 32, 31, true); // Clear lower 32bits
break;
case CR_GT_BIT:
AND(XA, XA, 0, 62, true); // XA & ~(1<<63)
break;
case CR_LT_BIT:
ORR(XA, XA, 64 - 62, 0, true); // XA | 1<<62
break;
}
ORR(XA, XA, 32, 0, true); // XA | 1<<32
STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val) + 8 * field);
gpr.Unlock(WA);
return;
}
ARM64Reg WA = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg WB = gpr.GetReg();
ARM64Reg XB = EncodeRegTo64(WB);
// creqv or crnand or crnor
bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
// crandc or crorc or crnand or crnor
bool negateB = inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
// GetCRFieldBit
for (int i = 0; i < 2; i++)
{
int field = i ? inst.CRBB >> 2 : inst.CRBA >> 2;
int bit = i ? 3 - (inst.CRBB & 3) : 3 - (inst.CRBA & 3);
ARM64Reg out = i ? XB : XA;
bool negate = i ? negateB : negateA;
ARM64Reg WC = gpr.GetReg();
ARM64Reg XC = EncodeRegTo64(WC);
LDR(INDEX_UNSIGNED, XC, X29, PPCSTATE_OFF(cr_val) + 8 * field);
switch (bit)
{
case CR_SO_BIT: // check bit 61 set
UBFX(out, XC, 61, 1);
if (negate)
EOR(out, out, 0, 0, true); // XC ^ 1
break;
case CR_EQ_BIT: // check bits 31-0 == 0
CMP(WC, WZR);
CSET(out, negate ? CC_NEQ : CC_EQ);
break;
case CR_GT_BIT: // check val > 0
CMP(XC, ZR);
CSET(out, negate ? CC_LE : CC_GT);
break;
case CR_LT_BIT: // check bit 62 set
UBFX(out, XC, 62, 1);
if (negate)
EOR(out, out, 0, 0, true); // XC ^ 1
break;
default:
_assert_msg_(DYNA_REC, false, "Invalid CR bit");
}
gpr.Unlock(WC);
}
// Compute combined bit
switch (inst.SUBOP10)
{
case 33: // crnor: ~(A || B) == (~A && ~B)
case 129: // crandc: A && ~B
case 257: // crand: A && B
AND(XA, XA, XB);
break;
case 193: // crxor: A ^ B
case 289: // creqv: ~(A ^ B) = ~A ^ B
EOR(XA, XA, XB);
break;
case 225: // crnand: ~(A && B) == (~A || ~B)
case 417: // crorc: A || ~B
case 449: // cror: A || B
ORR(XA, XA, XB);
break;
}
// Store result bit in CRBD
int field = inst.CRBD >> 2;
int bit = 3 - (inst.CRBD & 3);
LDR(INDEX_UNSIGNED, XB, X29, PPCSTATE_OFF(cr_val) + 8 * field);
// Gross but necessary; if the input is totally zero and we set SO or LT,
// or even just add the (1<<32), GT will suddenly end up set without us
// intending to. This can break actual games, so fix it up.
if (bit != CR_GT_BIT)
{
ARM64Reg WC = gpr.GetReg();
ARM64Reg XC = EncodeRegTo64(WC);
ORR(XC, XB, 64 - 63, 0, true); // XB | 1<<63
CMP(XB, ZR);
CSEL(XB, XB, XC, CC_NEQ);
gpr.Unlock(WC);
}
switch (bit)
{
case CR_SO_BIT: // set bit 61 to input
BFI(XB, XA, 61, 1);
break;
case CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input
AND(XB, XB, 32, 31, true); // Clear lower 32bits
EOR(XA, XA, 0, 0); // XA ^ 1<<0
ORR(XB, XB, XA);
break;
case CR_GT_BIT: // set bit 63 to !input
EOR(XA, XA, 0, 0); // XA ^ 1<<0
BFI(XB, XA, 63, 1);
break;
case CR_LT_BIT: // set bit 62 to input
BFI(XB, XA, 62, 1);
break;
}
ORR(XA, XA, 32, 0, true); // XA | 1<<32
STR(INDEX_UNSIGNED, XB, X29, PPCSTATE_OFF(cr_val) + 8 * field);
gpr.Unlock(WA);
gpr.Unlock(WB);
}

View File

@ -152,14 +152,14 @@ static GekkoOPTemplate table19[] =
{
{528, &JitArm64::bcctrx}, // bcctrx
{16, &JitArm64::bclrx}, // bclrx
{257, &JitArm64::FallBackToInterpreter}, // crand
{129, &JitArm64::FallBackToInterpreter}, // crandc
{289, &JitArm64::FallBackToInterpreter}, // creqv
{225, &JitArm64::FallBackToInterpreter}, // crnand
{33, &JitArm64::FallBackToInterpreter}, // crnor
{449, &JitArm64::FallBackToInterpreter}, // cror
{417, &JitArm64::FallBackToInterpreter}, // crorc
{193, &JitArm64::FallBackToInterpreter}, // crxor
{257, &JitArm64::crXXX}, // crand
{129, &JitArm64::crXXX}, // crandc
{289, &JitArm64::crXXX}, // creqv
{225, &JitArm64::crXXX}, // crnand
{33, &JitArm64::crXXX}, // crnor
{449, &JitArm64::crXXX}, // cror
{417, &JitArm64::crXXX}, // crorc
{193, &JitArm64::crXXX}, // crxor
{150, &JitArm64::DoNothing}, // isync
{0, &JitArm64::mcrf}, // mcrf