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/RiscV/RiscVCompSystem.cpp
Views: 1401
// Copyright (c) 2023- 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 "Common/Profiler/Profiler.h"18#include "Core/Core.h"19#include "Core/HLE/HLE.h"20#include "Core/HLE/ReplaceTables.h"21#include "Core/MemMap.h"22#include "Core/MIPS/RiscV/RiscVJit.h"23#include "Core/MIPS/RiscV/RiscVRegCache.h"2425// This file contains compilation for basic PC/downcount accounting, syscalls, debug funcs, etc.26//27// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.28// Currently known non working ones should have DISABLE. No flags because that's in IR already.2930// #define CONDITIONAL_DISABLE { CompIR_Generic(inst); return; }31#define CONDITIONAL_DISABLE {}32#define DISABLE { CompIR_Generic(inst); return; }33#define INVALIDOP { _assert_msg_(false, "Invalid IR inst %d", (int)inst.op); CompIR_Generic(inst); return; }3435namespace MIPSComp {3637using namespace RiscVGen;38using namespace RiscVJitConstants;3940void RiscVJitBackend::CompIR_Basic(IRInst inst) {41CONDITIONAL_DISABLE;4243switch (inst.op) {44case IROp::SetConst:45// Sign extend all constants. We get 0xFFFFFFFF sometimes, and it's more work to truncate.46// The register only holds 32 bits in the end anyway.47regs_.SetGPRImm(inst.dest, (int32_t)inst.constant);48break;4950case IROp::SetConstF:51regs_.Map(inst);52if (inst.constant == 0)53FCVT(FConv::S, FConv::W, regs_.F(inst.dest), R_ZERO);54else55QuickFLI(32, regs_.F(inst.dest), inst.constant, SCRATCH1);56break;5758case IROp::Downcount:59if (inst.constant <= 2048) {60ADDI(DOWNCOUNTREG, DOWNCOUNTREG, -(s32)inst.constant);61} else {62LI(SCRATCH1, inst.constant, SCRATCH2);63SUB(DOWNCOUNTREG, DOWNCOUNTREG, SCRATCH1);64}65break;6667case IROp::SetPC:68regs_.Map(inst);69MovToPC(regs_.R(inst.src1));70break;7172case IROp::SetPCConst:73LI(SCRATCH1, inst.constant, SCRATCH2);74MovToPC(SCRATCH1);75break;7677default:78INVALIDOP;79break;80}81}8283void RiscVJitBackend::CompIR_Transfer(IRInst inst) {84CONDITIONAL_DISABLE;8586switch (inst.op) {87case IROp::SetCtrlVFPU:88regs_.SetGPRImm(IRREG_VFPU_CTRL_BASE + inst.dest, inst.constant);89break;9091case IROp::SetCtrlVFPUReg:92regs_.Map(inst);93MV(regs_.R(IRREG_VFPU_CTRL_BASE + inst.dest), regs_.R(inst.src1));94regs_.MarkGPRDirty(IRREG_VFPU_CTRL_BASE + inst.dest, regs_.IsNormalized32(inst.src1));95break;9697case IROp::SetCtrlVFPUFReg:98regs_.Map(inst);99FMV(FMv::X, FMv::W, regs_.R(IRREG_VFPU_CTRL_BASE + inst.dest), regs_.F(inst.src1));100regs_.MarkGPRDirty(IRREG_VFPU_CTRL_BASE + inst.dest, true);101break;102103case IROp::FpCondFromReg:104regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });105MV(regs_.R(IRREG_FPCOND), regs_.R(inst.src1));106break;107108case IROp::FpCondToReg:109regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::INIT } });110MV(regs_.R(inst.dest), regs_.R(IRREG_FPCOND));111regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(IRREG_FPCOND));112break;113114case IROp::FpCtrlFromReg:115regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::NOINIT } });116LI(SCRATCH1, 0x0181FFFF);117AND(SCRATCH1, regs_.R(inst.src1), SCRATCH1);118// Extract the new fpcond value.119if (cpu_info.RiscV_Zbs) {120BEXTI(regs_.R(IRREG_FPCOND), SCRATCH1, 23);121} else {122SRLI(regs_.R(IRREG_FPCOND), SCRATCH1, 23);123ANDI(regs_.R(IRREG_FPCOND), regs_.R(IRREG_FPCOND), 1);124}125SW(SCRATCH1, CTXREG, IRREG_FCR31 * 4);126regs_.MarkGPRDirty(IRREG_FPCOND, true);127break;128129case IROp::FpCtrlToReg:130regs_.MapWithExtra(inst, { { 'G', IRREG_FPCOND, 1, MIPSMap::INIT } });131// Load fcr31 and clear the fpcond bit.132LW(SCRATCH1, CTXREG, IRREG_FCR31 * 4);133if (cpu_info.RiscV_Zbs) {134BCLRI(SCRATCH1, SCRATCH1, 23);135} else {136LI(SCRATCH2, ~(1 << 23));137AND(SCRATCH1, SCRATCH1, SCRATCH2);138}139140// Now get the correct fpcond bit.141ANDI(SCRATCH2, regs_.R(IRREG_FPCOND), 1);142SLLI(SCRATCH2, SCRATCH2, 23);143OR(regs_.R(inst.dest), SCRATCH1, SCRATCH2);144145// Also update mips->fcr31 while we're here.146SW(regs_.R(inst.dest), CTXREG, IRREG_FCR31 * 4);147regs_.MarkGPRDirty(inst.dest, true);148break;149150case IROp::VfpuCtrlToReg:151regs_.Map(inst);152MV(regs_.R(inst.dest), regs_.R(IRREG_VFPU_CTRL_BASE + inst.src1));153regs_.MarkGPRDirty(inst.dest, regs_.IsNormalized32(IRREG_VFPU_CTRL_BASE + inst.src1));154break;155156case IROp::FMovFromGPR:157if (regs_.IsGPRImm(inst.src1) && regs_.GetGPRImm(inst.src1) == 0) {158regs_.MapFPR(inst.dest, MIPSMap::NOINIT);159FCVT(FConv::S, FConv::W, regs_.F(inst.dest), R_ZERO);160} else {161regs_.Map(inst);162FMV(FMv::W, FMv::X, regs_.F(inst.dest), regs_.R(inst.src1));163}164break;165166case IROp::FMovToGPR:167regs_.Map(inst);168FMV(FMv::X, FMv::W, regs_.R(inst.dest), regs_.F(inst.src1));169regs_.MarkGPRDirty(inst.dest, true);170break;171172default:173INVALIDOP;174break;175}176}177178void RiscVJitBackend::CompIR_System(IRInst inst) {179CONDITIONAL_DISABLE;180181switch (inst.op) {182case IROp::Syscall:183FlushAll();184SaveStaticRegisters();185186WriteDebugProfilerStatus(IRProfilerStatus::SYSCALL);187#ifdef USE_PROFILER188// When profiling, we can't skip CallSyscall, since it times syscalls.189LI(X10, (int32_t)inst.constant);190QuickCallFunction(&CallSyscall, SCRATCH2);191#else192// Skip the CallSyscall where possible.193{194MIPSOpcode op(inst.constant);195void *quickFunc = GetQuickSyscallFunc(op);196if (quickFunc) {197LI(X10, (uintptr_t)GetSyscallFuncPointer(op));198QuickCallFunction((const u8 *)quickFunc, SCRATCH2);199} else {200LI(X10, (int32_t)inst.constant);201QuickCallFunction(&CallSyscall, SCRATCH2);202}203}204#endif205206WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);207LoadStaticRegisters();208// This is always followed by an ExitToPC, where we check coreState.209break;210211case IROp::CallReplacement:212FlushAll();213SaveStaticRegisters();214WriteDebugProfilerStatus(IRProfilerStatus::REPLACEMENT);215QuickCallFunction(GetReplacementFunc(inst.constant)->replaceFunc, SCRATCH2);216WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);217LoadStaticRegisters();218219regs_.Map(inst);220SRAIW(regs_.R(inst.dest), X10, 31);221222// Absolute value trick: if neg, abs(x) == (x ^ -1) + 1.223XOR(X10, X10, regs_.R(inst.dest));224SUBW(X10, X10, regs_.R(inst.dest));225SUB(DOWNCOUNTREG, DOWNCOUNTREG, X10);226break;227228case IROp::Break:229FlushAll();230// This doesn't naturally have restore/apply around it.231RestoreRoundingMode(true);232SaveStaticRegisters();233MovFromPC(X10);234QuickCallFunction(&Core_Break, SCRATCH2);235LoadStaticRegisters();236ApplyRoundingMode(true);237MovFromPC(SCRATCH1);238ADDI(SCRATCH1, SCRATCH1, 4);239QuickJ(R_RA, dispatcherPCInSCRATCH1_);240break;241242default:243INVALIDOP;244break;245}246}247248void RiscVJitBackend::CompIR_Breakpoint(IRInst inst) {249CONDITIONAL_DISABLE;250251switch (inst.op) {252case IROp::Breakpoint:253case IROp::MemoryCheck:254CompIR_Generic(inst);255break;256257default:258INVALIDOP;259break;260}261}262263void RiscVJitBackend::CompIR_ValidateAddress(IRInst inst) {264CONDITIONAL_DISABLE;265266switch (inst.op) {267case IROp::ValidateAddress8:268case IROp::ValidateAddress16:269case IROp::ValidateAddress32:270case IROp::ValidateAddress128:271CompIR_Generic(inst);272break;273274default:275INVALIDOP;276break;277}278}279280} // namespace MIPSComp281282283