Rename files. Rewrite ArmRegCache from scratch.

This commit is contained in:
Henrik Rydgard 2013-01-07 22:33:09 +01:00
parent 771382cab9
commit a2ff416534
25 changed files with 493 additions and 644 deletions

View File

@ -185,49 +185,55 @@
<ClCompile Include="Loaders.cpp" />
<ClCompile Include="MemMap.cpp" />
<ClCompile Include="MemmapFunctions.cpp" />
<ClCompile Include="MIPS\ARM\Asm.cpp">
<ClCompile Include="MIPS\ARM\ArmAsm.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompALU.cpp">
<ClCompile Include="MIPS\ARM\ArmCompALU.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompBranch.cpp">
<ClCompile Include="MIPS\ARM\ArmCompBranch.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompFPU.cpp">
<ClCompile Include="MIPS\ARM\ArmCompFPU.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompLoadStore.cpp">
<ClCompile Include="MIPS\ARM\ArmCompLoadStore.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\Jit.cpp">
<ClCompile Include="MIPS\ARM\ArmCompVFPU.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\JitCache.cpp">
<ClCompile Include="MIPS\ARM\ArmJit.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\RegCache.cpp">
<ClCompile Include="MIPS\ARM\ArmJitCache.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmRegCache.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@ -338,25 +344,25 @@
<ClInclude Include="HW\MemoryStick.h" />
<ClInclude Include="Loaders.h" />
<ClInclude Include="MemMap.h" />
<ClInclude Include="MIPS\ARM\Asm.h">
<ClInclude Include="MIPS\ARM\ArmAsm.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="MIPS\ARM\Jit.h">
<ClInclude Include="MIPS\ARM\ArmJit.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="MIPS\ARM\JitCache.h">
<ClInclude Include="MIPS\ARM\ArmJitCache.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="MIPS\ARM\RegCache.h">
<ClInclude Include="MIPS\ARM\ArmRegCache.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@ -409,4 +415,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -111,30 +111,6 @@
<ClCompile Include="MIPS\x86\CompVFPU.cpp">
<Filter>MIPS\x86</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\Asm.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompALU.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompBranch.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompFPU.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\Jit.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\CompLoadStore.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\JitCache.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\RegCache.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\JitCommon\JitCommon.cpp">
<Filter>MIPS\JitCommon</Filter>
</ClCompile>
@ -363,6 +339,33 @@
<ClCompile Include="..\ext\snappy\snappy.cpp">
<Filter>Ext\Snappy</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmAsm.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmCompALU.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmCompBranch.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmCompFPU.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmCompLoadStore.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmJit.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmJitCache.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmRegCache.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
<ClCompile Include="MIPS\ARM\ArmCompVFPU.cpp">
<Filter>MIPS\ARM</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -413,18 +416,6 @@
<ClInclude Include="MIPS\x86\RegCache.h">
<Filter>MIPS\x86</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\Asm.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\Jit.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\JitCache.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\RegCache.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\JitCommon\JitCommon.h">
<Filter>MIPS\JitCommon</Filter>
</ClInclude>
@ -674,6 +665,18 @@
<ClInclude Include="..\ext\snappy\snappy-internal.h">
<Filter>Ext\Snappy</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\ArmAsm.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\ArmJit.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\ArmJitCache.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
<ClInclude Include="MIPS\ARM\ArmRegCache.h">
<Filter>MIPS\ARM</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
@ -681,4 +684,4 @@
<None Include="..\android\jni\Android.mk" />
<None Include="GameLogNotes.txt" />
</ItemGroup>
</Project>
</Project>

View File

@ -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 <ArmEmitter.h>
#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<void *>(&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<void *>(&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);*/
}
}

View File

@ -21,19 +21,7 @@
#include <ArmEmitter.h>
#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

View File

@ -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 <ArmEmitter.h>
#include "ArmJit.h"
#include "ArmRegCache.h"
#include "ArmEmitter.h"
using namespace MIPSAnalyst;
#define _RS ((op>>21) & 0x1F)

View File

@ -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 <ArmEmitter.h>
#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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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 <ArmEmitter.h>
#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;

View File

@ -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 <ArmEmitter.h>
#include "ArmJitCache.h"
#include "../JitCommon/JitCommon.h"
#include "ArmAsm.h"
#if defined USE_OPROFILE && USE_OPROFILE
#include <opagent.h>
@ -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<int> *block_numbers)
void ArmJitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector<int> *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<u32, int>::iterator iter;
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
// equal_range(b) returns pair<iterator,iterator> 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<u32, int>::iterator iter;
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
ppp = links_to.equal_range(b.originalAddress);
if (ppp.first == ppp.second)
return;
for (multimap<u32, int>::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;

View File

@ -22,7 +22,7 @@
#include <string>
#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<u32, int> links_to;
std::map<std::pair<u32,u32>, 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();

View File

@ -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
}
}

112
Core/MIPS/ARM/ArmRegCache.h Normal file
View File

@ -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];
};

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -18,7 +18,7 @@
#pragma once
#if defined(ARM)
#include "../ARM/Jit.h"
#include "../ARM/ArmJit.h"
#else
#include "../x86/Jit.h"
#endif

View File

@ -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");
}

View File

@ -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.

View File

@ -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);*/
}
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -1,2 +1,5 @@
APP_STL := stlport_static
APP_ABI := armeabi armeabi-v7a
APP_ABI := armeabi-v7a
#armeabi