diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index fa795c4bf3..960e3f2a62 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -801,13 +801,13 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, u16 offset) if (single_reg) { - Write32(NO_COND | (0x1B << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \ + Write32(condition | (0x1B << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \ | ((Dest & 0x1E) << 11) | (10 << 8) | (offset >> 2)); } else { - Write32(NO_COND | (0x1B << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \ + Write32(condition | (0x1B << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \ | ((Dest & 0xF) << 12) | (11 << 8) | (offset >> 2)); } } @@ -828,13 +828,13 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, u16 offset) if (single_reg) { - Write32(NO_COND | (0x1B << 23) | ((Src & 0x1) << 22) | (Base << 16) \ + Write32(condition | (0x1B << 23) | ((Src & 0x1) << 22) | (Base << 16) \ | ((Src & 0x1E) << 11) | (10 << 8) | (offset >> 2)); } else { - Write32(NO_COND | (0x1B << 23) | ((Src & 0x10) << 18) | (Base << 16) \ + Write32(condition | (0x1B << 23) | ((Src & 0x10) << 18) | (Base << 16) \ | ((Src & 0xF) << 12) | (11 << 8) | (offset >> 2)); } } @@ -848,12 +848,12 @@ void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm, bool E) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x34 << 16) | ((Vd & 0x1E) << 11) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x34 << 16) | ((Vd & 0x1E) << 11) \ | (E << 7) | (0x29 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1)); } else { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x34 << 16) | ((Vd & 0xF) << 12) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x34 << 16) | ((Vd & 0xF) << 12) \ | (E << 7) | (0x2C << 6) | ((Vm & 0x10) << 1) | (Vm & 0xF)); } } @@ -866,18 +866,24 @@ void ARMXEmitter::VCMP(ARMReg Vd, bool E) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x35 << 16) | ((Vd & 0x1E) << 11) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x35 << 16) | ((Vd & 0x1E) << 11) \ | (E << 7) | (0x29 << 6)); } else { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x35 << 16) | ((Vd & 0xF) << 12) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x35 << 16) | ((Vd & 0xF) << 12) \ | (E << 7) | (0x2C << 6)); } } void ARMXEmitter::VMRS_APSR() { - Write32(0xEEF10A10 | (15 << 12)); + Write32(condition | 0xEF10A10 | (15 << 12)); +} +void ARMXEmitter::VMRS(ARMReg Rt) { + Write32(condition | (0xEF << 20) | (1 << 16) | (Rt << 12) | 0xA10); +} +void ARMXEmitter::VMSR(ARMReg Rt) { + Write32(condition | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10); } void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm) @@ -893,13 +899,13 @@ void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | ((Vn & 0x1E) << 15) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | ((Vn & 0x1E) << 15) \ | ((Vd & 0x1E) << 11) | (0xA << 8) | ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) \ | (Vm >> 1)); } else { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16) \ | ((Vd & 0xF) << 12) | (0xB << 8) | ((Vn & 0x10) << 3) | ((Vm & 0x10) << 2) \ | (Vm & 0xF)); } @@ -915,12 +921,12 @@ void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \ | ((Vd & 0x1E) << 11) | (0x2B << 6) | ((Vm & 0x1) << 5) | (Vm >> 1)); } else { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \ | ((Vd & 0xF) << 12) | (0x2F << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF)); } } @@ -940,7 +946,7 @@ void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \ | ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \ | ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1)); } @@ -948,7 +954,7 @@ void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm) { if (double_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x3 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x3 << 20) \ | ((Vn & 0xF) << 16) | ((Vd & 0xF) << 12) | (0xB << 8) \ | ((Vn & 0x10) << 3) | ((Vm & 0x10) << 2) | (Vm & 0xF)); } @@ -975,7 +981,7 @@ void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \ | ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \ | ((Vn & 0x1) << 7) | (1 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1)); } @@ -983,7 +989,7 @@ void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm) { if (double_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x3 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x3 << 20) \ | ((Vn & 0xF) << 16) | ((Vd & 0xF) << 12) | (0xB << 8) \ | ((Vn & 0x10) << 3) | (1 << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF)); } @@ -1011,7 +1017,7 @@ void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x2 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x2 << 20) \ | ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \ | ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1)); } @@ -1019,7 +1025,7 @@ void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm) { if (double_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x2 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x2 << 20) \ | ((Vn & 0xF) << 16) | ((Vd & 0xF) << 12) | (0xB << 8) \ | ((Vn & 0x10) << 3) | ((Vm & 0x10) << 2) | (Vm & 0xF)); } @@ -1044,7 +1050,7 @@ void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x0 << 20) \ + Write32(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x0 << 20) \ | ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \ | ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1)); } @@ -1063,12 +1069,12 @@ void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x30 << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x30 << 16) \ | ((Vd & 0x1E) << 11) | (0x2B << 6) | ((Vm & 0x1) << 5) | (Vm >> 1)); } else { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x30 << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x30 << 16) \ | ((Vd & 0xF) << 12) | (0x2F << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF)); } } @@ -1082,12 +1088,12 @@ void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \ | ((Vd & 0x1E) << 11) | (0x29 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1)); } else { - Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \ + Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \ | ((Vd & 0xF) << 12) | (0x2D << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF)); } } @@ -1099,7 +1105,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high) Dest = SubBase(Dest); - Write32(NO_COND | (0xE << 24) | (high << 21) | ((Dest & 0xF) << 16) | (Src << 12) \ + Write32(condition | (0xE << 24) | (high << 21) | ((Dest & 0xF) << 16) | (Src << 12) \ | (11 << 8) | ((Dest & 0x10) << 3) | (1 << 4)); } @@ -1113,7 +1119,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) { // Moving to a Neon register FROM ARM Reg Dest = (ARMReg)(Dest - S0); - Write32(NO_COND | (0xE0 << 20) | ((Dest & 0x1E) << 15) | (Src << 12) \ + Write32(condition | (0xE0 << 20) | ((Dest & 0x1E) << 15) | (Src << 12) \ | (0xA << 8) | ((Dest & 0x1) << 7) | (1 << 4)); return; } @@ -1133,7 +1139,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) { // Moving to ARM Reg from Neon Register Src = (ARMReg)(Src - S0); - Write32(NO_COND | (0xE1 << 20) | ((Src & 0x1E) << 15) | (Dest << 12) \ + Write32(condition | (0xE1 << 20) | ((Src & 0x1E) << 15) | (Dest << 12) \ | (0xA << 8) | ((Src & 0x1) << 7) | (1 << 4)); return; } @@ -1163,7 +1169,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) if (Single) { - Write32(NO_COND | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | ((Dest & 0x1E) << 11) \ + Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | ((Dest & 0x1E) << 11) \ | (0x5 << 9) | (1 << 6) | ((Src & 0x1) << 5) | ((Src & 0x1E) >> 1)); } else @@ -1180,7 +1186,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) } else { - Write32(NO_COND | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | ((Dest & 0xF) << 12) \ + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | ((Dest & 0xF) << 12) \ | (0x2D << 6) | ((Src & 0x10) << 1) | (Src & 0xF)); } } @@ -1196,10 +1202,10 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags) if (single_reg) { - Write32(NO_COND | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ + 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 { - Write32(NO_COND | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ | ((Dest & 0xF) << 12) | (1 << 8) | (op << 7) | (0x29 << 6) | ((Source & 0x10) << 1) | (Source & 0xF)); } } diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index 3d76ee3bde..d68a2390ad 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -560,6 +560,8 @@ public: void VCVT(ARMReg Dest, ARMReg Src, int flags); void VMRS_APSR(); + void VMRS(ARMReg Rt); + void VMSR(ARMReg Rt); void QuickCallFunction(ARMReg scratchreg, void *func); diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index 061f98fec2..2ef6bab6f5 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -222,10 +222,24 @@ void Jit::Comp_FPU2op(u32 op) VCVT(fpr.R(fd), fpr.R(fs), TO_FLOAT | IS_SIGNED); break; case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s - DISABLE; - // Seems to round wrong in hardware fpr.MapDirtyIn(fd, fs); - VCVT(fpr.R(fd), fpr.R(fs), TO_INT | ROUND_TO_ZERO); + LDR(R0, CTXREG, offsetof(MIPSState, fcr31)); + AND(R0, R0, Operand2(3)); + // MIPS Rounding Mode: + // 0: Round nearest + // 1: Round to zero + // 2: Round up (ceil) + // 3: Round down (floor) + CMP(R0, Operand2(2)); + SetCC(CC_GE); MOVI2F(S0, 0.5f, R1); + SetCC(CC_GT); VSUB(S0,fpr.R(fs),S0); + SetCC(CC_EQ); VADD(S0,fpr.R(fs),S0); + SetCC(CC_GE); VCVT(fpr.R(fd), S0, TO_INT | IS_SIGNED); /* 2,3 */ + SetCC(CC_AL); + CMP(R0, Operand2(1)); + SetCC(CC_EQ); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED | ROUND_TO_ZERO); /* 1 */ + SetCC(CC_LT); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED); /* 0 */ + SetCC(CC_AL); break; default: DISABLE; @@ -248,8 +262,21 @@ void Jit::Comp_mxc1(u32 op) LDR(gpr.R(rt), CTXREG, fpr.GetMipsRegOffset(fs)); return; - case 2: // R(rt) = currentMIPS->ReadFCR(fs); break; //cfc1 - Comp_Generic(op); + case 2: //cfc1 + if (fs == 31) + { + gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); + LDR(R0, CTXREG, offsetof(MIPSState, fpcond)); + AND(R0,R0, Operand2(1)); // Just in case + LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31)); + BIC(gpr.R(rt), gpr.R(rt), Operand2(0x1 << 23)); + ORR(gpr.R(rt), gpr.R(rt), Operand2(R0, ST_LSL, 23)); + } + else if (fs == 0) + { + gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); + LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr0)); + } return; case 4: //FI(fs) = R(rt); break; //mtc1 @@ -259,8 +286,33 @@ void Jit::Comp_mxc1(u32 op) VLDR(fpr.R(fs), CTXREG, gpr.GetMipsRegOffset(rt)); return; - case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1 - Comp_Generic(op); + case 6: //ctc1 + if (fs == 31) + { + gpr.MapReg(rt, 0); + // Hardware rounding method. + // Left here in case it is faster than conditional method. + /* + AND(R0, gpr.R(rt), Operand2(3)); + // MIPS Rounding Mode <-> ARM Rounding Mode + // 0, 1, 2, 3 <-> 0, 3, 1, 2 + CMP(R0, Operand2(1)); + SetCC(CC_EQ); ADD(R0, R0, Operand2(2)); + SetCC(CC_GT); SUB(R0, R0, Operand2(1)); + SetCC(CC_AL); + + // Load and Store RM to FPSCR + VMRS(R1); + BIC(R1, R1, Operand2(0x3 << 22)); + ORR(R1, R1, Operand2(R0, ST_LSL, 22)); + VMSR(R1); + */ + // Update MIPS state + STR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31)); + MOV(R0, Operand2(gpr.R(rt), ST_LSR, 23)); + AND(R0, R0, Operand2(1)); + STR(R0, CTXREG, offsetof(MIPSState, fpcond)); + } return; } }