From a2ff416534eb2ab50654fb9c1728635afe618a01 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 7 Jan 2013 22:33:09 +0100 Subject: [PATCH] Rename files. Rewrite ArmRegCache from scratch. --- Core/Core.vcxproj | 32 +-- Core/Core.vcxproj.filters | 77 +++--- Core/MIPS/ARM/{Asm.cpp => ArmAsm.cpp} | 89 ++----- Core/MIPS/ARM/{Asm.h => ArmAsm.h} | 20 +- Core/MIPS/ARM/{CompALU.cpp => ArmCompALU.cpp} | 6 +- .../ARM/{CompBranch.cpp => ArmCompBranch.cpp} | 10 +- Core/MIPS/ARM/{CompFPU.cpp => ArmCompFPU.cpp} | 4 +- ...CompLoadStore.cpp => ArmCompLoadStore.cpp} | 4 +- .../ARM/{CompVFPU.cpp => ArmCompVFPU.cpp} | 4 +- Core/MIPS/ARM/{Jit.cpp => ArmJit.cpp} | 55 ++--- Core/MIPS/ARM/{Jit.h => ArmJit.h} | 29 +-- .../ARM/{JitCache.cpp => ArmJitCache.cpp} | 73 +++--- Core/MIPS/ARM/{JitCache.h => ArmJitCache.h} | 14 +- Core/MIPS/ARM/ArmRegCache.cpp | 189 +++++++++++++++ Core/MIPS/ARM/ArmRegCache.h | 112 +++++++++ Core/MIPS/ARM/RegCache.cpp | 219 ------------------ Core/MIPS/ARM/RegCache.h | 96 -------- Core/MIPS/JitCommon/JitCommon.h | 2 +- Core/MIPS/MIPS.cpp | 10 +- Core/MIPS/MIPS.h | 9 +- Core/MIPS/x86/Asm.cpp | 41 +--- Core/MIPS/x86/Asm.h | 15 +- Core/MIPS/x86/Jit.cpp | 5 - android/jni/Android.mk | 17 +- android/jni/Application.mk | 5 +- 25 files changed, 493 insertions(+), 644 deletions(-) rename Core/MIPS/ARM/{Asm.cpp => ArmAsm.cpp} (65%) rename Core/MIPS/ARM/{Asm.h => ArmAsm.h} (62%) rename Core/MIPS/ARM/{CompALU.cpp => ArmCompALU.cpp} (99%) rename Core/MIPS/ARM/{CompBranch.cpp => ArmCompBranch.cpp} (98%) rename Core/MIPS/ARM/{CompFPU.cpp => ArmCompFPU.cpp} (99%) rename Core/MIPS/ARM/{CompLoadStore.cpp => ArmCompLoadStore.cpp} (98%) rename Core/MIPS/ARM/{CompVFPU.cpp => ArmCompVFPU.cpp} (87%) rename Core/MIPS/ARM/{Jit.cpp => ArmJit.cpp} (86%) rename Core/MIPS/ARM/{Jit.h => ArmJit.h} (89%) rename Core/MIPS/ARM/{JitCache.cpp => ArmJitCache.cpp} (84%) rename Core/MIPS/ARM/{JitCache.h => ArmJitCache.h} (95%) create mode 100644 Core/MIPS/ARM/ArmRegCache.cpp create mode 100644 Core/MIPS/ARM/ArmRegCache.h delete mode 100644 Core/MIPS/ARM/RegCache.cpp delete mode 100644 Core/MIPS/ARM/RegCache.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 8e3574417c..610f37f31a 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -185,49 +185,55 @@ - + true true true true - + true true true true - + true true true true - + true true true true - + true true true true - + true true true true - + true true true true - + + true + true + true + true + + true true true @@ -338,25 +344,25 @@ - + true true true true - + true true true true - + true true true true - + true true true @@ -409,4 +415,4 @@ - + \ No newline at end of file diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index c0c03cd556..03ca3df852 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -111,30 +111,6 @@ MIPS\x86 - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - MIPS\JitCommon @@ -363,6 +339,33 @@ Ext\Snappy + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + @@ -413,18 +416,6 @@ MIPS\x86 - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - - - MIPS\ARM - MIPS\JitCommon @@ -674,6 +665,18 @@ Ext\Snappy + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + + + MIPS\ARM + @@ -681,4 +684,4 @@ - + \ No newline at end of file diff --git a/Core/MIPS/ARM/Asm.cpp b/Core/MIPS/ARM/ArmAsm.cpp similarity index 65% rename from Core/MIPS/ARM/Asm.cpp rename to Core/MIPS/ARM/ArmAsm.cpp index 9072857f8a..e93e755fae 100644 --- a/Core/MIPS/ARM/Asm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -15,8 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "ABI.h" -#include +#include "ArmEmitter.h" +#include "ArmABI.h" #include "../../MemMap.h" @@ -24,11 +24,10 @@ #include "../../CoreTiming.h" #include "MemoryUtil.h" -#include "ABI.h" -#include "Jit.h" +#include "ArmJit.h" #include "../JitCommon/JitCommon.h" #include "../../Core.h" -#include "Asm.h" +#include "ArmAsm.h" using namespace ArmGen; @@ -72,24 +71,26 @@ void Jit() void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit) { enterCode = AlignCode16(); - //ARMABI_PushAllCalleeSavedRegsAndAdjustStack(); -/* -#ifndef _M_IX86 - // Two statically allocated registers. - MOV(64, R(RBX), Imm64((u64)Memory::base)); - MOV(64, R(R15), Imm64((u64)jit->GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough -#endif - */ PUSH(8, R5, R6, R7, R8, R9, R10, R11, _LR); SetCC(CC_AL); - //ARMABI_MOVIMM32(R11, (u32)Memory::base); - //ARMABI_MOVIMM32(R10, (u32)jit->GetBlockCache()->GetCodePointers()); + + // Fixed registers, these are always kept when in Jit context. + // R13 cannot be used as it's the stack pointer. + ARMABI_MOVI2R(R11, (u32)Memory::base); + ARMABI_MOVI2R(R12, (u32)currentMIPS); + ARMABI_MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers()); outerLoop = GetCodePtr(); //ARMABI_CallFunction(reinterpret_cast(&CoreTiming::Advance)); FixupBranch skipToRealDispatch = B(); //skip the sync and compare first time - + + dispatcherCheckCoreState = GetCodePtr(); + + //TODO: critical + //CMP(32, M((void*)&coreState), Imm32(0)); + FixupBranch badCoreState; // = J_CC(CC_NZ, true); + dispatcher = GetCodePtr(); // The result of slice decrementation should be in flags if somebody jumped here // IMPORTANT - We jump on negative, not carry!!! @@ -127,65 +128,15 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit) B(dispatcherNoCheck); // no point in special casing this SetJumpTarget(bail); - doTiming = GetCodePtr(); - testExternalExceptions = GetCodePtr(); - //TEST(32, M((void *)&mips->exceptions), Imm32(MIPSState::BREAKING_EXCEPTIONS)); - //FixupBranch noExtException = J_CC(CC_Z); - //MOV(32, R(EAX), M(&mips->pc)); - // MOV(32, M(&NPC), R(EAX)); - // ABI_CallFunction(reinterpret_cast(&MIPSState::CheckExternalExceptions)); - //SetJumpTarget(noExtException); + SetJumpTarget(badCoreState); //CMP(M((void*)&coreState), Imm8(0)); SetCC(CC_EQ); //B(outerLoop); SetCC(CC_AL); - //Landing pad for drec space - //ARMABI_PopAllCalleeSavedRegsAndAdjustStack(); - B(_LR); + //Landing pad for drec space PUSH(8, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns - - - - GenerateCommon(); -} - -void AsmRoutineManager::GenerateCommon() -{ - /* - fifoDirectWrite8 = AlignCode4(); - GenFifoWrite(8); - fifoDirectWrite16 = AlignCode4(); - GenFifoWrite(16); - fifoDirectWrite32 = AlignCode4(); - GenFifoWrite(32); - fifoDirectWriteFloat = AlignCode4(); - GenFifoFloatWrite(); - fifoDirectWriteXmm64 = AlignCode4(); - GenFifoXmm64Write(); - - GenQuantizedLoads(); - GenQuantizedStores(); - GenQuantizedSingleStores(); - */ - - //CMPSD(R(XMM0), M(&zero), - // TODO - - // Fast write routines - special case the most common hardware write - // TODO: use this. - // Even in x86, the param values will be in the right registers. - /* - const u8 *fastMemWrite8 = AlignCode16(); - CMP(32, R(ABI_PARAM2), Imm32(0xCC008000)); - FixupBranch skip_fast_write = J_CC(CC_NE, false); - MOV(32, EAX, M(&m_gatherPipeCount)); - MOV(8, MDisp(EAX, (u32)&m_gatherPipe), ABI_PARAM1); - ADD(32, 1, M(&m_gatherPipeCount)); - RET(); - SetJumpTarget(skip_fast_write); - CALL((void *)&Memory::Write_U8);*/ -} +} \ No newline at end of file diff --git a/Core/MIPS/ARM/Asm.h b/Core/MIPS/ARM/ArmAsm.h similarity index 62% rename from Core/MIPS/ARM/Asm.h rename to Core/MIPS/ARM/ArmAsm.h index 481e46374b..459582452e 100644 --- a/Core/MIPS/ARM/Asm.h +++ b/Core/MIPS/ARM/ArmAsm.h @@ -21,19 +21,7 @@ #include #include "../MIPS.h" -// In PPSSPP, we don't use inline assembly. Instead, we generate all machine-near -// code at runtime. In the case of fixed code like this, after writing it, we write -// protect the memory, essentially making it work just like precompiled code. - -// There are some advantages to this approach: -// 1) No need to setup an external assembler in the build. -// 2) Cross platform, as long as it's x86/x64. -// 3) Can optimize code at runtime for the specific CPU model. -// There aren't really any disadvantages other than having to maintain code emitters, -// which we have to do anyway :) -// -// To add a new asm routine, just add another const here, and add the code to Generate. -// Also, possibly increase the size of the code buffer. +// Runtime generated assembly routines, like the Dispatcher. namespace MIPSComp { @@ -65,14 +53,10 @@ public: const u8 *enterCode; const u8 *outerLoop; + const u8 *dispatcherCheckCoreState; const u8 *dispatcher; const u8 *dispatcherNoCheck; const u8 *dispatcherPcInR0; - - const u8 *fpException; - const u8 *testExceptions; - const u8 *testExternalExceptions; - const u8 *doTiming; }; #endif // _JIT64ASM_H diff --git a/Core/MIPS/ARM/CompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp similarity index 99% rename from Core/MIPS/ARM/CompALU.cpp rename to Core/MIPS/ARM/ArmCompALU.cpp index 5560da52e4..459e5effa9 100644 --- a/Core/MIPS/ARM/CompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -15,9 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Jit.h" -#include "RegCache.h" -#include +#include "ArmJit.h" +#include "ArmRegCache.h" +#include "ArmEmitter.h" using namespace MIPSAnalyst; #define _RS ((op>>21) & 0x1F) diff --git a/Core/MIPS/ARM/CompBranch.cpp b/Core/MIPS/ARM/ArmCompBranch.cpp similarity index 98% rename from Core/MIPS/ARM/CompBranch.cpp rename to Core/MIPS/ARM/ArmCompBranch.cpp index cdcb257f4e..750589b654 100644 --- a/Core/MIPS/ARM/CompBranch.cpp +++ b/Core/MIPS/ARM/ArmCompBranch.cpp @@ -21,9 +21,9 @@ #include "../MIPSAnalyst.h" #include "../MIPSTables.h" -#include "Jit.h" -#include "RegCache.h" -#include "JitCache.h" +#include "ArmJit.h" +#include "ArmRegCache.h" +#include "ArmJitCache.h" #include #define _RS ((op>>21) & 0x1F) @@ -209,9 +209,9 @@ void Jit::BranchFPFlag(u32 op, ArmGen::CCFlags cc, bool likely) } FlushAll(); - ARMABI_MOVI2R(R0, (u32)&(mips_->fpcond)); + ARMABI_MOVI2R(R0, (u32)&(mips_->fcr31)); LDR(R0, R0, Operand2(0, TYPE_IMM)); - TST(R0, Operand2(1, TYPE_IMM)); + TST(R0, Operand2(1 << 23, TYPE_IMM)); ArmGen::FixupBranch ptr; js.inDelaySlot = true; if (!likely) diff --git a/Core/MIPS/ARM/CompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp similarity index 99% rename from Core/MIPS/ARM/CompFPU.cpp rename to Core/MIPS/ARM/ArmCompFPU.cpp index 0ed608eac2..d008d2308b 100644 --- a/Core/MIPS/ARM/CompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -16,8 +16,8 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "../MIPS.h" -#include "Jit.h" -#include "RegCache.h" +#include "ArmJit.h" +#include "ArmRegCache.h" #define _RS ((op>>21) & 0x1F) #define _RT ((op>>16) & 0x1F) diff --git a/Core/MIPS/ARM/CompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp similarity index 98% rename from Core/MIPS/ARM/CompLoadStore.cpp rename to Core/MIPS/ARM/ArmCompLoadStore.cpp index e8d8430447..fd458240f0 100644 --- a/Core/MIPS/ARM/CompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -17,8 +17,8 @@ #include "../../MemMap.h" #include "../MIPSAnalyst.h" -#include "Jit.h" -#include "RegCache.h" +#include "ArmJit.h" +#include "ArmRegCache.h" #define _RS ((op>>21) & 0x1F) diff --git a/Core/MIPS/ARM/CompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp similarity index 87% rename from Core/MIPS/ARM/CompVFPU.cpp rename to Core/MIPS/ARM/ArmCompVFPU.cpp index 7abf7a19af..b434446b68 100644 --- a/Core/MIPS/ARM/CompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -1,8 +1,8 @@ #include "../../MemMap.h" #include "../MIPSAnalyst.h" -#include "Jit.h" -#include "RegCache.h" +#include "ArmJit.h" +#include "ArmRegCache.h" #define _RS ((op>>21) & 0x1F) diff --git a/Core/MIPS/ARM/Jit.cpp b/Core/MIPS/ARM/ArmJit.cpp similarity index 86% rename from Core/MIPS/ARM/Jit.cpp rename to Core/MIPS/ARM/ArmJit.cpp index d3c33f61c7..9dc526d59d 100644 --- a/Core/MIPS/ARM/Jit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -22,11 +22,8 @@ #include "../MIPSInt.h" #include "../MIPSTables.h" -#include "RegCache.h" -#include "Jit.h" - - -extern u32 *pspmainram; +#include "ArmRegCache.h" +#include "ArmJit.h" namespace MIPSComp { @@ -74,7 +71,7 @@ Jit::Jit(MIPSState *mips) : blocks(mips), gpr(mips), mips_(mips) void Jit::FlushAll() { - gpr.Flush(); + gpr.FlushAll(); //fpr.Flush(FLUSH_ALL); } @@ -100,7 +97,7 @@ void Jit::Compile(u32 em_address) } int block_num = blocks.AllocateBlock(em_address); - JitBlock *b = blocks.GetBlock(block_num); + ArmJitBlock *b = blocks.GetBlock(block_num); blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, b)); } @@ -110,7 +107,7 @@ void Jit::RunLoopUntil(u64 globalticks) ((void (*)())asm_.enterCode)(); } -const u8 *Jit::DoJit(u32 em_address, JitBlock *b) +const u8 *Jit::DoJit(u32 em_address, ArmJitBlock *b) { js.cancel = false; js.blockStart = js.compilerPC = mips_->pc; @@ -166,42 +163,35 @@ void Jit::Comp_Generic(u32 op) void Jit::DoDownCount() { - ARMReg A = gpr.GetReg(); - ARMReg B = gpr.GetReg(); - ARMABI_MOVI2R(A, Mem(&CoreTiming::downcount)); - LDR(B, A); + ARMABI_MOVI2R(R0, Mem(&CoreTiming::downcount)); + LDR(R1, R0); if(js.downcountAmount < 255) // We can enlarge this if we used rotations { - SUBS(B, B, js.downcountAmount); - STR(A, B); + SUBS(R1, R1, js.downcountAmount); + STR(R0, R1); + } else { + // Should be fine to use R2 here, flushed the regcache anyway. + // If js.downcountAmount can be expressed as an Imm8, we don't need this anyway. + ARMABI_MOVI2R(R2, js.downcountAmount); + SUBS(R1, R1, R2); + STR(R0, R1); } - else - { - ARMReg C = gpr.GetReg(false); - ARMABI_MOVI2R(C, js.downcountAmount); - SUBS(B, B, C); - STR(A, B); - } - gpr.Unlock(A, B); } void Jit::WriteExitDestInR(ARMReg Reg) { - ARMReg A = gpr.GetReg(); - ARMABI_MOVI2R(A, (u32)&mips_->pc); - STR(A, Reg); - gpr.Unlock(Reg); // This was locked in the instruction beforehand. + ARMABI_MOVI2R(R0, (u32)&mips_->pc); + STR(R0, Reg); DoDownCount(); - ARMABI_MOVI2R(A, (u32)asm_.dispatcher); - B(A); - gpr.Unlock(A); + ARMABI_MOVI2R(R0, (u32)asm_.dispatcher); + B(R0); } void Jit::WriteExit(u32 destination, int exit_num) { DoDownCount(); //If nobody has taken care of this yet (this can be removed when all branches are done) - JitBlock *b = js.curBlock; + ArmJitBlock *b = js.curBlock; b->exitAddress[exit_num] = destination; b->exitPtrs[exit_num] = GetWritableCodePtr(); @@ -218,9 +208,8 @@ void Jit::WriteExit(u32 destination, int exit_num) ARMABI_MOVI2R(R0, (u32)&mips_->pc); // Watch out! This uses R14 and R12! ARMABI_MOVI2R(R1, destination); // Watch out! This uses R14 and R12! STR(R0, R1); // Watch out! This uses R14 and R12! - ARMReg A = gpr.GetReg(false); - ARMABI_MOVI2R(A, (u32)asm_.dispatcher); - B(A); + ARMABI_MOVI2R(R0, (u32)asm_.dispatcher); + B(R0); } } diff --git a/Core/MIPS/ARM/Jit.h b/Core/MIPS/ARM/ArmJit.h similarity index 89% rename from Core/MIPS/ARM/Jit.h rename to Core/MIPS/ARM/ArmJit.h index 60e91a43cf..8d9f1de9ee 100644 --- a/Core/MIPS/ARM/Jit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -18,23 +18,18 @@ #pragma once #include "../../../Globals.h" -#include "Asm.h" - -#if !defined(ARM) -#error DO NOT BUILD ARM JIT ON NON-ARM -#endif - +#include "ArmAsm.h" #include -#include "JitCache.h" -#include "RegCache.h" +#include "ArmJitCache.h" +#include "ArmRegCache.h" namespace MIPSComp { -struct JitOptions +struct ArmJitOptions { - JitOptions() + ArmJitOptions() { enableBlocklink = false; } @@ -42,7 +37,7 @@ struct JitOptions bool enableBlocklink; }; -struct JitState +struct ArmJitState { u32 compilerPC; u32 blockStart; @@ -50,7 +45,7 @@ struct JitState bool inDelaySlot; int downcountAmount; bool compiling; // TODO: get rid of this in favor of using analysis results to determine end of block - JitBlock *curBlock; + ArmJitBlock *curBlock; }; class Jit : public ArmGen::ARMXCodeBlock @@ -66,7 +61,7 @@ public: void RunLoopUntil(u64 globalticks); void Compile(u32 em_address); // Compiles a block at current MIPS PC - const u8 *DoJit(u32 em_address, JitBlock *b); + const u8 *DoJit(u32 em_address, ArmJitBlock *b); void CompileAt(u32 addr); void Comp_RunBlock(u32 op); @@ -92,7 +87,7 @@ public: void Comp_FPU2op(u32 op); void Comp_mxc1(u32 op); - JitBlockCache *GetBlockCache() { return &blocks; } + ArmJitBlockCache *GetBlockCache() { return &blocks; } AsmRoutineManager &Asm() { return asm_; } void ClearCache(); @@ -121,9 +116,9 @@ private: void CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters); */ - JitBlockCache blocks; - JitOptions jo; - JitState js; + ArmJitBlockCache blocks; + ArmJitOptions jo; + ArmJitState js; ArmRegCache gpr; // FPURegCache fpr; diff --git a/Core/MIPS/ARM/JitCache.cpp b/Core/MIPS/ARM/ArmJitCache.cpp similarity index 84% rename from Core/MIPS/ARM/JitCache.cpp rename to Core/MIPS/ARM/ArmJitCache.cpp index 68a5aa5d3c..7c7b2c76f5 100644 --- a/Core/MIPS/ARM/JitCache.cpp +++ b/Core/MIPS/ARM/ArmJitCache.cpp @@ -29,12 +29,11 @@ #include "../MIPSTables.h" #include "../MIPSAnalyst.h" -#include "JitCache.h" -#include "../JitCommon/JitCommon.h" -#include "Asm.h" -// #include "JitBase.h" +#include "ArmEmitter.h" -#include +#include "ArmJitCache.h" +#include "../JitCommon/JitCommon.h" +#include "ArmAsm.h" #if defined USE_OPROFILE && USE_OPROFILE #include @@ -52,30 +51,30 @@ using namespace ArmGen; #define INVALID_EXIT 0xFFFFFFFF -bool JitBlock::ContainsAddress(u32 em_address) +bool ArmJitBlock::ContainsAddress(u32 em_address) { // WARNING - THIS DOES NOT WORK WITH INLINING ENABLED. return (em_address >= originalAddress && em_address < originalAddress + 4 * originalSize); } -bool JitBlockCache::IsFull() const +bool ArmJitBlockCache::IsFull() const { return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; } -void JitBlockCache::Init() +void ArmJitBlockCache::Init() { MAX_NUM_BLOCKS = 65536*2; #if defined USE_OPROFILE && USE_OPROFILE agent = op_open_agent(); #endif - blocks = new JitBlock[MAX_NUM_BLOCKS]; + blocks = new ArmJitBlock[MAX_NUM_BLOCKS]; blockCodePointers = new const u8*[MAX_NUM_BLOCKS]; Clear(); } -void JitBlockCache::Shutdown() +void ArmJitBlockCache::Shutdown() { delete[] blocks; delete[] blockCodePointers; @@ -91,7 +90,7 @@ void JitBlockCache::Shutdown() #endif } -JitBlockCache::~JitBlockCache() +ArmJitBlockCache::~ArmJitBlockCache() { Shutdown(); } @@ -99,7 +98,7 @@ JitBlockCache::~JitBlockCache() // This clears the JIT cache. It's called from JitCache.cpp when the JIT cache // is full and when saving and loading states. -void JitBlockCache::Clear() +void ArmJitBlockCache::Clear() { for (int i = 0; i < num_blocks; i++) { @@ -111,7 +110,7 @@ void JitBlockCache::Clear() memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS); } -void JitBlockCache::ClearSafe() +void ArmJitBlockCache::ClearSafe() { #ifdef JIT_UNLIMITED_ICACHE memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); @@ -129,23 +128,23 @@ void JitBlockCache::ClearSafe() } }*/ -void JitBlockCache::Reset() +void ArmJitBlockCache::Reset() { Shutdown(); Init(); } -JitBlock *JitBlockCache::GetBlock(int no) +ArmJitBlock *ArmJitBlockCache::GetBlock(int no) { return &blocks[no]; } -int JitBlockCache::GetNumBlocks() const +int ArmJitBlockCache::GetNumBlocks() const { return num_blocks; } -bool JitBlockCache::RangeIntersect(int s1, int e1, int s2, int e2) const +bool ArmJitBlockCache::RangeIntersect(int s1, int e1, int s2, int e2) const { // check if any endpoint is inside the other range if ((s1 >= s2 && s1 <= e2) || @@ -157,9 +156,9 @@ bool JitBlockCache::RangeIntersect(int s1, int e1, int s2, int e2) const return false; } -int JitBlockCache::AllocateBlock(u32 em_address) +int ArmJitBlockCache::AllocateBlock(u32 em_address) { - JitBlock &b = blocks[num_blocks]; + ArmJitBlock &b = blocks[num_blocks]; b.invalid = false; b.originalAddress = em_address; b.exitAddress[0] = INVALID_EXIT; @@ -173,10 +172,10 @@ int JitBlockCache::AllocateBlock(u32 em_address) return num_blocks - 1; } -void JitBlockCache::FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr) +void ArmJitBlockCache::FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr) { blockCodePointers[block_num] = code_ptr; - JitBlock &b = blocks[block_num]; + ArmJitBlock &b = blocks[block_num]; b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress); u32 opcode = MIPS_MAKE_EMUHACK(0, block_num); @@ -222,12 +221,12 @@ void JitBlockCache::FinalizeBlock(int block_num, bool block_link, const u8 *code #endif } -const u8 **JitBlockCache::GetCodePointers() +const u8 **ArmJitBlockCache::GetCodePointers() { return blockCodePointers; } -int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr) +int ArmJitBlockCache::GetBlockNumberFromStartAddress(u32 addr) { if (!blocks) return -1; @@ -242,14 +241,14 @@ int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr) return bl; } -void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers) +void ArmJitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers) { for (int i = 0; i < num_blocks; i++) if (blocks[i].ContainsAddress(em_address)) block_numbers->push_back(i); } -u32 JitBlockCache::GetOriginalFirstOp(int block_num) +u32 ArmJitBlockCache::GetOriginalFirstOp(int block_num) { if (block_num >= num_blocks) { @@ -259,12 +258,12 @@ u32 JitBlockCache::GetOriginalFirstOp(int block_num) return blocks[block_num].originalFirstOpcode; } -CompiledCode JitBlockCache::GetCompiledCodeFromBlock(int block_num) +CompiledCode ArmJitBlockCache::GetCompiledCodeFromBlock(int block_num) { return (CompiledCode)blockCodePointers[block_num]; } -std::string JitBlockCache::GetCompiledDisassembly(int block_num) +std::string ArmJitBlockCache::GetCompiledDisassembly(int block_num) { /* std::string buf; @@ -287,9 +286,9 @@ std::string JitBlockCache::GetCompiledDisassembly(int block_num) //Can be faster by doing a queue for blocks to link up, and only process those //Should probably be done -void JitBlockCache::LinkBlockExits(int i) +void ArmJitBlockCache::LinkBlockExits(int i) { - JitBlock &b = blocks[i]; + ArmJitBlock &b = blocks[i]; if (b.invalid) { // This block is dead. Don't relink it. @@ -312,10 +311,10 @@ void JitBlockCache::LinkBlockExits(int i) using namespace std; -void JitBlockCache::LinkBlock(int i) +void ArmJitBlockCache::LinkBlock(int i) { LinkBlockExits(i); - JitBlock &b = blocks[i]; + ArmJitBlock &b = blocks[i]; std::map::iterator iter; pair::iterator, multimap::iterator> ppp; // equal_range(b) returns pair representing the range @@ -329,16 +328,16 @@ void JitBlockCache::LinkBlock(int i) } } -void JitBlockCache::UnlinkBlock(int i) +void ArmJitBlockCache::UnlinkBlock(int i) { - JitBlock &b = blocks[i]; + ArmJitBlock &b = blocks[i]; std::map::iterator iter; pair::iterator, multimap::iterator> ppp; ppp = links_to.equal_range(b.originalAddress); if (ppp.first == ppp.second) return; for (multimap::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) { - JitBlock &sourceBlock = blocks[iter2->second]; + ArmJitBlock &sourceBlock = blocks[iter2->second]; for (int e = 0; e < 2; e++) { if (sourceBlock.exitAddress[e] == b.originalAddress) @@ -347,14 +346,14 @@ void JitBlockCache::UnlinkBlock(int i) } } -void JitBlockCache::DestroyBlock(int block_num, bool invalidate) +void ArmJitBlockCache::DestroyBlock(int block_num, bool invalidate) { if (block_num < 0 || block_num >= num_blocks) { ERROR_LOG(JIT, "DestroyBlock: Invalid block number %d", block_num); return; } - JitBlock &b = blocks[block_num]; + ArmJitBlock &b = blocks[block_num]; if (b.invalid) { if (invalidate) @@ -382,7 +381,7 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate) */ } -void JitBlockCache::InvalidateICache(u32 address, const u32 length) +void ArmJitBlockCache::InvalidateICache(u32 address, const u32 length) { // Convert the logical address to a physical address for the block map u32 pAddr = address & 0x1FFFFFFF; diff --git a/Core/MIPS/ARM/JitCache.h b/Core/MIPS/ARM/ArmJitCache.h similarity index 95% rename from Core/MIPS/ARM/JitCache.h rename to Core/MIPS/ARM/ArmJitCache.h index ae38f06e6a..d464417115 100644 --- a/Core/MIPS/ARM/JitCache.h +++ b/Core/MIPS/ARM/ArmJitCache.h @@ -22,7 +22,7 @@ #include #include "../MIPSAnalyst.h" - +#include "../MIPS.h" // Define this in order to get VTune profile support for the Jit generated code. // Add the VTune include/lib directories to the project directories to get this to build. // #define USE_VTUNE @@ -42,7 +42,7 @@ #define JIT_OPCODE 0xFFCCCCCC // yeah this ain't gonna work -struct JitBlock +struct ArmJitBlock { const u8 *checkedEntry; const u8 *normalEntry; @@ -77,11 +77,11 @@ struct JitBlock typedef void (*CompiledCode)(); -class JitBlockCache +class ArmJitBlockCache { MIPSState *mips; const u8 **blockCodePointers; - JitBlock *blocks; + ArmJitBlock *blocks; int num_blocks; std::multimap links_to; std::map, u32> block_map; // (end_addr, start_addr) -> number @@ -94,10 +94,10 @@ class JitBlockCache void UnlinkBlock(int i); public: - JitBlockCache(MIPSState *mips_) : + ArmJitBlockCache(MIPSState *mips_) : mips(mips_), blockCodePointers(0), blocks(0), num_blocks(0), MAX_NUM_BLOCKS(0) { } - ~JitBlockCache(); + ~ArmJitBlockCache(); int AllocateBlock(u32 em_address); void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr); @@ -110,7 +110,7 @@ public: bool IsFull() const; // Code Cache - JitBlock *GetBlock(int block_num); + ArmJitBlock *GetBlock(int block_num); int GetNumBlocks() const; const u8 **GetCodePointers(); diff --git a/Core/MIPS/ARM/ArmRegCache.cpp b/Core/MIPS/ARM/ArmRegCache.cpp new file mode 100644 index 0000000000..83037335df --- /dev/null +++ b/Core/MIPS/ARM/ArmRegCache.cpp @@ -0,0 +1,189 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "ArmABI.h" +#include "ArmRegCache.h" +#include "ArmEmitter.h" + +using namespace ArmGen; + +#define CTXREG ((ARMReg)14) + +ArmRegCache::ArmRegCache(MIPSState *mips) : mips_(mips) { +} + +void ArmRegCache::Init(ARMXEmitter *emitter) { + emit = emitter; +} + +void ArmRegCache::Start(MIPSAnalyst::AnalysisResults &stats) { + for (int i = 0; i < 16; i++) { + ar[i].mipsReg = -1; + ar[i].spillLock = false; + ar[i].allocLock = false; + ar[i].isDirty = false; + } + for (int i = 0; i < 32; i++) { + mr[i].loc = ML_MEM; + } +} + +static const ARMReg *GetMIPSAllocationOrder(int &count) { + // Note that R0 and R1 are reserved as scratch for now. We can probably free up R1 eventually. + static const ARMReg allocationOrder[] = { + R2, R3, R4, R5, R6, R7, R8, R9 + }; + count = sizeof(allocationOrder) / sizeof(const int); + return allocationOrder; +} + +ARMReg ArmRegCache::MapReg(MIPSReg mipsReg, int mapFlags) { + // Let's see if it's already mapped. + for (int i = 0; i < NUM_ARMREG; i++) { + if (ar[i].mipsReg == mipsReg) { + // Already mapped, no need to do anything more. + return (ARMReg)i; + } + } + + // Okay, so we need to allocate one. + + int allocCount; + const ARMReg *allocOrder = GetMIPSAllocationOrder(allocCount); + +allocate: + for (int i = 0; i < allocCount; i++) { + int reg = allocOrder[i]; + + if (ar[reg].mipsReg == -1 && !ar[reg].allocLock) { + // That means it's free. Grab it, and load the value into it (if requested). + ar[reg].mipsReg = mipsReg; + ar[reg].isDirty = (mapFlags & MAP_DIRTY) ? true : false; + if (mapFlags & MAP_INITVAL) { + if (mr[mipsReg].loc == ML_MEM) + emit->LDR((ARMReg)reg, CTXREG, 4 * mipsReg); + else if (mr[mipsReg].loc == ML_IMM) + emit->ARMABI_MOVI2R((ARMReg)reg, mr[mipsReg].imm); + } + return (ARMReg)reg; + } + } + + // Still nothing. Let's spill a reg and goto 10 + + for (int i = 0; i < allocCount; i++) { + if (ar[i].spillLock || ar[i].allocLock) + continue; + FlushArmReg((ARMReg)i); + goto allocate; + } + + // Uh oh, we have all them alloclocked and spilllocked.... + _assert_msg_(JIT, false, "All available registers are locked dumb dumb"); + return INVALID_REG; +} + +void ArmRegCache::FlushArmReg(ARMReg r) { + if (ar[r].mipsReg == -1) { + // Nothing to do + return; + } + if (ar[r].isDirty) { + if (mr[ar[r].mipsReg].loc == ML_MEM) + emit->STR(r, CTXREG, 4 * ar[r].mipsReg); + } +} + +void ArmRegCache::FlushMipsReg(MIPSReg r) { + switch (mr[r].loc) { + case ML_IMM: + // IMM is always "dirty". + emit->ARMABI_MOVI2R(R0, mr[r].imm); + emit->STR(R0, CTXREG, GetMipsRegOffset(r)); + break; + + case ML_ARMREG: + if (ar[mr[r].reg].isDirty) + emit->STR(mr[r].reg, CTXREG, GetMipsRegOffset(r)); + ar[mr[r].reg].mipsReg = -1; + ar[mr[r].reg].isDirty = false; + break; + + default: + //BAD + break; + } + mr[r].loc = ML_MEM; +} + +void ArmRegCache::FlushAll() { + for (int i = 0; i < NUM_MIPSREG; i++) { + FlushMipsReg(i); + } +} + +void ArmRegCache::SetImm(MIPSReg r, u32 immVal) { + // Zap existing value + if (mr[r].loc == ML_ARMREG) + ar[mr[r].reg].mipsReg = -1; + mr[r].loc = ML_IMM; + mr[r].imm = immVal; +} + +bool ArmRegCache::IsImm(MIPSReg r) const { + return mr[r].loc == ML_IMM; +} + +u32 ArmRegCache::GetImm(MIPSReg r) const { + // TODO: Check. + return mr[r].imm; +} + +int ArmRegCache::GetMipsRegOffset(MIPSReg r) { + if (r < 32) + return r * 4; + switch (r) { + case MIPSREG_HI: + return offsetof(MIPSState, hi); + case MIPSREG_LO: + return offsetof(MIPSState, lo); + } + _dbg_assert_msg_(JIT, false, "bad mips register %i", (int)r); + return -999; // boom! +} + +void ArmRegCache::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3) { + if (mr[r1].loc == ML_ARMREG) ar[mr[r1].reg].spillLock = true; + if (r2 != -1 && mr[r2].loc == ML_ARMREG) ar[mr[r2].reg].spillLock = true; + if (r3 != -1 && mr[r3].loc == ML_ARMREG) ar[mr[r3].reg].spillLock = true; +} + +void ArmRegCache::ReleaseSpillLocks() { + for (int i = 0; i < 16; i++) { + ar[i].spillLock = false; + } +} + +ARMReg ArmRegCache::R(int mipsReg) { + if (mr[mipsReg].loc == ML_ARMREG) { + return mr[mipsReg].reg; + } else { + _dbg_assert_msg_(JIT, false, "R: not mapped"); + return INVALID_REG; // BAAAD + } +} + diff --git a/Core/MIPS/ARM/ArmRegCache.h b/Core/MIPS/ARM/ArmRegCache.h new file mode 100644 index 0000000000..dfbcf2b4da --- /dev/null +++ b/Core/MIPS/ARM/ArmRegCache.h @@ -0,0 +1,112 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "ArmEmitter.h" +#include "../MIPS.h" +#include "../MIPSAnalyst.h" +#include "ArmABI.h" + +using namespace ArmGen; + +// R2 to R9: mapped MIPS regs +// R11 = base pointer +// R12 = MIPS context +// R14 = code pointers + +// Special MIPS registers: +enum { + MIPSREG_HI = 32, + MIPSREG_LO = 33, + TOTAL_MAPPABLE_MIPSREGS = 34, +}; + +typedef int MIPSReg; + +struct RegARM { + int mipsReg; // if -1, no mipsreg attached. + bool isDirty; // Should the register be written back? + bool allocLock; // if true, this ARM register cannot be used for allocation. + bool spillLock; // if true, this register cannot be spilled. +}; + +enum RegMIPSLoc { + ML_IMM, + ML_ARMREG, + ML_MEM, +}; + +struct RegMIPS { + // Where is this MIPS register? + RegMIPSLoc loc; + // Data (only one of these is used, depending on loc. Could make a union). + u32 imm; + ARMReg reg; + // If loc == ML_MEM, it's back in its location in the CPU context struct. +}; + +enum { + MAP_DIRTY = 1, + MAP_INITVAL = 2, +}; + +class ArmRegCache +{ +public: + ArmRegCache(MIPSState *mips); + ~ArmRegCache() {} + + void Init(ARMXEmitter *emitter); + void Start(MIPSAnalyst::AnalysisResults &stats); + + // void AllocLock(ARMReg reg, ARMReg reg2 = INVALID_REG, ARMReg reg3 = INVALID_REG); + // void ReleaseAllocLock(ARMReg reg); + + // Protect the arm register containing a MIPS register from spilling, to ensure that + // it's being kept allocated. + void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1); + void ReleaseSpillLocks(); + + void SetImm(MIPSReg reg, u32 immVal); + bool IsImm(MIPSReg reg) const; + u32 GetImm(MIPSReg reg) const; + + // Returns an ARM register containing the requested MIPS register. + ARMReg MapReg(MIPSReg reg, int mapFlags = 0); + void FlushArmReg(ARMReg r); + void FlushMipsReg(MIPSReg r); + + void FlushAll(); + + ARMReg R(int preg); // Returns a cached register + + void SetEmitter(ARMXEmitter *emitter) { emit = emitter; } + +private: + int GetMipsRegOffset(MIPSReg r); + MIPSState *mips_; + ARMXEmitter *emit; + + enum { + NUM_ARMREG = 16, + NUM_MIPSREG = TOTAL_MAPPABLE_MIPSREGS, + }; + + RegARM ar[16]; + RegMIPS mr[32]; +}; diff --git a/Core/MIPS/ARM/RegCache.cpp b/Core/MIPS/ARM/RegCache.cpp deleted file mode 100644 index 80ec9ec8f3..0000000000 --- a/Core/MIPS/ARM/RegCache.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "RegCache.h" -#include "ArmEmitter.h" - -using namespace ArmGen; - -/* -// these are MIPS reg indices -void RegCache::Lock(int p1, int p2, int p3, int p4) -{ - locks[p1] = true; - if (p2 != 0xFF) locks[p2] = true; - if (p3 != 0xFF) locks[p3] = true; - if (p4 != 0xFF) locks[p4] = true; -} - -// these are x64 reg indices -void RegCache::LockX(int x1, int x2, int x3, int x4) -{ - if (xlocks[x1]) { - PanicAlert("RegCache: x %i already locked!", x1); - } - xlocks[x1] = true; - if (x2 != 0xFF) xlocks[x2] = true; - if (x3 != 0xFF) xlocks[x3] = true; - if (x4 != 0xFF) xlocks[x4] = true; -} - -bool RegCache::IsFreeX(int xreg) const -{ - return xregs[xreg].free && !xlocks[xreg]; -} - -void RegCache::UnlockAll() -{ - for (int i = 0; i < 32; i++) - locks[i] = false; -} -*/ - -ArmRegCache::ArmRegCache(MIPSState *mips) - : mips_(mips) -{ - emit = 0; - -} - -void ArmRegCache::Init(ARMXEmitter *emitter) -{ - emit = emitter; - ARMReg *PPCRegs = GetMIPSAllocationOrder(NUMMIPSREG); - ARMReg *Regs = GetAllocationOrder(NUMARMREG); - for(int a = 0; a < 32; ++a) - { - // This gives us the memory locations of the gpr registers so we can - // load them. - regs[a].location = (u8*)&mips_->r[a]; - } - for(int a = 0; a < NUMMIPSREG; ++a) - { - ArmCRegs[a].MIPSReg = 33; - ArmCRegs[a].Reg = PPCRegs[a]; - ArmCRegs[a].LastLoad = 0; - } - for(int a = 0; a < NUMARMREG; ++a) - { - ArmRegs[a].Reg = Regs[a]; - ArmRegs[a].free = true; - } -} - -void ArmRegCache::Start(MIPSAnalyst::AnalysisResults &stats) -{ - for(int a = 0; a < NUMMIPSREG; ++a) - { - ArmCRegs[a].MIPSReg = 33; - ArmCRegs[a].LastLoad = 0; - } -} - -ARMReg *ArmRegCache::GetMIPSAllocationOrder(int &count) -{ - // This will return us the allocation order of the registers we can use on - // the MIPS side. - static ARMReg allocationOrder[] = - { - R0, R1, R2, R3, R4, R5, R6, R7, R8, R9 - }; - count = sizeof(allocationOrder) / sizeof(const int); - return allocationOrder; -} -ARMReg *ArmRegCache::GetAllocationOrder(int &count) -{ - // This will return us the allocation order of the registers we can use on - // the host side. - static ARMReg allocationOrder[] = - { - R14, R12, R11, R10 - }; - count = sizeof(allocationOrder) / sizeof(const int); - return allocationOrder; -} - -ARMReg ArmRegCache::GetReg(bool AutoLock) -{ - for (int a = 0; a < NUMARMREG; ++a) - { - if(ArmRegs[a].free) - { - // Alright, this one is free - if (AutoLock) - ArmRegs[a].free = false; - return ArmRegs[a].Reg; - } - } - // Uh Oh, we have all them locked.... - _assert_msg_(JIT, false, "All available registers are locked dumb dumb"); -} -void ArmRegCache::Lock(ARMReg Reg) -{ - for (int RegNum = 0; RegNum < NUMARMREG; ++RegNum) - { - if(ArmRegs[RegNum].Reg == Reg) - { - _assert_msg_(JIT, ArmRegs[RegNum].free, "This register is already locked"); - ArmRegs[RegNum].free = false; - } - } - _assert_msg_(JIT, false, "Register %d can't be used with lock", Reg); -} -void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3) -{ - for (int RegNum = 0; RegNum < NUMARMREG; ++RegNum) - { - if(ArmRegs[RegNum].Reg == R0) - { - _assert_msg_(JIT, !ArmRegs[RegNum].free, "This register is already unlocked"); - ArmRegs[RegNum].free = true; - } - if( R1 != INVALID_REG && ArmRegs[RegNum].Reg == R1) ArmRegs[RegNum].free = true; - if( R2 != INVALID_REG && ArmRegs[RegNum].Reg == R2) ArmRegs[RegNum].free = true; - if( R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3) ArmRegs[RegNum].free = true; - } -} - -ARMReg ArmRegCache::R(int preg) -{ - u32 HighestUsed = 0; - u8 Num = 0; - for (int a = 0; a < NUMMIPSREG; ++a){ - ++ArmCRegs[a].LastLoad; - if (ArmCRegs[a].LastLoad > HighestUsed) - { - HighestUsed = ArmCRegs[a].LastLoad; - Num = a; - } - } - // Check if already Loaded - for (int a = 0; a < NUMMIPSREG; ++a) { - if (ArmCRegs[a].MIPSReg == preg) - { - ArmCRegs[a].LastLoad = 0; - return ArmCRegs[a].Reg; - } - } - // Check if we have a free register - for (u8 a = 0; a < NUMMIPSREG; ++a) - if (ArmCRegs[a].MIPSReg == 33) - { - emit->ARMABI_MOVI2R(ArmCRegs[a].Reg, (u32)&mips_->r); - emit->LDR(ArmCRegs[a].Reg, ArmCRegs[a].Reg, preg * 4); - ArmCRegs[a].MIPSReg = preg; - ArmCRegs[a].LastLoad = 0; - return ArmCRegs[a].Reg; - } - // Alright, we couldn't get a free space, dump that least used register - // Note that this is incredibly dangerous if references to the register - // are still floating around out there! - ARMReg rA = GetReg(false); - emit->ARMABI_MOVI2R(rA, (u32)&mips_->r); - emit->STR(rA, ArmCRegs[Num].Reg, ArmCRegs[Num].MIPSReg * 4); - emit->LDR(ArmCRegs[Num].Reg, rA, preg * 4); - ArmCRegs[Num].MIPSReg = preg; - ArmCRegs[Num].LastLoad = 0; - return ArmCRegs[Num].Reg; -} - -void ArmRegCache::Flush() -{ - // Maybe we should keep this pointer around permanently? - emit->MOVW(R14, (u32)&mips_->r); - emit->MOVT(R14, (u32)&mips_->r, true); - - for (int a = 0; a < NUMMIPSREG; ++a) { - if (ArmCRegs[a].MIPSReg != 33) - { - emit->STR(R14, ArmCRegs[a].Reg, ArmCRegs[a].MIPSReg * 4); - ArmCRegs[a].MIPSReg = 33; - ArmCRegs[a].LastLoad = 0; - } - } -} - diff --git a/Core/MIPS/ARM/RegCache.h b/Core/MIPS/ARM/RegCache.h deleted file mode 100644 index ab5d85c0ca..0000000000 --- a/Core/MIPS/ARM/RegCache.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _JITARMREGCACHE_H -#define _JITARMREGCACHE_H - -#include "ArmEmitter.h" -#include "../MIPS.h" -#include "../MIPSAnalyst.h" -#include "ArmABI.h" - -using namespace ArmGen; - -// This ARM Register cache actually pre loads the most used registers before -// the block to increase speed since every memory load requires two -// instructions to load it. We are going to use R0-RMAX as registers for the -// use of MIPS Registers. -// Allocation order as follows -#define ARMREGS 16 -// Allocate R0 to R9 for MIPS first. -// For General registers on the host side, start with R14 and go down as we go -// R13 is reserved for our stack pointer, don't ever use that. Unless you save -// it -// So we have R14, R12, R11, R10 to work with instructions - -struct MIPSCachedReg -{ - const u8 *location; -}; - -struct JRCPPC -{ - u32 MIPSReg; // Tied to which MIPS Register - ARMReg Reg; // Tied to which ARM Register - u32 LastLoad; -}; -struct JRCReg -{ - ARMReg Reg; // Which reg this is. - bool free; -}; -class ArmRegCache -{ -private: - MIPSCachedReg regs[32]; - JRCPPC ArmCRegs[ARMREGS]; - JRCReg ArmRegs[ARMREGS]; // Four registers remaining - - int NUMMIPSREG; // + LO, HI, ... - int NUMARMREG; - - ARMReg *GetAllocationOrder(int &count); - ARMReg *GetMIPSAllocationOrder(int &count); - - MIPSState *mips_; - -protected: - ARMXEmitter *emit; - -public: - ArmRegCache(MIPSState *mips); - ~ArmRegCache() {} - - void Init(ARMXEmitter *emitter); - void Start(MIPSAnalyst::AnalysisResults &stats); - - void SetEmitter(ARMXEmitter *emitter) {emit = emitter;} - - // TODO: Add a way to lock MIPS registers so they aren't kicked out when you don't expect it. - - ARMReg GetReg(bool AutoLock = true); // Return a ARM register we can use. - void Lock(ARMReg R0); - void Unlock(ARMReg R0, ARMReg R1 = INVALID_REG, ARMReg R2 = INVALID_REG, ARMReg R3 = INVALID_REG); - void Flush(); - ARMReg R(int preg); // Returns a cached register - -}; - - - - -#endif diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index a7b4673484..a8630e6fbe 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -18,7 +18,7 @@ #pragma once #if defined(ARM) -#include "../ARM/Jit.h" +#include "../ARM/ArmJit.h" #else #include "../x86/Jit.h" #endif diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index d784419212..b7d89cd873 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -24,8 +24,8 @@ #include "../HLE/sceDisplay.h" #if defined(ARM) -#include "ARM/JitCache.h" -#include "ARM/Jit.h" +#include "ARM/ArmJitCache.h" +#include "ARM/ArmJit.h" #else #include "x86/JitCache.h" #include "x86/Jit.h" @@ -40,7 +40,6 @@ MIPSDebugInterface *currentDebugMIPS = &debugr4k; MIPSState::MIPSState() { - cpuType = CPUTYPE_ALLEGREX; MIPSComp::jit = 0; } @@ -57,7 +56,7 @@ void MIPSState::Reset() delete MIPSComp::jit; MIPSComp::jit = 0; } - + if (PSP_CoreParameter().cpuCore == CPU_JIT) MIPSComp::jit = new MIPSComp::Jit(this); @@ -90,7 +89,6 @@ void MIPSState::Reset() fcr0 = 0; fcr31 = 0; debugCount = 0; - exceptions = 0; currentMIPS = this; inDelaySlot = false; llBit = 0; @@ -120,8 +118,6 @@ void MIPSState::DoState(PointerWrap &p) rng.DoState(p); p.Do(inDelaySlot); p.Do(llBit); - p.Do(cpuType); - p.Do(exceptions); p.Do(debugCount); p.DoMarker("MIPSState"); } diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index 1e8bd29a6f..92c440e606 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -124,22 +124,15 @@ public: u32 hi; u32 lo; - u32 fpcond; //separate for speed - TODO: not worth it - u32 fcr0; u32 fcr31; //fpu control register + u32 fpcond; // cache the cond flag of fcr31 (& 1 << 23) GMRng rng; // VFPU hardware random number generator. Probably not the right type. bool inDelaySlot; int llBit; // ll/sc - CPUType cpuType; - - // TODO: How do we handle exceptions? - u32 exceptions; - enum { BREAKING_EXCEPTIONS = 1 }; - // Debug stuff u32 debugCount; // can be used to count basic blocks before crashes, etc. diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index 08cfa7d0c0..715d8bef10 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -149,43 +149,4 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit) //Landing pad for drec space ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); - - GenerateCommon(); -} - -void AsmRoutineManager::GenerateCommon() -{ - /* - fifoDirectWrite8 = AlignCode4(); - GenFifoWrite(8); - fifoDirectWrite16 = AlignCode4(); - GenFifoWrite(16); - fifoDirectWrite32 = AlignCode4(); - GenFifoWrite(32); - fifoDirectWriteFloat = AlignCode4(); - GenFifoFloatWrite(); - fifoDirectWriteXmm64 = AlignCode4(); - GenFifoXmm64Write(); - - GenQuantizedLoads(); - GenQuantizedStores(); - GenQuantizedSingleStores(); - */ - - //CMPSD(R(XMM0), M(&zero), - // TODO - - // Fast write routines - special case the most common hardware write - // TODO: use this. - // Even in x86, the param values will be in the right registers. - /* - const u8 *fastMemWrite8 = AlignCode16(); - CMP(32, R(ABI_PARAM2), Imm32(0xCC008000)); - FixupBranch skip_fast_write = J_CC(CC_NE, false); - MOV(32, EAX, M(&m_gatherPipeCount)); - MOV(8, MDisp(EAX, (u32)&m_gatherPipe), ABI_PARAM1); - ADD(32, 1, M(&m_gatherPipeCount)); - RET(); - SetJumpTarget(skip_fast_write); - CALL((void *)&Memory::Write_U8);*/ -} +} \ No newline at end of file diff --git a/Core/MIPS/x86/Asm.h b/Core/MIPS/x86/Asm.h index 226332c676..d60aa4172d 100644 --- a/Core/MIPS/x86/Asm.h +++ b/Core/MIPS/x86/Asm.h @@ -20,19 +20,8 @@ #include "x64Emitter.h" #include "../MIPS.h" -// In Dolphin, we don't use inline assembly. Instead, we generate all machine-near -// code at runtime. In the case of fixed code like this, after writing it, we write -// protect the memory, essentially making it work just like precompiled code. -// There are some advantages to this approach: -// 1) No need to setup an external assembler in the build. -// 2) Cross platform, as long as it's x86/x64. -// 3) Can optimize code at runtime for the specific CPU model. -// There aren't really any disadvantages other than having to maintain a x86 emitter, -// which we have to do anyway :) -// -// To add a new asm routine, just add another const here, and add the code to Generate. -// Also, possibly increase the size of the code buffer. +// Runtime generated assembly routines, like the Dispatcher. namespace MIPSComp { @@ -68,8 +57,6 @@ public: const u8 *dispatcherCheckCoreState; const u8 *dispatcherNoCheck; - const u8 *fpException; - const u8 *breakpointBailout; }; diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 58b04562fc..cfdc23963d 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -25,9 +25,6 @@ #include "RegCache.h" #include "Jit.h" - -extern u32 *pspmainram; - namespace MIPSComp { @@ -52,8 +49,6 @@ void Jit::ClearCache() ClearCodeSpace(); } -u8 *codeCache; -#define CACHESIZE 16384*1024 void Jit::CompileAt(u32 addr) { u32 op = Memory::Read_Instruction(addr); diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 0b99805fe0..4e54d3bcff 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -168,14 +168,15 @@ LOCAL_SRC_FILES := \ $(SRC)/Core/MIPS/MIPSCodeUtils.cpp \ $(SRC)/Core/MIPS/MIPSDebugInterface.cpp \ $(SRC)/Core/MIPS/JitCommon/JitCommon.cpp \ - $(SRC)/Core/MIPS/ARM/JitCache.cpp \ - $(SRC)/Core/MIPS/ARM/CompALU.cpp \ - $(SRC)/Core/MIPS/ARM/CompBranch.cpp \ - $(SRC)/Core/MIPS/ARM/CompFPU.cpp \ - $(SRC)/Core/MIPS/ARM/Asm.cpp \ - $(SRC)/Core/MIPS/ARM/Jit.cpp \ - $(SRC)/Core/MIPS/ARM/CompLoadStore.cpp \ - $(SRC)/Core/MIPS/ARM/RegCache.cpp \ + $(SRC)/Core/MIPS/ARM/ArmJitCache.cpp \ + $(SRC)/Core/MIPS/ARM/ArmCompALU.cpp \ + $(SRC)/Core/MIPS/ARM/ArmCompBranch.cpp \ + $(SRC)/Core/MIPS/ARM/ArmCompFPU.cpp \ + $(SRC)/Core/MIPS/ARM/ArmCompLoadStore.cpp \ + $(SRC)/Core/MIPS/ARM/ArmCompVFPU.cpp \ + $(SRC)/Core/MIPS/ARM/ArmAsm.cpp \ + $(SRC)/Core/MIPS/ARM/ArmJit.cpp \ + $(SRC)/Core/MIPS/ARM/ArmRegCache.cpp \ $(SRC)/Core/Util/BlockAllocator.cpp \ $(SRC)/Core/Util/ppge_atlas.cpp \ $(SRC)/Core/Util/PPGeDraw.cpp diff --git a/android/jni/Application.mk b/android/jni/Application.mk index dd83bdcd41..62367cb819 100644 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -1,2 +1,5 @@ APP_STL := stlport_static -APP_ABI := armeabi armeabi-v7a +APP_ABI := armeabi-v7a + + +#armeabi