ARMJIT: Fix and use DIV, DIVU, INS and EXT (ARMv7 and VFPv4 implementations).

This commit is contained in:
Sacha 2013-05-24 08:26:19 +10:00
parent 3587cef738
commit a14a2fafa9
2 changed files with 40 additions and 19 deletions

View file

@ -1156,13 +1156,39 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags)
{
bool single_reg = (Dest < D0) && (Source < D0);
bool single_double = !single_reg && (Source < D0 || Dest < D0);
bool single_to_double = Source < D0;
int op = ((flags & TO_INT) ? (flags & ROUND_TO_ZERO) : (flags & IS_SIGNED)) ? 1 : 0;
int op2 = ((flags & TO_INT) ? (flags & IS_SIGNED) : 0) ? 1 : 0;
Dest = SubBase(Dest);
Source = SubBase(Source);
if (single_reg)
if (single_double)
{
// S32<->F64
if ((flags & TO_INT) || (flags & TO_FLOAT))
{
if (single_to_double)
{
Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) \
| ((Dest & 0xF) << 12) | (op << 7) | (0x2D << 6) | ((Source & 0x1) << 5) | (Source >> 1));
} else {
Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \
| ((Dest & 0x1E) << 11) | (op << 7) | (0x2D << 6) | ((Source & 0x10) << 1) | (Source & 0xF));
}
}
// F32<->F64
else {
if (single_to_double)
{
Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | (0x7 << 16) \
| ((Dest & 0xF) << 12) | (0x2F << 6) | ((Source & 0x1) << 5) | (Source >> 1));
} else {
Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | (0x7 << 16) \
| ((Dest & 0x1E) << 11) | (0x2B << 6) | ((Source & 0x10) << 1) | (Source & 0xF));
}
}
} else if (single_reg) {
Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \
| ((Dest & 0x1E) << 11) | (op << 7) | (0x29 << 6) | ((Source & 0x1) << 5) | (Source >> 1));
} else {

View file

@ -382,12 +382,6 @@ namespace MIPSComp
void Jit::Comp_Special3(u32 op)
{
CONDITIONAL_DISABLE;
bool useUBFXandBFI = false;
if (!cpu_info.bArmV7) {
// useUBFXandBFI = true;
}
int rs = _RS;
int rt = _RT;
@ -409,11 +403,8 @@ namespace MIPSComp
return;
}
// Reported to break Disgaea.
DISABLE;
gpr.MapDirtyIn(rt, rs);
if (useUBFXandBFI) {
if (cpu_info.bArmV7) {
UBFX(gpr.R(rt), gpr.R(rs), pos, size);
} else {
MOV(gpr.R(rt), Operand2(gpr.R(rs), ST_LSR, pos));
@ -440,9 +431,9 @@ namespace MIPSComp
}
else
{
if (useUBFXandBFI) {
if (cpu_info.bArmV7) {
gpr.MapDirtyIn(rt, rs, false);
BFI(gpr.R(rt), gpr.R(rs), pos, size);
BFI(gpr.R(rt), gpr.R(rs), pos, size-pos);
} else {
gpr.MapDirtyIn(rt, rs, false);
ANDI2R(R0, gpr.R(rs), sourcemask, R1);
@ -554,40 +545,44 @@ namespace MIPSComp
break;
case 26: //div
DISABLE;
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
if (cpu_info.bIDIVa)
{
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
SDIV(gpr.R(MIPSREG_LO), gpr.R(rs), gpr.R(rt));
MUL(R0, gpr.R(rt), gpr.R(MIPSREG_LO));
SUB(gpr.R(MIPSREG_HI), gpr.R(rs), Operand2(R0));
} else {
DISABLE;
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
VMOV(S0, gpr.R(rs));
VMOV(S1, gpr.R(rt));
VCVT(D0, S0, TO_FLOAT | IS_SIGNED);
VCVT(D1, S1, TO_FLOAT | IS_SIGNED);
VDIV(D0, D0, D1);
VCVT(gpr.R(MIPSREG_LO), D0, TO_INT | IS_SIGNED);
VCVT(S0, D0, TO_INT);
VMOV(gpr.R(MIPSREG_LO), S0);
MUL(R0, gpr.R(rt), gpr.R(MIPSREG_LO));
SUB(gpr.R(MIPSREG_HI), gpr.R(rs), Operand2(R0));
}
break;
case 27: //divu
DISABLE;
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
if (cpu_info.bIDIVa)
{
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
UDIV(gpr.R(MIPSREG_LO), gpr.R(rs), gpr.R(rt));
MUL(R0, gpr.R(rt), gpr.R(MIPSREG_LO));
SUB(gpr.R(MIPSREG_HI), gpr.R(rs), Operand2(R0));
} else {
DISABLE;
gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt);
VMOV(S0, gpr.R(rs));
VMOV(S1, gpr.R(rt));
VCVT(D0, S0, TO_FLOAT);
VCVT(D1, S1, TO_FLOAT);
VDIV(D0, D0, D1);
VCVT(gpr.R(MIPSREG_LO), D0, TO_INT);
VCVT(S0, D0, TO_INT);
VMOV(gpr.R(MIPSREG_LO), S0);
MUL(R0, gpr.R(rt), gpr.R(MIPSREG_LO));
SUB(gpr.R(MIPSREG_HI), gpr.R(rs), Operand2(R0));
}