From fbef590bed217409703e9483ace61bc7ad9918dd Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 8 Mar 2013 03:38:27 +1000 Subject: [PATCH 1/3] Add emitters for VMRS/VMSR. Undisable ceil, which works. Add stub for rounding mode handling. --- Common/ArmEmitter.cpp | 8 +++++++- Common/ArmEmitter.h | 2 ++ Core/MIPS/ARM/ArmCompFPU.cpp | 30 ++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index fa795c4bf3..c1193d544c 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -877,7 +877,13 @@ void ARMXEmitter::VCMP(ARMReg Vd, bool E) } void ARMXEmitter::VMRS_APSR() { - Write32(0xEEF10A10 | (15 << 12)); + Write32(NO_COND | 0xEF10A10 | (15 << 12)); +} +void ARMXEmitter::VMRS(ARMReg Rt) { + Write32(NO_COND | (0xEF << 20) | (1 << 16) | (Rt << 12) | 0xA10); +} +void ARMXEmitter::VMSR(ARMReg Rt) { + Write32(NO_COND | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10); } void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm) 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..821d581974 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -223,9 +223,9 @@ void Jit::Comp_FPU2op(u32 op) break; case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s DISABLE; - // Seems to round wrong in hardware + // Requires correct floating mode set fpr.MapDirtyIn(fd, fs); - VCVT(fpr.R(fd), fpr.R(fs), TO_INT | ROUND_TO_ZERO); + VCVT(fpr.R(fd), fpr.R(fs), TO_INT); break; default: DISABLE; @@ -260,6 +260,32 @@ void Jit::Comp_mxc1(u32 op) return; case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1 + // Rounding isn't right. + /*if (fs == 31) + { + fpr.MapReg(rt, 0); + 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); + SUB(R0, R0, Operand2(1)); + SetCC(CC_GT); + ADD(R0, R0, Operand2(2)); + 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); + + // For interpreter (currently doesn't replace properly) + 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)); + }*/ Comp_Generic(op); return; } From 7782be9a3e40021020636f0448cf3a314ae12c1e Mon Sep 17 00:00:00 2001 From: Sacha Date: Fri, 8 Mar 2013 16:09:27 +1000 Subject: [PATCH 2/3] Try software rounding mode instead. Use conditionals for VFP functions. Note: Round to Zero not working for some reason? --- Common/ArmEmitter.cpp | 66 ++++++++++++++++++------------------ Core/MIPS/ARM/ArmCompFPU.cpp | 32 +++++++++++++---- 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index c1193d544c..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,24 +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(NO_COND | 0xEF10A10 | (15 << 12)); + Write32(condition | 0xEF10A10 | (15 << 12)); } void ARMXEmitter::VMRS(ARMReg Rt) { - Write32(NO_COND | (0xEF << 20) | (1 << 16) | (Rt << 12) | 0xA10); + Write32(condition | (0xEF << 20) | (1 << 16) | (Rt << 12) | 0xA10); } void ARMXEmitter::VMSR(ARMReg Rt) { - Write32(NO_COND | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10); + Write32(condition | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10); } void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm) @@ -899,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)); } @@ -921,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)); } } @@ -946,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)); } @@ -954,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)); } @@ -981,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)); } @@ -989,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)); } @@ -1017,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)); } @@ -1025,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)); } @@ -1050,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)); } @@ -1069,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)); } } @@ -1088,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)); } } @@ -1105,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)); } @@ -1119,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; } @@ -1139,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; } @@ -1169,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 @@ -1186,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)); } } @@ -1202,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/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index 821d581974..c594f2e020 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -222,10 +222,30 @@ 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; - // Requires correct floating mode set fpr.MapDirtyIn(fd, fs); - VCVT(fpr.R(fd), fpr.R(fs), TO_INT); + 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 */ + 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; @@ -260,7 +280,7 @@ void Jit::Comp_mxc1(u32 op) return; case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1 - // Rounding isn't right. + // Hardware rounding method. /*if (fs == 31) { fpr.MapReg(rt, 0); @@ -269,9 +289,9 @@ void Jit::Comp_mxc1(u32 op) // 0, 1, 2, 3 <-> 0, 3, 1, 2 CMP(R0, Operand2(1)); SetCC(CC_EQ); - SUB(R0, R0, Operand2(1)); - SetCC(CC_GT); ADD(R0, R0, Operand2(2)); + SetCC(CC_GT); + SUB(R0, R0, Operand2(1)); SetCC(CC_AL); // Load and Store RM to FPSCR From ac3f3099e10fac636381cbb6b4ad545672ea4714 Mon Sep 17 00:00:00 2001 From: Sacha Date: Sun, 10 Mar 2013 11:25:24 +1000 Subject: [PATCH 3/3] Fix the conditional rounding for round to zero. Implement ctc1, cfc1. --- Core/MIPS/ARM/ArmCompFPU.cpp | 60 ++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index c594f2e020..2ef6bab6f5 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -230,21 +230,15 @@ void Jit::Comp_FPU2op(u32 op) // 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_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_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: @@ -268,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 @@ -279,19 +286,19 @@ void Jit::Comp_mxc1(u32 op) VLDR(fpr.R(fs), CTXREG, gpr.GetMipsRegOffset(rt)); return; - case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1 - // Hardware rounding method. - /*if (fs == 31) + case 6: //ctc1 + if (fs == 31) { - fpr.MapReg(rt, 0); + 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_EQ); ADD(R0, R0, Operand2(2)); + SetCC(CC_GT); SUB(R0, R0, Operand2(1)); SetCC(CC_AL); // Load and Store RM to FPSCR @@ -299,14 +306,13 @@ void Jit::Comp_mxc1(u32 op) BIC(R1, R1, Operand2(0x3 << 22)); ORR(R1, R1, Operand2(R0, ST_LSL, 22)); VMSR(R1); - - // For interpreter (currently doesn't replace properly) + */ + // 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)); - }*/ - Comp_Generic(op); + } return; } }