mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Play around with function replacement. Turned off by default of course.
This commit is contained in:
parent
832c933cb8
commit
2eab4aa1bf
@ -869,6 +869,7 @@ if(ARM)
|
||||
Core/MIPS/ARM/ArmCompLoadStore.cpp
|
||||
Core/MIPS/ARM/ArmCompVFPU.cpp
|
||||
Core/MIPS/ARM/ArmCompVFPUNEON.cpp
|
||||
Core/MIPS/ARM/ArmCompReplace.cpp
|
||||
Core/MIPS/ARM/ArmJit.cpp
|
||||
Core/MIPS/ARM/ArmJit.h
|
||||
Core/MIPS/ARM/ArmRegCache.cpp
|
||||
@ -887,6 +888,7 @@ elseif(X86)
|
||||
Core/MIPS/x86/CompFPU.cpp
|
||||
Core/MIPS/x86/CompLoadStore.cpp
|
||||
Core/MIPS/x86/CompVFPU.cpp
|
||||
Core/MIPS/x86/CompReplace.cpp
|
||||
Core/MIPS/x86/Jit.cpp
|
||||
Core/MIPS/x86/Jit.h
|
||||
Core/MIPS/x86/RegCache.cpp
|
||||
|
@ -291,6 +291,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\ARM\ArmCompReplace.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\ArmCompVFPU.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@ -359,6 +365,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompReplace.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\PPC\PpcCompVFPU.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@ -382,6 +394,7 @@
|
||||
<ClCompile Include="MIPS\x86\CompBranch.cpp" />
|
||||
<ClCompile Include="MIPS\x86\CompFPU.cpp" />
|
||||
<ClCompile Include="MIPS\x86\CompLoadStore.cpp" />
|
||||
<ClCompile Include="MIPS\x86\CompReplace.cpp" />
|
||||
<ClCompile Include="MIPS\x86\CompVFPU.cpp" />
|
||||
<ClCompile Include="MIPS\x86\RegCacheFPU.cpp" />
|
||||
<ClCompile Include="MIPS\x86\Jit.cpp" />
|
||||
|
@ -508,6 +508,15 @@
|
||||
<ClCompile Include="HLE\ReplaceTables.cpp">
|
||||
<Filter>HLE</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\x86\CompReplace.cpp">
|
||||
<Filter>MIPS\x86</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\ARM\ArmCompReplace.cpp">
|
||||
<Filter>MIPS\ARM</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompReplace.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@ -949,4 +958,4 @@
|
||||
<None Include="..\android\jni\Android.mk" />
|
||||
<None Include="GameLogNotes.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -15,28 +15,114 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/HLE/ReplaceTables.h"
|
||||
#include "Core/HLE/FunctionWrappers.h"
|
||||
|
||||
void NormalizeVector(u32 vecPtr) {
|
||||
// TODO
|
||||
#include "GPU/Math3D.h"
|
||||
|
||||
// I think these have to be pretty accurate, but we can probably
|
||||
// get away with approximating the VFPU vsin/vcos and vrot pretty roughly.
|
||||
static int Replace_sinf() {
|
||||
float f = PARAMF(0);
|
||||
RETURNF(sinf(f));
|
||||
return 80; // guess number of cycles
|
||||
}
|
||||
|
||||
static int Replace_cosf() {
|
||||
float f = PARAMF(0);
|
||||
RETURNF(cosf(f));
|
||||
return 80; // guess number of cycles
|
||||
}
|
||||
|
||||
// Should probably do JIT versions of this, possibly ones that only delegate
|
||||
// large copies to a C function.
|
||||
static int Replace_memcpy() {
|
||||
u32 destPtr = PARAM(0);
|
||||
u8 *dst = Memory::GetPointer(destPtr);
|
||||
u8 *src = Memory::GetPointer(PARAM(1));
|
||||
u32 bytes = PARAM(2);
|
||||
if (dst && src) {
|
||||
memcpy(dst, src, bytes);
|
||||
}
|
||||
RETURN(destPtr);
|
||||
return 10 + bytes / 4; // approximation
|
||||
}
|
||||
|
||||
static int Replace_memset() {
|
||||
u32 destPtr = PARAM(0);
|
||||
u8 *dst = Memory::GetPointer(destPtr);
|
||||
u8 value = PARAM(1);
|
||||
u32 bytes = PARAM(2);
|
||||
if (dst) {
|
||||
memset(dst, value, bytes);
|
||||
}
|
||||
RETURN(destPtr);
|
||||
return 10 + bytes / 4; // approximation
|
||||
}
|
||||
|
||||
static int Replace_strlen() {
|
||||
u32 srcPtr = PARAM(0);
|
||||
const char *src = (const char *)Memory::GetPointer(srcPtr);
|
||||
u32 len = (u32)strlen(src);
|
||||
RETURN(len);
|
||||
return 4 + len; // approximation
|
||||
}
|
||||
|
||||
static int Replace_vmmul_q_transp() {
|
||||
float *out = (float *)Memory::GetPointerUnchecked(PARAM(0));
|
||||
const float *a = (const float *)Memory::GetPointerUnchecked(PARAM(1));
|
||||
const float *b = (const float *)Memory::GetPointerUnchecked(PARAM(2));
|
||||
|
||||
// TODO: Actually use an optimized matrix multiply here...
|
||||
Matrix4ByMatrix4(out, b, a);
|
||||
return 16;
|
||||
}
|
||||
|
||||
// Can either replace with C functions or functions emitted in Asm/ArmAsm.
|
||||
// The latter is recommended for fast math functions.
|
||||
static const ReplacementTableEntry entries[] = {
|
||||
{ 0x0, 64, "NormalizeVector", WrapV_U<NormalizeVector>, 20 }
|
||||
// TODO: I think some games can be helped quite a bit by implementing the
|
||||
// double-precision soft-float routines: __adddf3, __subdf3 and so on. These
|
||||
// should of course be implemented JIT style, inline.
|
||||
{ "sinf", &Replace_sinf, 0, 0},
|
||||
{ "cosf", &Replace_cosf, 0, 0},
|
||||
{ "memcpy", &Replace_memcpy, 0, 0},
|
||||
{ "memset", &Replace_memset, 0, 0},
|
||||
{ "strlen", &Replace_strlen, 0, 0},
|
||||
{ "fabsf", 0, &MIPSComp::Jit::Replace_fabsf, REPFLAG_ALLOWINLINE},
|
||||
{ "vmmul_q_transp", &Replace_vmmul_q_transp, 0, 0},
|
||||
{}
|
||||
};
|
||||
|
||||
static std::map<u32, u32> replacedInstructions;
|
||||
|
||||
void Replacement_Init() {
|
||||
}
|
||||
|
||||
void Replacement_Shutdown() {
|
||||
replacedInstructions.clear();
|
||||
}
|
||||
|
||||
int GetNumReplacementFuncs() {
|
||||
return ARRAY_SIZE(entries);
|
||||
}
|
||||
|
||||
int GetReplacementFuncIndex(u64 hash, int size) {
|
||||
int GetReplacementFuncIndex(u64 hash, int funcSize) {
|
||||
const char *name = MIPSAnalyst::LookupHash(hash, funcSize);
|
||||
if (!name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: Build a lookup and keep it around
|
||||
for (int i = 0; i < ARRAY_SIZE(entries); i++) {
|
||||
if (entries[i].hash == hash && entries[i].size == size) {
|
||||
if (!entries[i].name)
|
||||
continue;
|
||||
if (!strcmp(name, entries[i].name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -45,4 +131,13 @@ int GetReplacementFuncIndex(u64 hash, int size) {
|
||||
|
||||
const ReplacementTableEntry *GetReplacementFunc(int i) {
|
||||
return &entries[i];
|
||||
}
|
||||
}
|
||||
|
||||
void WriteReplaceInstruction(u32 address, u64 hash, int size) {
|
||||
int index = GetReplacementFuncIndex(hash, size);
|
||||
if (index >= 0) {
|
||||
replacedInstructions[address] = Memory::Read_U32(address);
|
||||
ILOG("Replaced %s at %08x", entries[index].name, address);
|
||||
Memory::Write_U32(MIPS_EMUHACK_CALL_REPLACEMENT | (int)index, address);
|
||||
}
|
||||
}
|
||||
|
@ -15,22 +15,45 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
// Regular replacement funcs are just C functions. These take care of their
|
||||
// own parameter parsing using the old school PARAM macros.
|
||||
// The return value is the number of cycles to eat.
|
||||
|
||||
// JIT replacefuncs can be for inline or "outline" replacement.
|
||||
// With inline replacement, we recognize the call to the functions
|
||||
// at jal time already. With outline replacement, we just replace the
|
||||
// implementation.
|
||||
|
||||
// In both cases the jit needs to know how much to subtract downcount.
|
||||
//
|
||||
// If the replacement func returned a positive number, this will be treated
|
||||
// as the number of cycles to subtract.
|
||||
// If the replacement func returns -1, it will be assumed that the subtraction
|
||||
// was done by the replacement func.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
|
||||
typedef void (* ReplaceFunc)();
|
||||
typedef int (* ReplaceFunc)();
|
||||
|
||||
enum {
|
||||
REPFLAG_ALLOWINLINE = 1,
|
||||
};
|
||||
|
||||
// Kind of similar to HLE functions but with different data.
|
||||
struct ReplacementTableEntry {
|
||||
u32 hash;
|
||||
int size;
|
||||
const char *name;
|
||||
ReplaceFunc replaceFunc;
|
||||
int cyclesToEat;
|
||||
MIPSComp::MIPSReplaceFunc jitReplaceFunc;
|
||||
int flags;
|
||||
};
|
||||
|
||||
void Replacement_Init();
|
||||
void Replacement_Shutdown();
|
||||
|
||||
int GetNumReplacementFuncs();
|
||||
int GetReplacementFuncIndex(u64 hash, int size);
|
||||
const ReplacementTableEntry *GetReplacementFunc(int index);
|
||||
int GetReplacementFuncIndex(u64 hash, int funcSize);
|
||||
const ReplacementTableEntry *GetReplacementFunc(int index);
|
||||
void WriteReplaceInstruction(u32 address, u64 hash, int size);
|
||||
|
@ -821,8 +821,8 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
module->nm.data_size -= textSize;
|
||||
|
||||
#if !defined(USING_GLES2)
|
||||
if (!reader.LoadSymbols())
|
||||
MIPSAnalyst::ScanForFunctions(textStart, textStart + textSize, true);
|
||||
bool gotSymbols = reader.LoadSymbols();
|
||||
MIPSAnalyst::ScanForFunctions(textStart, textStart + textSize, !gotSymbols);
|
||||
#else
|
||||
// Scan for functions (for the analysis results which can help the JIT).
|
||||
// But don't insert into the symbol map.
|
||||
@ -981,8 +981,8 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
u32 textStart = reader.GetVaddr();
|
||||
u32 textEnd = firstImportStubAddr - 4;
|
||||
#if !defined(USING_GLES2)
|
||||
if (!reader.LoadSymbols())
|
||||
MIPSAnalyst::ScanForFunctions(textStart, textEnd, true);
|
||||
bool gotSymbols = reader.LoadSymbols();
|
||||
MIPSAnalyst::ScanForFunctions(textStart, textEnd, !gotSymbols);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
32
Core/MIPS/ARM/ArmCompReplace.cpp
Normal file
32
Core/MIPS/ARM/ArmCompReplace.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2013- PPSSPP 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 or later versions.
|
||||
|
||||
// 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 git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "Core/MIPS/ARM/ArmJit.h"
|
||||
#include "Core/MIPS/ARM/ArmRegCache.h"
|
||||
|
||||
namespace MIPSComp {
|
||||
|
||||
int Jit::Replace_fabsf() {
|
||||
fpr.MapDirtyIn(0, 13);
|
||||
VABS(fpr.R(0), fpr.R(13));
|
||||
return 6; // Number of instructions in the MIPS function
|
||||
}
|
||||
|
||||
}
|
@ -341,21 +341,45 @@ void Jit::Comp_RunBlock(MIPSOpcode op)
|
||||
|
||||
void Jit::Comp_ReplacementFunc(MIPSOpcode op)
|
||||
{
|
||||
// None of the code of this function is relevant so we'll just
|
||||
// call the replacement and move RA to PC.
|
||||
int index = op.encoding & 0xFFFFFF;
|
||||
// We get here if we execute the first instruction of a replaced function. This means
|
||||
// that we do need to return to RA.
|
||||
|
||||
// Inlined function calls (caught in jal) are handled differently.
|
||||
|
||||
int index = op.encoding & MIPS_EMUHACK_VALUE_MASK;
|
||||
|
||||
const ReplacementTableEntry *entry = GetReplacementFunc(index);
|
||||
if (!entry) {
|
||||
ERROR_LOG(HLE, "Invalid replacement op %08x", op.encoding);
|
||||
return;
|
||||
}
|
||||
|
||||
BL((void *)(entry->replaceFunc));
|
||||
// Alternatively, we could inline it here, instead of calling out, if it's a function
|
||||
// we can emit.
|
||||
// JIT goes first.
|
||||
if (entry->jitReplaceFunc) {
|
||||
MIPSReplaceFunc repl = entry->jitReplaceFunc;
|
||||
int cycles = (this->*repl)();
|
||||
FlushAll();
|
||||
LDR(R1, CTXREG, MIPS_REG_RA * 4);
|
||||
js.downcountAmount = cycles;
|
||||
WriteExitDestInR(R1);
|
||||
} else if (entry->replaceFunc) {
|
||||
FlushAll();
|
||||
// Standard function call, nothing fancy.
|
||||
// The function returns the number of cycles it took in EAX.
|
||||
BL((const void *)(entry->replaceFunc));
|
||||
// Alternatively, we could inline it here, instead of calling out, if it's a function
|
||||
// we can emit.
|
||||
|
||||
LDR(R1, CTXREG, MIPS_REG_RA * 4);
|
||||
WriteDownCountR(R0);
|
||||
js.downcountAmount = 0; // we just subtracted most of it
|
||||
WriteExitDestInR(R1);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Replacement function has neither jit nor regular impl");
|
||||
}
|
||||
|
||||
MOVI2R(R0, currentMIPS->r[MIPS_REG_RA], R1);
|
||||
MovToPC(R0);
|
||||
js.compiling = false;
|
||||
js.downcountAmount = entry->cyclesToEat;
|
||||
WriteDownCount(0);
|
||||
|
||||
|
||||
// We could even do this in the jal that is branching to the function
|
||||
// but having the op is necessary for the interpreter anyway.
|
||||
}
|
||||
@ -430,6 +454,18 @@ void Jit::WriteDownCount(int offset)
|
||||
}
|
||||
}
|
||||
|
||||
// Abuses R1
|
||||
void Jit::WriteDownCountR(ARMReg reg)
|
||||
{
|
||||
if (jo.downcountInRegister) {
|
||||
SUBS(DOWNCOUNTREG, DOWNCOUNTREG, reg);
|
||||
} else {
|
||||
LDR(R2, CTXREG, offsetof(MIPSState, downcount));
|
||||
SUBS(R2, R2, reg);
|
||||
STR(R2, CTXREG, offsetof(MIPSState, downcount));
|
||||
}
|
||||
}
|
||||
|
||||
// IDEA - could have a WriteDualExit that takes two destinations and two condition flags,
|
||||
// and just have conditional that set PC "twice". This only works when we fall back to dispatcher
|
||||
// though, as we need to have the SUBS flag set in the end. So with block linking in the mix,
|
||||
|
@ -177,6 +177,7 @@ public:
|
||||
void CompNEON_Vsgn(MIPSOpcode op);
|
||||
void CompNEON_Vocp(MIPSOpcode op);
|
||||
|
||||
int Replace_fabsf();
|
||||
|
||||
JitBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
@ -191,6 +192,7 @@ private:
|
||||
void FlushPrefixV();
|
||||
|
||||
void WriteDownCount(int offset = 0);
|
||||
void WriteDownCountR(ARMReg reg);
|
||||
void MovFromPC(ARMReg r);
|
||||
void MovToPC(ARMReg r);
|
||||
|
||||
@ -260,6 +262,7 @@ public:
|
||||
};
|
||||
|
||||
typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode);
|
||||
typedef int (Jit::*MIPSReplaceFunc)();
|
||||
|
||||
} // namespace MIPSComp
|
||||
|
||||
|
@ -39,9 +39,12 @@ struct JitBlock;
|
||||
|
||||
#define MIPS_EMUHACK_OPCODE 0x68000000
|
||||
#define MIPS_EMUHACK_MASK 0xFC000000
|
||||
#define MIPS_EMUHACK_VALUE_MASK 0x03FFFFFF
|
||||
#define MIPS_JITBLOCK_MASK 0xFF000000
|
||||
#define MIPS_EMUHACK_VALUE_MASK 0x00FFFFFF
|
||||
|
||||
#define MIPS_IS_EMUHACK(op) (((op) & 0xFC000000) == MIPS_EMUHACK_OPCODE) // masks away the subop
|
||||
#define MIPS_IS_RUNBLOCK(op) (((op) & 0xFF000000) == MIPS_EMUHACK_OPCODE) // masks away the subop
|
||||
#define MIPS_IS_REPLACEMENT(op) (((op) & 0xFF000000) == (MIPS_EMUHACK_OPCODE | (EMUOP_CALL_REPLACEMENT << 24))) // masks away the subop
|
||||
|
||||
// There are 2 bits available for sub-opcodes, 0x03000000.
|
||||
#define EMUOP_RUNBLOCK 0 // Runs a JIT block
|
||||
|
@ -433,12 +433,45 @@ namespace MIPSAnalyst {
|
||||
|
||||
HashFunctions();
|
||||
|
||||
std::string hashMapFilename = GetSysDirectory(DIRECTORY_SYSTEM) + "knownfuncs.ini";
|
||||
if (g_Config.bFuncHashMap) {
|
||||
LoadHashMap(GetSysDirectory(DIRECTORY_SYSTEM) + "knownfuncs.ini");
|
||||
StoreHashMap(GetSysDirectory(DIRECTORY_SYSTEM) + "knownfuncs.ini");
|
||||
LoadHashMap(hashMapFilename);
|
||||
StoreHashMap(hashMapFilename);
|
||||
if (insertSymbols) {
|
||||
ApplyHashMap();
|
||||
}
|
||||
if (g_Config.bFuncHashMap) {
|
||||
ReplaceFunctions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnalyzeFunction(u32 startAddr, u32 size, const char *name) {
|
||||
// Check if we have this already
|
||||
for (auto iter = functions.begin(); iter != functions.end(); iter++) {
|
||||
if (iter->start == startAddr) {
|
||||
// Let's just add it to the hashmap.
|
||||
if (iter->hasHash) {
|
||||
HashMapFunc hfun;
|
||||
hfun.hash = iter->hash;
|
||||
strncpy(hfun.name, name, 64);
|
||||
hfun.size = iter->size;
|
||||
hashMap.insert(hfun);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceFunctions();
|
||||
// Cheats a little.
|
||||
AnalyzedFunction fun;
|
||||
fun.start = startAddr;
|
||||
fun.end = startAddr + size - 4;
|
||||
fun.isStraightLeaf = false; // dunno really
|
||||
strncpy(fun.name, name, 64);
|
||||
fun.name[63] = 0;
|
||||
functions.push_back(fun);
|
||||
|
||||
HashFunctions();
|
||||
}
|
||||
|
||||
void ForgetFunctions(u32 startAddr, u32 endAddr) {
|
||||
@ -463,10 +496,7 @@ namespace MIPSAnalyst {
|
||||
|
||||
void ReplaceFunctions() {
|
||||
for (size_t i = 0; i < functions.size(); i++) {
|
||||
int index = GetReplacementFuncIndex(functions[i].hash, functions[i].size);
|
||||
if (index >= 0) {
|
||||
Memory::Write_U32(MIPS_EMUHACK_CALL_REPLACEMENT | (int)i, functions[i].start);
|
||||
}
|
||||
WriteReplaceInstruction(functions[i].start, functions[i].hash, functions[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,10 +519,30 @@ namespace MIPSAnalyst {
|
||||
}
|
||||
}
|
||||
|
||||
const char *LookupHash(u64 hash, int funcsize) {
|
||||
for (auto it = hashMap.begin(), end = hashMap.end(); it != end; ++it) {
|
||||
if (it->hash == hash && it->size == funcsize) {
|
||||
return it->name;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetHashMapFilename(std::string filename) {
|
||||
if (filename.empty())
|
||||
hashmapFileName = GetSysDirectory(DIRECTORY_SYSTEM) + "knownfuncs.ini";
|
||||
else
|
||||
hashmapFileName = filename;
|
||||
}
|
||||
|
||||
void StoreHashMap(std::string filename) {
|
||||
if (filename.empty())
|
||||
filename = hashmapFileName;
|
||||
|
||||
if (!hashMap.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *file = File::OpenCFile(filename, "wt");
|
||||
if (!file) {
|
||||
WARN_LOG(LOADER, "Could not store hash map: %s", filename.c_str());
|
||||
@ -557,8 +607,6 @@ namespace MIPSAnalyst {
|
||||
hashMap.insert(mf);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
ApplyHashMap();
|
||||
}
|
||||
|
||||
std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op) {
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/HLE/ReplaceTables.h"
|
||||
|
||||
class DebugInterface;
|
||||
|
||||
@ -88,16 +87,26 @@ namespace MIPSAnalyst
|
||||
char name[64];
|
||||
};
|
||||
|
||||
struct ReplacementTableEntry;
|
||||
|
||||
void Reset();
|
||||
|
||||
bool IsRegisterUsed(u32 reg, u32 addr);
|
||||
// This will not only create a database of "AnalyzedFunction" structs, it also
|
||||
// will insert all the functions it finds into the symbol map, if insertSymbols is true.
|
||||
|
||||
// If we have loaded symbols from the elf, we'll register functions as they are touched
|
||||
// so that we don't just dump them all in the cache.
|
||||
void AnalyzeFunction(u32 startAddr, u32 size, const char *name);
|
||||
void ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols);
|
||||
void ForgetFunctions(u32 startAddr, u32 endAddr);
|
||||
void CompileLeafs();
|
||||
|
||||
void SetHashMapFilename(std::string filename = "");
|
||||
void LoadHashMap(std::string filename);
|
||||
void StoreHashMap(std::string filename = "");
|
||||
|
||||
const char *LookupHash(u64 hash, int funcSize);
|
||||
void ReplaceFunctions(const ReplacementTableEntry *e, int numEntries);
|
||||
|
||||
void UpdateHashMap();
|
||||
|
@ -917,8 +917,6 @@ const MIPSInstruction *MIPSGetInstruction(MIPSOpcode op)
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MIPSCompileOp(MIPSOpcode op)
|
||||
{
|
||||
if (op == 0)
|
||||
@ -927,12 +925,10 @@ void MIPSCompileOp(MIPSOpcode op)
|
||||
const MIPSInfo info = MIPSGetInfo(op);
|
||||
if (instr)
|
||||
{
|
||||
if (instr->compile)
|
||||
(MIPSComp::jit->*(instr->compile))(op); // woohoo, member functions pointers!
|
||||
else
|
||||
{
|
||||
if (instr->compile) {
|
||||
(MIPSComp::jit->*(instr->compile))(op);
|
||||
} else {
|
||||
ERROR_LOG_REPORT(CPU,"MIPSCompileOp %08x failed",op.encoding);
|
||||
//MessageBox(0,"ARGH2",0,0);//compile an interpreter call
|
||||
}
|
||||
|
||||
if (info & OUT_EAT_PREFIX)
|
||||
@ -944,15 +940,11 @@ void MIPSCompileOp(MIPSOpcode op)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MIPSDisAsm(MIPSOpcode op, u32 pc, char *out, bool tabsToSpaces)
|
||||
{
|
||||
if (op == 0)
|
||||
{
|
||||
if (op == 0) {
|
||||
sprintf(out,"nop");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
disPC = pc;
|
||||
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
||||
if (instr && instr->disasm) {
|
||||
@ -966,26 +958,16 @@ void MIPSDisAsm(MIPSOpcode op, u32 pc, char *out, bool tabsToSpaces)
|
||||
}
|
||||
} else {
|
||||
strcpy(out, "no instruction :(");
|
||||
//__asm int 3
|
||||
MIPSGetInstruction(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MIPSInterpret(MIPSOpcode op) //only for those rare ones
|
||||
{
|
||||
//if ((op&0xFFFFF000) == 0xd0110000)
|
||||
// Crash();
|
||||
//if (atable[CRUNCH_MIPS_OP(op)].interpret)
|
||||
// atable[CRUNCH_MIPS_OP(op)].interpret(op);
|
||||
// else
|
||||
// _dbg_assert_msg_(MIPS,0,"Trying to interpret instruction that can't be interpreted");
|
||||
void MIPSInterpret(MIPSOpcode op) {
|
||||
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
||||
if (instr && instr->interpret)
|
||||
if (instr && instr->interpret) {
|
||||
instr->interpret(op);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ERROR_LOG_REPORT(CPU, "Unknown instruction %08x at %08x", op.encoding, currentMIPS->pc);
|
||||
// Try to disassemble it
|
||||
char disasm[256];
|
||||
|
39
Core/MIPS/PPC/PpcCompReplace.cpp
Normal file
39
Core/MIPS/PPC/PpcCompReplace.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2012- PPSSPP 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 or later versions.
|
||||
|
||||
// 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 git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <cmath>
|
||||
#include "math/math_util.h"
|
||||
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
|
||||
namespace MIPSComp {
|
||||
|
||||
int Jit::Replace_fabsf() {
|
||||
return -1;
|
||||
// fpr.MapDirtyIn(0, 13);
|
||||
// VABS(fpr.R(0), fpr.R(13));
|
||||
// return 6; // Number of instructions in the MIPS function
|
||||
}
|
||||
|
||||
}
|
@ -36,8 +36,7 @@ const bool disablePrefixes = false;
|
||||
|
||||
using namespace PpcGen;
|
||||
|
||||
|
||||
//#define USE_VMX128
|
||||
// #define USE_VMX128
|
||||
|
||||
namespace MIPSComp
|
||||
{
|
||||
|
@ -240,6 +240,7 @@ namespace MIPSComp
|
||||
void Comp_Vsgn(MIPSOpcode op);
|
||||
void Comp_Vocp(MIPSOpcode op);
|
||||
|
||||
int Replace_fabsf();
|
||||
|
||||
// Utility compilation functions
|
||||
void BranchFPFlag(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely);
|
||||
@ -325,6 +326,7 @@ namespace MIPSComp
|
||||
};
|
||||
|
||||
typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode);
|
||||
typedef int (Jit::*MIPSReplaceFunc)();
|
||||
|
||||
} // namespace MIPSComp
|
||||
|
||||
|
@ -110,7 +110,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
|
||||
MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0));
|
||||
#endif
|
||||
MOV(32, R(EDX), R(EAX));
|
||||
AND(32, R(EDX), Imm32(MIPS_EMUHACK_MASK));
|
||||
AND(32, R(EDX), Imm32(MIPS_JITBLOCK_MASK));
|
||||
CMP(32, R(EDX), Imm32(MIPS_EMUHACK_OPCODE));
|
||||
FixupBranch notfound = J_CC(CC_NZ);
|
||||
// IDEA - we have 24 bits, why not just use offsets from base of code?
|
||||
|
33
Core/MIPS/x86/CompReplace.cpp
Normal file
33
Core/MIPS/x86/CompReplace.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2013- PPSSPP 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 or later versions.
|
||||
|
||||
// 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 git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "Core/MIPS/x86/RegCache.h"
|
||||
|
||||
static const u64 MEMORY_ALIGNED16(ssNoSignMask[2]) = {0x7FFFFFFF7FFFFFFFULL, 0x7FFFFFFF7FFFFFFFULL};
|
||||
|
||||
namespace MIPSComp {
|
||||
|
||||
int Jit::Replace_fabsf() {
|
||||
fpr.MapReg(0, MAP_DIRTY | MAP_NOINIT);
|
||||
MOVSS(fpr.RX(0), fpr.R(12));
|
||||
ANDPS(fpr.RX(0), M((void *)&ssNoSignMask));
|
||||
return 4; // Number of instructions in the MIPS function
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "math/math_util.h"
|
||||
|
||||
@ -30,7 +31,6 @@
|
||||
#include "Core/MIPS/x86/Jit.h"
|
||||
#include "Core/MIPS/x86/RegCache.h"
|
||||
|
||||
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define DISABLE { fpr.ReleaseSpillLocks(); Comp_Generic(op); return; }
|
||||
|
||||
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
|
@ -374,24 +374,45 @@ void Jit::Comp_RunBlock(MIPSOpcode op)
|
||||
|
||||
void Jit::Comp_ReplacementFunc(MIPSOpcode op)
|
||||
{
|
||||
// None of the code of this function is relevant so we'll just
|
||||
// call the replacement and move RA to PC.
|
||||
int index = op.encoding & 0xFFFFFF;
|
||||
// We get here if we execute the first instruction of a replaced function. This means
|
||||
// that we do need to return to RA.
|
||||
|
||||
// Inlined function calls (caught in jal) are handled differently.
|
||||
|
||||
int index = op.encoding & MIPS_EMUHACK_VALUE_MASK;
|
||||
|
||||
const ReplacementTableEntry *entry = GetReplacementFunc(index);
|
||||
if (!entry) {
|
||||
ERROR_LOG(HLE, "Invalid replacement op %08x", op.encoding);
|
||||
return;
|
||||
}
|
||||
|
||||
CALL((const void *)entry->replaceFunc);
|
||||
// Alternatively, we could inline it here, instead of calling out, if it's a function
|
||||
// we can emit.
|
||||
// JIT goes first.
|
||||
if (entry->jitReplaceFunc) {
|
||||
MIPSReplaceFunc repl = entry->jitReplaceFunc;
|
||||
int cycles = (this->*repl)();
|
||||
FlushAll();
|
||||
MOV(32, R(ECX), M(¤tMIPS->r[MIPS_REG_RA]));
|
||||
js.downcountAmount = cycles;
|
||||
WriteExitDestInReg(ECX);
|
||||
js.compiling = false;
|
||||
} else if (entry->replaceFunc) {
|
||||
FlushAll();
|
||||
// Standard function call, nothing fancy.
|
||||
// The function returns the number of cycles it took in EAX.
|
||||
CALL((const void *)entry->replaceFunc);
|
||||
// Alternatively, we could inline it here, instead of calling out, if it's a function
|
||||
// we can emit.
|
||||
|
||||
MOV(32, R(EAX), Imm32(currentMIPS->r[MIPS_REG_RA]));
|
||||
MOV(32, M(&mips_->pc), R(EAX));
|
||||
SUB(32, M(¤tMIPS->downcount), Imm32(entry->cyclesToEat));
|
||||
JMP(asm_.dispatcher, true);
|
||||
MOV(32, R(ECX), M(¤tMIPS->r[MIPS_REG_RA]));
|
||||
SUB(32, M(¤tMIPS->downcount - 1), R(EAX));
|
||||
js.downcountAmount = 1; // we just subtracted most of it
|
||||
WriteExitDestInReg(ECX);
|
||||
|
||||
js.compiling = false;
|
||||
|
||||
// We could even do this in the jal that is branching to the function
|
||||
// but having the op is necessary for the interpreter anyway.
|
||||
js.compiling = false;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Replacement function has neither jit nor regular impl");
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Generic(MIPSOpcode op)
|
||||
@ -460,10 +481,10 @@ void Jit::WriteExit(u32 destination, int exit_num)
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::WriteExitDestInEAX()
|
||||
void Jit::WriteExitDestInReg(X64Reg reg)
|
||||
{
|
||||
// TODO: Some wasted potential, dispatcher will always read this back into EAX.
|
||||
MOV(32, M(&mips_->pc), R(EAX));
|
||||
MOV(32, M(&mips_->pc), R(reg));
|
||||
|
||||
// If we need to verify coreState and rewind, we may not jump yet.
|
||||
if (js.afterOp & (JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE))
|
||||
@ -483,9 +504,9 @@ void Jit::WriteExitDestInEAX()
|
||||
// Validate the jump to avoid a crash?
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
CMP(32, R(EAX), Imm32(PSP_GetKernelMemoryBase()));
|
||||
CMP(32, R(reg), Imm32(PSP_GetKernelMemoryBase()));
|
||||
FixupBranch tooLow = J_CC(CC_B);
|
||||
CMP(32, R(EAX), Imm32(PSP_GetUserMemoryEnd()));
|
||||
CMP(32, R(reg), Imm32(PSP_GetUserMemoryEnd()));
|
||||
FixupBranch tooHigh = J_CC(CC_AE);
|
||||
|
||||
// Need to set neg flag again if necessary.
|
||||
@ -495,8 +516,8 @@ void Jit::WriteExitDestInEAX()
|
||||
SetJumpTarget(tooLow);
|
||||
SetJumpTarget(tooHigh);
|
||||
|
||||
CallProtectedFunction((void *) Memory::GetPointer, R(EAX));
|
||||
CMP(32, R(EAX), Imm32(0));
|
||||
CallProtectedFunction((void *) Memory::GetPointer, R(reg));
|
||||
CMP(32, R(reg), Imm32(0));
|
||||
FixupBranch skip = J_CC(CC_NE);
|
||||
|
||||
// TODO: "Ignore" this so other threads can continue?
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/MIPS/JitCommon/JitBlockCache.h"
|
||||
#include "Core/MIPS/JitCommon/JitState.h"
|
||||
#include "Core/HLE/ReplaceTables.h"
|
||||
#include "RegCache.h"
|
||||
#include "RegCacheFPU.h"
|
||||
|
||||
@ -146,6 +145,8 @@ public:
|
||||
|
||||
void Comp_DoNothing(MIPSOpcode op);
|
||||
|
||||
int Replace_fabsf();
|
||||
|
||||
void ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz);
|
||||
void ApplyPrefixD(const u8 *vregs, VectorSize sz);
|
||||
void GetVectorRegsPrefixS(u8 *regs, VectorSize sz, int vectorReg) {
|
||||
@ -181,7 +182,9 @@ private:
|
||||
void EatInstruction(MIPSOpcode op);
|
||||
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteExitDestInEAX();
|
||||
void WriteExitDestInReg(X64Reg reg);
|
||||
void WriteExitDestInEAX() { WriteExitDestInReg(EAX); }
|
||||
|
||||
// void WriteRfiExitDestInEAX();
|
||||
void WriteSyscallExit();
|
||||
bool CheckJitBreakpoint(u32 addr, int downcountOffset);
|
||||
@ -294,6 +297,7 @@ private:
|
||||
};
|
||||
|
||||
typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode);
|
||||
typedef int (Jit::*MIPSReplaceFunc)();
|
||||
|
||||
} // namespace MIPSComp
|
||||
|
||||
|
@ -173,7 +173,7 @@ void Clear()
|
||||
Opcode Read_Instruction(u32 address)
|
||||
{
|
||||
Opcode inst = Opcode(Read_U32(address));
|
||||
if (MIPS_IS_EMUHACK(inst) && MIPSComp::jit)
|
||||
if (MIPS_IS_RUNBLOCK(inst) && MIPSComp::jit)
|
||||
{
|
||||
JitBlockCache *bc = MIPSComp::jit->GetBlockCache();
|
||||
int block_num = bc->GetBlockNumberFromEmuHackOp(inst, true);
|
||||
@ -182,6 +182,8 @@ Opcode Read_Instruction(u32 address)
|
||||
} else {
|
||||
return inst;
|
||||
}
|
||||
} else if (MIPS_IS_REPLACEMENT(inst)) {
|
||||
return inst;
|
||||
} else {
|
||||
return inst;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "Core/System.h"
|
||||
#include "Core/PSPMixer.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/ReplaceTables.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceAudio.h"
|
||||
@ -167,6 +168,7 @@ void CPU_Init() {
|
||||
IdentifiedFileType type = Identify_File(filename);
|
||||
|
||||
MIPSAnalyst::Reset();
|
||||
Replacement_Init();
|
||||
|
||||
switch (type) {
|
||||
case FILETYPE_PSP_ISO:
|
||||
@ -215,6 +217,8 @@ void CPU_Shutdown() {
|
||||
host->SaveSymbolMap();
|
||||
}
|
||||
|
||||
Replacement_Shutdown();
|
||||
|
||||
CoreTiming::Shutdown();
|
||||
__KernelShutdown();
|
||||
HLEShutdown();
|
||||
|
@ -916,9 +916,10 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
|
||||
char name[256];
|
||||
std::string newname;
|
||||
strncpy_s(name, symbolMap.GetLabelName(funcBegin),_TRUNCATE);
|
||||
if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), L"New function name", name, newname))
|
||||
{
|
||||
if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), L"New function name", name, newname)) {
|
||||
symbolMap.SetLabelName(newname.c_str(),funcBegin);
|
||||
u32 funcSize = symbolMap.GetFunctionSize(curAddress);
|
||||
MIPSAnalyst::AnalyzeFunction(funcBegin, funcSize, newname.c_str());
|
||||
MIPSAnalyst::UpdateHashMap();
|
||||
MIPSAnalyst::ApplyHashMap();
|
||||
SendMessage(GetParent(wnd),WM_DEB_MAPLOADED,0,0);
|
||||
|
@ -39,6 +39,7 @@ ARCH_FILES := \
|
||||
$(SRC)/Core/MIPS/x86/CompFPU.cpp \
|
||||
$(SRC)/Core/MIPS/x86/CompLoadStore.cpp \
|
||||
$(SRC)/Core/MIPS/x86/CompVFPU.cpp \
|
||||
$(SRC)/Core/MIPS/x86/CompReplace.cpp \
|
||||
$(SRC)/Core/MIPS/x86/Asm.cpp \
|
||||
$(SRC)/Core/MIPS/x86/Jit.cpp \
|
||||
$(SRC)/Core/MIPS/x86/RegCache.cpp \
|
||||
@ -58,6 +59,7 @@ ARCH_FILES := \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompLoadStore.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompVFPU.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompVFPUNEON.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompReplace.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmAsm.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmJit.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmRegCache.cpp \
|
||||
@ -77,6 +79,7 @@ ARCH_FILES := \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompLoadStore.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompVFPU.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompVFPUNEON.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmCompReplace.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmAsm.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmJit.cpp \
|
||||
$(SRC)/Core/MIPS/ARM/ArmRegCache.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user