void JitArm::stmw(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); FALLBACK_IF(!Core::g_CoreStartupParameter.bFastmem); u32 a = inst.RA; ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg rC = gpr.GetReg(); MOVI2R(rA, inst.SIMM_16); if (a) ADD(rA, rA, gpr.R(a)); Operand2 mask(2, 1); // ~(Memory::MEMVIEW32_MASK) BIC(rA, rA, mask); // 3 MOVI2R(rB, (u32)Memory::base, false); // 4-5 ADD(rA, rA, rB); // 6 for (int i = inst.RD; i < 32; i++) { ARMReg RX = gpr.R(i); REV(rC, RX); STR(rC, rA, (i - inst.RD) * 4); } gpr.Unlock(rA, rB, rC); }
void JitArm::lha(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg RD = gpr.R(inst.RD); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); if (inst.RA) { MOVI2R(rB, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); ADD(rB, rB, RA); } else MOVI2R(rB, (u32)inst.SIMM_16); MOVI2R(rA, (u32)&Memory::Read_U16); PUSH(4, R0, R1, R2, R3); MOV(R0, rB); BL(rA); MOV(rA, R0); SXTH(rA, rA); POP(4, R0, R1, R2, R3); MOV(RD, rA); gpr.Unlock(rA, rB); SetJumpTarget(DoNotLoad); }
void JitArm::stbu(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg RA = gpr.R(inst.RA); ARMReg RS = gpr.R(inst.RS); ARMReg ValueReg = gpr.GetReg(); ARMReg Addr = gpr.GetReg(); ARMReg Function = gpr.GetReg(); MOVI2R(Addr, inst.SIMM_16); ADD(Addr, Addr, RA); // Check for DSI exception prior to writing back address LDR(Function, R9, PPCSTATE_OFF(Exceptions)); CMP(Function, EXCEPTION_DSI); FixupBranch DoNotWrite = B_CC(CC_EQ); MOV(RA, Addr); SetJumpTarget(DoNotWrite); MOV(ValueReg, RS); MOVI2R(Function, (u32)&Memory::Write_U8); PUSH(4, R0, R1, R2, R3); MOV(R0, ValueReg); MOV(R1, Addr); BL(Function); POP(4, R0, R1, R2, R3); gpr.Unlock(ValueReg, Addr, Function); }
void JitArm::sth(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg RS = gpr.R(inst.RS); ARMReg ValueReg = gpr.GetReg(); ARMReg Addr = gpr.GetReg(); ARMReg Function = gpr.GetReg(); MOV(ValueReg, RS); if (inst.RA) { MOVI2R(Addr, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); ADD(Addr, Addr, RA); } else MOVI2R(Addr, (u32)inst.SIMM_16); MOVI2R(Function, (u32)&Memory::Write_U16); PUSH(4, R0, R1, R2, R3); MOV(R0, ValueReg); MOV(R1, Addr); BL(Function); POP(4, R0, R1, R2, R3); gpr.Unlock(ValueReg, Addr, Function); }
void JitArm::stfs(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg v0 = fpr.R0(inst.FS); VCVT(S0, v0, 0); if (inst.RA) { MOVI2R(rB, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); ADD(rB, rB, RA); } else { MOVI2R(rB, (u32)inst.SIMM_16); } MOVI2R(rA, (u32)&Memory::Write_U32); PUSH(4, R0, R1, R2, R3); VMOV(R0, S0); MOV(R1, rB); BL(rA); POP(4, R0, R1, R2, R3); gpr.Unlock(rA, rB); }
void JitArm::lwz(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg RD = gpr.R(inst.RD); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); { if (inst.RA) { MOVI2R(rB, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); ADD(rB, rB, RA); } else MOVI2R(rB, (u32)inst.SIMM_16); MOVI2R(rA, (u32)&Memory::Read_U32); PUSH(4, R0, R1, R2, R3); MOV(R0, rB); BL(rA); MOV(rA, R0); POP(4, R0, R1, R2, R3); MOV(RD, rA); gpr.Unlock(rA, rB); } SetJumpTarget(DoNotLoad); if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle && (inst.hex & 0xFFFF0000) == 0x800D0000 && (Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 || (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) && Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8) { gpr.Flush(); fpr.Flush(); // if it's still 0, we can wait until the next event TST(RD, RD); FixupBranch noIdle = B_CC(CC_NEQ); rA = gpr.GetReg(); MOVI2R(rA, (u32)&PowerPC::OnIdle); MOVI2R(R0, PowerPC::ppcState.gpr[inst.RA] + (s32)(s16)inst.SIMM_16); BL(rA); gpr.Unlock(rA); WriteExceptionExit(); SetJumpTarget(noIdle); //js.compilerPC += 8; return; } }
void JitArm::SafeLoadToReg(bool fastmem, u32 dest, s32 addr, s32 offsetReg, int accessSize, s32 offset, bool signExtend, bool reverse) { ARMReg RD = gpr.R(dest); if (Core::g_CoreStartupParameter.bFastmem && fastmem) { if (addr != -1) MOV(R10, gpr.R(addr)); else MOV(R10, 0); UnsafeLoadToReg(RD, R10, accessSize, offset); return; } ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); if (offsetReg == -1) MOVI2R(rA, offset); else MOV(rA, gpr.R(offsetReg)); if (addr != -1) ADD(rA, rA, gpr.R(addr)); switch (accessSize) { case 8: MOVI2R(rB, (u32)&Memory::Read_U8); break; case 16: MOVI2R(rB, (u32)&Memory::Read_U16); break; case 32: MOVI2R(rB, (u32)&Memory::Read_U32); break; } PUSH(4, R0, R1, R2, R3); MOV(R0, rA); BL(rB); MOV(rA, R0); POP(4, R0, R1, R2, R3); MOV(RD, rA); if (signExtend) // Only on 16 loads SXTH(RD, RD); if (reverse) { if (accessSize == 32) REV(RD, RD); else if (accessSize == 16) REV16(RD, RD); } gpr.Unlock(rA, rB); }
void JitArm::UnsafeLoadToReg(ARMReg dest, ARMReg addr, int accessSize, s32 offsetReg, s32 offset) { ARMReg rA = gpr.GetReg(); if (offsetReg == -1) { MOVI2R(rA, offset, false); // -3 ADD(addr, addr, rA); // - 1 } else { NOP(2); // -3, -2 // offsetReg is preloaded here ADD(addr, addr, gpr.R(offsetReg)); // -1 } // All this gets replaced on backpatch Operand2 mask(2, 1); // ~(Memory::MEMVIEW32_MASK) BIC(addr, addr, mask); // 1 MOVI2R(rA, (u32)Memory::base, false); // 2-3 ADD(addr, addr, rA); // 4 switch (accessSize) { case 32: LDR(dest, addr); // 5 break; case 16: LDRH(dest, addr); break; case 8: LDRB(dest, addr); break; } switch (accessSize) { case 32: REV(dest, dest); // 6 break; case 16: REV16(dest, dest); break; case 8: NOP(1); break; } NOP(2); // 7-8 gpr.Unlock(rA); }
void JitArm::ps_rsqrte(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; ARMReg vB0 = fpr.R0(b); ARMReg vB1 = fpr.R1(b); ARMReg vD0 = fpr.R0(d, false); ARMReg vD1 = fpr.R1(d, false); ARMReg fpscrReg = gpr.GetReg(); ARMReg V0 = D1; ARMReg rA = gpr.GetReg(); MOVI2R(fpscrReg, (u32)&PPC_NAN); VLDR(V0, fpscrReg, 0); LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); VCMP(vB0); VMRS(_PC); FixupBranch Less0 = B_CC(CC_LT); VMOV(vD0, V0); SetFPException(fpscrReg, FPSCR_VXSQRT); FixupBranch SkipOrr0 = B(); SetJumpTarget(Less0); SetCC(CC_EQ); ORR(rA, rA, 1); SetCC(); SetJumpTarget(SkipOrr0); VCMP(vB1); VMRS(_PC); FixupBranch Less1 = B_CC(CC_LT); VMOV(vD1, V0); SetFPException(fpscrReg, FPSCR_VXSQRT); FixupBranch SkipOrr1 = B(); SetJumpTarget(Less1); SetCC(CC_EQ); ORR(rA, rA, 2); SetCC(); SetJumpTarget(SkipOrr1); CMP(rA, 0); FixupBranch noException = B_CC(CC_EQ); SetFPException(fpscrReg, FPSCR_ZX); SetJumpTarget(noException); VCVT(S0, vB0, 0); VCVT(S1, vB1, 0); NEONXEmitter nemit(this); nemit.VRSQRTE(F_32, D0, D0); VCVT(vD0, S0, 0); VCVT(vD1, S1, 0); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(fpscrReg, rA); }
void JitArm::lwzx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg RB = gpr.R(inst.RB); ARMReg RD = gpr.R(inst.RD); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); { if (inst.RA) { ARMReg RA = gpr.R(inst.RA); ADD(rB, RA, RB); } else MOV(rB, RB); MOVI2R(rA, (u32)&Memory::Read_U32); PUSH(4, R0, R1, R2, R3); MOV(R0, rB); BL(rA); MOV(rA, R0); POP(4, R0, R1, R2, R3); MOV(RD, rA); gpr.Unlock(rA, rB); } SetJumpTarget(DoNotLoad); //// u32 temp = Memory::Read_U32(_inst.RA ? (m_GPR[_inst.RA] + m_GPR[_inst.RB]) : m_GPR[_inst.RB]); }
void Jit::SetCCAndR0ForSafeAddress(MIPSGPReg rs, s16 offset, ARMReg tempReg, bool reverse) { SetR0ToEffectiveAddress(rs, offset); // There are three valid ranges. Each one gets a bit. const u32 BIT_SCRATCH = 1, BIT_RAM = 2, BIT_VRAM = 4; MOVI2R(tempReg, BIT_SCRATCH | BIT_RAM | BIT_VRAM); CMP(R0, AssumeMakeOperand2(PSP_GetScratchpadMemoryBase())); SetCC(CC_LO); BIC(tempReg, tempReg, BIT_SCRATCH); SetCC(CC_HS); CMP(R0, AssumeMakeOperand2(PSP_GetScratchpadMemoryEnd())); BIC(tempReg, tempReg, BIT_SCRATCH); // If it was in that range, later compares don't matter. CMP(R0, AssumeMakeOperand2(PSP_GetVidMemBase())); SetCC(CC_LO); BIC(tempReg, tempReg, BIT_VRAM); SetCC(CC_HS); CMP(R0, AssumeMakeOperand2(PSP_GetVidMemEnd())); BIC(tempReg, tempReg, BIT_VRAM); CMP(R0, AssumeMakeOperand2(PSP_GetKernelMemoryBase())); SetCC(CC_LO); BIC(tempReg, tempReg, BIT_RAM); SetCC(CC_HS); CMP(R0, AssumeMakeOperand2(PSP_GetUserMemoryEnd())); BIC(tempReg, tempReg, BIT_RAM); // If we left any bit set, the address is OK. SetCC(CC_AL); CMP(tempReg, 0); SetCC(reverse ? CC_EQ : CC_GT); }
void JitArm::UnsafeStoreFromReg(ARMReg dest, ARMReg value, int accessSize, s32 offset) { // All this gets replaced on backpatch Operand2 mask(2, 1); // ~(Memory::MEMVIEW32_MASK) BIC(dest, dest, mask); // 1 MOVI2R(R14, (u32)Memory::base, false); // 2-3 ADD(dest, dest, R14); // 4 switch (accessSize) { case 32: REV(value, value); // 5 break; case 16: REV16(value, value); break; case 8: NOP(1); break; } switch (accessSize) { case 32: STR(value, dest); // 6 break; case 16: STRH(value, dest); break; case 8: STRB(value, dest); break; } NOP(1); // 7 }
void PPCXEmitter::QuickCallFunction(void *func) { /** TODO : can use simple jump **/ u32 func_addr = (u32) func; // Load func address MOVI2R(R0, func_addr); // Set it to link register MTCTR(R0); // Branch BCTRL(); }
void JitArm::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START // Don't interpret this, if we do we get thrown out //JITDISABLE(SystemRegisters) ARMReg rA = gpr.GetReg(); MOVI2R(rA, (u32)&MSR); STR(rA, gpr.R(inst.RS)); gpr.Unlock(rA); WriteExit(js.compilerPC + 4, 0); }
void PPCXEmitter::MOVI2F (PPCReg dest, float imm, bool negate) { u32 tmp; union convert { unsigned int i; float f; } fc; fc.f = imm; MOVI2R(R6, fc.i); // R7 = imm MOVI2R(R7, (u32)&tmp); STW(R6, R7); // dest = R7 LFS(dest, R7, 0); if (negate == true) { FNEG(dest, dest); } }
void PPCXEmitter::SaveFloatSwap(PPCReg FRt, PPCReg Base, PPCReg offset) { // used for swapping float ... u32 tmp; // Save Value in tmp MOVI2R(R7, (u32)&tmp); SFS(FRt, R7, 0); // Load the value in R6 LWZ(R6, R7); // Save the final value STWBRX(R6, Base, offset); }
void PPCXEmitter::LoadFloatSwap(PPCReg FRt, PPCReg Base, PPCReg offset) { // used for swapping float ... u32 tmp; // Load Value into a temp REG LWBRX(R6, Base, offset); // Save it in tmp MOVI2R(R7, (u32)&tmp); STW(R6, R7); // Load the final value LFS(FRt, R7, 0); }
void JitArm::lfs(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStoreFloating) Default(inst); return; ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); LDR(rA, R9, STRUCT_OFF(PowerPC::ppcState, Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); if (inst.RA) { MOVI2R(rB, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); ADD(rB, rB, RA); } else MOVI2R(rB, (u32)inst.SIMM_16); MOVI2R(rA, (u32)&Memory::Read_U32); PUSH(4, R0, R1, R2, R3); MOV(R0, rB); BL(rA); MOV(rA, R0); POP(4, R0, R1, R2, R3); ARMReg v0 = fpr.R0(inst.FD, false); ARMReg v1 = fpr.R1(inst.FD, false); VMOV(v0, rA, false); VMOV(v1, rA, false); gpr.Unlock(rA, rB); SetJumpTarget(DoNotLoad); }
void JitArm::mtspr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(SystemRegisters) u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); ARMReg RD = gpr.R(inst.RD); switch (iIndex) { case SPR_LR: case SPR_CTR: case SPR_XER: // These are safe to do the easy way, see the bottom of this function. break; case SPR_GQR0: case SPR_GQR0 + 1: case SPR_GQR0 + 2: case SPR_GQR0 + 3: case SPR_GQR0 + 4: case SPR_GQR0 + 5: case SPR_GQR0 + 6: case SPR_GQR0 + 7: // Prevent recompiler from compiling in old quantizer values. // If the value changed, destroy all blocks using this quantizer // This will create a little bit of block churn, but hopefully not too bad. { /* MOV(32, R(EAX), M(&PowerPC::ppcState.spr[iIndex])); // Load old value CMP(32, R(EAX), gpr.R(inst.RD)); FixupBranch skip_destroy = J_CC(CC_E, false); int gqr = iIndex - SPR_GQR0; ABI_CallFunctionC(ProtectFunction(&Jit64::DestroyBlocksWithFlag, 1), (u32)BLOCK_USE_GQR0 << gqr); SetJumpTarget(skip_destroy);*/ } // TODO - break block if quantizers are written to. default: Default(inst); return; } // OK, this is easy. ARMReg rA = gpr.GetReg(false); MOVI2R(rA, (u32)&PowerPC::ppcState.spr); STR(rA, RD, iIndex * 4); }
void PPCXEmitter::BLT (const void *fnptr) { //CHECK_JUMP if (!IS_SMALL_JUMP) { u32 func_addr = (u32) fnptr; // Load func address MOVI2R(R0, func_addr); // Set it to link register MTCTR(R0); // Branch BLTCTR(); return; } s32 func = (s32)fnptr - s32(code); u32 instr = (0x41800000 | (((s16)(((func)+1))) & 0xfffc)); Write32(instr); }
void JitArm::oris(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) u32 a = inst.RA, s = inst.RS; if (gpr.IsImm(s)) { gpr.SetImmediate(a, gpr.GetImm(s) | (inst.UIMM << 16)); return; } ARMReg RA = gpr.R(a); ARMReg RS = gpr.R(s); ARMReg rA = gpr.GetReg(); MOVI2R(rA, inst.UIMM << 16); ORR(RA, RS, rA); gpr.Unlock(rA); }
void JitArm::mulli(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) u32 a = inst.RA, d = inst.RD; if (gpr.IsImm(a)) { gpr.SetImmediate(d, gpr.GetImm(a) * inst.SIMM_16); return; } ARMReg RA = gpr.R(a); ARMReg RD = gpr.R(d); ARMReg rA = gpr.GetReg(); MOVI2R(rA, inst.SIMM_16); MUL(RD, RA, rA); gpr.Unlock(rA); }
void JitArm::ps_res(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); u32 b = inst.FB, d = inst.FD; ARMReg vB0 = fpr.R0(b); ARMReg vB1 = fpr.R1(b); ARMReg vD0 = fpr.R0(d, false); ARMReg vD1 = fpr.R1(d, false); ARMReg V0 = fpr.GetReg(); MOVI2R(V0, 1.0, INVALID_REG); // temp reg not needed for 1.0 VDIV(vD0, V0, vB0); VDIV(vD1, V0, vB1); fpr.Unlock(V0); }
void JitArm::andis_rc(UGeckoInstruction inst) { u32 a = inst.RA, s = inst.RS; if (gpr.IsImm(s)) { gpr.SetImmediate(a, gpr.GetImm(s) & ((u32)inst.UIMM << 16)); ComputeRC(gpr.GetImm(a), 0); return; } ARMReg rA = gpr.R(a); ARMReg rS = gpr.R(s); ARMReg RA = gpr.GetReg(); MOVI2R(RA, (u32)inst.UIMM << 16); ANDS(rA, rS, RA); ComputeRC(); gpr.Unlock(RA); }
void JitArm::addis(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) u32 d = inst.RD, a = inst.RA; if (a) { if (gpr.IsImm(a)) { gpr.SetImmediate(d, gpr.GetImm(a) + (inst.SIMM_16 << 16)); return; } ARMReg rA = gpr.GetReg(false); ARMReg RA = gpr.R(a); ARMReg RD = gpr.R(d); MOVI2R(rA, inst.SIMM_16 << 16); ADD(RD, RA, rA); } else gpr.SetImmediate(d, inst.SIMM_16 << 16); }
void JitArm::mfspr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(SystemRegisters) u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); ARMReg RD = gpr.R(inst.RD); switch (iIndex) { case SPR_WPAR: case SPR_DEC: case SPR_TL: case SPR_TU: Default(inst); return; default: ARMReg rA = gpr.GetReg(false); MOVI2R(rA, (u32)&PowerPC::ppcState.spr); LDR(RD, rA, iIndex * 4); break; } }
void PPCXEmitter::Epilogue() { u32 regSize = 8; // 4 in 32bit system u32 stackFrameSize = 0x1F0; //Break(); // Write Epilogue (restore stack frame, return) // free stack ADDI(R1, R1, stackFrameSize); #if 0 ADDI(R12, R1, -0x98); // Restore fpr for(int i = 14; i < 32; i ++) { LFD((PPCReg)i, R1, -((32 - i) * regSize)); } #endif // Restore gpr for(int i = 14; i < 32; i ++) { LD((PPCReg)i, R1, -((33 - i) * regSize)); } // recover r12 (LR saved register) LWZ (R12, R1, -0x8); // Restore Lr MTLR(R12); #if 1 // load fpr buff MOVI2R(R5, (u32)&_fprTmp); // Load fpr for(int i = 14; i < 32; i ++) { LFD((PPCReg)i, R5, i * regSize); } #endif }
void PPCXEmitter::Prologue() { // Save regs u32 regSize = 8; // 4 in 32bit system u32 stackFrameSize = 0x1F0; // Write Prologue (setup stack frame etc ...) // Save Lr MFLR(R12); // Save gpr for(int i = 14; i < 32; i ++) { STD((PPCReg)i, R1, -((33 - i) * regSize)); } // Save r12 STW(R12, R1, -0x8); #if 0 // add fpr frame ADDI(R12, R1, -0x98); // Load fpr for(int i = 14; i < 32; i ++) { SFD((PPCReg)i, R1, -((32 - i) * regSize)); } #endif // allocate stack STWU(R1, R1, -stackFrameSize); #if 1 // load fpr buff MOVI2R(R10, (u32)&_fprTmp); // Save fpr for(int i = 14; i < 32; i ++) { SFD((PPCReg)i, R10, i * regSize); } #endif }
void Jit::Comp_FPULS(u32 op) { CONDITIONAL_DISABLE; s32 offset = (s16)(op & 0xFFFF); int ft = _FT; int rs = _RS; // u32 addr = R(rs) + offset; // logBlocks = 1; bool doCheck = false; switch(op >> 26) { case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY); if (gpr.IsImm(rs)) { u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, offset); } else { SetCCAndR0ForSafeAddress(rs, offset, R1); doCheck = true; } ADD(R0, R0, R11); } VLDR(fpr.R(ft), R0, 0); if (doCheck) { SetCC(CC_EQ); MOVI2R(R0, 0); VMOV(fpr.R(ft), R0); SetCC(CC_AL); } break; case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 fpr.MapReg(ft); if (gpr.IsImm(rs)) { u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, offset); } else { SetCCAndR0ForSafeAddress(rs, offset, R1); doCheck = true; } ADD(R0, R0, R11); } VSTR(fpr.R(ft), R0, 0); if (doCheck) { SetCC(CC_AL); } break; default: Comp_Generic(op); return; } }
void Jit::Comp_FPUComp(u32 op) { CONDITIONAL_DISABLE; int opc = op & 0xF; if (opc >= 8) opc -= 8; // alias if (opc == 0)//f, sf (signalling false) { MOVI2R(R0, 0); STR(R0, CTXREG, offsetof(MIPSState, fpcond)); return; } int fs = _FS; int ft = _FT; fpr.MapInIn(fs, ft); VCMP(fpr.R(fs), fpr.R(ft)); VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags). switch(opc) { case 1: // un, ngle (unordered) SetCC(CC_VS); MOVI2R(R0, 1); SetCC(CC_VC); break; case 2: // eq, seq (equal, ordered) SetCC(CC_EQ); MOVI2R(R0, 1); SetCC(CC_NEQ); break; case 3: // ueq, ngl (equal, unordered) SetCC(CC_EQ); MOVI2R(R0, 1); SetCC(CC_NEQ); MOVI2R(R0, 0); SetCC(CC_VS); MOVI2R(R0, 1); SetCC(CC_AL); STR(R0, CTXREG, offsetof(MIPSState, fpcond)); return; case 4: // olt, lt (less than, ordered) SetCC(CC_LO); MOVI2R(R0, 1); SetCC(CC_HS); break; case 5: // ult, nge (less than, unordered) SetCC(CC_LT); MOVI2R(R0, 1); SetCC(CC_GE); break; case 6: // ole, le (less equal, ordered) SetCC(CC_LS); MOVI2R(R0, 1); SetCC(CC_HI); break; case 7: // ule, ngt (less equal, unordered) SetCC(CC_LE); MOVI2R(R0, 1); SetCC(CC_GT); break; default: Comp_Generic(op); return; } MOVI2R(R0, 0); SetCC(CC_AL); STR(R0, CTXREG, offsetof(MIPSState, fpcond)); }