mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Mostly cleanup and some better crash messages. Also enabled partial block linking (see JitCache.cpp), should give a small speedup but may cause problems, please report!
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@12 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="Common"
|
||||
ProjectGUID="{C573CAF7-EE6A-458E-8049-16C0BF34C2E9}"
|
||||
RootNamespace="Common"
|
||||
@ -471,6 +471,14 @@
|
||||
RelativePath=".\Src\DynamicLibrary.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\FileUtil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\FileUtil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Hash.cpp"
|
||||
>
|
||||
|
@ -69,7 +69,9 @@ typedef signed __int16 s16;
|
||||
typedef signed __int8 s8;
|
||||
|
||||
#define GC_ALIGNED16(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED64(x) __declspec(align(64)) x
|
||||
#define GC_ALIGNED16_DECL(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED64_DECL(x) __declspec(align(64)) x
|
||||
|
||||
#else
|
||||
|
||||
|
11
Source/Core/Common/Src/FileUtil.cpp
Normal file
11
Source/Core/Common/Src/FileUtil.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
bool File::Exists(const std::string &filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return GetFileAttributes(filename.c_str()) != INVALID_FILE_ATTRIBUTES;
|
||||
#else
|
||||
return true; //TODO
|
||||
#endif
|
||||
}
|
12
Source/Core/Common/Src/FileUtil.h
Normal file
12
Source/Core/Common/Src/FileUtil.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _FILEUTIL_H
|
||||
#define _FILEUTIL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
static bool Exists(const std::string &filename);
|
||||
};
|
||||
|
||||
#endif
|
@ -104,11 +104,10 @@ u64 MemArena::Find4GBBase()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
#ifdef _WIN32
|
||||
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
|
||||
// 64 bit
|
||||
u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
return((u64)base);
|
||||
|
||||
#else
|
||||
// Very precarious - mmap cannot return an error when trying to map already used pages.
|
||||
// This makes the Windows approach above unusable on Linux, so we will simply pray...
|
||||
@ -116,12 +115,13 @@ u64 MemArena::Find4GBBase()
|
||||
#endif
|
||||
|
||||
#else
|
||||
// Only grab a bit less than 1GB
|
||||
// 32 bit
|
||||
// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
|
||||
u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
if (base) {
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
}
|
||||
return((u64)base);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="Core"
|
||||
ProjectGUID="{F0B874CB-4476-4199-9315-8343D05AE684}"
|
||||
RootNamespace="Core"
|
||||
@ -901,6 +901,14 @@
|
||||
RelativePath=".\Src\PowerPC\Jit64\JitAsm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PowerPC\Jit64\JitBackpatch.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PowerPC\Jit64\JitBackpatch.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PowerPC\Jit64\JitCache.cpp"
|
||||
>
|
||||
|
@ -233,6 +233,7 @@ void Advance()
|
||||
if (!first)
|
||||
{
|
||||
LOG(GEKKO, "WARNING - no events in queue. Setting downcount to 10000");
|
||||
// PanicAlert?
|
||||
downcount += 10000;
|
||||
}
|
||||
else
|
||||
|
@ -24,12 +24,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Common.h"
|
||||
#include "x64Analyzer.h"
|
||||
#include "PowerPC/Jit64/Jit.h"
|
||||
|
||||
#include "MemTools.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "PowerPC/Jit64/Jit.h"
|
||||
#include "PowerPC/Jit64/JitBackpatch.h"
|
||||
#include "x64Analyzer.h"
|
||||
|
||||
//#ifdef ASDFKJLASJDF
|
||||
namespace EMM
|
||||
{
|
||||
/* DESIGN
|
||||
@ -98,14 +98,11 @@ struct Watch
|
||||
|
||||
std::vector<Watch> watches;
|
||||
|
||||
|
||||
|
||||
void UpdateProtection(EAddr startAddr, EAddr endAddr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
int AddWatchRegion(EAddr startAddr, EAddr endAddr, WR watchFor, WatchType type, WatchCallback callback, u64 userData)
|
||||
{
|
||||
static int watchIDGen = 0;
|
||||
@ -124,8 +121,6 @@ int AddWatchRegion(EAddr startAddr, EAddr endAddr, WR watchFor, WatchType type,
|
||||
return watch.ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Notify(EAddr address, WR action)
|
||||
{
|
||||
for (std::vector<Watch>::iterator iter = watches.begin(); iter != watches.end(); ++iter)
|
||||
@ -208,6 +203,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ======
|
||||
// From here on is the code in this file that actually works and is active.
|
||||
|
||||
LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
||||
{
|
||||
switch (pPtrs->ExceptionRecord->ExceptionCode)
|
||||
@ -233,6 +231,7 @@ LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
||||
//Figure out what address was hit
|
||||
DWORD_PTR badAddress = (DWORD_PTR)pPtrs->ExceptionRecord->ExceptionInformation[1];
|
||||
//TODO: First examine the address, make sure it's within the emulated memory space
|
||||
u64 memspaceBottom = (u64)Memory::base;
|
||||
if (badAddress < memspaceBottom) {
|
||||
PanicAlert("Exception handler - access below memory space. %08x%08x",
|
||||
badAddress >> 32, badAddress);
|
||||
@ -240,17 +239,15 @@ LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
||||
u32 emAddress = (u32)(badAddress - memspaceBottom);
|
||||
|
||||
//Now we have the emulated address.
|
||||
//_assert_msg_(DYNA_REC,0,"MT : %08x",emAddress);
|
||||
|
||||
//Let's notify everyone who wants to be notified
|
||||
//Notify(emAddress, accessType == 0 ? Read : Write);
|
||||
|
||||
CONTEXT *ctx = pPtrs->ContextRecord;
|
||||
//opportunity to change the debug regs!
|
||||
//opportunity to play with the context - we can change the debug regs!
|
||||
|
||||
//We could emulate the memory accesses here, but then they would still be around to take up
|
||||
//execution resources. Instead, we backpatch and retry.
|
||||
Jit64::BackPatch(codePtr, accessType);
|
||||
//execution resources. Instead, we backpatch into a generic memory call and retry.
|
||||
Jit64::BackPatch(codePtr, accessType, emAddress);
|
||||
|
||||
// We no longer touch Rip, since we return back to the instruction, after overwriting it with a
|
||||
// trampoline jump and some nops
|
||||
|
@ -14,6 +14,11 @@
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
// Low hanging fruit:
|
||||
// all used in zelda
|
||||
// negx
|
||||
|
||||
#ifndef _JIT_H
|
||||
#define _JIT_H
|
||||
|
||||
@ -74,7 +79,6 @@ namespace Jit64
|
||||
void WriteExitDestInEAX(int exit_num);
|
||||
void WriteExceptionExit(u32 exception);
|
||||
void WriteRfiExitDestInEAX();
|
||||
void BackPatch(u8 *codePtr, int accessType);
|
||||
|
||||
void HLEFunction(UGeckoInstruction _inst);
|
||||
|
||||
|
126
Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.cpp
Normal file
126
Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include "disasm.h"
|
||||
#include "JitBackpatch.h"
|
||||
#include "../../HW/Memmap.h"
|
||||
|
||||
#include "x64Emitter.h"
|
||||
#include "x64Analyzer.h"
|
||||
|
||||
#include "StringUtil.h"
|
||||
#include "Jit.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
namespace Jit64 {
|
||||
|
||||
extern u8 *trampolineCodePtr;
|
||||
|
||||
void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
|
||||
u64 code_addr = (u64)codePtr;
|
||||
disassembler disasm;
|
||||
char disbuf[256];
|
||||
memset(disbuf, 0, 256);
|
||||
#ifdef _M_IX86
|
||||
disasm.disasm32(
|
||||
#else
|
||||
disasm.disasm64(
|
||||
#endif
|
||||
0, code_addr, codePtr, disbuf);
|
||||
PanicAlert("%s\n\n"
|
||||
"Error encountered accessing emulated address %08x.\n"
|
||||
"Culprit instruction: \n%s\nat %08x%08x",
|
||||
text.c_str(), emAddress, disbuf, code_addr>>32, code_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
||||
{
|
||||
if (!IsInJitCode(codePtr))
|
||||
return; // this will become a regular crash real soon after this
|
||||
|
||||
// TODO: also mark and remember the instruction address as known HW memory access, for use in later compiles.
|
||||
// But to do that we need to be able to reconstruct what instruction wrote this code, and we can't do that yet.
|
||||
u8 *oldCodePtr = GetWritableCodePtr();
|
||||
InstructionInfo info;
|
||||
if (!DisassembleMov(codePtr, info, accessType)) {
|
||||
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
|
||||
}
|
||||
if (info.operandSize != 4) {
|
||||
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
|
||||
}
|
||||
u64 code_addr = (u64)codePtr;
|
||||
X64Reg addrReg = (X64Reg)info.scaledReg;
|
||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||
if (info.otherReg != RBX)
|
||||
PanicAlert("BackPatch : Base reg not RBX."
|
||||
"\n\nAttempted to access %08x.", emAddress);
|
||||
if (accessType == OP_ACCESS_WRITE)
|
||||
PanicAlert("BackPatch : Currently only supporting reads."
|
||||
"\n\nAttempted to write to %08x.", emAddress);
|
||||
//if (info.instructionSize < 5)
|
||||
// PanicAlert("Instruction at %08x Too Small : %i", (u32)codePtr, info.instructionSize);
|
||||
// OK, let's write a trampoline, and a jump to it.
|
||||
// Later, let's share trampolines.
|
||||
|
||||
// In the first iteration, we assume that all accesses are 32-bit. We also only deal with reads.
|
||||
// Next step - support writes, special case FIFO writes. Also, support 32-bit mode.
|
||||
u8 *trampoline = trampolineCodePtr;
|
||||
SetCodePtr(trampolineCodePtr);
|
||||
// * Save all volatile regs
|
||||
PUSH(RCX);
|
||||
PUSH(RDX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(R8);
|
||||
PUSH(R9);
|
||||
PUSH(R10);
|
||||
PUSH(R11);
|
||||
//TODO: Also preserve XMM0-3?
|
||||
SUB(64, R(RSP), Imm8(0x20));
|
||||
// * Set up stack frame.
|
||||
// * Call ReadMemory32
|
||||
//LEA(32, ECX, MDisp((X64Reg)addrReg, info.displacement));
|
||||
MOV(32, R(ECX), R((X64Reg)addrReg));
|
||||
if (info.displacement) {
|
||||
ADD(32, R(ECX), Imm32(info.displacement));
|
||||
}
|
||||
switch (info.operandSize) {
|
||||
//case 1:
|
||||
// CALL((void *)&Memory::Read_U8);
|
||||
// break;
|
||||
case 4:
|
||||
CALL((void *)&Memory::Read_U32);
|
||||
break;
|
||||
default:
|
||||
BackPatchError(StringFromFormat("We don't handle the size %i yet in backpatch", info.operandSize), codePtr, emAddress);
|
||||
break;
|
||||
}
|
||||
// * Tear down stack frame.
|
||||
ADD(64, R(RSP), Imm8(0x20));
|
||||
POP(R11);
|
||||
POP(R10);
|
||||
POP(R9);
|
||||
POP(R8);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RDX);
|
||||
POP(RCX);
|
||||
MOV(32, R(dataReg), R(EAX));
|
||||
RET();
|
||||
trampolineCodePtr = GetWritableCodePtr();
|
||||
|
||||
SetCodePtr(codePtr);
|
||||
int bswapNopCount;
|
||||
// Check the following BSWAP for REX byte
|
||||
if ((GetCodePtr()[info.instructionSize] & 0xF0) == 0x40)
|
||||
bswapNopCount = 3;
|
||||
else
|
||||
bswapNopCount = 2;
|
||||
CALL(trampoline);
|
||||
NOP((int)info.instructionSize + bswapNopCount - 5);
|
||||
SetCodePtr(oldCodePtr);
|
||||
}
|
||||
|
||||
} // namespace
|
10
Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.h
Normal file
10
Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _JITBACKPATCH_H
|
||||
#define _JITBACKPATCH_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace Jit64 {
|
||||
void BackPatch(u8 *codePtr, int accessType, u32 emAddress);
|
||||
}
|
||||
|
||||
#endif
|
@ -26,7 +26,6 @@
|
||||
#include "../PPCTables.h"
|
||||
#include "../PPCAnalyst.h"
|
||||
|
||||
|
||||
#include "x64Emitter.h"
|
||||
#include "x64Analyzer.h"
|
||||
|
||||
@ -34,6 +33,8 @@
|
||||
#include "JitCache.h"
|
||||
#include "JitAsm.h"
|
||||
|
||||
#include "disasm.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
namespace Jit64
|
||||
@ -43,6 +44,8 @@ namespace Jit64
|
||||
u8 *trampolineCache;
|
||||
u8 *trampolineCodePtr;
|
||||
#define INVALID_EXIT 0xFFFFFFFF
|
||||
void LinkBlockExits(int i);
|
||||
void LinkBlock(int i);
|
||||
|
||||
enum
|
||||
{
|
||||
@ -54,8 +57,7 @@ namespace Jit64
|
||||
|
||||
u8 **blockCodePointers; // cut these in half and force below 2GB?
|
||||
|
||||
// todo - replace with something faster
|
||||
std::map<u32, int> unlinked;
|
||||
std::multimap<u32, int> links_to;
|
||||
|
||||
JitBlock *blocks;
|
||||
int numBlocks;
|
||||
@ -72,98 +74,15 @@ namespace Jit64
|
||||
LOG(DYNA_REC, "======================================");
|
||||
}
|
||||
|
||||
JitBlock *CurBlock()
|
||||
{
|
||||
return &blocks[numBlocks];
|
||||
}
|
||||
JitBlock *GetBlock(int no)
|
||||
{
|
||||
return &blocks[no];
|
||||
}
|
||||
int GetNumBlocks()
|
||||
{
|
||||
return numBlocks;
|
||||
}
|
||||
|
||||
|
||||
bool RangeIntersect(int s1, int e1, int s2, int e2)
|
||||
{
|
||||
// check if any endpoint is inside the other range
|
||||
if ( (s1 >= s2 && s1 <= e2) ||
|
||||
(e1 >= s2 && e1 <= e2) ||
|
||||
(s2 >= s1 && s2 <= e1) ||
|
||||
(e2 >= s1 && e2 <= e1))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void LinkBlocksCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
LinkBlocks();
|
||||
}
|
||||
|
||||
u8 *Jit(u32 emaddress)
|
||||
{
|
||||
if (GetCodePtr() >= codeCache + CODE_SIZE - 0x10000 || numBlocks>=MAX_NUM_BLOCKS-1)
|
||||
{
|
||||
//PanicAlert("Cleared cache");
|
||||
LOG(DYNA_REC, "JIT code cache full - clearing cache and restoring memory")
|
||||
ClearCache();
|
||||
}
|
||||
JitBlock &b = blocks[numBlocks];
|
||||
b.originalAddress = emaddress;
|
||||
b.exitAddress[0] = INVALID_EXIT;
|
||||
b.exitAddress[1] = INVALID_EXIT;
|
||||
b.exitPtrs[0] = 0;
|
||||
b.exitPtrs[1] = 0;
|
||||
b.linkStatus[0] = false;
|
||||
b.linkStatus[1] = false;
|
||||
b.originalFirstOpcode = Memory::ReadFast32(emaddress);
|
||||
|
||||
blockCodePointers[numBlocks] = (u8*)DoJit(emaddress, b); //cast away const, evil
|
||||
Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | numBlocks, emaddress);
|
||||
|
||||
//Flatten should also compute exits
|
||||
//Success!
|
||||
|
||||
if (jo.enableBlocklink) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (b.exitAddress[0] != INVALID_EXIT)
|
||||
{
|
||||
unlinked[b.exitAddress[0]] = numBlocks;
|
||||
}
|
||||
}
|
||||
// Link max once per half billion cycles
|
||||
//LinkBlocks();
|
||||
/*if (!CoreTiming::IsScheduled(&LinkBlocksCallback))
|
||||
{
|
||||
CoreTiming::ScheduleEvent(50000000, &LinkBlocksCallback, "Link JIT blocks", 0);
|
||||
}*/
|
||||
//if ((numBlocks & 1) == 0)
|
||||
LinkBlocks();
|
||||
}
|
||||
numBlocks++; //commit the current block
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unknown_instruction(UGeckoInstruction _inst)
|
||||
{
|
||||
// CCPU::Break();
|
||||
PanicAlert("unknown_instruction Jit64 - Fix me ;)");
|
||||
_dbg_assert_(DYNA_REC, 0);
|
||||
}
|
||||
|
||||
u8 **GetCodePointers()
|
||||
{
|
||||
return blockCodePointers;
|
||||
}
|
||||
|
||||
void InitCache()
|
||||
{
|
||||
jo.optimizeStack = true;
|
||||
jo.enableBlocklink = false; // Large speed boost but currently causes slowdowns too, due to stupid O(n^2) algo :P
|
||||
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
||||
#ifdef _M_X64
|
||||
jo.enableFastMem = true;
|
||||
#else
|
||||
jo.enableFastMem = false;
|
||||
#endif
|
||||
jo.noAssumeFPLoadFromMem = false;
|
||||
jo.fpAccurateFlags = true;
|
||||
|
||||
@ -183,6 +102,84 @@ namespace Jit64
|
||||
SetCodePtr(codeCache);
|
||||
}
|
||||
|
||||
JitBlock *CurBlock()
|
||||
{
|
||||
return &blocks[numBlocks];
|
||||
}
|
||||
|
||||
JitBlock *GetBlock(int no)
|
||||
{
|
||||
return &blocks[no];
|
||||
}
|
||||
|
||||
int GetNumBlocks()
|
||||
{
|
||||
return numBlocks;
|
||||
}
|
||||
|
||||
bool RangeIntersect(int s1, int e1, int s2, int e2)
|
||||
{
|
||||
// check if any endpoint is inside the other range
|
||||
if ( (s1 >= s2 && s1 <= e2) ||
|
||||
(e1 >= s2 && e1 <= e2) ||
|
||||
(s2 >= s1 && s2 <= e1) ||
|
||||
(e2 >= s1 && e2 <= e1))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 *Jit(u32 emAddress)
|
||||
{
|
||||
if (GetCodePtr() >= codeCache + CODE_SIZE - 0x10000 || numBlocks >= MAX_NUM_BLOCKS - 1)
|
||||
{
|
||||
// PanicAlert("Cleared cache");
|
||||
LOG(DYNA_REC, "JIT code cache full - clearing cache and restoring memory")
|
||||
ClearCache();
|
||||
}
|
||||
JitBlock &b = blocks[numBlocks];
|
||||
b.invalid = false;
|
||||
b.originalAddress = emAddress;
|
||||
b.originalFirstOpcode = Memory::ReadFast32(emAddress);
|
||||
b.exitAddress[0] = INVALID_EXIT;
|
||||
b.exitAddress[1] = INVALID_EXIT;
|
||||
b.exitPtrs[0] = 0;
|
||||
b.exitPtrs[1] = 0;
|
||||
b.linkStatus[0] = false;
|
||||
b.linkStatus[1] = false;
|
||||
|
||||
blockCodePointers[numBlocks] = (u8*)DoJit(emAddress, b); //cast away const
|
||||
Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | numBlocks, emAddress);
|
||||
|
||||
if (jo.enableBlocklink) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (b.exitAddress[i] != INVALID_EXIT) {
|
||||
links_to.insert(std::pair<u32, int>(b.exitAddress[i], numBlocks));
|
||||
}
|
||||
}
|
||||
|
||||
u8 *oldCodePtr = GetWritableCodePtr();
|
||||
LinkBlock(numBlocks);
|
||||
LinkBlockExits(numBlocks);
|
||||
SetCodePtr(oldCodePtr);
|
||||
}
|
||||
numBlocks++; //commit the current block
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unknown_instruction(UGeckoInstruction _inst)
|
||||
{
|
||||
// CCPU::Break();
|
||||
PanicAlert("unknown_instruction Jit64 - Fix me ;)");
|
||||
_dbg_assert_(DYNA_REC, 0);
|
||||
}
|
||||
|
||||
u8 **GetCodePointers()
|
||||
{
|
||||
return blockCodePointers;
|
||||
}
|
||||
|
||||
|
||||
bool IsInJitCode(u8 *codePtr) {
|
||||
return codePtr >= codeCache && codePtr <= GetCodePtr();
|
||||
}
|
||||
@ -271,6 +268,11 @@ namespace Jit64
|
||||
void LinkBlockExits(int i)
|
||||
{
|
||||
JitBlock &b = blocks[i];
|
||||
if (b.invalid)
|
||||
{
|
||||
// This block is dead. Don't relink it.
|
||||
return;
|
||||
}
|
||||
for (int e = 0; e < 2; e++)
|
||||
{
|
||||
if (b.exitAddress[e] != INVALID_EXIT && !b.linkStatus[e])
|
||||
@ -286,37 +288,31 @@ namespace Jit64
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if ((b.exitAddress[0] == INVALID_EXIT || b.linkStatus[0]) &&
|
||||
(b.exitAddress[1] == INVALID_EXIT || b.linkStatus[1])) {
|
||||
unlinked.erase(iter);
|
||||
if (unlinked.size() > 4000) PanicAlert("Removed from unlinked. Size = %i", unlinked.size());
|
||||
}
|
||||
*/
|
||||
using namespace std;
|
||||
void LinkBlock(int i)
|
||||
{
|
||||
LinkBlockExits(i);
|
||||
JitBlock &b = blocks[i];
|
||||
std::map<u32, int>::iterator iter;
|
||||
iter = unlinked.find(b.originalAddress);
|
||||
if (iter != unlinked.end())
|
||||
{
|
||||
LinkBlockExits(iter->second);
|
||||
// todo - remove stuff from unlinked
|
||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||
// equal_range(b) returns pair<iterator,iterator> representing the range
|
||||
// of element with key b
|
||||
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) {
|
||||
// PanicAlert("Linking block %i to block %i", iter2->second, i);
|
||||
LinkBlockExits(iter2->second);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkBlocks()
|
||||
{
|
||||
u8 *oldCodePtr = GetWritableCodePtr();
|
||||
//for (int i = 0; i < numBlocks; i++)
|
||||
// LinkBlockExits(i);
|
||||
|
||||
for (std::map<u32, int>::iterator iter = unlinked.begin();
|
||||
iter != unlinked.end(); iter++)
|
||||
{
|
||||
LinkBlockExits(iter->second);
|
||||
}
|
||||
// for (int i = 0; i < 2000; i++)
|
||||
LinkBlock(numBlocks);
|
||||
SetCodePtr(oldCodePtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DestroyBlock(int blocknum, bool invalidate)
|
||||
{
|
||||
u32 codebytes = (JIT_OPCODE << 26) | blocknum; //generate from i
|
||||
@ -336,6 +332,8 @@ namespace Jit64
|
||||
//for something else, then it's fine.
|
||||
LOG(MASTER_LOG, "WARNING - ClearCache detected code overwrite @ %08x", blocks[blocknum].originalAddress);
|
||||
}
|
||||
// TODO: Unlink block.
|
||||
|
||||
u8 *prev_code = GetWritableCodePtr();
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
SetCodePtr((u8*)b.checkedEntry);
|
||||
@ -344,7 +342,7 @@ namespace Jit64
|
||||
SetCodePtr(blockCodePointers[blocknum]);
|
||||
MOV(32, M(&PC), Imm32(b.originalAddress));
|
||||
JMP(Asm::dispatcher, true);
|
||||
SetCodePtr(prev_code);
|
||||
SetCodePtr(prev_code); // reset code pointer
|
||||
}
|
||||
|
||||
#define BLR_OP 0x4e800020
|
||||
@ -358,7 +356,7 @@ namespace Jit64
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
if (RangeIntersect(blocks[i].originalAddress, blocks[i].originalAddress+blocks[i].originalSize,
|
||||
address, address+length))
|
||||
address, address + length))
|
||||
{
|
||||
DestroyBlock(i, true);
|
||||
}
|
||||
@ -368,11 +366,10 @@ namespace Jit64
|
||||
void ClearCache()
|
||||
{
|
||||
// Is destroying the blocks really necessary?
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
DestroyBlock(i, false);
|
||||
}
|
||||
unlinked.clear();
|
||||
links_to.clear();
|
||||
trampolineCodePtr = trampolineCache;
|
||||
numBlocks = 0;
|
||||
numFlushes++;
|
||||
@ -381,96 +378,5 @@ namespace Jit64
|
||||
SetCodePtr(codeCache);
|
||||
}
|
||||
|
||||
extern u8 *trampolineCodePtr;
|
||||
void BackPatch(u8 *codePtr, int accessType)
|
||||
{
|
||||
if (codePtr < codeCache || codePtr > codeCache + CODE_SIZE)
|
||||
return; // this will become a regular crash real soon after this
|
||||
|
||||
static int counter = 0;
|
||||
++counter;
|
||||
if (counter == 30)
|
||||
{
|
||||
counter++;
|
||||
counter--;
|
||||
}
|
||||
|
||||
// TODO: also mark and remember the instruction address as known HW memory access, for use in later compiles.
|
||||
// But to do that we need to be able to reconstruct what instruction wrote this code, and we can't do that yet.
|
||||
u8 *oldCodePtr = GetWritableCodePtr();
|
||||
InstructionInfo info;
|
||||
if (!DisassembleMov(codePtr, info, accessType))
|
||||
PanicAlert("BackPatch - failed to disassemble MOV instruction");
|
||||
|
||||
X64Reg addrReg = (X64Reg)info.scaledReg;
|
||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||
if (info.otherReg != RBX)
|
||||
PanicAlert("BackPatch : Base reg not RBX.");
|
||||
if (accessType == OP_ACCESS_WRITE)
|
||||
PanicAlert("BackPatch : Currently only supporting reads.");
|
||||
//if (info.instructionSize < 5)
|
||||
// PanicAlert("Instruction at %08x Too Small : %i", (u32)codePtr, info.instructionSize);
|
||||
// OK, let's write a trampoline, and a jump to it.
|
||||
// Later, let's share trampolines.
|
||||
|
||||
// In the first iteration, we assume that all accesses are 32-bit. We also only deal with reads.
|
||||
u8 *trampoline = trampolineCodePtr;
|
||||
SetCodePtr(trampolineCodePtr);
|
||||
// * Save all volatile regs
|
||||
PUSH(RCX);
|
||||
PUSH(RDX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(R8);
|
||||
PUSH(R9);
|
||||
PUSH(R10);
|
||||
PUSH(R11);
|
||||
//TODO: Also preserve XMM0-3?
|
||||
SUB(64, R(RSP), Imm8(0x20));
|
||||
// * Set up stack frame.
|
||||
// * Call ReadMemory32
|
||||
//LEA(32, ECX, MDisp((X64Reg)addrReg, info.displacement));
|
||||
MOV(32, R(ECX), R((X64Reg)addrReg));
|
||||
if (info.displacement) {
|
||||
ADD(32, R(ECX), Imm32(info.displacement));
|
||||
}
|
||||
switch (info.operandSize) {
|
||||
//case 1:
|
||||
// CALL((void *)&Memory::Read_U8);
|
||||
// break;
|
||||
case 4:
|
||||
CALL((void *)&Memory::Read_U32);
|
||||
break;
|
||||
default:
|
||||
PanicAlert("We don't handle this size %i yet in backpatch", info.operandSize);
|
||||
break;
|
||||
}
|
||||
// * Tear down stack frame.
|
||||
ADD(64, R(RSP), Imm8(0x20));
|
||||
POP(R11);
|
||||
POP(R10);
|
||||
POP(R9);
|
||||
POP(R8);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RDX);
|
||||
POP(RCX);
|
||||
MOV(32, R(dataReg), R(EAX));
|
||||
RET();
|
||||
trampolineCodePtr = GetWritableCodePtr();
|
||||
|
||||
SetCodePtr(codePtr);
|
||||
int bswapNopCount;
|
||||
// Check the following BSWAP for REX byte
|
||||
if ((GetCodePtr()[info.instructionSize] & 0xF0) == 0x40)
|
||||
bswapNopCount = 3;
|
||||
else
|
||||
bswapNopCount = 2;
|
||||
CALL(trampoline);
|
||||
NOP((int)info.instructionSize + bswapNopCount - 5);
|
||||
// There is also a BSWAP to kill.
|
||||
SetCodePtr(oldCodePtr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -44,21 +44,21 @@
|
||||
namespace Jit64
|
||||
{
|
||||
#ifdef _M_X64
|
||||
void SafeLoadECXtoEAX(int accessSize, int offset)
|
||||
void SafeLoadECXtoEAX(int accessSize, s32 offset)
|
||||
{
|
||||
if (offset)
|
||||
ADD(32,R(ECX),Imm32((u32)offset));
|
||||
TEST(32,R(ECX),Imm32(0x0C000000));
|
||||
ADD(32, R(ECX), Imm32((u32)offset));
|
||||
TEST(32, R(ECX), Imm32(0x0C000000));
|
||||
FixupBranch argh = J_CC(CC_NZ);
|
||||
if (accessSize != 32)
|
||||
XOR(32, R(EAX), R(EAX));
|
||||
MOV(accessSize, R(EAX), MComplex(RBX, ECX, SCALE_1, 0));
|
||||
if (accessSize == 32)
|
||||
BSWAP(32,EAX);
|
||||
BSWAP(32, EAX);
|
||||
else if (accessSize == 16)
|
||||
{
|
||||
BSWAP(32,EAX);
|
||||
SHR(32,R(EAX),Imm8(16));
|
||||
BSWAP(32, EAX);
|
||||
SHR(32, R(EAX), Imm8(16));
|
||||
}
|
||||
FixupBranch arg2 = J();
|
||||
SetJumpTarget(argh);
|
||||
@ -71,7 +71,7 @@ namespace Jit64
|
||||
SetJumpTarget(arg2);
|
||||
}
|
||||
#elif _M_IX86
|
||||
void SafeLoadECXtoEAX(int accessSize, int offset)
|
||||
void SafeLoadECXtoEAX(int accessSize, s32 offset)
|
||||
{
|
||||
if (offset)
|
||||
ADD(32, R(ECX), Imm32((u32)offset));
|
||||
@ -86,7 +86,7 @@ namespace Jit64
|
||||
BSWAP(32,EAX);
|
||||
else if (accessSize == 16)
|
||||
{
|
||||
BSWAP(32,EAX);
|
||||
BSWAP(32, EAX);
|
||||
SHR(32, R(EAX), Imm8(16));
|
||||
}
|
||||
FixupBranch arg2 = J();
|
||||
@ -183,10 +183,10 @@ namespace Jit64
|
||||
// Safe and boring
|
||||
gpr.Flush(FLUSH_VOLATILE);
|
||||
gpr.Lock(d, a);
|
||||
MOV(32,R(ECX), gpr.R(a));
|
||||
MOV(32, R(ECX), gpr.R(a));
|
||||
SafeLoadECXtoEAX(accessSize, offset);
|
||||
gpr.LoadToX64(d, false, true);
|
||||
MOV(32,gpr.R(d), R(EAX));
|
||||
MOV(32, gpr.R(d), R(EAX));
|
||||
gpr.UnlockAll();
|
||||
return;
|
||||
}
|
||||
|
@ -23,6 +23,11 @@
|
||||
#include "JitCache.h"
|
||||
#include "JitRegCache.h"
|
||||
|
||||
// TODO
|
||||
// ps_madds0
|
||||
// ps_muls0
|
||||
// ps_madds1
|
||||
|
||||
|
||||
//#define OLD Default(inst); return;
|
||||
#define OLD
|
||||
|
@ -29,7 +29,8 @@
|
||||
|
||||
namespace PowerPC
|
||||
{
|
||||
GC_ALIGNED16_DECL(PowerPCState ppcState);
|
||||
// align to cache line
|
||||
GC_ALIGNED64_DECL(PowerPCState ppcState);
|
||||
ICPUCore* m_pCore = NULL;
|
||||
|
||||
volatile CPUState state = CPU_STEPPING;
|
||||
|
@ -36,7 +36,7 @@ namespace PowerPC
|
||||
CORE_INTERPRETER,
|
||||
CORE_DYNAREC,
|
||||
};
|
||||
struct GC_ALIGNED16(PowerPCState)
|
||||
struct GC_ALIGNED64(PowerPCState)
|
||||
{
|
||||
u32 mojs[128];
|
||||
// sets of registers
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="DebuggerWX"
|
||||
ProjectGUID="{4D3CD4C5-412B-4B49-9B1B-A68A2A129C77}"
|
||||
RootNamespace="DebuggerWX"
|
||||
@ -238,6 +238,7 @@
|
||||
AdditionalIncludeDirectories="..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\Core\Src;;..\Common\Src"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;__WXMSW__"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="DiscIO"
|
||||
ProjectGUID="{B7F1A9FB-BEA8-416E-9460-AE35A6A5165C}"
|
||||
RootNamespace="DiscIO"
|
||||
@ -24,6 +24,7 @@
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
@ -88,6 +89,7 @@
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
@ -153,7 +155,7 @@
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
@ -215,7 +217,7 @@
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
@ -279,7 +281,7 @@
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
@ -341,7 +343,7 @@
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
WholeProgramOptimization="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="DolphinWX"
|
||||
ProjectGUID="{A72606EF-C5C1-4954-90AD-F0F93A8D97D9}"
|
||||
RootNamespace="DolphinWX"
|
||||
@ -157,9 +157,11 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/EHsc "
|
||||
Optimization="2"
|
||||
Optimization="3"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="false"
|
||||
AdditionalIncludeDirectories="..\Common\Src;..\Core\Src;..\DiscIO\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\DebuggerWX\src"
|
||||
PreprocessorDefinitions="WIN32;__WXMSW__;_WINDOWS;NOPCH;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS"
|
||||
StringPooling="true"
|
||||
|
@ -170,7 +170,6 @@ void Host_UpdateDisasmDialog()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATEDISASMDIALOG);
|
||||
wxPostEvent(main_frame, event);
|
||||
|
||||
if (code_frame)
|
||||
{
|
||||
wxPostEvent(code_frame, event);
|
||||
|
@ -18,10 +18,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Common.h"
|
||||
#include "PluginManager.h"
|
||||
#include "Globals.h"
|
||||
#include "FileSearch.h"
|
||||
#include "FileUtil.h"
|
||||
#include "PluginManager.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
CPluginManager CPluginManager::m_Instance;
|
||||
@ -57,7 +58,7 @@ CPluginManager::ScanForPlugins(wxWindow* _wxWindow)
|
||||
{
|
||||
wxProgressDialog dialog(_T("Scanning for Plugins"),
|
||||
_T("Scanning..."),
|
||||
rFilenames.size(), // range
|
||||
(int)rFilenames.size(), // range
|
||||
_wxWindow, // parent
|
||||
wxPD_CAN_ABORT |
|
||||
wxPD_APP_MODAL |
|
||||
@ -67,8 +68,6 @@ CPluginManager::ScanForPlugins(wxWindow* _wxWindow)
|
||||
wxPD_REMAINING_TIME |
|
||||
wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small
|
||||
);
|
||||
|
||||
|
||||
dialog.CenterOnParent();
|
||||
|
||||
for (size_t i = 0; i < rFilenames.size(); i++)
|
||||
@ -85,7 +84,7 @@ CPluginManager::ScanForPlugins(wxWindow* _wxWindow)
|
||||
|
||||
wxString msg;
|
||||
msg.Printf("Scanning %s", FileName.c_str());
|
||||
bool Cont = dialog.Update(i, msg);
|
||||
bool Cont = dialog.Update((int)i, msg);
|
||||
|
||||
if (!Cont)
|
||||
{
|
||||
@ -154,7 +153,11 @@ CPluginInfo::CPluginInfo(const std::string& _rFileName)
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Failed to load plugin %s\nhello world", _rFileName.c_str());
|
||||
if (!File::Exists(_rFileName)) {
|
||||
PanicAlert("Could not load plugin %s - file does not exist", _rFileName.c_str());
|
||||
} else {
|
||||
PanicAlert("Failed to load plugin %s - unknown error.\n", _rFileName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user