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/ArmAsm.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/MemMap.h"21#include "Core/MIPS/MIPS.h"22#include "Core/System.h"23#include "Core/CoreTiming.h"24#include "Common/MemoryUtil.h"25#include "Common/CPUDetect.h"26#include "Common/ArmEmitter.h"27#include "Core/MIPS/ARM/ArmJit.h"28#include "Core/MIPS/JitCommon/JitCommon.h"2930using namespace ArmGen;3132//static int temp32; // unused?3334static const bool enableDebug = false;35static const bool disasm = false;3637//static bool enableStatistics = false; //unused?3839//The standard ARM calling convention allocates the 16 ARM registers as:4041// r15 is the program counter.42// r14 is the link register. (The BL instruction, used in a subroutine call, stores the return address in this register).43// r13 is the stack pointer. (The Push/Pop instructions in "Thumb" operating mode use this register only).44// r12 is the Intra-Procedure-call scratch register.45// r4 to r11: used to hold local variables.46// r0 to r3: used to hold argument values passed to a subroutine, and also hold results returned from a subroutine.4748// Mappable registers:49// R2, R3, R4, R5, R6, R8, R115051// STATIC ALLOCATION ARM:52// R10 : MIPS state53// R11 : Memory base pointer.54// R7 : Down counter55extern volatile CoreState coreState;5657void ShowPC(u32 sp) {58ERROR_LOG(Log::JIT, "ShowPC : %08x ArmSP : %08x", currentMIPS->pc, sp);59// Sleep(1);60}6162void DisassembleArm(const u8 *data, int size);6364// PLAN: no more block numbers - crazy opcodes just contain offset within65// dynarec buffer66// At this offset - 4, there is an int specifying the block number.6768namespace MIPSComp {6970using namespace ArmJitConstants;7172void ArmJit::GenerateFixedCode() {73BeginWrite(GetMemoryProtectPageSize());74const u8 *start = AlignCodePage();7576// LR == SCRATCHREG2 on ARM32 so it needs to be pushed.77restoreRoundingMode = AlignCode16(); {78PUSH(1, R_LR);79VMRS(SCRATCHREG2);80// Outside the JIT we run with round-to-nearest and flush0 off.81BIC(SCRATCHREG2, SCRATCHREG2, AssumeMakeOperand2((3 | 4) << 22));82VMSR(SCRATCHREG2);83POP(1, R_PC);84}8586// Must preserve SCRATCHREG1 (R0), destroys SCRATCHREG2 (LR)87applyRoundingMode = AlignCode16(); {88PUSH(2, SCRATCHREG1, R_LR);89LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31));9091TST(SCRATCHREG2, AssumeMakeOperand2(1 << 24));92AND(SCRATCHREG2, SCRATCHREG2, Operand2(3));93SetCC(CC_NEQ);94ADD(SCRATCHREG2, SCRATCHREG2, Operand2(4));95SetCC(CC_AL);9697// We can skip if the rounding mode is nearest (0) and flush is not set.98// (as restoreRoundingMode cleared it out anyway)99CMP(SCRATCHREG2, Operand2(0));100FixupBranch skip = B_CC(CC_EQ);101102// MIPS Rounding Mode: ARM Rounding Mode103// 0: Round nearest 0104// 1: Round to zero 3105// 2: Round up (ceil) 1106// 3: Round down (floor) 2107AND(SCRATCHREG1, SCRATCHREG2, Operand2(3));108CMP(SCRATCHREG1, Operand2(1));109110SetCC(CC_EQ); ADD(SCRATCHREG2, SCRATCHREG2, Operand2(2));111SetCC(CC_GT); SUB(SCRATCHREG2, SCRATCHREG2, Operand2(1));112SetCC(CC_AL);113114VMRS(SCRATCHREG1);115// Assume we're always in round-to-nearest mode beforehand.116// But we need to clear flush to zero in this case anyway.117BIC(SCRATCHREG1, SCRATCHREG1, AssumeMakeOperand2((3 | 4) << 22));118ORR(SCRATCHREG1, SCRATCHREG1, Operand2(SCRATCHREG2, ST_LSL, 22));119VMSR(SCRATCHREG1);120121SetJumpTarget(skip);122POP(2, SCRATCHREG1, R_PC);123}124125FlushLitPool();126127enterDispatcher = AlignCode16();128129DEBUG_LOG(Log::JIT, "Base: %08x", (u32)Memory::base);130131SetCC(CC_AL);132133PUSH(9, R4, R5, R6, R7, R8, R9, R10, R11, R_LR);134// Take care to 8-byte align stack for function calls.135// We are misaligned here because of an odd number of args for PUSH.136// It's not like x86 where you need to account for an extra 4 bytes137// consumed by CALL.138SUB(R_SP, R_SP, 4);139// Now we are correctly aligned and plan to stay that way.140VPUSH(D8, 8);141142// Fixed registers, these are always kept when in Jit context.143// R8 is used to hold flags during delay slots. Not always needed.144// R13 cannot be used as it's the stack pointer.145// TODO: Consider statically allocating:146// * r2-r4147// Really starting to run low on registers already though...148149// R11, R10, R9150MOVP2R(MEMBASEREG, Memory::base);151MOVP2R(CTXREG, mips_);152MOVP2R(JITBASEREG, GetBasePtr());153154RestoreDowncount();155MovFromPC(R0);156outerLoopPCInR0 = GetCodePtr();157MovToPC(R0);158outerLoop = GetCodePtr();159SaveDowncount();160RestoreRoundingMode(true);161QuickCallFunction(R0, &CoreTiming::Advance);162ApplyRoundingMode(true);163RestoreDowncount();164FixupBranch skipToCoreStateCheck = B(); //skip the downcount check165166dispatcherCheckCoreState = GetCodePtr();167168// The result of slice decrementation should be in flags if somebody jumped here169// IMPORTANT - We jump on negative, not carry!!!170FixupBranch bailCoreState = B_CC(CC_MI);171172SetJumpTarget(skipToCoreStateCheck);173174MOVI2R(R0, (u32)(uintptr_t)&coreState);175LDR(R0, R0);176CMP(R0, 0);177FixupBranch badCoreState = B_CC(CC_NEQ);178FixupBranch skipToRealDispatch2 = B(); //skip the sync and compare first time179180dispatcherPCInR0 = GetCodePtr();181// TODO: Do we always need to write PC to RAM here?182MovToPC(R0);183184// At this point : flags = EQ. Fine for the next check, no need to jump over it.185dispatcher = GetCodePtr();186187// The result of slice decrementation should be in flags if somebody jumped here188// IMPORTANT - We jump on negative, not carry!!!189FixupBranch bail = B_CC(CC_MI);190191SetJumpTarget(skipToRealDispatch2);192193dispatcherNoCheck = GetCodePtr();194195// Debug196if (enableDebug) {197MOV(R0, R13);198QuickCallFunction(R1, (void *)&ShowPC);199}200201LDR(R0, CTXREG, offsetof(MIPSState, pc));202// TODO: In practice, do we ever run code from uncached space (| 0x40000000)? If not, we can remove this BIC.203BIC(R0, R0, Operand2(0xC0, 4)); // &= 0x3FFFFFFF204dispatcherFetch = GetCodePtr();205LDR(R0, MEMBASEREG, R0);206AND(R1, R0, Operand2(0xFF, 4)); // rotation is to the right, in 2-bit increments.207BIC(R0, R0, Operand2(0xFF, 4));208CMP(R1, Operand2(MIPS_EMUHACK_OPCODE >> 24, 4));209SetCC(CC_EQ);210// IDEA - we have 26 bits, why not just use offsets from base of code?211// Another idea: Shift the bloc number left by two in the op, this would let us do212// LDR(R0, R9, R0); here, replacing the next instructions.213#if PPSSPP_PLATFORM(IOS)214// On iOS, R9 (JITBASEREG) is volatile. We have to reload it.215MOVI2R(JITBASEREG, (u32)(uintptr_t)GetBasePtr());216#endif217ADD(R0, R0, JITBASEREG);218B(R0);219SetCC(CC_AL);220221// No block found, let's jit222SaveDowncount();223RestoreRoundingMode(true);224QuickCallFunction(R2, (void *)&MIPSComp::JitAt);225ApplyRoundingMode(true);226RestoreDowncount();227228B(dispatcherNoCheck); // no point in special casing this229230SetJumpTarget(bail);231SetJumpTarget(bailCoreState);232233MOVI2R(R0, (u32)(uintptr_t)&coreState);234LDR(R0, R0);235CMP(R0, 0);236B_CC(CC_EQ, outerLoop);237238const uint8_t *quitLoop = GetCodePtr();239SetJumpTarget(badCoreState);240241SaveDowncount();242RestoreRoundingMode(true);243244VPOP(D8, 8);245246ADD(R_SP, R_SP, 4);247248POP(9, R4, R5, R6, R7, R8, R9, R10, R11, R_PC); // Returns249250crashHandler = GetCodePtr();251MOVP2R(R0, &coreState);252MOVI2R(R1, CORE_RUNTIME_ERROR);253STR(R1, R0, 0);254B(quitLoop);255256// Uncomment if you want to see the output...257if (disasm) {258INFO_LOG(Log::JIT, "THE DISASM ========================");259DisassembleArm(start, GetCodePtr() - start);260INFO_LOG(Log::JIT, "END OF THE DISASM ========================");261}262263// Don't forget to zap the instruction cache!264FlushLitPool();265FlushIcache();266267// Let's spare the pre-generated code from unprotect-reprotect.268AlignCodePage();269EndWrite();270}271272} // namespace MIPSComp273274#endif // PPSSPP_ARCH(ARM)275276277