CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/MIPS/ARM/ArmCompFPU.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "ppsspp_config.h"18#if PPSSPP_ARCH(ARM)1920#include "Core/Config.h"21#include "Core/MemMap.h"22#include "Core/MIPS/MIPS.h"23#include "Core/MIPS/MIPSCodeUtils.h"24#include "Core/MIPS/MIPSTables.h"2526#include "Core/MIPS/ARM/ArmJit.h"27#include "Core/MIPS/ARM/ArmRegCache.h"28#include "Common/CPUDetect.h"2930#define _RS MIPS_GET_RS(op)31#define _RT MIPS_GET_RT(op)32#define _RD MIPS_GET_RD(op)33#define _FS MIPS_GET_FS(op)34#define _FT MIPS_GET_FT(op)35#define _FD MIPS_GET_FD(op)36#define _SA MIPS_GET_SA(op)37#define _POS ((op>> 6) & 0x1F)38#define _SIZE ((op>>11) & 0x1F)39#define _IMM16 (signed short)(op & 0xFFFF)40#define _IMM26 (op & 0x03FFFFFF)4142// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.43// Currently known non working ones should have DISABLE.4445// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }46#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }47#define DISABLE { Comp_Generic(op); return; }4849namespace MIPSComp50{51using namespace ArmGen;52using namespace ArmJitConstants;5354void ArmJit::Comp_FPU3op(MIPSOpcode op)55{56CONDITIONAL_DISABLE(FPU);5758int ft = _FT;59int fs = _FS;60int fd = _FD;6162fpr.MapDirtyInIn(fd, fs, ft);63switch (op & 0x3f)64{65case 0: VADD(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) + F(ft); //add66case 1: VSUB(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) - F(ft); //sub67case 2: { //F(fd) = F(fs) * F(ft); //mul68MIPSOpcode nextOp = GetOffsetInstruction(1);69// Optimization possible if destination is the same70if (fd == (int)((nextOp>>6) & 0x1F)) {71// VMUL + VNEG -> VNMUL72if (!strcmp(MIPSGetName(nextOp), "neg.s")) {73if (fd == (int)((nextOp>>11) & 0x1F)) {74VNMUL(fpr.R(fd), fpr.R(fs), fpr.R(ft));75EatInstruction(nextOp);76}77return;78}79}80VMUL(fpr.R(fd), fpr.R(fs), fpr.R(ft));81break;82}83case 3: VDIV(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) / F(ft); //div84default:85DISABLE;86return;87}88}8990extern int logBlocks;9192void ArmJit::Comp_FPULS(MIPSOpcode op)93{94CONDITIONAL_DISABLE(LSU_FPU);95CheckMemoryBreakpoint();9697s32 offset = SignExtend16ToS32(op & 0xFFFF);98int ft = _FT;99MIPSGPReg rs = _RS;100// u32 addr = R(rs) + offset;101// logBlocks = 1;102bool doCheck = false;103switch(op >> 26)104{105case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1106if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) {107gpr.MapRegAsPointer(rs);108fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY);109VLDR(fpr.R(ft), gpr.RPtr(rs), offset);110break;111}112113fpr.SpillLock(ft);114fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY);115if (gpr.IsImm(rs)) {116u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF;117gpr.SetRegImm(R0, addr + (u32)Memory::base);118} else {119gpr.MapReg(rs);120if (g_Config.bFastMemory) {121SetR0ToEffectiveAddress(rs, offset);122} else {123SetCCAndR0ForSafeAddress(rs, offset, SCRATCHREG2);124doCheck = true;125}126ADD(R0, R0, MEMBASEREG);127}128#ifdef __ARM_ARCH_7S__129FixupBranch skip;130if (doCheck) {131skip = B_CC(CC_EQ);132}133VLDR(fpr.R(ft), R0, 0);134if (doCheck) {135SetJumpTarget(skip);136}137#else138VLDR(fpr.R(ft), R0, 0);139if (doCheck) {140SetCC(CC_EQ);141MOVI2R(R0, 0);142VMOV(fpr.R(ft), R0);143SetCC(CC_AL);144}145#endif146fpr.ReleaseSpillLocksAndDiscardTemps();147break;148149case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1150if (!gpr.IsImm(rs) && jo.cachePointers && g_Config.bFastMemory && (offset & 3) == 0 && offset < 0x400 && offset > -0x400) {151gpr.MapRegAsPointer(rs);152fpr.MapReg(ft, 0);153VSTR(fpr.R(ft), gpr.RPtr(rs), offset);154break;155}156157fpr.MapReg(ft);158if (gpr.IsImm(rs)) {159u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF;160gpr.SetRegImm(R0, addr + (u32)Memory::base);161} else {162gpr.MapReg(rs);163if (g_Config.bFastMemory) {164SetR0ToEffectiveAddress(rs, offset);165} else {166SetCCAndR0ForSafeAddress(rs, offset, SCRATCHREG2);167doCheck = true;168}169ADD(R0, R0, MEMBASEREG);170}171#ifdef __ARM_ARCH_7S__172FixupBranch skip2;173if (doCheck) {174skip2 = B_CC(CC_EQ);175}176VSTR(fpr.R(ft), R0, 0);177if (doCheck) {178SetJumpTarget(skip2);179}180#else181VSTR(fpr.R(ft), R0, 0);182if (doCheck) {183SetCC(CC_AL);184}185#endif186break;187188default:189Comp_Generic(op);190return;191}192}193194void ArmJit::Comp_FPUComp(MIPSOpcode op) {195CONDITIONAL_DISABLE(FPU_COMP);196197int opc = op & 0xF;198if (opc >= 8) opc -= 8; // alias199if (opc == 0) { // f, sf (signalling false)200gpr.SetImm(MIPS_REG_FPCOND, 0);201return;202}203204int fs = _FS;205int ft = _FT;206gpr.MapReg(MIPS_REG_FPCOND, MAP_DIRTY | MAP_NOINIT);207fpr.MapInIn(fs, ft);208VCMP(fpr.R(fs), fpr.R(ft));209VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags).210switch(opc)211{212case 1: // un, ngle (unordered)213SetCC(CC_VS);214MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);215SetCC(CC_VC);216break;217case 2: // eq, seq (equal, ordered)218SetCC(CC_EQ);219MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);220SetCC(CC_NEQ);221break;222case 3: // ueq, ngl (equal, unordered)223SetCC(CC_EQ);224MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);225SetCC(CC_NEQ);226MOVI2R(gpr.R(MIPS_REG_FPCOND), 0);227SetCC(CC_VS);228MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);229SetCC(CC_AL);230return;231case 4: // olt, lt (less than, ordered)232SetCC(CC_LO);233MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);234SetCC(CC_HS);235break;236case 5: // ult, nge (less than, unordered)237SetCC(CC_LT);238MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);239SetCC(CC_GE);240break;241case 6: // ole, le (less equal, ordered)242SetCC(CC_LS);243MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);244SetCC(CC_HI);245break;246case 7: // ule, ngt (less equal, unordered)247SetCC(CC_LE);248MOVI2R(gpr.R(MIPS_REG_FPCOND), 1);249SetCC(CC_GT);250break;251default:252Comp_Generic(op);253return;254}255MOVI2R(gpr.R(MIPS_REG_FPCOND), 0);256SetCC(CC_AL);257}258259void ArmJit::Comp_FPU2op(MIPSOpcode op) {260CONDITIONAL_DISABLE(FPU);261262int fs = _FS;263int fd = _FD;264265switch (op & 0x3f) {266case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt267fpr.MapDirtyIn(fd, fs);268VSQRT(fpr.R(fd), fpr.R(fs));269break;270case 5: //F(fd) = fabsf(F(fs)); break; //abs271fpr.MapDirtyIn(fd, fs);272VABS(fpr.R(fd), fpr.R(fs));273break;274case 6: //F(fd) = F(fs); break; //mov275fpr.MapDirtyIn(fd, fs);276VMOV(fpr.R(fd), fpr.R(fs));277break;278case 7: //F(fd) = -F(fs); break; //neg279fpr.MapDirtyIn(fd, fs);280VNEG(fpr.R(fd), fpr.R(fs));281break;282case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s283RestoreRoundingMode();284fpr.MapDirtyIn(fd, fs);285VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED);286break;287case 13: //FsI(fd) = Rto0(F(fs))); break; //trunc.w.s288fpr.MapDirtyIn(fd, fs);289VCMP(fpr.R(fs), fpr.R(fs));290VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED | ROUND_TO_ZERO);291VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags).292SetCC(CC_VS);293MOVIU2F(fpr.R(fd), 0x7FFFFFFF, SCRATCHREG1);294SetCC(CC_AL);295break;296case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s297{298RestoreRoundingMode();299fpr.MapDirtyIn(fd, fs);300VMRS(SCRATCHREG2);301// Assume we're always in round-to-nearest mode.302ORR(SCRATCHREG1, SCRATCHREG2, AssumeMakeOperand2(1 << 22));303VMSR(SCRATCHREG1);304VCMP(fpr.R(fs), fpr.R(fs));305VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED);306VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags).307SetCC(CC_VS);308MOVIU2F(fpr.R(fd), 0x7FFFFFFF, SCRATCHREG1);309SetCC(CC_AL);310// Set the rounding mode back. TODO: Keep it? Dirty?311VMSR(SCRATCHREG2);312break;313}314case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s315{316RestoreRoundingMode();317fpr.MapDirtyIn(fd, fs);318VMRS(SCRATCHREG2);319// Assume we're always in round-to-nearest mode.320ORR(SCRATCHREG1, SCRATCHREG2, AssumeMakeOperand2(2 << 22));321VMSR(SCRATCHREG1);322VCMP(fpr.R(fs), fpr.R(fs));323VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED);324VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags).325SetCC(CC_VS);326MOVIU2F(fpr.R(fd), 0x7FFFFFFF, SCRATCHREG1);327SetCC(CC_AL);328// Set the rounding mode back. TODO: Keep it? Dirty?329VMSR(SCRATCHREG2);330break;331}332case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w333fpr.MapDirtyIn(fd, fs);334VCVT(fpr.R(fd), fpr.R(fs), TO_FLOAT | IS_SIGNED);335break;336case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s337fpr.MapDirtyIn(fd, fs);338VCMP(fpr.R(fs), fpr.R(fs));339VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED);340VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags).341SetCC(CC_VS);342MOVIU2F(fpr.R(fd), 0x7FFFFFFF, SCRATCHREG1);343SetCC(CC_AL);344break;345default:346DISABLE;347}348}349350void ArmJit::Comp_mxc1(MIPSOpcode op)351{352CONDITIONAL_DISABLE(FPU_XFER);353354int fs = _FS;355MIPSGPReg rt = _RT;356357switch ((op >> 21) & 0x1f)358{359case 0: // R(rt) = FI(fs); break; //mfc1360if (rt == MIPS_REG_ZERO) {361return;362}363gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT);364if (fpr.IsMapped(fs)) {365VMOV(gpr.R(rt), fpr.R(fs));366} else {367LDR(gpr.R(rt), CTXREG, fpr.GetMipsRegOffset(fs));368}369return;370371case 2: //cfc1372if (rt == MIPS_REG_ZERO) {373return;374}375if (fs == 31) {376if (gpr.IsImm(MIPS_REG_FPCOND)) {377gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT);378LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31));379if (gpr.GetImm(MIPS_REG_FPCOND) & 1) {380ORI2R(gpr.R(rt), gpr.R(rt), 0x1 << 23, SCRATCHREG2);381} else {382ANDI2R(gpr.R(rt), gpr.R(rt), ~(0x1 << 23), SCRATCHREG2);383}384} else {385gpr.MapDirtyIn(rt, MIPS_REG_FPCOND);386LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31));387#if PPSSPP_ARCH(ARMV7)388BFI(gpr.R(rt), gpr.R(MIPS_REG_FPCOND), 23, 1);389#else390AND(SCRATCHREG1, gpr.R(MIPS_REG_FPCOND), Operand2(1)); // Just in case391ANDI2R(gpr.R(rt), gpr.R(rt), ~(0x1 << 23), SCRATCHREG2); // SCRATCHREG2 won't be used, this turns into a simple BIC.392ORR(gpr.R(rt), gpr.R(rt), Operand2(SCRATCHREG1, ST_LSL, 23));393#endif394}395} else if (fs == 0) {396gpr.SetImm(rt, MIPSState::FCR0_VALUE);397} else {398// Unsupported regs are always 0.399gpr.SetImm(rt, 0);400}401return;402403case 4: //FI(fs) = R(rt); break; //mtc1404if (gpr.IsImm(rt) && gpr.GetImm(rt) == 0) {405fpr.MapReg(fs, MAP_NOINIT);406MOVI2F(fpr.R(fs), 0.0f, R0);407} else {408gpr.MapReg(rt);409fpr.MapReg(fs, MAP_NOINIT);410VMOV(fpr.R(fs), gpr.R(rt));411}412return;413414case 6: //ctc1415if (fs == 31) {416// Must clear before setting, since ApplyRoundingMode() assumes it was cleared.417RestoreRoundingMode();418bool wasImm = gpr.IsImm(rt);419u32 immVal = -1;420if (wasImm) {421immVal = gpr.GetImm(rt);422gpr.SetImm(MIPS_REG_FPCOND, (immVal >> 23) & 1);423gpr.MapReg(rt);424} else {425gpr.MapDirtyIn(MIPS_REG_FPCOND, rt);426}427428// Update MIPS state429// TODO: Technically, should mask by 0x0181FFFF. Maybe just put all of FCR31 in the reg?430STR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31));431if (!wasImm) {432#if PPSSPP_ARCH(ARMV7)433UBFX(gpr.R(MIPS_REG_FPCOND), gpr.R(rt), 23, 1);434#else435MOV(SCRATCHREG1, Operand2(gpr.R(rt), ST_LSR, 23));436AND(gpr.R(MIPS_REG_FPCOND), SCRATCHREG1, Operand2(1));437#endif438UpdateRoundingMode();439} else {440UpdateRoundingMode(immVal);441}442ApplyRoundingMode();443} else {444Comp_Generic(op);445}446return;447}448}449450} // namespace MIPSComp451452#endif // PPSSPP_ARCH(ARM)453454455