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/x86/Asm.cpp
Views: 1401
// Copyright (C) 2003 Dolphin 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 SVN repository and contact information can be found at15// http://code.google.com/p/dolphin-emu/1617#include "ppsspp_config.h"18#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)1920#include "Common/Math/math_util.h"2122#include "ABI.h"23#include "x64Emitter.h"2425#include "Core/Core.h"26#include "Core/MemMap.h"27#include "Core/System.h"28#include "Core/MIPS/MIPS.h"29#include "Core/CoreTiming.h"30#include "Common/MemoryUtil.h"3132#include "Core/MIPS/JitCommon/JitCommon.h"33#include "Core/MIPS/x86/Jit.h"3435using namespace Gen;36using namespace X64JitConstants;3738extern volatile CoreState coreState;3940namespace MIPSComp41{4243//TODO - make an option44//#if _DEBUG45static bool enableDebug = false;4647//#else48// bool enableDebug = false;49//#endif5051//static bool enableStatistics = false; //unused?5253//GLOBAL STATIC ALLOCATIONS x8654//EAX - ubiquitous scratch register - EVERYBODY scratches this55//EBP - Pointer to fpr/gpr regs5657//GLOBAL STATIC ALLOCATIONS x6458//EAX - ubiquitous scratch register - EVERYBODY scratches this59//RBX - Base pointer of memory60//R14 - Pointer to fpr/gpr regs61//R15 - Pointer to array of block pointers6263void ImHere() {64DEBUG_LOG(Log::CPU, "JIT Here: %08x", currentMIPS->pc);65}6667void Jit::GenerateFixedCode(JitOptions &jo) {68BeginWrite(GetMemoryProtectPageSize());69AlignCodePage();7071restoreRoundingMode = AlignCode16(); {72STMXCSR(MIPSSTATE_VAR(temp));73// Clear the rounding mode and flush-to-zero bits back to 0.74AND(32, MIPSSTATE_VAR(temp), Imm32(~(7 << 13)));75LDMXCSR(MIPSSTATE_VAR(temp));76RET();77}7879applyRoundingMode = AlignCode16(); {80MOV(32, R(EAX), MIPSSTATE_VAR(fcr31));81AND(32, R(EAX), Imm32(0x01000003));8283// If it's 0 (nearest + no flush0), we don't actually bother setting - we cleared the rounding84// mode out in restoreRoundingMode anyway. This is the most common.85FixupBranch skip = J_CC(CC_Z);86STMXCSR(MIPSSTATE_VAR(temp));8788// The MIPS bits don't correspond exactly, so we have to adjust.89// 0 -> 0 (skip2), 1 -> 3, 2 -> 2 (skip2), 3 -> 190TEST(8, R(AL), Imm8(1));91FixupBranch skip2 = J_CC(CC_Z);92XOR(32, R(EAX), Imm8(2));93SetJumpTarget(skip2);9495// Adjustment complete, now reconstruct MXCSR96SHL(32, R(EAX), Imm8(13));97// Before setting new bits, we must clear the old ones.98AND(32, MIPSSTATE_VAR(temp), Imm32(~(7 << 13))); // Clearing bits 13-14 (rounding mode) and 15 (flush to zero)99OR(32, MIPSSTATE_VAR(temp), R(EAX));100101TEST(32, MIPSSTATE_VAR(fcr31), Imm32(1 << 24));102FixupBranch skip3 = J_CC(CC_Z);103OR(32, MIPSSTATE_VAR(temp), Imm32(1 << 15));104SetJumpTarget(skip3);105106LDMXCSR(MIPSSTATE_VAR(temp));107SetJumpTarget(skip);108RET();109}110111enterDispatcher = AlignCode16();112ABI_PushAllCalleeSavedRegsAndAdjustStack();113#if PPSSPP_ARCH(AMD64)114// Two statically allocated registers.115MOV(64, R(MEMBASEREG), ImmPtr(Memory::base));116uintptr_t jitbase = (uintptr_t)GetBasePtr();117if (jitbase > 0x7FFFFFFFULL) {118MOV(64, R(JITBASEREG), ImmPtr(GetBasePtr()));119jo.reserveR15ForAsm = true;120}121#endif122// From the start of the FP reg, a single byte offset can reach all GPR + all FPR (but no VFPUR)123MOV(PTRBITS, R(CTXREG), ImmPtr(&mips_->f[0]));124125outerLoop = GetCodePtr();126RestoreRoundingMode(true);127ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));128ApplyRoundingMode(true);129FixupBranch skipToCoreStateCheck = J(); //skip the downcount check130131dispatcherCheckCoreState = GetCodePtr();132133// The result of slice decrementation should be in flags if somebody jumped here134// IMPORTANT - We jump on negative, not carry!!!135FixupBranch bailCoreState = J_CC(CC_S, true);136137SetJumpTarget(skipToCoreStateCheck);138if (RipAccessible((const void *)&coreState)) {139CMP(32, M(&coreState), Imm32(0)); // rip accessible140} else {141MOV(PTRBITS, R(RAX), ImmPtr((const void *)&coreState));142CMP(32, MatR(RAX), Imm32(0));143}144FixupBranch badCoreState = J_CC(CC_NZ, true);145FixupBranch skipToRealDispatch2 = J(); //skip the sync and compare first time146147dispatcher = GetCodePtr();148149// The result of slice decrementation should be in flags if somebody jumped here150// IMPORTANT - We jump on negative, not carry!!!151FixupBranch bail = J_CC(CC_S, true);152153SetJumpTarget(skipToRealDispatch2);154155dispatcherNoCheck = GetCodePtr();156157MOV(32, R(EAX), MIPSSTATE_VAR(pc));158dispatcherInEAXNoCheck = GetCodePtr();159160#ifdef MASKED_PSP_MEMORY161AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));162#endif163dispatcherFetch = GetCodePtr();164#if PPSSPP_ARCH(X86)165_assert_msg_( Memory::base != 0, "Memory base bogus");166MOV(32, R(EAX), MDisp(EAX, (u32)Memory::base));167#elif PPSSPP_ARCH(AMD64)168MOV(32, R(EAX), MComplex(MEMBASEREG, RAX, SCALE_1, 0));169#endif170MOV(32, R(EDX), R(EAX));171_assert_msg_(MIPS_JITBLOCK_MASK == 0xFF000000, "Hardcoded assumption of emuhack mask");172SHR(32, R(EDX), Imm8(24));173CMP(32, R(EDX), Imm8(MIPS_EMUHACK_OPCODE >> 24));174FixupBranch notfound = J_CC(CC_NE);175if (enableDebug) {176ADD(32, MIPSSTATE_VAR(debugCount), Imm8(1));177}178//grab from list and jump to it179AND(32, R(EAX), Imm32(MIPS_EMUHACK_VALUE_MASK));180#if PPSSPP_ARCH(X86)181ADD(32, R(EAX), ImmPtr(GetBasePtr()));182#elif PPSSPP_ARCH(AMD64)183if (jo.reserveR15ForAsm) {184ADD(64, R(RAX), R(JITBASEREG));185} else {186// See above, reserveR15ForAsm is used when above 0x7FFFFFFF.187ADD(64, R(EAX), Imm32((u32)jitbase));188}189#endif190JMPptr(R(EAX));191SetJumpTarget(notfound);192193//Ok, no block, let's jit194RestoreRoundingMode(true);195ABI_CallFunction(&MIPSComp::JitAt);196ApplyRoundingMode(true);197JMP(dispatcherNoCheck, true); // Let's just dispatch again, we'll enter the block since we know it's there.198199SetJumpTarget(bail);200SetJumpTarget(bailCoreState);201202if (RipAccessible((const void *)&coreState)) {203CMP(32, M(&coreState), Imm32(0)); // rip accessible204} else {205MOV(PTRBITS, R(RAX), ImmPtr((const void *)&coreState));206CMP(32, MatR(RAX), Imm32(0));207}208J_CC(CC_Z, outerLoop, true);209210const uint8_t *quitLoop = GetCodePtr();211SetJumpTarget(badCoreState);212RestoreRoundingMode(true);213ABI_PopAllCalleeSavedRegsAndAdjustStack();214RET();215216crashHandler = GetCodePtr();217if (RipAccessible((const void *)&coreState)) {218MOV(32, M(&coreState), Imm32(CORE_RUNTIME_ERROR));219} else {220MOV(PTRBITS, R(RAX), ImmPtr((const void *)&coreState));221MOV(32, MatR(RAX), Imm32(CORE_RUNTIME_ERROR));222}223JMP(quitLoop, true);224225// Let's spare the pre-generated code from unprotect-reprotect.226endOfPregeneratedCode = AlignCodePage();227EndWrite();228}229230} // namespace231232#endif // PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)233234235