diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index 47ccd22c4..d1a957485 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -453,6 +453,21 @@ void ARMXEmitter::MULS(ARMReg dest, ARMReg src, ARMReg op2) { Write32(condition | (1 << 20) | (dest << 16) | (src << 8) | (9 << 4) | op2); } + +void ARMXEmitter::Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) { + Write32(condition | (op << 20) | (destHi << 16) | (destLo << 12) | (rm << 8) | (9 << 4) | rn); +} + +void ARMXEmitter::UMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0x8, destLo, destHi, rn, rm); +} + +void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0xC, destLo, destHi, rn, rm); +} + void ARMXEmitter::SXTB (ARMReg dest, ARMReg op2) { Write32(condition | (0x6AF << 16) | (dest << 12) | (7 << 4) | op2); diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index 201b3b5c5..7585e9f35 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -333,6 +333,9 @@ private: void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2); void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2); + + void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + // New Ops void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false); @@ -439,6 +442,10 @@ public: void MUL (ARMReg dest, ARMReg src, ARMReg op2); void MULS(ARMReg dest, ARMReg src, ARMReg op2); + + void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void SXTB(ARMReg dest, ARMReg op2); void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0); void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0); diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 5fe97db48..934dbbe41 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -115,7 +115,6 @@ namespace MIPSComp case 11: // R(rt) = R(rs) < uimm; break; //sltiu { - LogBlockNumber(); gpr.MapDirtyIn(rt, rs); Operand2 op2; bool negated; @@ -310,7 +309,45 @@ namespace MIPSComp void Jit::Comp_MulDivType(u32 op) { - DISABLE; + // DISABLE; + int rt = _RT; + int rs = _RS; + int rd = _RD; + + switch (op & 63) + { + case 16: // R(rd) = HI; //mfhi + gpr.MapDirtyIn(rd, MIPSREG_HI); + MOV(gpr.R(rd), gpr.R(MIPSREG_HI)); + break; + + case 17: // HI = R(rs); //mthi + gpr.MapDirtyIn(MIPSREG_HI, rs); + MOV(gpr.R(MIPSREG_HI), gpr.R(rs)); + break; + + case 18: // R(rd) = LO; break; //mflo + gpr.MapDirtyIn(rd, MIPSREG_LO); + MOV(gpr.R(rd), gpr.R(MIPSREG_LO)); + break; + + case 19: // LO = R(rs); break; //mtlo + gpr.MapDirtyIn(MIPSREG_LO, rs); + MOV(gpr.R(MIPSREG_LO), gpr.R(rs)); + break; + + case 24: //mult (the most popular one). lo,hi = signed mul (rs * rt) + gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); + SMULL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); + break; + + case 25: //multu (2nd) lo,hi = unsigned mul (rs * rt) + gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); + UMULL(gpr.R(MIPSREG_LO), gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); + + default: + DISABLE; + } } } diff --git a/Core/MIPS/ARM/ArmRegCache.cpp b/Core/MIPS/ARM/ArmRegCache.cpp index 4b539787e..e62977daa 100644 --- a/Core/MIPS/ARM/ArmRegCache.cpp +++ b/Core/MIPS/ARM/ArmRegCache.cpp @@ -83,7 +83,7 @@ allocate: if (!(mapFlags & MAP_NOINIT)) { if (mr[mipsReg].loc == ML_MEM) { if (mipsReg != 0) { - emit->LDR((ARMReg)reg, CTXREG, 4 * mipsReg); + emit->LDR((ARMReg)reg, CTXREG, GetMipsRegOffset(mipsReg)); } else { // If we get a request to load the zero register, at least we won't spend // time on a memory access... @@ -148,6 +148,17 @@ void ArmRegCache::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoa ReleaseSpillLocks(); } +void ArmRegCache::MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad) { + SpillLock(rd1, rd2, rs, rt); + bool overlap1 = avoidLoad && (rd1 == rs || rd1 == rt); + bool overlap2 = avoidLoad && (rd2 == rs || rd2 == rt); + MapReg(rd1, MAP_DIRTY | (overlap1 ? 0 : MAP_NOINIT)); + MapReg(rd2, MAP_DIRTY | (overlap2 ? 0 : MAP_NOINIT)); + MapReg(rt); + MapReg(rs); + ReleaseSpillLocks(); +} + void ArmRegCache::FlushArmReg(ARMReg r) { if (ar[r].mipsReg == -1) { // Nothing to do, reg not mapped. @@ -155,7 +166,7 @@ void ArmRegCache::FlushArmReg(ARMReg r) { } if (ar[r].mipsReg != -1) { if (ar[r].isDirty && mr[ar[r].mipsReg].loc == ML_ARMREG) - emit->STR(CTXREG, r, 4 * ar[r].mipsReg); + emit->STR(CTXREG, r, GetMipsRegOffset(ar[r].mipsReg)); // IMMs won't be in an ARM reg. mr[ar[r].mipsReg].loc = ML_MEM; mr[ar[r].mipsReg].reg = INVALID_REG; @@ -246,10 +257,11 @@ int ArmRegCache::GetMipsRegOffset(MIPSReg r) { return 0; // or what? } -void ArmRegCache::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3) { +void ArmRegCache::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) { mr[r1].spillLock = true; if (r2 != -1) mr[r2].spillLock = true; if (r3 != -1) mr[r3].spillLock = true; + if (r4 != -1) mr[r4].spillLock = true; } void ArmRegCache::ReleaseSpillLocks() { diff --git a/Core/MIPS/ARM/ArmRegCache.h b/Core/MIPS/ARM/ArmRegCache.h index 7a57d7a4d..a06d61a32 100644 --- a/Core/MIPS/ARM/ArmRegCache.h +++ b/Core/MIPS/ARM/ArmRegCache.h @@ -77,7 +77,7 @@ public: // Protect the arm register containing a MIPS register from spilling, to ensure that // it's being kept allocated. - void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1); + void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1, MIPSReg reg4 = -1); void ReleaseSpillLocks(); void SetImm(MIPSReg reg, u32 immVal); @@ -89,6 +89,7 @@ public: void MapInIn(MIPSReg rd, MIPSReg rs); void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true); void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); + void MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); void FlushArmReg(ARMReg r); void FlushMipsReg(MIPSReg r);