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/MIPS.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 <cmath>18#include <limits>19#include <mutex>20#include <utility>2122#include "Common/Math/math_util.h"2324#include "Common/CommonTypes.h"25#include "Common/Serialize/Serializer.h"26#include "Common/Serialize/SerializeFuncs.h"27#include "Core/ConfigValues.h"28#include "Core/MIPS/MIPS.h"29#include "Core/MIPS/MIPSInt.h"30#include "Core/MIPS/MIPSTables.h"31#include "Core/MIPS/MIPSDebugInterface.h"32#include "Core/MIPS/MIPSVFPUUtils.h"33#include "Core/MIPS/IR/IRJit.h"34#include "Core/Reporting.h"35#include "Core/System.h"36#include "Core/MIPS/JitCommon/JitCommon.h"37#include "Core/CoreTiming.h"3839MIPSState mipsr4k;40MIPSState *currentMIPS = &mipsr4k;41MIPSDebugInterface debugr4k(&mipsr4k);42MIPSDebugInterface *currentDebugMIPS = &debugr4k;4344u8 voffset[128];45u8 fromvoffset[128];4647#ifndef M_LOG2E48#define M_E 2.71828182845904523536f49#define M_LOG2E 1.44269504088896340736f50#define M_LOG10E 0.434294481903251827651f51#define M_LN2 0.693147180559945309417f52#define M_LN10 2.30258509299404568402f53#undef M_PI54#define M_PI 3.14159265358979323846f5556#ifndef M_PI_257#define M_PI_2 1.57079632679489661923f58#endif59#define M_PI_4 0.785398163397448309616f60#define M_1_PI 0.318309886183790671538f61#define M_2_PI 0.636619772367581343076f62#define M_2_SQRTPI 1.12837916709551257390f63#define M_SQRT2 1.41421356237309504880f64#define M_SQRT1_2 0.707106781186547524401f65#endif6667const float cst_constants[32] = {680,69std::numeric_limits<float>::max(), // all these are verified on real PSP70sqrtf(2.0f),71sqrtf(0.5f),722.0f/sqrtf((float)M_PI),732.0f/(float)M_PI,741.0f/(float)M_PI,75(float)M_PI/4,76(float)M_PI/2,77(float)M_PI,78(float)M_E,79(float)M_LOG2E,80(float)M_LOG10E,81(float)M_LN2,82(float)M_LN10,832*(float)M_PI,84(float)M_PI/6,85log10f(2.0f),86logf(10.0f)/logf(2.0f),87sqrtf(3.0f)/2.0f,88};8990MIPSState::MIPSState() {91MIPSComp::jit = nullptr;9293// Initialize vorder9495// This reordering of the VFPU registers in RAM means that instead of being like this:9697// 0x00 0x20 0x40 0x60 -> "columns", the most common direction98// 0x01 0x21 0x41 0x6199// 0x02 0x22 0x42 0x62100// 0x03 0x23 0x43 0x63101102// 0x04 0x24 0x44 0x64103// 0x06 0x26 0x45 0x65104// ....105106// the VPU registers are effectively organized like this:107// 0x00 0x01 0x02 0x03108// 0x04 0x05 0x06 0x07109// 0x08 0x09 0x0a 0x0b110// ....111112// This is because the original indices look like this:113// 0XXMMMYY where M is the matrix number.114115// We will now map 0YYMMMXX to 0MMMXXYY.116117// Advantages:118// * Columns can be flushed and reloaded faster "at once"119// * 4x4 Matrices are contiguous in RAM, making them, too, fast-loadable in NEON120121// Disadvantages:122// * Extra indirection, can be confusing and slower (interpreter only, however we can often skip the table by rerranging formulas)123// * Flushing and reloading row registers is now slower124125int i = 0;126for (int m = 0; m < 8; m++) {127for (int y = 0; y < 4; y++) {128for (int x = 0; x < 4; x++) {129voffset[m * 4 + x * 32 + y] = i++;130}131}132}133134// And the inverse.135for (int i = 0; i < 128; i++) {136fromvoffset[voffset[i]] = i;137}138139// Sanity check that things that should be ordered are ordered.140static const u8 firstThirtyTwo[] = {1410x0, 0x20, 0x40, 0x60,1420x1, 0x21, 0x41, 0x61,1430x2, 0x22, 0x42, 0x62,1440x3, 0x23, 0x43, 0x63,1451460x4, 0x24, 0x44, 0x64,1470x5, 0x25, 0x45, 0x65,1480x6, 0x26, 0x46, 0x66,1490x7, 0x27, 0x47, 0x67,150};151152for (int i = 0; i < (int)ARRAY_SIZE(firstThirtyTwo); i++) {153if (voffset[firstThirtyTwo[i]] != i) {154ERROR_LOG(Log::CPU, "Wrong voffset order! %i: %i should have been %i", firstThirtyTwo[i], voffset[firstThirtyTwo[i]], i);155}156}157}158159MIPSState::~MIPSState() {160}161162void MIPSState::Shutdown() {163std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);164MIPSComp::JitInterface *oldjit = MIPSComp::jit;165if (oldjit) {166MIPSComp::jit = nullptr;167delete oldjit;168}169}170171void MIPSState::Reset() {172Shutdown();173Init();174}175176void MIPSState::Init() {177memset(r, 0, sizeof(r));178memset(f, 0, sizeof(f));179memset(v, 0, sizeof(v));180memset(vfpuCtrl, 0, sizeof(vfpuCtrl));181182vfpuCtrl[VFPU_CTRL_SPREFIX] = 0xe4; //passthru183vfpuCtrl[VFPU_CTRL_TPREFIX] = 0xe4; //passthru184vfpuCtrl[VFPU_CTRL_DPREFIX] = 0;185vfpuCtrl[VFPU_CTRL_CC] = 0x3f;186vfpuCtrl[VFPU_CTRL_INF4] = 0;187vfpuCtrl[VFPU_CTRL_REV] = 0x7772ceab;188vfpuCtrl[VFPU_CTRL_RCX0] = 0x3f800001;189vfpuCtrl[VFPU_CTRL_RCX1] = 0x3f800002;190vfpuCtrl[VFPU_CTRL_RCX2] = 0x3f800004;191vfpuCtrl[VFPU_CTRL_RCX3] = 0x3f800008;192vfpuCtrl[VFPU_CTRL_RCX4] = 0x3f800000;193vfpuCtrl[VFPU_CTRL_RCX5] = 0x3f800000;194vfpuCtrl[VFPU_CTRL_RCX6] = 0x3f800000;195vfpuCtrl[VFPU_CTRL_RCX7] = 0x3f800000;196197pc = 0;198hi = 0;199lo = 0;200fpcond = 0;201fcr31 = 0;202debugCount = 0;203currentMIPS = this;204inDelaySlot = false;205llBit = 0;206nextPC = 0;207downcount = 0;208209std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);210if (PSP_CoreParameter().cpuCore == CPUCore::JIT || PSP_CoreParameter().cpuCore == CPUCore::JIT_IR) {211MIPSComp::jit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR);212} else if (PSP_CoreParameter().cpuCore == CPUCore::IR_INTERPRETER) {213MIPSComp::jit = new MIPSComp::IRJit(this, false);214} else {215MIPSComp::jit = nullptr;216}217}218219bool MIPSState::HasDefaultPrefix() const {220return vfpuCtrl[VFPU_CTRL_SPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_TPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_DPREFIX] == 0;221}222223void MIPSState::UpdateCore(CPUCore desired) {224if (PSP_CoreParameter().cpuCore == desired) {225return;226}227228PSP_CoreParameter().cpuCore = desired;229MIPSComp::JitInterface *oldjit = MIPSComp::jit;230MIPSComp::JitInterface *newjit = nullptr;231232switch (PSP_CoreParameter().cpuCore) {233case CPUCore::JIT:234case CPUCore::JIT_IR:235INFO_LOG(Log::CPU, "Switching to JIT%s", PSP_CoreParameter().cpuCore == CPUCore::JIT_IR ? " IR" : "");236if (oldjit) {237std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);238MIPSComp::jit = nullptr;239delete oldjit;240}241newjit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR);242break;243244case CPUCore::IR_INTERPRETER:245INFO_LOG(Log::CPU, "Switching to IR interpreter");246if (oldjit) {247std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);248MIPSComp::jit = nullptr;249delete oldjit;250}251newjit = new MIPSComp::IRJit(this, false);252break;253254case CPUCore::INTERPRETER:255INFO_LOG(Log::CPU, "Switching to interpreter");256if (oldjit) {257std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);258MIPSComp::jit = nullptr;259delete oldjit;260}261break;262}263264std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);265MIPSComp::jit = newjit;266}267268void MIPSState::DoState(PointerWrap &p) {269auto s = p.Section("MIPSState", 1, 4);270if (!s)271return;272273// Reset the jit if we're loading.274if (p.mode == p.MODE_READ)275Reset();276// Assume we're not saving state during a CPU core reset, so no lock.277if (MIPSComp::jit)278MIPSComp::jit->DoState(p);279else280MIPSComp::DoDummyJitState(p);281282DoArray(p, r, sizeof(r) / sizeof(r[0]));283DoArray(p, f, sizeof(f) / sizeof(f[0]));284if (s <= 2) {285float vtemp[128];286DoArray(p, vtemp, sizeof(v) / sizeof(v[0]));287for (int i = 0; i < 128; i++) {288v[voffset[i]] = vtemp[i];289}290} else {291DoArray(p, v, sizeof(v) / sizeof(v[0]));292}293DoArray(p, vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0]));294Do(p, pc);295Do(p, nextPC);296Do(p, downcount);297// Reversed, but we can just leave it that way.298Do(p, hi);299Do(p, lo);300Do(p, fpcond);301if (s <= 1) {302u32 fcr0_unused = 0;303Do(p, fcr0_unused);304}305Do(p, fcr31);306if (s <= 3) {307uint32_t dummy;308Do(p, dummy); // rng.m_w309Do(p, dummy); // rng.m_z310}311312Do(p, inDelaySlot);313Do(p, llBit);314Do(p, debugCount);315316if (p.mode == p.MODE_READ && MIPSComp::jit) {317// Now that we've loaded fcr31, update any jit state associated.318MIPSComp::jit->UpdateFCR31();319}320}321322void MIPSState::SingleStep() {323int cycles = MIPS_SingleStep();324currentMIPS->downcount -= cycles;325CoreTiming::Advance();326}327328// returns 1 if reached ticks limit329int MIPSState::RunLoopUntil(u64 globalTicks) {330switch (PSP_CoreParameter().cpuCore) {331case CPUCore::JIT:332case CPUCore::JIT_IR:333case CPUCore::IR_INTERPRETER:334while (inDelaySlot) {335// We must get out of the delay slot before going into jit.336SingleStep();337}338insideJit = true;339if (hasPendingClears)340ProcessPendingClears();341MIPSComp::jit->RunLoopUntil(globalTicks);342insideJit = false;343break;344345case CPUCore::INTERPRETER:346return MIPSInterpret_RunUntil(globalTicks);347}348return 1;349}350351// Kept outside MIPSState to avoid header pollution (MIPS.h doesn't even have vector, and is used widely.)352static std::vector<std::pair<u32, int>> pendingClears;353354void MIPSState::ProcessPendingClears() {355std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);356for (auto &p : pendingClears) {357if (p.first == 0 && p.second == 0)358MIPSComp::jit->ClearCache();359else360MIPSComp::jit->InvalidateCacheAt(p.first, p.second);361}362pendingClears.clear();363hasPendingClears = false;364}365366void MIPSState::InvalidateICache(u32 address, int length) {367// Only really applies to jit.368// Note that the backend is responsible for ensuring native code can still be returned to.369std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);370if (MIPSComp::jit && length != 0) {371MIPSComp::jit->InvalidateCacheAt(address, length);372}373}374375void MIPSState::ClearJitCache() {376std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);377if (MIPSComp::jit) {378if (coreState == CORE_RUNNING || insideJit) {379pendingClears.emplace_back(0, 0);380hasPendingClears = true;381CoreTiming::ForceCheck();382} else {383MIPSComp::jit->ClearCache();384}385}386}387388389