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/IR/IRCompFPU.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 "Core/Config.h"18#include "Core/MemMap.h"19#include "Core/MIPS/MIPS.h"20#include "Core/MIPS/MIPSCodeUtils.h"21#include "Core/MIPS/MIPSTables.h"2223#include "Core/MIPS/IR/IRFrontend.h"24#include "Core/MIPS/IR/IRRegCache.h"25#include "Common/CPUDetect.h"2627#define _RS MIPS_GET_RS(op)28#define _RT MIPS_GET_RT(op)29#define _RD MIPS_GET_RD(op)30#define _FS MIPS_GET_FS(op)31#define _FT MIPS_GET_FT(op)32#define _FD MIPS_GET_FD(op)33#define _SA MIPS_GET_SA(op)34#define _POS ((op>> 6) & 0x1F)35#define _SIZE ((op>>11) & 0x1F)36#define _IMM16 (signed short)(op & 0xFFFF)37#define _IMM26 (op & 0x03FFFFFF)383940// FPCR interesting bits:41// 24: FZ (flush-to-zero)42// 23:22: RMode (0 = nearest, 1 = +inf, 2 = -inf, 3 = zero)43// not much else is interesting for us, but should be preserved.44// To access: MRS Xt, FPCR ; MSR FPCR, Xt454647// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.48// Currently known non working ones should have DISABLE.4950// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }51#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }52#define DISABLE { Comp_Generic(op); return; }53#define INVALIDOP { Comp_Generic(op); return; }5455namespace MIPSComp {5657void IRFrontend::Comp_FPU3op(MIPSOpcode op) {58CONDITIONAL_DISABLE(FPU);5960int ft = _FT;61int fs = _FS;62int fd = _FD;6364switch (op & 0x3f) {65case 0: ir.Write(IROp::FAdd, fd, fs, ft); break; //F(fd) = F(fs) + F(ft); //add66case 1: ir.Write(IROp::FSub, fd, fs, ft); break; //F(fd) = F(fs) - F(ft); //sub67case 2: ir.Write(IROp::FMul, fd, fs, ft); break; //F(fd) = F(fs) * F(ft); //mul68case 3: ir.Write(IROp::FDiv, fd, fs, ft); break; //F(fd) = F(fs) / F(ft); //div69default:70INVALIDOP;71return;72}73}7475void IRFrontend::Comp_FPULS(MIPSOpcode op) {76CONDITIONAL_DISABLE(LSU_FPU);77s32 offset = _IMM16;78int ft = _FT;79MIPSGPReg rs = _RS;8081CheckMemoryBreakpoint(rs, offset);8283switch (op >> 26) {84case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc185ir.Write(IROp::LoadFloat, ft, rs, ir.AddConstant(offset));86break;8788case 57: //Memory::Write_U32(FI(ft), addr); break; //swc189ir.Write(IROp::StoreFloat, ft, rs, ir.AddConstant(offset));90break;9192default:93INVALIDOP;94break;95}96}9798void IRFrontend::Comp_FPUComp(MIPSOpcode op) {99CONDITIONAL_DISABLE(FPU_COMP);100101int opc = op & 0xF;102if (opc >= 8) opc -= 8; // alias103if (opc == 0) { // f, sf (signalling false)104ir.Write(IROp::FpCondFromReg, 0, MIPS_REG_ZERO);105return;106}107108int fs = _FS;109int ft = _FT;110IRFpCompareMode mode;111switch (opc) {112case 1: // un, ngle (unordered)113mode = IRFpCompareMode::EitherUnordered;114break;115case 2: // eq, seq (equal, ordered)116mode = IRFpCompareMode::EqualOrdered;117break;118case 3: // ueq, ngl (equal, unordered)119mode = IRFpCompareMode::EqualUnordered;120break;121case 4: // olt, lt (less than, ordered)122mode = IRFpCompareMode::LessOrdered;123break;124case 5: // ult, nge (less than, unordered)125mode = IRFpCompareMode::LessUnordered;126break;127case 6: // ole, le (less equal, ordered)128mode = IRFpCompareMode::LessEqualOrdered;129break;130case 7: // ule, ngt (less equal, unordered)131mode = IRFpCompareMode::LessEqualUnordered;132break;133default:134INVALIDOP;135return;136}137ir.Write(IROp::FCmp, (int)mode, fs, ft);138}139140void IRFrontend::Comp_FPU2op(MIPSOpcode op) {141CONDITIONAL_DISABLE(FPU);142143int fs = _FS;144int fd = _FD;145146switch (op & 0x3f) {147case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt148ir.Write(IROp::FSqrt, fd, fs);149break;150case 5: //F(fd) = fabsf(F(fs)); break; //abs151ir.Write(IROp::FAbs, fd, fs);152break;153case 6: //F(fd) = F(fs); break; //mov154if (fd != fs)155ir.Write(IROp::FMov, fd, fs);156break;157case 7: //F(fd) = -F(fs); break; //neg158ir.Write(IROp::FNeg, fd, fs);159break;160161case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s162ir.Write(IROp::FRound, fd, fs);163break;164case 13: //FsI(fd) = Rto0(F(fs))); break; //trunc.w.s165ir.Write(IROp::FTrunc, fd, fs);166break;167case 14://FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s168ir.Write(IROp::FCeil, fd, fs);169break;170case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s171ir.Write(IROp::FFloor, fd, fs);172break;173174case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w175ir.Write(IROp::FCvtSW, fd, fs);176break;177178case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s179ir.Write(IROp::FCvtWS, fd, fs);180break;181182default:183INVALIDOP;184}185}186187void IRFrontend::Comp_mxc1(MIPSOpcode op) {188CONDITIONAL_DISABLE(FPU_XFER);189190int fs = _FS;191MIPSGPReg rt = _RT;192193switch ((op >> 21) & 0x1f) {194case 0: // R(rt) = FI(fs); break; //mfc1195if (rt == MIPS_REG_ZERO) {196return;197}198ir.Write(IROp::FMovToGPR, rt, fs);199return;200201case 2: //cfc1202if (rt == MIPS_REG_ZERO) {203return;204}205if (fs == 31) {206// This needs to insert fpcond.207ir.Write(IROp::FpCtrlToReg, rt);208} else if (fs == 0) {209ir.Write(IROp::SetConst, rt, ir.AddConstant(MIPSState::FCR0_VALUE));210} else {211// Unsupported regs are always 0.212ir.Write(IROp::SetConst, rt, ir.AddConstant(0));213}214return;215216case 4: //FI(fs) = R(rt); break; //mtc1217ir.Write(IROp::FMovFromGPR, fs, rt);218return;219220case 6: //ctc1221if (fs == 31) {222// Set rounding mode223RestoreRoundingMode();224ir.Write(IROp::FpCtrlFromReg, 0, rt);225// TODO: Do the UpdateRoundingMode check at runtime?226UpdateRoundingMode();227ApplyRoundingMode();228} else {229// Maybe not strictly invalid? But likely invalid.230INVALIDOP;231}232return;233default:234INVALIDOP;235break;236}237}238239} // namespace MIPSComp240241242