void MipsJit::Comp_Generic(MIPSOpcode op) { FlushAll(); MIPSInterpretFunc func = MIPSGetInterpretFunc(op); if (func) { //SaveDowncount(); RestoreRoundingMode(); // Move Imm32(js.compilerPC) in to M(&mips_->pc) QuickCallFunction(V1, (void *)func); ApplyRoundingMode(); //RestoreDowncount(); } const MIPSInfo info = MIPSGetInfo(op); if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0) { // If it does eat them, it'll happen in MIPSCompileOp(). if ((info & OUT_EAT_PREFIX) == 0) js.PrefixUnknown(); } }
void Jit::Comp_mxc1(MIPSOpcode op) { CONDITIONAL_DISABLE(FPU_XFER); int fs = _FS; MIPSGPReg rt = _RT; switch ((op >> 21) & 0x1f) { case 0: // R(rt) = FI(fs); break; //mfc1 if (rt == MIPS_REG_ZERO) return; gpr.MapReg(rt, false, true); // If fs is not mapped, most likely it's being abandoned. // Just load from memory in that case. if (fpr.R(fs).IsSimpleReg()) { MOVD_xmm(gpr.R(rt), fpr.RX(fs)); } else { MOV(32, gpr.R(rt), fpr.R(fs)); } break; case 2: // R(rt) = currentMIPS->ReadFCR(fs); break; //cfc1 if (rt == MIPS_REG_ZERO) return; if (fs == 31) { bool wasImm = gpr.IsImm(MIPS_REG_FPCOND); if (!wasImm) { gpr.Lock(rt, MIPS_REG_FPCOND); gpr.MapReg(MIPS_REG_FPCOND, true, false); } gpr.MapReg(rt, false, true); MOV(32, gpr.R(rt), MIPSSTATE_VAR(fcr31)); if (wasImm) { if (gpr.GetImm(MIPS_REG_FPCOND) & 1) { OR(32, gpr.R(rt), Imm32(1 << 23)); } else { AND(32, gpr.R(rt), Imm32(~(1 << 23))); } } else { AND(32, gpr.R(rt), Imm32(~(1 << 23))); MOV(32, R(TEMPREG), gpr.R(MIPS_REG_FPCOND)); AND(32, R(TEMPREG), Imm32(1)); SHL(32, R(TEMPREG), Imm8(23)); OR(32, gpr.R(rt), R(TEMPREG)); } gpr.UnlockAll(); } else if (fs == 0) { gpr.SetImm(rt, MIPSState::FCR0_VALUE); } else { Comp_Generic(op); } return; case 4: //FI(fs) = R(rt); break; //mtc1 fpr.MapReg(fs, false, true); if (gpr.IsImm(rt) && gpr.GetImm(rt) == 0) { XORPS(fpr.RX(fs), fpr.R(fs)); } else { gpr.KillImmediate(rt, true, false); MOVD_xmm(fpr.RX(fs), gpr.R(rt)); } return; case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1 if (fs == 31) { // Must clear before setting, since ApplyRoundingMode() assumes it was cleared. RestoreRoundingMode(); if (gpr.IsImm(rt)) { gpr.SetImm(MIPS_REG_FPCOND, (gpr.GetImm(rt) >> 23) & 1); MOV(32, MIPSSTATE_VAR(fcr31), Imm32(gpr.GetImm(rt) & 0x0181FFFF)); if ((gpr.GetImm(rt) & 0x1000003) == 0) { // Default nearest / no-flush mode, just leave it cleared. } else { UpdateRoundingMode(gpr.GetImm(rt)); ApplyRoundingMode(); } } else {