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::fcmpu(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff) u32 a = inst.FA, b = inst.FB; int cr = inst.CRFD; ARMReg vA = fpr.R0(a); ARMReg vB = fpr.R0(b); ARMReg fpscrReg = gpr.GetReg(); ARMReg crReg = gpr.GetReg(); Operand2 FPRFMask(0x1F, 0xA); // 0x1F000 Operand2 LessThan(0x8, 0xA); // 0x8000 Operand2 GreaterThan(0x4, 0xA); // 0x4000 Operand2 EqualTo(0x2, 0xA); // 0x2000 Operand2 NANRes(0x1, 0xA); // 0x1000 FixupBranch Done1, Done2, Done3; LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); BIC(fpscrReg, fpscrReg, FPRFMask); VCMPE(vA, vB); VMRS(_PC); SetCC(CC_LT); ORR(fpscrReg, fpscrReg, LessThan); MOV(crReg, 8); Done1 = B(); SetCC(CC_GT); ORR(fpscrReg, fpscrReg, GreaterThan); MOV(crReg, 4); Done2 = B(); SetCC(CC_EQ); ORR(fpscrReg, fpscrReg, EqualTo); MOV(crReg, 2); Done3 = B(); SetCC(); ORR(fpscrReg, fpscrReg, NANRes); MOV(crReg, 1); VCMPE(vA, vA); VMRS(_PC); FixupBranch NanA = B_CC(CC_NEQ); VCMPE(vB, vB); VMRS(_PC); FixupBranch NanB = B_CC(CC_NEQ); FixupBranch Done4 = B(); SetJumpTarget(NanA); SetJumpTarget(NanB); SetFPException(fpscrReg, FPSCR_VXSNAN); SetJumpTarget(Done1); SetJumpTarget(Done2); SetJumpTarget(Done3); SetJumpTarget(Done4); STRB(crReg, R9, PPCSTATE_OFF(cr_fast) + cr); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(fpscrReg, crReg); }
void JitArm::ComputeRC(int cr) { ARMReg rB = gpr.GetReg(); MOV(rB, 0x2); // Result == 0 SetCC(CC_LT); MOV(rB, 0x8); // Result < 0 SetCC(CC_GT); MOV(rB, 0x4); // Result > 0 SetCC(); STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr); gpr.Unlock(rB); }
void JitArm::FinalizeCarry(ARMReg reg) { ARMReg tmp = gpr.GetReg(); Operand2 mask = Operand2(2, 2); // XER_CA_MASK SetCC(CC_CS); ORR(reg, reg, mask); SetCC(); LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); ORR(tmp, tmp, reg); STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); gpr.Unlock(tmp); }
void JitArm::ComputeCarry() { ARMReg tmp = gpr.GetReg(); Operand2 mask = Operand2(2, 2); // XER_CA_MASK LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); SetCC(CC_CS); ORR(tmp, tmp, mask); SetCC(CC_CC); BIC(tmp, tmp, mask); SetCC(); STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); gpr.Unlock(tmp); }
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::fctiwx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff) u32 b = inst.FB; u32 d = inst.FD; ARMReg vB = fpr.R0(b); ARMReg vD = fpr.R0(d); ARMReg V0 = fpr.GetReg(); ARMReg V1 = fpr.GetReg(); ARMReg V2 = fpr.GetReg(); ARMReg rA = gpr.GetReg(); ARMReg fpscrReg = gpr.GetReg(); FixupBranch DoneMax, DoneMin; LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); MOVI2R(rA, (u32)minmaxFloat); // Check if greater than max float { VLDR(V0, rA, 8); // Load Max VCMPE(vB, V0); VMRS(_PC); // Loads in to APSR FixupBranch noException = B_CC(CC_LE); VMOV(vD, V0); // Set to max SetFPException(fpscrReg, FPSCR_VXCVI); DoneMax = B(); SetJumpTarget(noException); } // Check if less than min float { VLDR(V0, rA, 0); VCMPE(vB, V0); VMRS(_PC); FixupBranch noException = B_CC(CC_GE); VMOV(vD, V0); SetFPException(fpscrReg, FPSCR_VXCVI); DoneMin = B(); SetJumpTarget(noException); } // Within ranges, convert to integer // Set rounding mode first // PPC <-> ARM rounding modes // 0, 1, 2, 3 <-> 0, 3, 1, 2 ARMReg rB = gpr.GetReg(); VMRS(rA); // Bits 22-23 BIC(rA, rA, Operand2(3, 5)); LDR(rB, R9, PPCSTATE_OFF(fpscr)); AND(rB, rB, 0x3); // Get the FPSCR rounding bits CMP(rB, 1); SetCC(CC_EQ); // zero ORR(rA, rA, Operand2(3, 5)); SetCC(CC_NEQ); CMP(rB, 2); // +inf SetCC(CC_EQ); ORR(rA, rA, Operand2(1, 5)); SetCC(CC_NEQ); CMP(rB, 3); // -inf SetCC(CC_EQ); ORR(rA, rA, Operand2(2, 5)); SetCC(); VMSR(rA); ORR(rA, rA, Operand2(3, 5)); VCVT(vD, vB, TO_INT | IS_SIGNED); VMSR(rA); gpr.Unlock(rB); VCMPE(vD, vB); VMRS(_PC); SetCC(CC_EQ); BIC(fpscrReg, fpscrReg, FRFIMask); FixupBranch DoneEqual = B(); SetCC(); SetFPException(fpscrReg, FPSCR_XX); ORR(fpscrReg, fpscrReg, FIMask); VABS(V1, vB); VABS(V2, vD); VCMPE(V2, V1); VMRS(_PC); SetCC(CC_GT); ORR(fpscrReg, fpscrReg, FRMask); SetCC(); SetJumpTarget(DoneEqual); SetJumpTarget(DoneMax); SetJumpTarget(DoneMin); MOVI2R(rA, (u32)&doublenum); VLDR(V0, rA, 0); NEONXEmitter nemit(this); nemit.VORR(vD, vD, V0); if (inst.Rc) Helper_UpdateCR1(fpscrReg, rA); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(rA); gpr.Unlock(fpscrReg); fpr.Unlock(V0); fpr.Unlock(V1); fpr.Unlock(V2); }
void JitArm::fctiwzx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff) u32 b = inst.FB; u32 d = inst.FD; ARMReg vB = fpr.R0(b); ARMReg vD = fpr.R0(d); ARMReg V0 = fpr.GetReg(); ARMReg V1 = fpr.GetReg(); ARMReg V2 = fpr.GetReg(); ARMReg rA = gpr.GetReg(); ARMReg fpscrReg = gpr.GetReg(); FixupBranch DoneMax, DoneMin; LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); MOVI2R(rA, (u32)minmaxFloat); // Check if greater than max float { VLDR(V0, rA, 8); // Load Max VCMPE(vB, V0); VMRS(_PC); // Loads in to APSR FixupBranch noException = B_CC(CC_LE); VMOV(vD, V0); // Set to max SetFPException(fpscrReg, FPSCR_VXCVI); DoneMax = B(); SetJumpTarget(noException); } // Check if less than min float { VLDR(V0, rA, 0); VCMPE(vB, V0); VMRS(_PC); FixupBranch noException = B_CC(CC_GE); VMOV(vD, V0); SetFPException(fpscrReg, FPSCR_VXCVI); DoneMin = B(); SetJumpTarget(noException); } // Within ranges, convert to integer VCVT(vD, vB, TO_INT | IS_SIGNED | ROUND_TO_ZERO); VCMPE(vD, vB); VMRS(_PC); SetCC(CC_EQ); BIC(fpscrReg, fpscrReg, FRFIMask); FixupBranch DoneEqual = B(); SetCC(); SetFPException(fpscrReg, FPSCR_XX); ORR(fpscrReg, fpscrReg, FIMask); VABS(V1, vB); VABS(V2, vD); VCMPE(V2, V1); VMRS(_PC); SetCC(CC_GT); ORR(fpscrReg, fpscrReg, FRMask); SetCC(); SetJumpTarget(DoneEqual); SetJumpTarget(DoneMax); SetJumpTarget(DoneMin); MOVI2R(rA, (u32)&doublenum); VLDR(V0, rA, 0); NEONXEmitter nemit(this); nemit.VORR(vD, vD, V0); if (inst.Rc) Helper_UpdateCR1(fpscrReg, rA); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(rA); gpr.Unlock(fpscrReg); fpr.Unlock(V0); fpr.Unlock(V1); fpr.Unlock(V2); }
void Jit::Comp_SVQ(MIPSOpcode op) { CONDITIONAL_DISABLE; int imm = (signed short)(op&0xFFFC); int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5); MIPSGPReg rs = _RS; bool doCheck = false; switch (op >> 26) { case 54: //lv.q { // CC might be set by slow path below, so load regs first. u8 vregs[4]; GetVectorRegs(vregs, V_Quad, vt); fpr.MapRegsAndSpillLockV(vregs, V_Quad, MAP_DIRTY | MAP_NOINIT); if (gpr.IsImm(rs)) { u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, imm); } else { SetCCAndR0ForSafeAddress(rs, imm, R1); doCheck = true; } ADD(R0, R0, R11); } #ifdef __ARM_ARCH_7S__ FixupBranch skip; if (doCheck) { skip = B_CC(CC_EQ); } for (int i = 0; i < 4; i++) VLDR(fpr.V(vregs[i]), R0, i * 4); if (doCheck) { SetJumpTarget(skip); SetCC(CC_AL); } #else for (int i = 0; i < 4; i++) VLDR(fpr.V(vregs[i]), R0, i * 4); if (doCheck) { SetCC(CC_EQ); MOVI2R(R0, 0); for (int i = 0; i < 4; i++) VMOV(fpr.V(vregs[i]), R0); SetCC(CC_AL); } #endif } break; case 62: //sv.q { // CC might be set by slow path below, so load regs first. u8 vregs[4]; GetVectorRegs(vregs, V_Quad, vt); fpr.MapRegsAndSpillLockV(vregs, V_Quad, 0); if (gpr.IsImm(rs)) { u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, imm); } else { SetCCAndR0ForSafeAddress(rs, imm, R1); doCheck = true; } ADD(R0, R0, R11); } #ifdef __ARM_ARCH_7S__ FixupBranch skip; if (doCheck) { skip = B_CC(CC_EQ); } for (int i = 0; i < 4; i++) VSTR(fpr.V(vregs[i]), R0, i * 4); if (doCheck) { SetJumpTarget(skip); SetCC(CC_AL); } #else for (int i = 0; i < 4; i++) VSTR(fpr.V(vregs[i]), R0, i * 4); if (doCheck) { SetCC(CC_AL); } #endif } break; default: DISABLE; break; } fpr.ReleaseSpillLocksAndDiscardTemps(); }
void Jit::Comp_SV(MIPSOpcode op) { CONDITIONAL_DISABLE; s32 imm = (signed short)(op&0xFFFC); int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5); MIPSGPReg rs = _RS; bool doCheck = false; switch (op >> 26) { case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); { // CC might be set by slow path below, so load regs first. fpr.MapRegV(vt, MAP_DIRTY | MAP_NOINIT); if (gpr.IsImm(rs)) { u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, imm); } else { SetCCAndR0ForSafeAddress(rs, imm, R1); doCheck = true; } ADD(R0, R0, R11); } #ifdef __ARM_ARCH_7S__ FixupBranch skip; if (doCheck) { skip = B_CC(CC_EQ); } VLDR(fpr.V(vt), R0, 0); if (doCheck) { SetJumpTarget(skip); SetCC(CC_AL); } #else VLDR(fpr.V(vt), R0, 0); if (doCheck) { SetCC(CC_EQ); MOVI2F(fpr.V(vt), 0.0f, R0); SetCC(CC_AL); } #endif } break; case 58: //sv.s // Memory::Write_U32(VI(vt), addr); { // CC might be set by slow path below, so load regs first. fpr.MapRegV(vt); if (gpr.IsImm(rs)) { u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, imm); } else { SetCCAndR0ForSafeAddress(rs, imm, R1); doCheck = true; } ADD(R0, R0, R11); } #ifdef __ARM_ARCH_7S__ FixupBranch skip; if (doCheck) { skip = B_CC(CC_EQ); } VSTR(fpr.V(vt), R0, 0); if (doCheck) { SetJumpTarget(skip); SetCC(CC_AL); } #else VSTR(fpr.V(vt), R0, 0); if (doCheck) { SetCC(CC_AL); } #endif } break; default: DISABLE; } }
void Jit::ApplyPrefixD(const u8 *vregs, VectorSize sz) { _assert_(js.prefixDFlag & ArmJitState::PREFIX_KNOWN); if (!js.prefixD) return; int n = GetNumVectorElements(sz); for (int i = 0; i < n; i++) { if (js.VfpuWriteMask(i)) continue; // TODO: These clampers are wrong - put this into google // and look at the plot: abs(x) - abs(x-0.5) + 0.5 // It's too steep. // Also, they mishandle NaN and Inf. int sat = (js.prefixD >> (i * 2)) & 3; if (sat == 1) { // clamped = fabs(x) - fabs(x-0.5f) + 0.5f; // [ 0, 1] fpr.MapRegV(vregs[i], MAP_DIRTY); MOVI2F(S0, 0.0f, R0); MOVI2F(S1, 1.0f, R0); VCMP(fpr.V(vregs[i]), S0); VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags). SetCC(CC_LE); VMOV(fpr.V(vregs[i]), S0); SetCC(CC_AL); VCMP(fpr.V(vregs[i]), S1); VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags). SetCC(CC_GT); VMOV(fpr.V(vregs[i]), S1); SetCC(CC_AL); /* VABS(S1, fpr.V(vregs[i])); // S1 = fabs(x) VSUB(fpr.V(vregs[i]), fpr.V(vregs[i]), S0); // S2 = fabs(x-0.5f) {VABD} VABS(fpr.V(vregs[i]), fpr.V(vregs[i])); VSUB(fpr.V(vregs[i]), S1, fpr.V(vregs[i])); // v[i] = S1 - S2 + 0.5f VADD(fpr.V(vregs[i]), fpr.V(vregs[i]), S0);*/ } else if (sat == 3) { fpr.MapRegV(vregs[i], MAP_DIRTY); MOVI2F(S0, -1.0f, R0); MOVI2F(S1, 1.0f, R0); VCMP(fpr.V(vregs[i]), S0); VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags). SetCC(CC_LT); VMOV(fpr.V(vregs[i]), S0); SetCC(CC_AL); VCMP(fpr.V(vregs[i]), S1); VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags). SetCC(CC_GT); VMOV(fpr.V(vregs[i]), S1); SetCC(CC_AL); // clamped = fabs(x) - fabs(x-1.0f); // [-1, 1] /* fpr.MapRegV(vregs[i], MAP_DIRTY); MOVI2F(S0, 1.0f, R0); VABS(S1, fpr.V(vregs[i])); // S1 = fabs(x) VSUB(fpr.V(vregs[i]), fpr.V(vregs[i]), S0); // S2 = fabs(x-1.0f) {VABD} VABS(fpr.V(vregs[i]), fpr.V(vregs[i])); VSUB(fpr.V(vregs[i]), S1, fpr.V(vregs[i])); // v[i] = S1 - S2 */ } } }
void JitArmILAsmRoutineManager::Generate() { enterCode = GetCodePtr(); PUSH(9, R4, R5, R6, R7, R8, R9, R10, R11, _LR); // Take care to 8-byte align stack for function calls. // We are misaligned here because of an odd number of args for PUSH. // It's not like x86 where you need to account for an extra 4 bytes // consumed by CALL. SUB(_SP, _SP, 4); MOVI2R(R0, (u32)&CoreTiming::downcount); MOVI2R(R9, (u32)&PowerPC::ppcState.spr[0]); FixupBranch skipToRealDispatcher = B(); dispatcher = GetCodePtr(); printf("ILDispatcher is %p\n", dispatcher); // Downcount Check // The result of slice decrementation should be in flags if somebody jumped here // IMPORTANT - We jump on negative, not carry!!! FixupBranch bail = B_CC(CC_MI); SetJumpTarget(skipToRealDispatcher); dispatcherNoCheck = GetCodePtr(); // This block of code gets the address of the compiled block of code // It runs though to the compiling portion if it isn't found LDR(R12, R9, PPCSTATE_OFF(pc));// Load the current PC into R12 Operand2 iCacheMask = Operand2(0xE, 2); // JIT_ICACHE_MASK BIC(R12, R12, iCacheMask); // R12 contains PC & JIT_ICACHE_MASK here. MOVI2R(R14, (u32)jit->GetBlockCache()->iCache); LDR(R12, R14, R12); // R12 contains iCache[PC & JIT_ICACHE_MASK] here // R12 Confirmed this is the correct iCache Location loaded. TST(R12, 0x80); // Test to see if it is a JIT block. SetCC(CC_EQ); // Success, it is our Jitblock. MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers()); // LDR R14 right here to get CodePointers()[0] pointer. LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size LDR(R14, R14, R12); // Load the block address in to R14 B(R14); // No need to jump anywhere after here, the block will go back to dispatcher start SetCC(); // If we get to this point, that means that we don't have the block cached to execute // So call ArmJit to compile the block and then execute it. MOVI2R(R14, (u32)&Jit); BL(R14); B(dispatcherNoCheck); // fpException() // Floating Point Exception Check, Jumped to if false fpException = GetCodePtr(); LDR(R0, R9, PPCSTATE_OFF(Exceptions)); ORR(R0, R0, EXCEPTION_FPU_UNAVAILABLE); STR(R0, R9, PPCSTATE_OFF(Exceptions)); QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions); LDR(R0, R9, PPCSTATE_OFF(npc)); STR(R0, R9, PPCSTATE_OFF(pc)); B(dispatcher); SetJumpTarget(bail); doTiming = GetCodePtr(); // XXX: In JIT64, Advance() gets called /after/ the exception checking // once it jumps back to the start of outerLoop QuickCallFunction(R14, (void*)&CoreTiming::Advance); // Does exception checking testExceptions = GetCodePtr(); LDR(R0, R9, PPCSTATE_OFF(pc)); STR(R0, R9, PPCSTATE_OFF(npc)); QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions); LDR(R0, R9, PPCSTATE_OFF(npc)); STR(R0, R9, PPCSTATE_OFF(pc)); // Check the state pointer to see if we are exiting // Gets checked on every exception check MOVI2R(R0, (u32)PowerPC::GetStatePtr()); MVN(R1, 0); LDR(R0, R0); TST(R0, R1); FixupBranch Exit = B_CC(CC_NEQ); B(dispatcher); SetJumpTarget(Exit); ADD(_SP, _SP, 4); POP(9, R4, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns GenerateCommon(); FlushIcache(); }
void Jit::Comp_FPU2op(u32 op) { CONDITIONAL_DISABLE; int fs = _FS; int fd = _FD; // logBlocks = 1; switch (op & 0x3f) { case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt fpr.MapDirtyIn(fd, fs); VSQRT(fpr.R(fd), fpr.R(fs)); break; case 5: //F(fd) = fabsf(F(fs)); break; //abs fpr.MapDirtyIn(fd, fs); VABS(fpr.R(fd), fpr.R(fs)); break; case 6: //F(fd) = F(fs); break; //mov fpr.MapDirtyIn(fd, fs); VMOV(fpr.R(fd), fpr.R(fs)); break; case 7: //F(fd) = -F(fs); break; //neg fpr.MapDirtyIn(fd, fs); VNEG(fpr.R(fd), fpr.R(fs)); break; case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s fpr.MapDirtyIn(fd, fs); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED); break; case 13: //FsI(fd) = Rto0(F(fs))); break; //trunc.w.s fpr.MapDirtyIn(fd, fs); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED | ROUND_TO_ZERO); break; case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s fpr.MapDirtyIn(fd, fs); MOVI2F(S0, 0.5f, R0); VADD(S0,fpr.R(fs),S0); VCVT(fpr.R(fd), S0, TO_INT | IS_SIGNED); break; case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s fpr.MapDirtyIn(fd, fs); MOVI2F(S0, 0.5f, R0); VSUB(S0,fpr.R(fs),S0); VCVT(fpr.R(fd), S0, TO_INT | IS_SIGNED); break; case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w fpr.MapDirtyIn(fd, fs); VCVT(fpr.R(fd), fpr.R(fs), TO_FLOAT | IS_SIGNED); break; case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s fpr.MapDirtyIn(fd, fs); 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; } }
BNFDefinition :: BNFDefinition (BNFParser *bs_parent, char *trace_path ) : BNFParser ("bnf",bs_parent,NO,NO,trace_path) { BNFExpression *__expression; /* bnf := bnf_stmt(*) bnf_stmt := definition | keyword | reference | comment_line | nl definition := sym_name ':=' rule [comment] nl rule := prule [ alt_prule(*) ] alt_prule := '|' prule prule := ext_symbol(*) ext_symbol := elm_symbol [ multiple ] multiple := '(' maxnum ')' maxnum := '*' | std_number elm_symbol := sym_name | cstring | impl_symbol | opt_symbol impl_symbol := '{' rule '}' opt_symbol := '[' rule ']' keyword := sym_name '::' keydef [ alt_keydef(*) ] nl alt_keydef := '|' keydef keydef := cstring reference := name '::=' symref nl symref := class_ref | symbol_ref class_ref := 'class' '(' name ')' symbol_ref := 'ref' '(' name ')' sym_name := name name := std_name cstring := std_str comment_line:= comment nl comment := '//' std_anychar(*) CC := '//' std_symbols ::= class(BNFStandardSymbols) std_name ::= ref(std_name) std_number ::= ref(std_integer) std_str ::= ref(std_string) std_anychar ::= ref(std_anychar) nl ::= ref(std_nl) */ BNFSymbol *bnf = this; if ( !bs_parent ) bs_parent = this; BNFSymbol *std_symbols = new BNFStandardSymbols(bs_parent); BNFSymbol *std_name = top_symbol->GetSymbol("std_name"); BNFSymbol *std_number = top_symbol->GetSymbol("std_integer"); BNFSymbol *std_str = top_symbol->GetSymbol("std_string"); BNFSymbol *std_anychar = top_symbol->GetSymbol("std_anychar"); BNFSymbol *nl = top_symbol->GetSymbol("std_nl"); if ( !bs_parent || bs_parent == this ) SetFirst(); BNFSymbol *bnf_stmt = new BNFSymbol(top_symbol,"bnf_stmt"); BNFSymbol *definition = new BNFSymbol(top_symbol,"definition"); BNFSymbol *rule = new BNFSymbol(top_symbol,"rule"); BNFSymbol *alt_prule = new BNFSymbol(top_symbol,"alt_prule"); BNFSymbol *prule = new BNFSymbol(top_symbol,"prule"); BNFSymbol *ext_symbol = new BNFSymbol(top_symbol,"ext_symbol"); BNFSymbol *multiple = new BNFSymbol(top_symbol,"multiple"); BNFSymbol *maxnum = new BNFSymbol(top_symbol,"maxnum"); BNFSymbol *elm_symbol = new BNFSymbol(top_symbol,"elm_symbol"); BNFSymbol *impl_symbol = new BNFSymbol(top_symbol,"impl_symbol"); BNFSymbol *opt_symbol = new BNFSymbol(top_symbol,"opt_symbol"); BNFSymbol *keyword = new BNFSymbol(top_symbol,"keyword"); BNFSymbol *alt_keydef = new BNFSymbol(top_symbol,"alt_keydef"); BNFSymbol *keydef = new BNFSymbol(top_symbol,"keydef"); BNFSymbol *reference = new BNFSymbol(top_symbol,"reference"); BNFSymbol *symref = new BNFSymbol(top_symbol,"symref"); BNFSymbol *class_ref = new BNFSymbol(top_symbol,"class_ref"); BNFSymbol *symbol_ref = new BNFSymbol(top_symbol,"symbol_ref"); BNFSymbol *sym_name = new BNFSymbol(top_symbol,"sym_name"); BNFSymbol *name = new BNFSymbol(top_symbol,"name"); BNFSymbol *cstring = new BNFSymbol(top_symbol,"cstring"); BNFSymbol *comment_line = new BNFSymbol(top_symbol,"comment_line"); BNFSymbol *comment = new BNFSymbol(top_symbol,"comment"); // bnf __expression = new BNFExpression(bnf); __expression->AddElement(bnf_stmt,NO,UNDEF,YES,YES); // bnf_stmt __expression = new BNFExpression(bnf_stmt); __expression->AddElement(definition,NO,1,YES,YES); __expression = new BNFExpression(bnf_stmt); __expression->AddElement(keyword,NO,1,YES,YES); __expression = new BNFExpression(bnf_stmt); __expression->AddElement(reference,NO,1,YES,YES); __expression = new BNFExpression(bnf_stmt); __expression->AddElement(comment_line,NO,1,YES,YES); __expression = new BNFExpression(bnf_stmt); __expression->AddElement(nl,NO,1,YES,YES); // definition __expression = new BNFExpression(definition); __expression->AddElement(sym_name,NO,1,YES,YES); __expression->AddElement(ElementaryToken(':'),NO,1,NO,NO); __expression->AddElement(ElementaryToken('='),NO,1,NO,YES); __expression->AddElement(rule,NO,1,YES,YES); __expression->AddElement(comment,YES,1,YES,YES); __expression->AddElement(nl,NO,1,YES,YES); // rule __expression = new BNFExpression(rule); __expression->AddElement(prule,NO,1,YES,YES); __expression->AddElement(alt_prule,YES,UNDEF,YES,YES); // alt_prule __expression = new BNFExpression(alt_prule); __expression->AddElement(ElementaryToken('|'),NO,1,NO,YES); __expression->AddElement(prule,NO,1,YES,YES); // prule __expression = new BNFExpression(prule); __expression->AddElement(ext_symbol,NO,UNDEF,YES,YES); // ext_symbol __expression = new BNFExpression(ext_symbol); __expression->AddElement(elm_symbol,NO,1,YES,YES); __expression->AddElement(multiple,YES,1,YES,YES); // multiple __expression = new BNFExpression(multiple); __expression->AddElement(ElementaryToken('('),NO,1,NO,YES); __expression->AddElement(maxnum,NO,1,YES,YES); __expression->AddElement(ElementaryToken(')'),NO,1,NO,YES); // maxnum __expression = new BNFExpression(maxnum); __expression->AddElement(ElementaryToken('*'),NO,1,NO,YES); __expression = new BNFExpression(maxnum); __expression->AddElement(std_number,NO,1,YES,YES); // elm_symbol __expression = new BNFExpression(elm_symbol); __expression->AddElement(sym_name,NO,1,YES,YES); __expression = new BNFExpression(elm_symbol); __expression->AddElement(cstring,NO,1,YES,YES); __expression = new BNFExpression(elm_symbol); __expression->AddElement(impl_symbol,NO,1,YES,YES); __expression = new BNFExpression(elm_symbol); __expression->AddElement(opt_symbol,NO,1,YES,YES); // impl_symbol __expression = new BNFExpression(impl_symbol); __expression->AddElement(ElementaryToken('{'),NO,1,NO,YES); __expression->AddElement(rule,NO,1,YES,YES); __expression->AddElement(ElementaryToken('}'),NO,1,NO,YES); // opt_symbol __expression = new BNFExpression(opt_symbol); __expression->AddElement(ElementaryToken('['),NO,1,NO,YES); __expression->AddElement(rule,NO,1,YES,YES); __expression->AddElement(ElementaryToken(']'),NO,1,NO,YES); // keyword __expression = new BNFExpression(keyword); __expression->AddElement(sym_name,NO,1,YES,YES); __expression->AddElement(ElementaryToken(':'),NO,1,NO,NO); __expression->AddElement(ElementaryToken(':'),NO,1,NO,YES); __expression->AddElement(keydef,NO,1,YES,YES); __expression->AddElement(alt_keydef,YES,UNDEF,YES,YES); __expression->AddElement(nl,NO,1,YES,YES); // alt_keydef __expression = new BNFExpression(alt_keydef); __expression->AddElement(ElementaryToken('|'),NO,1,NO,YES); __expression->AddElement(keydef,NO,1,YES,YES); // keydef __expression = new BNFExpression(keydef); __expression->AddElement(cstring,NO,1,YES,YES); // reference __expression = new BNFExpression(reference); __expression->AddElement(name,NO,1,YES,YES); __expression->AddElement(ElementaryToken(':'),NO,1,NO,NO); __expression->AddElement(ElementaryToken(':'),NO,1,NO,NO); __expression->AddElement(ElementaryToken('='),NO,1,NO,YES); __expression->AddElement(symref,NO,1,YES,YES); __expression->AddElement(nl,NO,1,YES,YES); // symref __expression = new BNFExpression(symref); __expression->AddElement(class_ref,NO,1,YES,YES); __expression = new BNFExpression(symref); __expression->AddElement(symbol_ref,NO,1,YES,YES); // class_ref __expression = new BNFExpression(class_ref); __expression->AddElement(ElementaryToken('c'),NO,1,YES,NO); __expression->AddElement(ElementaryToken('l'),NO,1,YES,NO); __expression->AddElement(ElementaryToken('a'),NO,1,YES,NO); __expression->AddElement(ElementaryToken('s'),NO,1,YES,NO); __expression->AddElement(ElementaryToken('s'),NO,1,YES,YES); __expression->AddElement(ElementaryToken('('),NO,1,NO,YES); __expression->AddElement(name,NO,1,YES,YES); __expression->AddElement(ElementaryToken(')'),NO,1,NO,YES); // symbol_ref __expression = new BNFExpression(symbol_ref); __expression->AddElement(ElementaryToken('r'),NO,1,YES,NO); __expression->AddElement(ElementaryToken('e'),NO,1,YES,NO); __expression->AddElement(ElementaryToken('f'),NO,1,YES,YES); __expression->AddElement(ElementaryToken('('),NO,1,NO,YES); __expression->AddElement(name,NO,1,YES,YES); __expression->AddElement(ElementaryToken(')'),NO,1,NO,YES); // sym_name __expression = new BNFExpression(sym_name); __expression->AddElement(name,NO,1,YES,YES); // name __expression = new BNFExpression(name); __expression->AddElement(std_name,NO,1,YES,YES); // cstring __expression = new BNFExpression(cstring); __expression->AddElement(std_str,NO,1,YES,YES); // comment_line __expression = new BNFExpression(comment_line); __expression->AddElement(comment,NO,1,YES,YES); __expression->AddElement(nl,NO,1,YES,YES); // comment __expression = new BNFExpression(comment); __expression->AddElement(ElementaryToken('/'),NO,1,NO,NO); __expression->AddElement(ElementaryToken('/'),NO,1,NO,YES); __expression->AddElement(std_anychar,NO,UNDEF,YES,YES); // CC SetCC("//"); if ( !bs_parent || bs_parent == this ) ReorderSymbols(); }
void Jit::Comp_SV(u32 op) { CONDITIONAL_DISABLE; s32 imm = (signed short)(op&0xFFFC); int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5); int rs = _RS; bool doCheck = false; switch (op >> 26) { case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); { // CC might be set by slow path below, so load regs first. fpr.MapRegV(vt, MAP_DIRTY | MAP_NOINIT); fpr.ReleaseSpillLocks(); if (gpr.IsImm(rs)) { u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, imm); } else { SetCCAndR0ForSafeAddress(rs, imm, R1); doCheck = true; } ADD(R0, R0, R11); } VLDR(fpr.V(vt), R0, 0); if (doCheck) { SetCC(CC_EQ); MOVI2R(R0, 0); VMOV(fpr.V(vt), R0); SetCC(CC_AL); } } break; case 58: //sv.s // Memory::Write_U32(VI(vt), addr); { // CC might be set by slow path below, so load regs first. fpr.MapRegV(vt); fpr.ReleaseSpillLocks(); if (gpr.IsImm(rs)) { u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; MOVI2R(R0, addr + (u32)Memory::base); } else { gpr.MapReg(rs); if (g_Config.bFastMemory) { SetR0ToEffectiveAddress(rs, imm); } else { SetCCAndR0ForSafeAddress(rs, imm, R1); doCheck = true; } ADD(R0, R0, R11); } VSTR(fpr.V(vt), R0, 0); if (doCheck) { SetCC(CC_AL); } } break; default: DISABLE; } }
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)); }
void JitArm::stfXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg RA; u32 a = inst.RA, b = inst.RB; s32 offset = inst.SIMM_16; bool single = false; bool update = false; bool zeroA = false; s32 offsetReg = -1; switch (inst.OPCD) { case 31: switch (inst.SUBOP10) { case 663: // stfsx single = true; zeroA = true; offsetReg = b; break; case 695: // stfsux single = true; offsetReg = b; break; case 727: // stfdx zeroA = true; offsetReg = b; break; case 759: // stfdux update = true; offsetReg = b; break; } break; case 53: // stfsu update = true; single = true; break; case 52: // stfs single = true; zeroA = true; break; case 55: // stfdu update = true; break; case 54: // stfd zeroA = true; break; } ARMReg v0 = fpr.R0(inst.FS); if (update) { RA = gpr.R(a); // Update path /always/ uses RA if (offsetReg == -1) // uses SIMM_16 { MOVI2R(rB, offset); ADD(rB, rB, RA); } else { ADD(rB, gpr.R(offsetReg), RA); } } else { if (zeroA) { if (offsetReg == -1) { if (a) { RA = gpr.R(a); MOVI2R(rB, offset); ADD(rB, rB, RA); } else { MOVI2R(rB, (u32)offset); } } else { ARMReg RB = gpr.R(offsetReg); if (a) { RA = gpr.R(a); ADD(rB, RB, RA); } else { MOV(rB, RB); } } } } if (update) { LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); SetCC(CC_NEQ); MOV(RA, rB); SetCC(); } if (Core::g_CoreStartupParameter.bFastmem) { Operand2 mask(2, 1); // ~(Memory::MEMVIEW32_MASK) BIC(rB, rB, mask); // 1 MOVI2R(rA, (u32)Memory::base, false); // 2-3 ADD(rB, rB, rA); // 4 NEONXEmitter nemit(this); if (single) { VCVT(S0, v0, 0); nemit.VREV32(I_8, D0, D0); VSTR(S0, rB, 0); } else { nemit.VREV64(I_8, D0, v0); VSTR(D0, rB, 0); } } else { PUSH(4, R0, R1, R2, R3); if (single) { MOVI2R(rA, (u32)&Memory::Write_U32); VCVT(S0, v0, 0); VMOV(R0, S0); MOV(R1, rB); BL(rA); } else { MOVI2R(rA, (u32)&Memory::Write_F64); #if !defined(__ARM_PCS_VFP) // SoftFP returns in R0 and R1 VMOV(R0, v0); MOV(R2, rB); #else VMOV(D0, v0); MOV(R0, rB); #endif BL(rA); } POP(4, R0, R1, R2, R3); } gpr.Unlock(rA, rB); }
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 PDECond::SetCC(double lenght, double dist){ int posy = (Ydim-lenght)/(2*passoY); int posx = (Xdim-dist)/(2.*passoX); SetCC(posy,posx); std::cout<< "SetCC(double lenght, double dist) done\n"; }