mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-09 15:49:25 +01:00
32-bit speedup (videos mostly affected). Lots of various cleanup and future proofing. A small debugger feature.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@162 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
61398ea83f
commit
e3d21c0b11
@ -100,6 +100,7 @@ void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
// Win64 Specific Code
|
// Win64 Specific Code
|
||||||
// ====================================
|
// ====================================
|
||||||
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||||
@ -107,27 +108,54 @@ void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
|||||||
PUSH(RBX);
|
PUSH(RBX);
|
||||||
PUSH(RSI);
|
PUSH(RSI);
|
||||||
PUSH(RDI);
|
PUSH(RDI);
|
||||||
//PUSH(RBP);
|
PUSH(RBP);
|
||||||
PUSH(R12);
|
PUSH(R12);
|
||||||
PUSH(R13);
|
PUSH(R13);
|
||||||
PUSH(R14);
|
PUSH(R14);
|
||||||
PUSH(R15);
|
PUSH(R15);
|
||||||
//TODO: Also preserve XMM0-3?
|
//TODO: Also preserve XMM0-3?
|
||||||
SUB(64, R(RSP), Imm8(0x20));
|
SUB(64, R(RSP), Imm8(0x28));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||||
ADD(64, R(RSP), Imm8(0x20));
|
ADD(64, R(RSP), Imm8(0x28));
|
||||||
POP(R15);
|
POP(R15);
|
||||||
POP(R14);
|
POP(R14);
|
||||||
POP(R13);
|
POP(R13);
|
||||||
POP(R12);
|
POP(R12);
|
||||||
//POP(RBP);
|
POP(RBP);
|
||||||
POP(RDI);
|
POP(RDI);
|
||||||
POP(RSI);
|
POP(RSI);
|
||||||
POP(RBX);
|
POP(RBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Win64 Specific Code
|
||||||
|
// ====================================
|
||||||
|
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||||
|
PUSH(RCX);
|
||||||
|
PUSH(RDX);
|
||||||
|
PUSH(RSI);
|
||||||
|
PUSH(RDI);
|
||||||
|
PUSH(R8);
|
||||||
|
PUSH(R9);
|
||||||
|
PUSH(R10);
|
||||||
|
PUSH(R11);
|
||||||
|
//TODO: Also preserve XMM0-15?
|
||||||
|
SUB(64, R(RSP), Imm8(0x28));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||||
|
ADD(64, R(RSP), Imm8(0x28));
|
||||||
|
POP(R11);
|
||||||
|
POP(R10);
|
||||||
|
POP(R9);
|
||||||
|
POP(R8);
|
||||||
|
POP(RDI);
|
||||||
|
POP(RSI);
|
||||||
|
POP(RDX);
|
||||||
|
POP(RCX);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Unix64 Specific Code
|
// Unix64 Specific Code
|
||||||
// ====================================
|
// ====================================
|
||||||
@ -151,6 +179,16 @@ void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
|||||||
POP(RBX);
|
POP(RBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||||
|
INT3();
|
||||||
|
//not yet supported
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||||
|
INT3();
|
||||||
|
//not yet supported
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -92,8 +92,17 @@ void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2);
|
|||||||
void ABI_CallFunctionR(void *func, Gen::X64Reg reg1);
|
void ABI_CallFunctionR(void *func, Gen::X64Reg reg1);
|
||||||
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2);
|
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2);
|
||||||
|
|
||||||
|
// A function that doesn't have any control over what it will do to regs,
|
||||||
|
// such as the dispatcher, should be surrounded by these.
|
||||||
void ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
void ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||||
void ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
void ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
|
|
||||||
|
// A function that doesn't know anything about it's surroundings, should
|
||||||
|
// be surrounded by these to establish a safe environment, where it can roam free.
|
||||||
|
// An example is a backpatch injected function.
|
||||||
|
void ABI_PushAllCallerSavedRegsAndAdjustStack();
|
||||||
|
void ABI_PopAllCallerSavedRegsAndAdjustStack();
|
||||||
|
|
||||||
|
|
||||||
#endif // _JIT_ABI_H
|
#endif // _JIT_ABI_H
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
|||||||
//Check for regular prefix
|
//Check for regular prefix
|
||||||
info.operandSize = 4;
|
info.operandSize = 4;
|
||||||
info.zeroExtend = false;
|
info.zeroExtend = false;
|
||||||
|
info.signExtend = false;
|
||||||
|
info.hasImmediate = false;
|
||||||
|
info.isMemoryWrite = false;
|
||||||
|
|
||||||
int addressSize = 8;
|
int addressSize = 8;
|
||||||
u8 modRMbyte = 0;
|
u8 modRMbyte = 0;
|
||||||
@ -33,7 +36,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
|||||||
bool hasModRM = false;
|
bool hasModRM = false;
|
||||||
bool hasSIBbyte = false;
|
bool hasSIBbyte = false;
|
||||||
bool hasDisplacement = false;
|
bool hasDisplacement = false;
|
||||||
info.hasImmediate = false;
|
|
||||||
|
|
||||||
int displacementSize = 0;
|
int displacementSize = 0;
|
||||||
|
|
||||||
@ -136,6 +138,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
|||||||
|
|
||||||
if (accessType == 1)
|
if (accessType == 1)
|
||||||
{
|
{
|
||||||
|
info.isMemoryWrite = true;
|
||||||
//Write access
|
//Write access
|
||||||
switch (codeByte)
|
switch (codeByte)
|
||||||
{
|
{
|
||||||
@ -179,7 +182,9 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//mov eax,dword ptr [rax] == 8b 00
|
// Memory read
|
||||||
|
|
||||||
|
//mov eax, dword ptr [rax] == 8b 00
|
||||||
switch (codeByte)
|
switch (codeByte)
|
||||||
{
|
{
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
@ -193,6 +198,14 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
|||||||
info.zeroExtend = true;
|
info.zeroExtend = true;
|
||||||
info.operandSize = 2;
|
info.operandSize = 2;
|
||||||
break;
|
break;
|
||||||
|
case 0xBE: //movsx on byte
|
||||||
|
info.signExtend = true;
|
||||||
|
info.operandSize = 1;
|
||||||
|
break;
|
||||||
|
case 0xBF:
|
||||||
|
info.signExtend = true;
|
||||||
|
info.operandSize = 2;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,9 @@ struct InstructionInfo
|
|||||||
int otherReg;
|
int otherReg;
|
||||||
int scaledReg;
|
int scaledReg;
|
||||||
bool zeroExtend;
|
bool zeroExtend;
|
||||||
|
bool signExtend;
|
||||||
bool hasImmediate;
|
bool hasImmediate;
|
||||||
|
bool isMemoryWrite;
|
||||||
u64 immediate;
|
u64 immediate;
|
||||||
s32 displacement;
|
s32 displacement;
|
||||||
};
|
};
|
||||||
|
@ -879,6 +879,10 @@
|
|||||||
RelativePath=".\Src\PowerPC\Jit64\Jit_LoadStore.cpp"
|
RelativePath=".\Src\PowerPC\Jit64\Jit_LoadStore.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Src\PowerPC\Jit64\Jit_LoadStoreFloating.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Src\PowerPC\Jit64\Jit_LoadStorePaired.cpp"
|
RelativePath=".\Src\PowerPC\Jit64\Jit_LoadStorePaired.cpp"
|
||||||
>
|
>
|
||||||
|
@ -185,10 +185,7 @@ void CBoot::EmulatedBIOS(bool _bDebug)
|
|||||||
// return
|
// return
|
||||||
PC = PowerPC::ppcState.gpr[3];
|
PC = PowerPC::ppcState.gpr[3];
|
||||||
|
|
||||||
//
|
|
||||||
// --- preinit some stuff from bios ---
|
// --- preinit some stuff from bios ---
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
// Bus Clock Speed
|
// Bus Clock Speed
|
||||||
Memory::Write_U32(0x09a7ec80, 0x800000F8);
|
Memory::Write_U32(0x09a7ec80, 0x800000F8);
|
||||||
|
@ -186,9 +186,16 @@ THREAD_RETURN CpuThread(void *pArg)
|
|||||||
if (_CoreParameter.bLockThreads)
|
if (_CoreParameter.bLockThreads)
|
||||||
Common::Thread::SetCurrentThreadAffinity(1); //Force to first core
|
Common::Thread::SetCurrentThreadAffinity(1); //Force to first core
|
||||||
|
|
||||||
// Let's run under memory watch
|
if (_CoreParameter.bUseFastMem)
|
||||||
EMM::InstallExceptionHandler();
|
{
|
||||||
// StartConsoleThread();
|
#ifdef _M_X64
|
||||||
|
// Let's run under memory watch
|
||||||
|
EMM::InstallExceptionHandler();
|
||||||
|
#else
|
||||||
|
PanicAlert("32-bit platforms do not support fastmem yet. Report this bug.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
CCPU::Run();
|
CCPU::Run();
|
||||||
|
|
||||||
if (_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
|
if (_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
|
||||||
|
@ -144,7 +144,7 @@ template <class T, u8* P> void HWCALL HW_Write_Memory(T _Data, const u32 _Addres
|
|||||||
|
|
||||||
void InitHWMemFuncs()
|
void InitHWMemFuncs()
|
||||||
{
|
{
|
||||||
for (int i=0; i<NUMHWMEMFUN; i++)
|
for (int i = 0; i < NUMHWMEMFUN; i++)
|
||||||
{
|
{
|
||||||
hwWrite8 [i] = HW_Default_Write<u8>;
|
hwWrite8 [i] = HW_Default_Write<u8>;
|
||||||
hwWrite16[i] = HW_Default_Write<u16>;
|
hwWrite16[i] = HW_Default_Write<u16>;
|
||||||
@ -156,7 +156,7 @@ void InitHWMemFuncs()
|
|||||||
hwRead64 [i] = HW_Default_Read<u64&>;
|
hwRead64 [i] = HW_Default_Read<u64&>;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<BLOCKSIZE; i++)
|
for (int i = 0; i < BLOCKSIZE; i++)
|
||||||
{
|
{
|
||||||
hwRead16 [i] = CommandProcessor::Read16;
|
hwRead16 [i] = CommandProcessor::Read16;
|
||||||
hwWrite16[i] = CommandProcessor::Write16;
|
hwWrite16[i] = CommandProcessor::Write16;
|
||||||
@ -322,13 +322,13 @@ writeFn32 GetHWWriteFun32(const u32 _Address)
|
|||||||
PanicAlert("READ: Invalid address: %08x", _Address); \
|
PanicAlert("READ: Invalid address: %08x", _Address); \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
if ((_Address & 0xFE000000) == 0x7e000000) \
|
if (bFakeVMEM && (_Address & 0xFE000000) == 0x7e000000) \
|
||||||
{ \
|
{ \
|
||||||
_var = bswap((*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK])); \
|
_var = bswap((*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK])); \
|
||||||
} \
|
} \
|
||||||
else {/* LOG(MEMMAP,"READ (unknown): %08x (PC: %08x)",_Address,PC);*/ \
|
else {/* LOG(MEMMAP,"READ (unknown): %08x (PC: %08x)",_Address,PC);*/ \
|
||||||
/*CCPU::EnableStepping(TRUE);*/ \
|
/*CCPU::EnableStepping(TRUE);*/ \
|
||||||
/*PanicAlert("READ: Unknown Address", "1", MB_OK);*/ \
|
/*PanicAlert("READ: Unknown Address", "1", MB_OK);*/ \
|
||||||
u32 tmpAddress = CheckDTLB(EffictiveAddress, flag); \
|
u32 tmpAddress = CheckDTLB(EffictiveAddress, flag); \
|
||||||
tmpAddress =(tmpAddress & 0xFFFFFFF0) | (_Address & 0xF); \
|
tmpAddress =(tmpAddress & 0xFFFFFFF0) | (_Address & 0xF); \
|
||||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) \
|
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) \
|
||||||
@ -393,7 +393,7 @@ writeFn32 GetHWWriteFun32(const u32 _Address)
|
|||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
if ((_Address & 0xFE000000) == 0x7e000000) \
|
if (bFakeVMEM && (_Address & 0xFE000000) == 0x7e000000) \
|
||||||
{ \
|
{ \
|
||||||
*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK] = bswap(_Data); \
|
*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK] = bswap(_Data); \
|
||||||
return; \
|
return; \
|
||||||
@ -1100,7 +1100,7 @@ u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag)
|
|||||||
// hash function no 2 "not" .360
|
// hash function no 2 "not" .360
|
||||||
hash1 = ~hash1;
|
hash1 = ~hash1;
|
||||||
pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base;
|
pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base;
|
||||||
for (int i=0; i<8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
|
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
|
||||||
if ((pte & PTE1_V) && (pte & PTE1_H))
|
if ((pte & PTE1_V) && (pte & PTE1_H))
|
||||||
|
@ -153,10 +153,8 @@ int timeHistory[HISTORYLENGTH] = {0,0,0,0,0};
|
|||||||
|
|
||||||
void Throttle(u64 userdata, int cyclesLate)
|
void Throttle(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
if (!Core::GetStartupParameter().bThrottle)
|
||||||
// had some weird problem in linux. will investigate.
|
return;
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
static Common::Timer timer;
|
static Common::Timer timer;
|
||||||
|
|
||||||
for (int i=0; i<HISTORYLENGTH-1; i++)
|
for (int i=0; i<HISTORYLENGTH-1; i++)
|
||||||
@ -208,9 +206,9 @@ void Init()
|
|||||||
Common::Timer::IncreaseResolution();
|
Common::Timer::IncreaseResolution();
|
||||||
memset(timeHistory, 0, sizeof(timeHistory));
|
memset(timeHistory, 0, sizeof(timeHistory));
|
||||||
CoreTiming::Clear();
|
CoreTiming::Clear();
|
||||||
if (Core::GetStartupParameter().bThrottle) {
|
|
||||||
CoreTiming::ScheduleEvent((int)(GetTicksPerSecond()/ThrottleFrequency), &Throttle, "Throttle");
|
CoreTiming::ScheduleEvent((int)(GetTicksPerSecond() / ThrottleFrequency), &Throttle, "Throttle");
|
||||||
}
|
|
||||||
CoreTiming::ScheduleEvent(AI_PERIOD, &AICallback, "AICallback");
|
CoreTiming::ScheduleEvent(AI_PERIOD, &AICallback, "AICallback");
|
||||||
CoreTiming::ScheduleEvent(VI_PERIOD, &VICallback, "VICallback");
|
CoreTiming::ScheduleEvent(VI_PERIOD, &VICallback, "VICallback");
|
||||||
CoreTiming::ScheduleEvent(DSP_PERIOD, &DSPCallback, "DSPCallback");
|
CoreTiming::ScheduleEvent(DSP_PERIOD, &DSPCallback, "DSPCallback");
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
@ -32,179 +31,6 @@
|
|||||||
|
|
||||||
namespace EMM
|
namespace EMM
|
||||||
{
|
{
|
||||||
/* DESIGN
|
|
||||||
|
|
||||||
THIS IS NOT THE CURRENT STATE OF THIS FILE - IT'S UNFINISHED
|
|
||||||
|
|
||||||
We grab 4GB of virtual address space, and locate memories in there. The memories are either
|
|
||||||
VirtualAlloc or mapped swapfile.
|
|
||||||
|
|
||||||
I/O areas are mapped into the virtual memspace, and VirtualProtected where necessary.
|
|
||||||
|
|
||||||
Every chunk is mapped twice into memory, once into the virtual memspace, and once elsewhere.
|
|
||||||
This second mapping is used when a "read+writable" pointer is requested for a region. This
|
|
||||||
would generally be for internal use by IO functions, and for actually performing the writes
|
|
||||||
and reads after detecting them.
|
|
||||||
|
|
||||||
There is individual read and write protection for each chunk of memory.
|
|
||||||
|
|
||||||
Every region has a default read-write handler. If an exception is caught, this is executed.
|
|
||||||
|
|
||||||
The default read-write handlers use the "writable" pointers.
|
|
||||||
|
|
||||||
There should be a method to mark a region for "write notification". Dynarecs can use this
|
|
||||||
to flush their code caches if a region is written to.
|
|
||||||
|
|
||||||
At this moment, there can only be one wrapped memspace at a time.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DWORD_PTR memspaceBottom = 0;
|
|
||||||
DWORD_PTR memspaceTop = 0;
|
|
||||||
|
|
||||||
enum MSFlags
|
|
||||||
{
|
|
||||||
MEMSPACE_MIRROR_FIRST_PART = 1,
|
|
||||||
MEMSPACE_MIRROR_OF_PREVIOUS = 2,
|
|
||||||
MEMSPACE_MAPPED_HARDWARE = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MemSpaceEntry
|
|
||||||
{
|
|
||||||
u64 emulatedBase;
|
|
||||||
u64 emulatedSize;
|
|
||||||
u32 flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MEGABYTE 1024*1024
|
|
||||||
|
|
||||||
const MemSpaceEntry GCMemSpace[] =
|
|
||||||
{
|
|
||||||
{0x80000000, 24*MEGABYTE, MEMSPACE_MIRROR_FIRST_PART},
|
|
||||||
{0xC0000000, 24*MEGABYTE, MEMSPACE_MIRROR_OF_PREVIOUS},
|
|
||||||
{0xCC000000, 0x10000, MEMSPACE_MAPPED_HARDWARE},
|
|
||||||
{0xE0000000, 0x4000, 0}, //cache
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Watch
|
|
||||||
{
|
|
||||||
int ID;
|
|
||||||
EAddr startAddr;
|
|
||||||
EAddr endAddr;
|
|
||||||
WR watchFor;
|
|
||||||
WatchCallback callback;
|
|
||||||
WatchType type;
|
|
||||||
u64 userData;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
Watch watch;
|
|
||||||
watch.ID = watchIDGen++;
|
|
||||||
watch.startAddr = startAddr;
|
|
||||||
watch.endAddr = endAddr;
|
|
||||||
watch.watchFor = watchFor;
|
|
||||||
watch.callback = callback;
|
|
||||||
watch.userData = userData;
|
|
||||||
watch.type = type;
|
|
||||||
watches.push_back(watch);
|
|
||||||
UpdateProtection(startAddr, endAddr);
|
|
||||||
|
|
||||||
return watch.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Notify(EAddr address, WR action)
|
|
||||||
{
|
|
||||||
for (std::vector<Watch>::iterator iter = watches.begin(); iter != watches.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (action & iter->type)
|
|
||||||
{
|
|
||||||
if (address >= iter->startAddr && address < iter->endAddr)
|
|
||||||
{
|
|
||||||
//Alright!
|
|
||||||
iter->callback(address, Access32 /*TODO*/, action, iter->ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MemSpace
|
|
||||||
{
|
|
||||||
MemSpaceEntry *entries;
|
|
||||||
|
|
||||||
u64 emulatedBottom;
|
|
||||||
u64 emulatedTop;
|
|
||||||
u64 emulatedSize;
|
|
||||||
|
|
||||||
void *virtualBase;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void Init(const MemSpaceEntry *e, int count)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
//first pass: figure out minimum address, and total amount of allocated memory
|
|
||||||
emulatedBase = 0xFFFFFFFFFFFFFFFFL;
|
|
||||||
emulatedTop = 0;
|
|
||||||
|
|
||||||
u64 mappedTotal = 0;
|
|
||||||
for (int i=0; i<count; i++)
|
|
||||||
{
|
|
||||||
if (e[i].emulatedBase < emulatedBase)
|
|
||||||
emulatedBase = e[i].emulatedBase;
|
|
||||||
if (e[i].emulatedBase+e[i].emulatedSize > emulatedTop)
|
|
||||||
emulatedTop = e[i].emulatedBase+e[i].emulatedSize;
|
|
||||||
if (e[i].flags & MEMSPACE_MIRROR_FIRST_PART)
|
|
||||||
{
|
|
||||||
mappedTotal += e[i].emulatedSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
emulatedSize = emulatedTop - emulatedBase;
|
|
||||||
|
|
||||||
// The above stuff is not used atm - we just grab 4G
|
|
||||||
|
|
||||||
//second pass: grab 4G of virtual address space
|
|
||||||
virtualBase = VirtualAlloc(0, 0x100000000L, MEM_RESERVE, PAGE_READWRITE);
|
|
||||||
|
|
||||||
//also grab a bunch of virtual memory while we're at it
|
|
||||||
|
|
||||||
|
|
||||||
//Release the 4G space!
|
|
||||||
//Let's hope no weirdo thread klomps in here and grabs it
|
|
||||||
VirtualFree(base, 0, MEM_RELEASE);
|
|
||||||
|
|
||||||
for (int i=0; i<count; i++)
|
|
||||||
{
|
|
||||||
if (e[i].flags & MEMSPACE_MIRROR_FIRST_PART)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: fill all empty parts of the address space with no-access virtualalloc space
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 GetVirtualBaseAddr() {return (u64)virtualBase;}
|
|
||||||
void *GetVirtualBase() {return virtualBase;}
|
|
||||||
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ======
|
|
||||||
// From here on is the code in this file that actually works and is active.
|
|
||||||
|
|
||||||
LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
|
||||||
{
|
{
|
||||||
@ -299,9 +125,79 @@ void InstallExceptionHandler()
|
|||||||
|
|
||||||
namespace EMM {
|
namespace EMM {
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//
|
||||||
|
// backtrace useful function
|
||||||
|
//
|
||||||
|
void print_trace(const char * msg)
|
||||||
|
{
|
||||||
|
void *array[100];
|
||||||
|
size_t size;
|
||||||
|
char **strings;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
size = backtrace(array, 100);
|
||||||
|
strings = backtrace_symbols(array, size);
|
||||||
|
printf("%s Obtained %zd stack frames.\n", msg, size);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
printf("--> %s\n", strings[i]);
|
||||||
|
free(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigsegv_handler(int signal, int siginfo_t *info, void *raw_context)
|
||||||
|
{
|
||||||
|
if (signal != SIGSEGV)
|
||||||
|
{
|
||||||
|
// We are not interested in other signals - handle it as usual.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ucontext_t *context = (ucontext_t)raw_context;
|
||||||
|
int si_code = info->si_code;
|
||||||
|
if (si_code != SEGV_MAPERR)
|
||||||
|
{
|
||||||
|
// Huh? Return.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mcontext_t *ctx = &context->uc_mcontext;
|
||||||
|
void *fault_memory_ptr = (void *)info->si_addr;
|
||||||
|
void *fault_instruction_ptr = (void *)ctx->mc_rip;
|
||||||
|
|
||||||
|
if (!Jit64::IsInJitCode(fault_instruction_ptr)) {
|
||||||
|
// Let's not prevent debugging.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 memspaceBottom = (u64)Memory::base;
|
||||||
|
if (badAddress < memspaceBottom) {
|
||||||
|
PanicAlert("Exception handler - access below memory space. %08x%08x",
|
||||||
|
badAddress >> 32, badAddress);
|
||||||
|
}
|
||||||
|
u32 emAddress = (u32)(badAddress - memspaceBottom);
|
||||||
|
|
||||||
|
// Backpatch time.
|
||||||
|
Jit64::BackPatch(fault_instruction_ptr, accessType, emAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void InstallExceptionHandler()
|
void InstallExceptionHandler()
|
||||||
{
|
{
|
||||||
/*
|
#ifdef _M_IX86
|
||||||
|
PanicAlert("InstallExceptionHandler called, but this platform does not yet support it.");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
sighandler_t old_signal_handler = signal(SIGSEGV , sigsegv_handler);
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = sigsegv_handler;
|
||||||
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
* signal(xyz);
|
* signal(xyz);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@ -69,4 +69,3 @@ void WriteHandler32(EAddr address, u32 value);
|
|||||||
void WriteHandler64(EAddr address, u64 value);
|
void WriteHandler64(EAddr address, u64 value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
#include "JitCache.h"
|
#include "JitCache.h"
|
||||||
|
#include "x64Emitter.h"
|
||||||
|
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
@ -85,6 +86,7 @@ namespace Jit64
|
|||||||
|
|
||||||
void FlushRegCaches();
|
void FlushRegCaches();
|
||||||
|
|
||||||
|
void SafeLoadRegToEAX(Gen::X64Reg reg, int accessSize, s32 offset);
|
||||||
|
|
||||||
void addx(UGeckoInstruction inst);
|
void addx(UGeckoInstruction inst);
|
||||||
void orx(UGeckoInstruction inst);
|
void orx(UGeckoInstruction inst);
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
#include "ABI.h"
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
|
@ -1,3 +1,20 @@
|
|||||||
|
// Copyright (C) 2003-2008 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 <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
@ -36,6 +53,10 @@ void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This generates some fairly heavy trampolines, but:
|
||||||
|
// 1) It's really necessary. We don't know anything about the context.
|
||||||
|
// 2) It doesn't really hurt. Only instructions that access I/O will get these, and there won't be
|
||||||
|
// that many of them in a typical program/game.
|
||||||
void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
||||||
{
|
{
|
||||||
if (!IsInJitCode(codePtr))
|
if (!IsInJitCode(codePtr))
|
||||||
@ -48,6 +69,10 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
|||||||
if (!DisassembleMov(codePtr, info, accessType)) {
|
if (!DisassembleMov(codePtr, info, accessType)) {
|
||||||
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
|
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
|
||||||
}
|
}
|
||||||
|
if (info.isMemoryWrite) {
|
||||||
|
BackPatchError("BackPatch - determined that MOV is write, not yet supported and should have been caught before",
|
||||||
|
codePtr, emAddress);
|
||||||
|
}
|
||||||
if (info.operandSize != 4) {
|
if (info.operandSize != 4) {
|
||||||
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
|
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
|
||||||
}
|
}
|
||||||
@ -70,19 +95,10 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
|||||||
u8 *trampoline = trampolineCodePtr;
|
u8 *trampoline = trampolineCodePtr;
|
||||||
SetCodePtr(trampolineCodePtr);
|
SetCodePtr(trampolineCodePtr);
|
||||||
// * Save all volatile regs
|
// * Save all volatile regs
|
||||||
PUSH(RCX);
|
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
||||||
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.
|
// * Set up stack frame.
|
||||||
// * Call ReadMemory32
|
// * Call ReadMemory32
|
||||||
//LEA(32, ECX, MDisp((X64Reg)addrReg, info.displacement));
|
//LEA(32, ABI_PARAM1, MDisp((X64Reg)addrReg, info.displacement));
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
||||||
if (info.displacement) {
|
if (info.displacement) {
|
||||||
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
|
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
|
||||||
@ -91,7 +107,8 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
|||||||
//case 1:
|
//case 1:
|
||||||
// CALL((void *)&Memory::Read_U8);
|
// CALL((void *)&Memory::Read_U8);
|
||||||
// break;
|
// break;
|
||||||
case 4:
|
case 4:
|
||||||
|
// THIS FUNCTION CANNOT TOUCH FLOATING POINT REGISTERS.
|
||||||
CALL((void *)&Memory::Read_U32);
|
CALL((void *)&Memory::Read_U32);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -99,15 +116,7 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// * Tear down stack frame.
|
// * Tear down stack frame.
|
||||||
ADD(64, R(RSP), Imm8(0x20));
|
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
||||||
POP(R11);
|
|
||||||
POP(R10);
|
|
||||||
POP(R9);
|
|
||||||
POP(R8);
|
|
||||||
POP(RDI);
|
|
||||||
POP(RSI);
|
|
||||||
POP(RDX);
|
|
||||||
POP(RCX);
|
|
||||||
MOV(32, R(dataReg), R(EAX));
|
MOV(32, R(dataReg), R(EAX));
|
||||||
RET();
|
RET();
|
||||||
trampolineCodePtr = GetWritableCodePtr();
|
trampolineCodePtr = GetWritableCodePtr();
|
||||||
|
@ -1,3 +1,20 @@
|
|||||||
|
// Copyright (C) 2003-2008 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 _JITBACKPATCH_H
|
#ifndef _JITBACKPATCH_H
|
||||||
#define _JITBACKPATCH_H
|
#define _JITBACKPATCH_H
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "../../Core.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
@ -78,7 +79,7 @@ namespace Jit64
|
|||||||
jo.optimizeStack = true;
|
jo.optimizeStack = true;
|
||||||
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
jo.enableFastMem = true;
|
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
|
||||||
#else
|
#else
|
||||||
jo.enableFastMem = false;
|
jo.enableFastMem = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,6 +28,14 @@
|
|||||||
// The branches are known good, or at least reasonably good.
|
// The branches are known good, or at least reasonably good.
|
||||||
// No need for a disable-mechanism.
|
// No need for a disable-mechanism.
|
||||||
|
|
||||||
|
// If defined, clears CR0 at blr and bl-s. If the assumption that
|
||||||
|
// flags never carry over between functions holds, then the task for
|
||||||
|
// an optimizer becomes much easier.
|
||||||
|
|
||||||
|
// #define ACID_TEST
|
||||||
|
|
||||||
|
// Zelda and many more games seem to pass the Acid Test.
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
namespace Jit64
|
namespace Jit64
|
||||||
{
|
{
|
||||||
@ -70,11 +78,16 @@ namespace Jit64
|
|||||||
destination = SignExt26(inst.LI << 2);
|
destination = SignExt26(inst.LI << 2);
|
||||||
else
|
else
|
||||||
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
||||||
|
#ifdef ACID_TEST
|
||||||
|
if (inst.LK)
|
||||||
|
AND(32, M(&CR), Imm32(~(0xFF000000)));
|
||||||
|
#endif
|
||||||
|
|
||||||
WriteExit(destination, 0);
|
WriteExit(destination, 0);
|
||||||
} //else we were merged with the next block, we only need the link above, if that
|
}
|
||||||
else {
|
else {
|
||||||
PanicAlert("bx not last instruction of block"); // this should not happen atm
|
// TODO: investigate the good old method of merging blocks here.
|
||||||
|
PanicAlert("bx not last instruction of block"); // this should not happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,18 +184,21 @@ namespace Jit64
|
|||||||
|
|
||||||
if((inst.BO & 16) == 0)
|
if((inst.BO & 16) == 0)
|
||||||
{
|
{
|
||||||
|
PanicAlert("Bizarro bcctrx %08x, not supported.", inst.hex);
|
||||||
_assert_msg_(DYNA_REC, 0, "Bizarro bcctrx");
|
_assert_msg_(DYNA_REC, 0, "Bizarro bcctrx");
|
||||||
|
/*
|
||||||
fastway = false;
|
fastway = false;
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC+4));
|
MOV(32, M(&PC), Imm32(js.compilerPC+4));
|
||||||
MOV(32, R(EAX), M(&CR));
|
MOV(32, R(EAX), M(&CR));
|
||||||
XOR(32, R(ECX), R(ECX));
|
XOR(32, R(ECX), R(ECX));
|
||||||
AND(32, R(EAX), Imm32(0x80000000>>inst.BI));
|
AND(32, R(EAX), Imm32(0x80000000 >> inst.BI));
|
||||||
|
|
||||||
CCFlags branch;
|
CCFlags branch;
|
||||||
if(inst.BO & 8)
|
if(inst.BO & 8)
|
||||||
branch = CC_NZ;
|
branch = CC_NZ;
|
||||||
else
|
else
|
||||||
branch = CC_Z;
|
branch = CC_Z;
|
||||||
|
*/
|
||||||
// TODO(ector): Why is this commented out?
|
// TODO(ector): Why is this commented out?
|
||||||
//SETcc(branch, R(ECX));
|
//SETcc(branch, R(ECX));
|
||||||
// check for EBX
|
// check for EBX
|
||||||
@ -205,11 +221,17 @@ namespace Jit64
|
|||||||
if (inst.hex == 0x4e800020)
|
if (inst.hex == 0x4e800020)
|
||||||
{
|
{
|
||||||
//CDynaRegCache::Flush();
|
//CDynaRegCache::Flush();
|
||||||
|
// This below line can be used to prove that blr "eats flags" in practice.
|
||||||
|
// This observation will let us do a lot of fun observations.
|
||||||
|
#ifdef ACID_TEST
|
||||||
|
AND(32, M(&CR), Imm32(~(0xFF000000)));
|
||||||
|
#endif
|
||||||
MOV(32, R(EAX), M(&LR));
|
MOV(32, R(EAX), M(&LR));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
WriteExitDestInEAX(0);
|
WriteExitDestInEAX(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Call interpreter
|
||||||
Default(inst);
|
Default(inst);
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
WriteExitDestInEAX(0);
|
WriteExitDestInEAX(0);
|
||||||
|
@ -139,7 +139,7 @@ namespace Jit64
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Still here? Do regular path.
|
//Still here? Do regular path.
|
||||||
#if defined(_M_X64) && defined(_WIN32)
|
#if defined(_M_X64)
|
||||||
if (accessSize == 8 || accessSize == 16 || !jo.enableFastMem) {
|
if (accessSize == 8 || accessSize == 16 || !jo.enableFastMem) {
|
||||||
#else
|
#else
|
||||||
if (true) {
|
if (true) {
|
||||||
@ -173,154 +173,6 @@ namespace Jit64
|
|||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void lfs(UGeckoInstruction inst)
|
|
||||||
{
|
|
||||||
INSTRUCTION_START;
|
|
||||||
int d = inst.RD;
|
|
||||||
int a = inst.RA;
|
|
||||||
if (!a)
|
|
||||||
{
|
|
||||||
Default(inst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s32 offset = (s32)(s16)inst.SIMM_16;
|
|
||||||
|
|
||||||
gpr.Flush(FLUSH_VOLATILE);
|
|
||||||
gpr.Lock(d, a);
|
|
||||||
|
|
||||||
MOV(32, R(ABI_PARAM1), gpr.R(a));
|
|
||||||
#ifdef _M_X64
|
|
||||||
if (!jo.noAssumeFPLoadFromMem)
|
|
||||||
{
|
|
||||||
MOV(32, R(EAX), MComplex(RBX, ABI_PARAM1, SCALE_1, offset));
|
|
||||||
//#else
|
|
||||||
// MOV(32, R(EAX), MDisp(ABI_PARAM1, (u32)Memory::GetMainRAMPtr() + (u32)offset));
|
|
||||||
//#endif
|
|
||||||
BSWAP(32, EAX);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
SafeLoadRegToEAX(ABI_PARAM1, 32, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOV(32, M(&temp32), R(EAX));
|
|
||||||
fpr.Lock(d);
|
|
||||||
fpr.LoadToX64(d, false);
|
|
||||||
CVTSS2SD(fpr.RX(d), M(&temp32));
|
|
||||||
MOVDDUP(fpr.RX(d), fpr.R(d));
|
|
||||||
gpr.UnlockAll();
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfd(UGeckoInstruction inst)
|
|
||||||
{
|
|
||||||
INSTRUCTION_START;
|
|
||||||
DISABLE_32BIT;
|
|
||||||
int d = inst.RD;
|
|
||||||
int a = inst.RA;
|
|
||||||
if (!a)
|
|
||||||
{
|
|
||||||
Default(inst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s32 offset = (s32)(s16)inst.SIMM_16;
|
|
||||||
gpr.Lock(a);
|
|
||||||
MOV(32, R(ABI_PARAM1), gpr.R(a));
|
|
||||||
MOV(64, R(EAX), MComplex(RBX, ABI_PARAM1, SCALE_1, offset));
|
|
||||||
BSWAP(64,EAX);
|
|
||||||
MOV(64, M(&temp64), R(EAX));
|
|
||||||
fpr.Lock(d);
|
|
||||||
fpr.LoadToX64(d, false);
|
|
||||||
MOVSD(fpr.RX(d), M(&temp64));
|
|
||||||
MOVDDUP(fpr.RX(d), fpr.R(d));
|
|
||||||
gpr.UnlockAll();
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stfd(UGeckoInstruction inst)
|
|
||||||
{
|
|
||||||
INSTRUCTION_START;
|
|
||||||
DISABLE_32BIT;
|
|
||||||
int s = inst.RS;
|
|
||||||
int a = inst.RA;
|
|
||||||
if (!a)
|
|
||||||
{
|
|
||||||
Default(inst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s32 offset = (s32)(s16)inst.SIMM_16;
|
|
||||||
gpr.Lock(a);
|
|
||||||
fpr.Lock(s);
|
|
||||||
fpr.LoadToX64(s, true, false);
|
|
||||||
MOVSD(M(&temp64), fpr.RX(s));
|
|
||||||
MOV(32, R(ABI_PARAM1), gpr.R(a));
|
|
||||||
MOV(64, R(EAX), M(&temp64));
|
|
||||||
BSWAP(64, EAX);
|
|
||||||
MOV(64, MComplex(RBX, ABI_PARAM1, SCALE_1, offset), R(EAX));
|
|
||||||
gpr.UnlockAll();
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stfs(UGeckoInstruction inst)
|
|
||||||
{
|
|
||||||
INSTRUCTION_START;
|
|
||||||
DISABLE_32BIT;
|
|
||||||
bool update = inst.OPCD & 1;
|
|
||||||
int s = inst.RS;
|
|
||||||
int a = inst.RA;
|
|
||||||
s32 offset = (s32)(s16)inst.SIMM_16;
|
|
||||||
|
|
||||||
if (a && !update)
|
|
||||||
{
|
|
||||||
gpr.Flush(FLUSH_VOLATILE);
|
|
||||||
gpr.Lock(a);
|
|
||||||
fpr.Lock(s);
|
|
||||||
MOV(32, R(ABI_PARAM2), gpr.R(a));
|
|
||||||
if (offset)
|
|
||||||
ADD(32, R(ABI_PARAM2), Imm32((u32)offset));
|
|
||||||
if (update && offset)
|
|
||||||
{
|
|
||||||
MOV(32, gpr.R(a), R(ABI_PARAM2));
|
|
||||||
}
|
|
||||||
CVTSD2SS(XMM0, fpr.R(s));
|
|
||||||
MOVSS(M(&temp32), XMM0);
|
|
||||||
MOV(32, R(ABI_PARAM1), M(&temp32));
|
|
||||||
|
|
||||||
TEST(32, R(ABI_PARAM2), Imm32(0x0C000000));
|
|
||||||
FixupBranch argh = J_CC(CC_NZ);
|
|
||||||
BSWAP(32, ABI_PARAM1);
|
|
||||||
MOV(32, MComplex(RBX, ABI_PARAM2, SCALE_1, 0), R(ABI_PARAM1));
|
|
||||||
FixupBranch arg2 = J();
|
|
||||||
SetJumpTarget(argh);
|
|
||||||
CALL((void *)&Memory::Write_U32);
|
|
||||||
SetJumpTarget(arg2);
|
|
||||||
gpr.UnlockAll();
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Default(inst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void lfsx(UGeckoInstruction inst)
|
|
||||||
{
|
|
||||||
INSTRUCTION_START;
|
|
||||||
DISABLE_32BIT;
|
|
||||||
fpr.Lock(inst.RS);
|
|
||||||
fpr.LoadToX64(inst.RS, false, true);
|
|
||||||
MOV(32, R(EAX), gpr.R(inst.RB));
|
|
||||||
if (inst.RA)
|
|
||||||
ADD(32, R(EAX), gpr.R(inst.RA));
|
|
||||||
MOV(32, R(EAX), MComplex(RBX, EAX, SCALE_1, 0));
|
|
||||||
BSWAP(32, EAX);
|
|
||||||
MOV(32, M(&temp32), R(EAX));
|
|
||||||
CVTSS2SD(XMM0, M(&temp32));
|
|
||||||
MOVDDUP(fpr.R(inst.RS).GetSimpleReg(), R(XMM0));
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero cache line.
|
// Zero cache line.
|
||||||
void dcbz(UGeckoInstruction inst)
|
void dcbz(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
|
204
Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp
Normal file
204
Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
// Copyright (C) 2003-2008 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/
|
||||||
|
|
||||||
|
// TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only.
|
||||||
|
// Should give a very noticable speed boost to paired single heavy code.
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "../PowerPC.h"
|
||||||
|
#include "../../Core.h"
|
||||||
|
#include "../../HW/GPFifo.h"
|
||||||
|
#include "../../HW/CommandProcessor.h"
|
||||||
|
#include "../../HW/PixelEngine.h"
|
||||||
|
#include "../../HW/Memmap.h"
|
||||||
|
#include "../PPCTables.h"
|
||||||
|
#include "x64Emitter.h"
|
||||||
|
#include "ABI.h"
|
||||||
|
|
||||||
|
#include "Jit.h"
|
||||||
|
#include "JitCache.h"
|
||||||
|
#include "JitAsm.h"
|
||||||
|
#include "JitRegCache.h"
|
||||||
|
|
||||||
|
// #define INSTRUCTION_START Default(inst); return;
|
||||||
|
#define INSTRUCTION_START
|
||||||
|
|
||||||
|
#ifdef _M_IX86
|
||||||
|
#define DISABLE_32BIT Default(inst); return;
|
||||||
|
#else
|
||||||
|
#define DISABLE_32BIT ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Jit64
|
||||||
|
{
|
||||||
|
|
||||||
|
static u64 GC_ALIGNED16(temp64);
|
||||||
|
static u32 GC_ALIGNED16(temp32);
|
||||||
|
|
||||||
|
// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so common,
|
||||||
|
// and pshufb could help a lot.
|
||||||
|
// Also add hacks for things like lfs/stfs the same reg consecutively, that is, simple memory moves.
|
||||||
|
|
||||||
|
void lfs(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
INSTRUCTION_START;
|
||||||
|
int d = inst.RD;
|
||||||
|
int a = inst.RA;
|
||||||
|
if (!a)
|
||||||
|
{
|
||||||
|
Default(inst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s32 offset = (s32)(s16)inst.SIMM_16;
|
||||||
|
|
||||||
|
gpr.Flush(FLUSH_VOLATILE);
|
||||||
|
gpr.Lock(d, a);
|
||||||
|
|
||||||
|
MOV(32, R(ABI_PARAM1), gpr.R(a));
|
||||||
|
#ifdef _M_X64
|
||||||
|
if (!jo.noAssumeFPLoadFromMem)
|
||||||
|
{
|
||||||
|
MOV(32, R(EAX), MComplex(RBX, ABI_PARAM1, SCALE_1, offset));
|
||||||
|
//#else
|
||||||
|
// MOV(32, R(EAX), MDisp(ABI_PARAM1, (u32)Memory::GetMainRAMPtr() + (u32)offset));
|
||||||
|
//#endif
|
||||||
|
BSWAP(32, EAX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
SafeLoadRegToEAX(ABI_PARAM1, 32, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOV(32, M(&temp32), R(EAX));
|
||||||
|
fpr.Lock(d);
|
||||||
|
fpr.LoadToX64(d, false);
|
||||||
|
CVTSS2SD(fpr.RX(d), M(&temp32));
|
||||||
|
MOVDDUP(fpr.RX(d), fpr.R(d));
|
||||||
|
gpr.UnlockAll();
|
||||||
|
fpr.UnlockAll();
|
||||||
|
}
|
||||||
|
void lfd(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
INSTRUCTION_START;
|
||||||
|
DISABLE_32BIT;
|
||||||
|
int d = inst.RD;
|
||||||
|
int a = inst.RA;
|
||||||
|
if (!a)
|
||||||
|
{
|
||||||
|
Default(inst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s32 offset = (s32)(s16)inst.SIMM_16;
|
||||||
|
gpr.Lock(a);
|
||||||
|
MOV(32, R(ABI_PARAM1), gpr.R(a));
|
||||||
|
MOV(64, R(EAX), MComplex(RBX, ABI_PARAM1, SCALE_1, offset));
|
||||||
|
BSWAP(64, EAX);
|
||||||
|
MOV(64, M(&temp64), R(EAX));
|
||||||
|
fpr.Lock(d);
|
||||||
|
fpr.LoadToX64(d, false);
|
||||||
|
MOVSD(fpr.RX(d), M(&temp64));
|
||||||
|
MOVDDUP(fpr.RX(d), fpr.R(d));
|
||||||
|
gpr.UnlockAll();
|
||||||
|
fpr.UnlockAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stfd(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
INSTRUCTION_START;
|
||||||
|
DISABLE_32BIT;
|
||||||
|
int s = inst.RS;
|
||||||
|
int a = inst.RA;
|
||||||
|
if (!a)
|
||||||
|
{
|
||||||
|
Default(inst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s32 offset = (s32)(s16)inst.SIMM_16;
|
||||||
|
gpr.Lock(a);
|
||||||
|
fpr.Lock(s);
|
||||||
|
fpr.LoadToX64(s, true, false);
|
||||||
|
MOVSD(M(&temp64), fpr.RX(s));
|
||||||
|
MOV(32, R(ABI_PARAM1), gpr.R(a));
|
||||||
|
MOV(64, R(EAX), M(&temp64));
|
||||||
|
BSWAP(64, EAX);
|
||||||
|
MOV(64, MComplex(RBX, ABI_PARAM1, SCALE_1, offset), R(EAX));
|
||||||
|
gpr.UnlockAll();
|
||||||
|
fpr.UnlockAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stfs(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
INSTRUCTION_START;
|
||||||
|
DISABLE_32BIT;
|
||||||
|
bool update = inst.OPCD & 1;
|
||||||
|
int s = inst.RS;
|
||||||
|
int a = inst.RA;
|
||||||
|
s32 offset = (s32)(s16)inst.SIMM_16;
|
||||||
|
|
||||||
|
if (a && !update)
|
||||||
|
{
|
||||||
|
gpr.Flush(FLUSH_VOLATILE);
|
||||||
|
gpr.Lock(a);
|
||||||
|
fpr.Lock(s);
|
||||||
|
MOV(32, R(ABI_PARAM2), gpr.R(a));
|
||||||
|
if (offset)
|
||||||
|
ADD(32, R(ABI_PARAM2), Imm32((u32)offset));
|
||||||
|
if (update && offset)
|
||||||
|
{
|
||||||
|
MOV(32, gpr.R(a), R(ABI_PARAM2));
|
||||||
|
}
|
||||||
|
CVTSD2SS(XMM0, fpr.R(s));
|
||||||
|
MOVSS(M(&temp32), XMM0);
|
||||||
|
MOV(32, R(ABI_PARAM1), M(&temp32));
|
||||||
|
|
||||||
|
TEST(32, R(ABI_PARAM2), Imm32(0x0C000000));
|
||||||
|
FixupBranch argh = J_CC(CC_NZ);
|
||||||
|
BSWAP(32, ABI_PARAM1);
|
||||||
|
MOV(32, MComplex(RBX, ABI_PARAM2, SCALE_1, 0), R(ABI_PARAM1));
|
||||||
|
FixupBranch arg2 = J();
|
||||||
|
SetJumpTarget(argh);
|
||||||
|
CALL((void *)&Memory::Write_U32);
|
||||||
|
SetJumpTarget(arg2);
|
||||||
|
gpr.UnlockAll();
|
||||||
|
fpr.UnlockAll();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Default(inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lfsx(UGeckoInstruction inst)
|
||||||
|
{
|
||||||
|
INSTRUCTION_START;
|
||||||
|
DISABLE_32BIT;
|
||||||
|
fpr.Lock(inst.RS);
|
||||||
|
fpr.LoadToX64(inst.RS, false, true);
|
||||||
|
MOV(32, R(EAX), gpr.R(inst.RB));
|
||||||
|
if (inst.RA)
|
||||||
|
ADD(32, R(EAX), gpr.R(inst.RA));
|
||||||
|
MOV(32, R(EAX), MComplex(RBX, EAX, SCALE_1, 0));
|
||||||
|
BSWAP(32, EAX);
|
||||||
|
MOV(32, M(&temp32), R(EAX));
|
||||||
|
CVTSS2SD(XMM0, M(&temp32));
|
||||||
|
MOVDDUP(fpr.R(inst.RS).GetSimpleReg(), R(XMM0));
|
||||||
|
fpr.UnlockAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
@ -35,8 +35,8 @@
|
|||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
#include "JitRegCache.h"
|
#include "JitRegCache.h"
|
||||||
|
|
||||||
// #define INSTRUCTION_START
|
// #define INSTRUCTION_START Default(inst); return;
|
||||||
#define INSTRUCTION_START Default(inst); return;
|
#define INSTRUCTION_START
|
||||||
|
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
#define DISABLE_32BIT Default(inst); return;
|
#define DISABLE_32BIT Default(inst); return;
|
||||||
@ -56,7 +56,7 @@ void WriteDual32(u64 value, u32 address)
|
|||||||
Memory::Write_U32((u32)value, address + 4);
|
Memory::Write_U32((u32)value, address + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const double GC_ALIGNED16(m_quantizeTableD[]) =
|
const double GC_ALIGNED16(m_quantizeTableD[]) =
|
||||||
{
|
{
|
||||||
(1 << 0), (1 << 1), (1 << 2), (1 << 3),
|
(1 << 0), (1 << 1), (1 << 2), (1 << 3),
|
||||||
(1 << 4), (1 << 5), (1 << 6), (1 << 7),
|
(1 << 4), (1 << 5), (1 << 6), (1 << 7),
|
||||||
@ -76,7 +76,7 @@ static const double GC_ALIGNED16(m_quantizeTableD[]) =
|
|||||||
1.0 / (1 << 4), 1.0 / (1 << 3), 1.0 / (1 << 2), 1.0 / (1 << 1),
|
1.0 / (1 << 4), 1.0 / (1 << 3), 1.0 / (1 << 2), 1.0 / (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const double GC_ALIGNED16(m_dequantizeTableD[]) =
|
const double GC_ALIGNED16(m_dequantizeTableD[]) =
|
||||||
{
|
{
|
||||||
1.0 / (1 << 0), 1.0 / (1 << 1), 1.0 / (1 << 2), 1.0 / (1 << 3),
|
1.0 / (1 << 0), 1.0 / (1 << 1), 1.0 / (1 << 2), 1.0 / (1 << 3),
|
||||||
1.0 / (1 << 4), 1.0 / (1 << 5), 1.0 / (1 << 6), 1.0 / (1 << 7),
|
1.0 / (1 << 4), 1.0 / (1 << 5), 1.0 / (1 << 6), 1.0 / (1 << 7),
|
||||||
@ -101,7 +101,6 @@ static const double GC_ALIGNED16(m_dequantizeTableD[]) =
|
|||||||
void psq_st(UGeckoInstruction inst)
|
void psq_st(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START;
|
INSTRUCTION_START;
|
||||||
DISABLE_32BIT;
|
|
||||||
if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers)
|
if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers)
|
||||||
{
|
{
|
||||||
Default(inst);
|
Default(inst);
|
||||||
@ -124,6 +123,7 @@ void psq_st(UGeckoInstruction inst)
|
|||||||
|
|
||||||
if (stType == QUANTIZE_FLOAT)
|
if (stType == QUANTIZE_FLOAT)
|
||||||
{
|
{
|
||||||
|
DISABLE_32BIT;
|
||||||
gpr.Flush(FLUSH_VOLATILE);
|
gpr.Flush(FLUSH_VOLATILE);
|
||||||
gpr.Lock(a);
|
gpr.Lock(a);
|
||||||
fpr.Lock(s);
|
fpr.Lock(s);
|
||||||
@ -151,7 +151,10 @@ void psq_st(UGeckoInstruction inst)
|
|||||||
}
|
}
|
||||||
else if (stType == QUANTIZE_U8)
|
else if (stType == QUANTIZE_U8)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_VOLATILE);
|
gpr.FlushR(ABI_PARAM1);
|
||||||
|
gpr.FlushR(ABI_PARAM2);
|
||||||
|
gpr.LockX(ABI_PARAM1);
|
||||||
|
gpr.LockX(ABI_PARAM2);
|
||||||
gpr.Lock(a);
|
gpr.Lock(a);
|
||||||
fpr.Lock(s);
|
fpr.Lock(s);
|
||||||
if (update)
|
if (update)
|
||||||
@ -172,17 +175,22 @@ void psq_st(UGeckoInstruction inst)
|
|||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
MOV(16, MComplex(RBX, ABI_PARAM2, SCALE_1, 0), R(ABI_PARAM1));
|
MOV(16, MComplex(RBX, ABI_PARAM2, SCALE_1, 0), R(ABI_PARAM1));
|
||||||
#else
|
#else
|
||||||
BSWAP(32, ABI_PARAM1);
|
MOV(32, R(EAX), R(ABI_PARAM2));
|
||||||
SHR(32, R(ABI_PARAM1), Imm8(16));
|
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||||
CALL(&Memory::Write_U16);
|
MOV(16, MDisp(EAX, (u32)Memory::base), R(ABI_PARAM1));
|
||||||
#endif
|
#endif
|
||||||
if (update)
|
if (update)
|
||||||
MOV(32, gpr.R(a), R(ABI_PARAM2));
|
MOV(32, gpr.R(a), R(ABI_PARAM2));
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
|
gpr.UnlockAllX();
|
||||||
fpr.UnlockAll();
|
fpr.UnlockAll();
|
||||||
}
|
}
|
||||||
else if (stType == QUANTIZE_S16)
|
else if (stType == QUANTIZE_S16)
|
||||||
{
|
{
|
||||||
|
gpr.FlushR(ABI_PARAM1);
|
||||||
|
gpr.FlushR(ABI_PARAM2);
|
||||||
|
gpr.LockX(ABI_PARAM1);
|
||||||
|
gpr.LockX(ABI_PARAM2);
|
||||||
gpr.Lock(a);
|
gpr.Lock(a);
|
||||||
fpr.Lock(s);
|
fpr.Lock(s);
|
||||||
if (update)
|
if (update)
|
||||||
@ -200,15 +208,16 @@ void psq_st(UGeckoInstruction inst)
|
|||||||
PACKSSDW(XMM0, R(XMM0));
|
PACKSSDW(XMM0, R(XMM0));
|
||||||
MOVD_xmm(M(&temp64), XMM0);
|
MOVD_xmm(M(&temp64), XMM0);
|
||||||
MOV(32, R(ABI_PARAM1), M(&temp64));
|
MOV(32, R(ABI_PARAM1), M(&temp64));
|
||||||
#ifdef _M_X64
|
|
||||||
BSWAP(32, ABI_PARAM1);
|
BSWAP(32, ABI_PARAM1);
|
||||||
|
#ifdef _M_X64
|
||||||
MOV(32, MComplex(RBX, ABI_PARAM2, SCALE_1, 0), R(ABI_PARAM1));
|
MOV(32, MComplex(RBX, ABI_PARAM2, SCALE_1, 0), R(ABI_PARAM1));
|
||||||
#else
|
#else
|
||||||
BSWAP(32, ABI_PARAM1);
|
MOV(32, R(EAX), R(ABI_PARAM2));
|
||||||
PUSH(32, R(ABI_PARAM1));
|
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||||
CALL(&Memory::Write_U32);
|
MOV(32, MDisp(EAX, (u32)Memory::base), R(ABI_PARAM1));
|
||||||
#endif
|
#endif
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
|
gpr.UnlockAllX();
|
||||||
fpr.UnlockAll();
|
fpr.UnlockAll();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -223,7 +232,6 @@ void psq_st(UGeckoInstruction inst)
|
|||||||
void psq_l(UGeckoInstruction inst)
|
void psq_l(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START;
|
INSTRUCTION_START;
|
||||||
DISABLE_32BIT;
|
|
||||||
if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers)
|
if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers)
|
||||||
{
|
{
|
||||||
Default(inst);
|
Default(inst);
|
||||||
@ -241,11 +249,10 @@ void psq_l(UGeckoInstruction inst)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int offset = inst.SIMM_12;
|
int offset = inst.SIMM_12;
|
||||||
//INT3();
|
|
||||||
switch (ldType) {
|
switch (ldType) {
|
||||||
#ifdef _M_X64
|
|
||||||
case QUANTIZE_FLOAT:
|
case QUANTIZE_FLOAT:
|
||||||
{
|
{
|
||||||
|
#ifdef _M_X64
|
||||||
gpr.LoadToX64(inst.RA);
|
gpr.LoadToX64(inst.RA);
|
||||||
MOV(64, R(RAX), MComplex(RBX, gpr.R(inst.RA).GetSimpleReg(), 1, offset));
|
MOV(64, R(RAX), MComplex(RBX, gpr.R(inst.RA).GetSimpleReg(), 1, offset));
|
||||||
BSWAP(64, RAX);
|
BSWAP(64, RAX);
|
||||||
@ -253,17 +260,42 @@ void psq_l(UGeckoInstruction inst)
|
|||||||
fpr.LoadToX64(inst.RS, false);
|
fpr.LoadToX64(inst.RS, false);
|
||||||
X64Reg r = fpr.R(inst.RS).GetSimpleReg();
|
X64Reg r = fpr.R(inst.RS).GetSimpleReg();
|
||||||
CVTPS2PD(r, M(&psTemp[0]));
|
CVTPS2PD(r, M(&psTemp[0]));
|
||||||
SHUFPD(r, R(r),1);
|
SHUFPD(r, R(r), 1);
|
||||||
if (update)
|
if (update)
|
||||||
ADD(32, gpr.R(inst.RA), Imm32(offset));
|
ADD(32, gpr.R(inst.RA), Imm32(offset));
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
gpr.FlushR(ECX);
|
||||||
|
gpr.LockX(ECX);
|
||||||
|
gpr.LoadToX64(inst.RA);
|
||||||
|
// This can probably be optimized somewhat.
|
||||||
|
LEA(32, ECX, MDisp(gpr.R(inst.RA).GetSimpleReg(), offset));
|
||||||
|
AND(32, R(ECX), Imm32(Memory::MEMVIEW32_MASK));
|
||||||
|
MOV(32, R(EAX), MDisp(ECX, (u32)Memory::base));
|
||||||
|
BSWAP(32, RAX);
|
||||||
|
MOV(32, M(&psTemp[0]), R(RAX));
|
||||||
|
MOV(32, R(EAX), MDisp(ECX, (u32)Memory::base + 4));
|
||||||
|
BSWAP(32, RAX);
|
||||||
|
MOV(32, M(((float *)&psTemp[0]) + 1), R(RAX));
|
||||||
|
fpr.LoadToX64(inst.RS, false);
|
||||||
|
X64Reg r = fpr.R(inst.RS).GetSimpleReg();
|
||||||
|
CVTPS2PD(r, M(&psTemp[0]));
|
||||||
|
if (update)
|
||||||
|
ADD(32, gpr.R(inst.RA), Imm32(offset));
|
||||||
|
gpr.UnlockAllX();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case QUANTIZE_U8:
|
case QUANTIZE_U8:
|
||||||
{
|
{
|
||||||
gpr.LoadToX64(inst.RA);
|
gpr.LoadToX64(inst.RA);
|
||||||
XOR(32, R(EAX), R(EAX));
|
#ifdef _M_X64
|
||||||
MOV(16, R(EAX), MComplex(RBX, gpr.R(inst.RA).GetSimpleReg(), 1, offset));
|
MOVZX(32, 16, EAX, MComplex(RBX, gpr.R(inst.RA).GetSimpleReg(), 1, offset));
|
||||||
|
#else
|
||||||
|
LEA(32, EAX, MDisp(gpr.R(inst.RA).GetSimpleReg(), offset));
|
||||||
|
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||||
|
MOVZX(32, 16, EAX, MDisp(EAX, (u32)Memory::base));
|
||||||
|
#endif
|
||||||
MOV(32, M(&temp64), R(EAX));
|
MOV(32, M(&temp64), R(EAX));
|
||||||
MOVD_xmm(XMM0, M(&temp64));
|
MOVD_xmm(XMM0, M(&temp64));
|
||||||
// SSE4 optimization opportunity here.
|
// SSE4 optimization opportunity here.
|
||||||
@ -279,11 +311,16 @@ void psq_l(UGeckoInstruction inst)
|
|||||||
ADD(32, gpr.R(inst.RA), Imm32(offset));
|
ADD(32, gpr.R(inst.RA), Imm32(offset));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QUANTIZE_S16:
|
case QUANTIZE_S16:
|
||||||
{
|
{
|
||||||
gpr.LoadToX64(inst.RA);
|
gpr.LoadToX64(inst.RA);
|
||||||
|
#ifdef _M_X64
|
||||||
MOV(32, R(EAX), MComplex(RBX, gpr.R(inst.RA).GetSimpleReg(), 1, offset));
|
MOV(32, R(EAX), MComplex(RBX, gpr.R(inst.RA).GetSimpleReg(), 1, offset));
|
||||||
|
#else
|
||||||
|
LEA(32, EAX, MDisp(gpr.R(inst.RA).GetSimpleReg(), offset));
|
||||||
|
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||||
|
MOV(32, R(EAX), MDisp(EAX, (u32)Memory::base));
|
||||||
|
#endif
|
||||||
BSWAP(32, EAX);
|
BSWAP(32, EAX);
|
||||||
MOV(32, M(&temp64), R(EAX));
|
MOV(32, M(&temp64), R(EAX));
|
||||||
//INT3();
|
//INT3();
|
||||||
@ -308,12 +345,11 @@ void psq_l(UGeckoInstruction inst)
|
|||||||
MOV(32, R(ECX), Imm32((u32)&m_dequantizeTableD));
|
MOV(32, R(ECX), Imm32((u32)&m_dequantizeTableD));
|
||||||
MOVDDUP(r, MComplex(RCX, EAX, 8, 0));
|
MOVDDUP(r, MComplex(RCX, EAX, 8, 0));
|
||||||
*/
|
*/
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
// 4 0
|
// 4 0
|
||||||
// 6 0 //power tennis
|
// 6 0 //power tennis
|
||||||
// 5 0
|
// 5 0
|
||||||
//PanicAlert("ld:%i %i", ldType, (int)inst.W);
|
// PanicAlert("ld:%i %i", ldType, (int)inst.W);
|
||||||
Default(inst);
|
Default(inst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -292,8 +292,10 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
{
|
{
|
||||||
st.isFirstBlockOfFunction = true;
|
st.isFirstBlockOfFunction = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpa.any = true;
|
gpa.any = true;
|
||||||
fpa.any = false;
|
fpa.any = false;
|
||||||
|
|
||||||
enum Todo
|
enum Todo
|
||||||
{
|
{
|
||||||
JustCopy = 0, Flatten = 1, Nothing = 2
|
JustCopy = 0, Flatten = 1, Nothing = 2
|
||||||
@ -307,7 +309,6 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
if (iter != functions.end())
|
if (iter != functions.end())
|
||||||
{
|
{
|
||||||
SFunction &f = iter->second;
|
SFunction &f = iter->second;
|
||||||
|
|
||||||
if (f.flags & FFLAG_LEAF)
|
if (f.flags & FFLAG_LEAF)
|
||||||
{
|
{
|
||||||
//no reason to flatten
|
//no reason to flatten
|
||||||
@ -394,12 +395,14 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Do analysis of the code, look for dependencies etc
|
// Do analysis of the code, look for dependencies etc
|
||||||
int numSystemInstructions = 0;
|
int numSystemInstructions = 0;
|
||||||
|
|
||||||
for (int i=0; i<32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
gpa.firstRead[i] = -1;
|
gpa.firstRead[i] = -1;
|
||||||
gpa.firstWrite[i] = -1;
|
gpa.firstWrite[i] = -1;
|
||||||
@ -408,7 +411,7 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
}
|
}
|
||||||
|
|
||||||
gpa.any = true;
|
gpa.any = true;
|
||||||
for (size_t i=0; i<realsize; i++)
|
for (size_t i = 0; i < realsize; i++)
|
||||||
{
|
{
|
||||||
UGeckoInstruction inst = code[i].inst;
|
UGeckoInstruction inst = code[i].inst;
|
||||||
if (PPCTables::UsesFPU(inst))
|
if (PPCTables::UsesFPU(inst))
|
||||||
@ -416,7 +419,7 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
fpa.any = true;
|
fpa.any = true;
|
||||||
}
|
}
|
||||||
GekkoOPInfo *opinfo = GetOpInfo(code[i].inst);
|
GekkoOPInfo *opinfo = GetOpInfo(code[i].inst);
|
||||||
_assert_msg_(GEKKO,opinfo!=0,"Invalid Op - Error scanning %08x op %08x",address+i*4,inst);
|
_assert_msg_(GEKKO, opinfo != 0, "Invalid Op - Error scanning %08x op %08x",address+i*4,inst);
|
||||||
int flags = opinfo->flags;
|
int flags = opinfo->flags;
|
||||||
|
|
||||||
if (flags & FL_TIMER)
|
if (flags & FL_TIMER)
|
||||||
@ -424,7 +427,7 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
|
|
||||||
// Does the instruction output CR0?
|
// Does the instruction output CR0?
|
||||||
if (flags & FL_RC_BIT)
|
if (flags & FL_RC_BIT)
|
||||||
code[i].outputCR0 = inst.hex&1; //todo fix
|
code[i].outputCR0 = inst.hex & 1; //todo fix
|
||||||
else if ((flags & FL_SET_CRn) && inst.CRFD == 0)
|
else if ((flags & FL_SET_CRn) && inst.CRFD == 0)
|
||||||
code[i].outputCR0 = true;
|
code[i].outputCR0 = true;
|
||||||
else
|
else
|
||||||
@ -432,18 +435,18 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
|
|
||||||
// Does the instruction output CR1?
|
// Does the instruction output CR1?
|
||||||
if (flags & FL_RC_BIT_F)
|
if (flags & FL_RC_BIT_F)
|
||||||
code[i].outputCR1 = inst.hex&1; //todo fix
|
code[i].outputCR1 = inst.hex & 1; //todo fix
|
||||||
else if ((flags & FL_SET_CRn) && inst.CRFD == 1)
|
else if ((flags & FL_SET_CRn) && inst.CRFD == 1)
|
||||||
code[i].outputCR1 = true;
|
code[i].outputCR1 = true;
|
||||||
else
|
else
|
||||||
code[i].outputCR1 = (flags & FL_SET_CR1) ? true : false;
|
code[i].outputCR1 = (flags & FL_SET_CR1) ? true : false;
|
||||||
|
|
||||||
for (int j=0; j<3; j++)
|
for (int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
code[i].fregsIn[j] = -1;
|
code[i].fregsIn[j] = -1;
|
||||||
code[i].regsIn[j] = -1;
|
code[i].regsIn[j] = -1;
|
||||||
}
|
}
|
||||||
for (int j=0; j<2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
code[i].regsOut[j] = -1;
|
code[i].regsOut[j] = -1;
|
||||||
|
|
||||||
code[i].fregOut=-1;
|
code[i].fregOut=-1;
|
||||||
@ -485,14 +488,21 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
break;
|
break;
|
||||||
case OPTYPE_LOADFP:
|
case OPTYPE_LOADFP:
|
||||||
break;
|
break;
|
||||||
|
case OPTYPE_BRANCH:
|
||||||
|
if (code[i].inst.hex == 0x4e800020)
|
||||||
|
{
|
||||||
|
// For analysis purposes, we can assume that blr eats flags.
|
||||||
|
code[i].outputCR0 = true;
|
||||||
|
code[i].outputCR1 = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPTYPE_SYSTEM:
|
case OPTYPE_SYSTEM:
|
||||||
case OPTYPE_SYSTEMFP:
|
case OPTYPE_SYSTEMFP:
|
||||||
numSystemInstructions++;
|
numSystemInstructions++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j=0; j<numIn; j++)
|
for (int j = 0; j < numIn; j++)
|
||||||
{
|
{
|
||||||
int r = code[i].regsIn[j];
|
int r = code[i].regsIn[j];
|
||||||
if (gpa.firstRead[r] == -1)
|
if (gpa.firstRead[r] == -1)
|
||||||
@ -501,7 +511,7 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
gpa.numReads[r]++;
|
gpa.numReads[r]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j=0; j<numOut; j++)
|
for (int j = 0; j < numOut; j++)
|
||||||
{
|
{
|
||||||
int r = code[i].regsOut[j];
|
int r = code[i].regsOut[j];
|
||||||
if (gpa.firstWrite[r] == -1)
|
if (gpa.firstWrite[r] == -1)
|
||||||
@ -516,7 +526,7 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
bool wantsCR0 = true;
|
bool wantsCR0 = true;
|
||||||
bool wantsCR1 = true;
|
bool wantsCR1 = true;
|
||||||
bool wantsPS1 = true;
|
bool wantsPS1 = true;
|
||||||
for (int i=realsize-1; i; i--)
|
for (int i = realsize - 1; i; i--)
|
||||||
{
|
{
|
||||||
if (code[i].outputCR0)
|
if (code[i].outputCR0)
|
||||||
wantsCR0 = false;
|
wantsCR0 = false;
|
||||||
@ -527,12 +537,13 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
wantsCR0 |= code[i].wantsCR0;
|
wantsCR0 |= code[i].wantsCR0;
|
||||||
wantsCR1 |= code[i].wantsCR1;
|
wantsCR1 |= code[i].wantsCR1;
|
||||||
wantsPS1 |= code[i].wantsPS1;
|
wantsPS1 |= code[i].wantsPS1;
|
||||||
|
|
||||||
code[i].wantsCR0 = wantsCR0;
|
code[i].wantsCR0 = wantsCR0;
|
||||||
code[i].wantsCR1 = wantsCR1;
|
code[i].wantsCR1 = wantsCR1;
|
||||||
code[i].wantsPS1 = wantsPS1;
|
code[i].wantsPS1 = wantsPS1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Time for code shuffling, taking into account the above dependency analysis.
|
||||||
|
bool successful_shuffle = false;
|
||||||
//Move compares
|
//Move compares
|
||||||
// Try to push compares as close as possible to the following branch
|
// Try to push compares as close as possible to the following branch
|
||||||
// this way we can do neat stuff like combining compare and branch
|
// this way we can do neat stuff like combining compare and branch
|
||||||
@ -557,8 +568,10 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
else merge!
|
else merge!
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
if (successful_shuffle) {
|
||||||
|
// Disasm before and after, display side by side
|
||||||
|
}
|
||||||
// Decide what regs to potentially regcache
|
// Decide what regs to potentially regcache
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@ -566,7 +579,7 @@ PPCAnalyst::CodeOp *PPCAnalyst::Flatten(u32 address, u32 &realsize, BlockStats &
|
|||||||
// Adds the function to the list, unless it's already there
|
// Adds the function to the list, unless it's already there
|
||||||
PPCAnalyst::SFunction *PPCAnalyst::AddFunction(u32 startAddr)
|
PPCAnalyst::SFunction *PPCAnalyst::AddFunction(u32 startAddr)
|
||||||
{
|
{
|
||||||
if (startAddr<0x80000010)
|
if (startAddr < 0x80000010)
|
||||||
return 0;
|
return 0;
|
||||||
XFuncMap::iterator iter = functions.find(startAddr);
|
XFuncMap::iterator iter = functions.find(startAddr);
|
||||||
if (iter != functions.end())
|
if (iter != functions.end())
|
||||||
@ -643,9 +656,7 @@ void PPCAnalyst::FindFunctionsAfterBLR()
|
|||||||
if (!f)
|
if (!f)
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
{
|
|
||||||
location += f->size * 4;
|
location += f->size * 4;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -656,7 +667,7 @@ void PPCAnalyst::FindFunctionsAfterBLR()
|
|||||||
void PPCAnalyst::FindFunctions(u32 startAddr, u32 endAddr)
|
void PPCAnalyst::FindFunctions(u32 startAddr, u32 endAddr)
|
||||||
{
|
{
|
||||||
//Step 1: Find all functions
|
//Step 1: Find all functions
|
||||||
FindFunctionsFromBranches(startAddr,endAddr);
|
FindFunctionsFromBranches(startAddr, endAddr);
|
||||||
|
|
||||||
|
|
||||||
LOG(HLE,"Memory scan done. Found %i functions.",functions.size());
|
LOG(HLE,"Memory scan done. Found %i functions.",functions.size());
|
||||||
@ -861,30 +872,29 @@ bool PPCAnalyst::SaveFuncDB(const TCHAR *filename)
|
|||||||
|
|
||||||
bool PPCAnalyst::LoadFuncDB(const TCHAR *filename)
|
bool PPCAnalyst::LoadFuncDB(const TCHAR *filename)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(filename,"rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
LOG(HLE,"Database load failed");
|
LOG(HLE, "Database load failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
u32 fcount=0;
|
u32 fcount = 0;
|
||||||
fread(&fcount,4,1,f);
|
fread(&fcount, 4, 1, f);
|
||||||
for (size_t i=0; i<fcount; i++)
|
for (size_t i = 0; i < fcount; i++)
|
||||||
{
|
{
|
||||||
FuncDesc temp;
|
FuncDesc temp;
|
||||||
memset(&temp, 0, sizeof(temp));
|
memset(&temp, 0, sizeof(temp));
|
||||||
|
|
||||||
fread(&temp,sizeof(temp),1,f);
|
fread(&temp, sizeof(temp), 1, f);
|
||||||
SDBFunc f;
|
SDBFunc f;
|
||||||
f.name = temp.name;
|
f.name = temp.name;
|
||||||
f.size = temp.size;
|
f.size = temp.size;
|
||||||
|
|
||||||
database[temp.checkSum] = f;
|
database[temp.checkSum] = f;
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
UseFuncDB();
|
UseFuncDB();
|
||||||
LOG(HLE,"Database load successful");
|
LOG(HLE, "Database load successful");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,7 +976,7 @@ void PPCAnalyst::PrintCallers(u32 funcAddr)
|
|||||||
void PPCAnalyst::GetAllFuncs(functionGetterCallback callback)
|
void PPCAnalyst::GetAllFuncs(functionGetterCallback callback)
|
||||||
{
|
{
|
||||||
XFuncMap::iterator iter = functions.begin();
|
XFuncMap::iterator iter = functions.begin();
|
||||||
while(iter!=functions.end())
|
while (iter != functions.end())
|
||||||
{
|
{
|
||||||
callback(&(iter->second));
|
callback(&(iter->second));
|
||||||
iter++;
|
iter++;
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include "Debugger/PPCDebugInterface.h"
|
#include "Debugger/PPCDebugInterface.h"
|
||||||
#include "Debugger/Debugger_SymbolMap.h"
|
#include "Debugger/Debugger_SymbolMap.h"
|
||||||
|
#include "PowerPC/PPCAnalyst.h"
|
||||||
|
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
#include "LogManager.h"
|
#include "LogManager.h"
|
||||||
@ -64,6 +65,8 @@ BEGIN_EVENT_TABLE(CCodeWindow, wxFrame)
|
|||||||
EVT_MENU(IDM_REGISTERWINDOW, CCodeWindow::OnToggleRegisterWindow)
|
EVT_MENU(IDM_REGISTERWINDOW, CCodeWindow::OnToggleRegisterWindow)
|
||||||
EVT_MENU(IDM_BREAKPOINTWINDOW, CCodeWindow::OnToggleBreakPointWindow)
|
EVT_MENU(IDM_BREAKPOINTWINDOW, CCodeWindow::OnToggleBreakPointWindow)
|
||||||
EVT_MENU(IDM_MEMORYWINDOW, CCodeWindow::OnToggleMemoryWindow)
|
EVT_MENU(IDM_MEMORYWINDOW, CCodeWindow::OnToggleMemoryWindow)
|
||||||
|
|
||||||
|
EVT_MENU(IDM_SCANFUNCTIONS, CCodeWindow::OnSymbolsMenu)
|
||||||
// toolbar
|
// toolbar
|
||||||
EVT_MENU(IDM_DEBUG_GO, CCodeWindow::OnCodeStep)
|
EVT_MENU(IDM_DEBUG_GO, CCodeWindow::OnCodeStep)
|
||||||
EVT_MENU(IDM_STEP, CCodeWindow::OnCodeStep)
|
EVT_MENU(IDM_STEP, CCodeWindow::OnCodeStep)
|
||||||
@ -195,14 +198,14 @@ void CCodeWindow::CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParam
|
|||||||
wxMenuBar* pMenuBar = new wxMenuBar(wxMB_DOCKABLE);
|
wxMenuBar* pMenuBar = new wxMenuBar(wxMB_DOCKABLE);
|
||||||
|
|
||||||
{
|
{
|
||||||
wxMenu* pDebugMenu = new wxMenu;
|
wxMenu* pCoreMenu = new wxMenu;
|
||||||
wxMenuItem* interpreter = pDebugMenu->Append(IDM_INTERPRETER, _T("&Interpreter"), wxEmptyString, wxITEM_CHECK);
|
wxMenuItem* interpreter = pCoreMenu->Append(IDM_INTERPRETER, _T("&Interpreter"), wxEmptyString, wxITEM_CHECK);
|
||||||
interpreter->Check(!_LocalCoreStartupParameter.bUseDynarec);
|
interpreter->Check(!_LocalCoreStartupParameter.bUseDynarec);
|
||||||
|
|
||||||
// wxMenuItem* dualcore = pDebugMenu->Append(IDM_DUALCORE, _T("&DualCore"), wxEmptyString, wxITEM_CHECK);
|
// wxMenuItem* dualcore = pDebugMenu->Append(IDM_DUALCORE, _T("&DualCore"), wxEmptyString, wxITEM_CHECK);
|
||||||
// dualcore->Check(_LocalCoreStartupParameter.bUseDualCore);
|
// dualcore->Check(_LocalCoreStartupParameter.bUseDualCore);
|
||||||
|
|
||||||
pMenuBar->Append(pDebugMenu, _T("&Core Startup"));
|
pMenuBar->Append(pCoreMenu, _T("&Core Startup"));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -225,6 +228,11 @@ void CCodeWindow::CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParam
|
|||||||
pMenuBar->Append(pDebugDialogs, _T("&Views"));
|
pMenuBar->Append(pDebugDialogs, _T("&Views"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
wxMenu *pSymbolsMenu = new wxMenu;
|
||||||
|
pSymbolsMenu->Append(IDM_SCANFUNCTIONS, _T("&Scan for functions"));
|
||||||
|
pMenuBar->Append(pSymbolsMenu, _T("&Symbols"));
|
||||||
|
}
|
||||||
SetMenuBar(pMenuBar);
|
SetMenuBar(pMenuBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,6 +254,23 @@ void CCodeWindow::JumpToAddress(u32 _Address)
|
|||||||
codeview->Center(_Address);
|
codeview->Center(_Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
if (Core::GetState() == Core::CORE_UNINITIALIZED)
|
||||||
|
{
|
||||||
|
// TODO: disable menu items instead :P
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (event.GetId())
|
||||||
|
{
|
||||||
|
case IDM_SCANFUNCTIONS:
|
||||||
|
PPCAnalyst::FindFunctions(0x80003100, 0x80400000);
|
||||||
|
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
|
||||||
|
Debugger::GetFromAnalyzer();
|
||||||
|
NotifyMapLoaded();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CCodeWindow::OnCodeStep(wxCommandEvent& event)
|
void CCodeWindow::OnCodeStep(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
@ -537,6 +562,7 @@ void CCodeWindow::OnToggleMemoryWindow(wxCommandEvent& event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCodeWindow::OnHostMessage(wxCommandEvent& event)
|
void CCodeWindow::OnHostMessage(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
switch (event.GetId())
|
switch (event.GetId())
|
||||||
@ -582,13 +608,13 @@ void CCodeWindow::PopulateToolbar(wxToolBar* toolBar)
|
|||||||
h = m_Bitmaps[Toolbar_DebugGo].GetHeight();
|
h = m_Bitmaps[Toolbar_DebugGo].GetHeight();
|
||||||
|
|
||||||
toolBar->SetToolBitmapSize(wxSize(w, h));
|
toolBar->SetToolBitmapSize(wxSize(w, h));
|
||||||
toolBar->AddTool(IDM_DEBUG_GO, _T("Play"), m_Bitmaps[Toolbar_DebugGo], _T("Delete the selected BreakPoint or MemoryCheck"));
|
toolBar->AddTool(IDM_DEBUG_GO, _T("Play"), m_Bitmaps[Toolbar_DebugGo]);
|
||||||
toolBar->AddTool(IDM_STEP, _T("Step"), m_Bitmaps[Toolbar_Step], _T("Add BreakPoint..."));
|
toolBar->AddTool(IDM_STEP, _T("Step"), m_Bitmaps[Toolbar_Step]);
|
||||||
toolBar->AddTool(IDM_STEPOVER, _T("Step Over"), m_Bitmaps[Toolbar_StepOver], _T("Add BreakPoint..."));
|
toolBar->AddTool(IDM_STEPOVER, _T("Step Over"), m_Bitmaps[Toolbar_StepOver]);
|
||||||
toolBar->AddTool(IDM_SKIP, _T("Skip"), m_Bitmaps[Toolbar_Skip], _T("Add BreakPoint..."));
|
toolBar->AddTool(IDM_SKIP, _T("Skip"), m_Bitmaps[Toolbar_Skip]);
|
||||||
toolBar->AddSeparator();
|
toolBar->AddSeparator();
|
||||||
toolBar->AddTool(IDM_GOTOPC, _T("Goto PC"), m_Bitmaps[Toolbar_GotoPC], _T("Add BreakPoint..."));
|
toolBar->AddTool(IDM_GOTOPC, _T("Goto PC"), m_Bitmaps[Toolbar_GotoPC]);
|
||||||
toolBar->AddTool(IDM_SETPC, _T("Set PC"), m_Bitmaps[Toolbar_SetPC], _T("Add BreakPoint..."));
|
toolBar->AddTool(IDM_SETPC, _T("Set PC"), m_Bitmaps[Toolbar_SetPC]);
|
||||||
toolBar->AddSeparator();
|
toolBar->AddSeparator();
|
||||||
toolBar->AddControl(new wxTextCtrl(toolBar, IDM_ADDRBOX, _T("")));
|
toolBar->AddControl(new wxTextCtrl(toolBar, IDM_ADDRBOX, _T("")));
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ class CCodeWindow
|
|||||||
IDM_REGISTERWINDOW,
|
IDM_REGISTERWINDOW,
|
||||||
IDM_BREAKPOINTWINDOW,
|
IDM_BREAKPOINTWINDOW,
|
||||||
IDM_MEMORYWINDOW,
|
IDM_MEMORYWINDOW,
|
||||||
|
IDM_SCANFUNCTIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -120,6 +121,7 @@ class CCodeWindow
|
|||||||
void OnToggleLogWindow(wxCommandEvent& event);
|
void OnToggleLogWindow(wxCommandEvent& event);
|
||||||
void OnToggleMemoryWindow(wxCommandEvent& event);
|
void OnToggleMemoryWindow(wxCommandEvent& event);
|
||||||
void OnHostMessage(wxCommandEvent& event);
|
void OnHostMessage(wxCommandEvent& event);
|
||||||
|
void OnSymbolsMenu(wxCommandEvent& event);
|
||||||
|
|
||||||
void CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParameter);
|
void CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParameter);
|
||||||
|
|
||||||
|
@ -63,9 +63,12 @@ bool BootCore(const std::string& _rFilename)
|
|||||||
StartUp.bRunCompareServer = false;
|
StartUp.bRunCompareServer = false;
|
||||||
StartUp.bEnableDebugging = g_pCodeWindow ? true : false; // RUNNING_DEBUG
|
StartUp.bEnableDebugging = g_pCodeWindow ? true : false; // RUNNING_DEBUG
|
||||||
std::string BaseDataPath;
|
std::string BaseDataPath;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
StartUp.hInstance = wxGetInstance();
|
StartUp.hInstance = wxGetInstance();
|
||||||
#endif
|
#ifdef _M_X64
|
||||||
|
StartUp.bUseFastMem = true;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
StartUp.AutoSetup(SCoreStartupParameter::BOOT_DEFAULT);
|
StartUp.AutoSetup(SCoreStartupParameter::BOOT_DEFAULT);
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ EVT_MENU(IDM_CONFIG_PAD_PLUGIN, CFrame::OnPluginPAD)
|
|||||||
EVT_MENU(IDM_BROWSE, CFrame::OnBrowse)
|
EVT_MENU(IDM_BROWSE, CFrame::OnBrowse)
|
||||||
EVT_MENU(IDM_TOGGLE_FULLSCREEN, CFrame::OnToggleFullscreen)
|
EVT_MENU(IDM_TOGGLE_FULLSCREEN, CFrame::OnToggleFullscreen)
|
||||||
EVT_MENU(IDM_TOGGLE_DUALCORE, CFrame::OnToggleDualCore)
|
EVT_MENU(IDM_TOGGLE_DUALCORE, CFrame::OnToggleDualCore)
|
||||||
|
EVT_MENU(IDM_TOGGLE_THROTTLE, CFrame::OnToggleThrottle)
|
||||||
EVT_HOST_COMMAND(wxID_ANY, CFrame::OnHostMessage)
|
EVT_HOST_COMMAND(wxID_ANY, CFrame::OnHostMessage)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
@ -230,6 +231,12 @@ CFrame::CreateMenu()
|
|||||||
pEmulationMenu->Append(pItem);
|
pEmulationMenu->Append(pItem);
|
||||||
pItem->Check(SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore);
|
pItem->Check(SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// throttling
|
||||||
|
wxMenuItem* pItem = new wxMenuItem(pEmulationMenu, IDM_TOGGLE_THROTTLE, _T("&Speed throttle"), wxEmptyString, wxITEM_CHECK);
|
||||||
|
pEmulationMenu->Append(pItem);
|
||||||
|
pItem->Check(SConfig::GetInstance().m_LocalCoreStartupParameter.bThrottle);
|
||||||
|
}
|
||||||
m_pMenuBar->Append(pEmulationMenu, _T("&Emulation"));
|
m_pMenuBar->Append(pEmulationMenu, _T("&Emulation"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +525,6 @@ CFrame::OnHostMessage(wxCommandEvent& event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IDM_BOOTING_STARTED:
|
case IDM_BOOTING_STARTED:
|
||||||
|
|
||||||
if (m_pBootProcessDialog == NULL)
|
if (m_pBootProcessDialog == NULL)
|
||||||
{
|
{
|
||||||
/* m_pBootProcessDialog = new wxProgressDialog
|
/* m_pBootProcessDialog = new wxProgressDialog
|
||||||
@ -537,7 +543,6 @@ CFrame::OnHostMessage(wxCommandEvent& event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IDM_BOOTING_ENDED:
|
case IDM_BOOTING_ENDED:
|
||||||
|
|
||||||
if (m_pBootProcessDialog != NULL)
|
if (m_pBootProcessDialog != NULL)
|
||||||
{
|
{
|
||||||
// m_pBootProcessDialog->Destroy();
|
// m_pBootProcessDialog->Destroy();
|
||||||
@ -547,7 +552,6 @@ CFrame::OnHostMessage(wxCommandEvent& event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IDM_UPDATESTATUSBAR:
|
case IDM_UPDATESTATUSBAR:
|
||||||
|
|
||||||
if (m_pStatusBar != NULL)
|
if (m_pStatusBar != NULL)
|
||||||
{
|
{
|
||||||
m_pStatusBar->SetStatusText(event.GetString());
|
m_pStatusBar->SetStatusText(event.GetString());
|
||||||
@ -557,24 +561,26 @@ CFrame::OnHostMessage(wxCommandEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED (event))
|
||||||
CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED (event))
|
|
||||||
{
|
{
|
||||||
ShowFullScreen(true);
|
ShowFullScreen(true);
|
||||||
UpdateGUI();
|
UpdateGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void CFrame::OnToggleDualCore(wxCommandEvent& WXUNUSED (event))
|
||||||
CFrame::OnToggleDualCore(wxCommandEvent& WXUNUSED (event))
|
|
||||||
{
|
{
|
||||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore = !SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore;
|
SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore = !SConfig::GetInstance().m_LocalCoreStartupParameter.bUseDualCore;
|
||||||
SConfig::GetInstance().SaveSettings();
|
SConfig::GetInstance().SaveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFrame::OnToggleThrottle(wxCommandEvent& WXUNUSED (event))
|
||||||
|
{
|
||||||
|
SConfig::GetInstance().m_LocalCoreStartupParameter.bThrottle = !SConfig::GetInstance().m_LocalCoreStartupParameter.bThrottle;
|
||||||
|
SConfig::GetInstance().SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void CFrame::OnKeyDown(wxKeyEvent& event)
|
||||||
CFrame::OnKeyDown(wxKeyEvent& event)
|
|
||||||
{
|
{
|
||||||
if (((event.GetKeyCode() == WXK_RETURN) && (event.GetModifiers() == wxMOD_ALT)) ||
|
if (((event.GetKeyCode() == WXK_RETURN) && (event.GetModifiers() == wxMOD_ALT)) ||
|
||||||
(event.GetKeyCode() == WXK_ESCAPE))
|
(event.GetKeyCode() == WXK_ESCAPE))
|
||||||
@ -589,8 +595,7 @@ CFrame::OnKeyDown(wxKeyEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void CFrame::UpdateGUI()
|
||||||
CFrame::UpdateGUI()
|
|
||||||
{
|
{
|
||||||
// buttons
|
// buttons
|
||||||
{
|
{
|
||||||
|
@ -66,6 +66,7 @@ class CFrame
|
|||||||
void OnBrowse(wxCommandEvent& event);
|
void OnBrowse(wxCommandEvent& event);
|
||||||
void OnToggleFullscreen(wxCommandEvent& event);
|
void OnToggleFullscreen(wxCommandEvent& event);
|
||||||
void OnToggleDualCore(wxCommandEvent& event);
|
void OnToggleDualCore(wxCommandEvent& event);
|
||||||
|
void OnToggleThrottle(wxCommandEvent& event);
|
||||||
void OnKeyDown(wxKeyEvent& event);
|
void OnKeyDown(wxKeyEvent& event);
|
||||||
void OnHostMessage(wxCommandEvent& event);
|
void OnHostMessage(wxCommandEvent& event);
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ enum
|
|||||||
IDM_CONFIG_PAD_PLUGIN,
|
IDM_CONFIG_PAD_PLUGIN,
|
||||||
IDM_TOGGLE_FULLSCREEN,
|
IDM_TOGGLE_FULLSCREEN,
|
||||||
IDM_TOGGLE_DUALCORE,
|
IDM_TOGGLE_DUALCORE,
|
||||||
|
IDM_TOGGLE_THROTTLE,
|
||||||
IDM_NOTIFYMAPLOADED,
|
IDM_NOTIFYMAPLOADED,
|
||||||
IDM_UPDATELOGDISPLAY,
|
IDM_UPDATELOGDISPLAY,
|
||||||
IDM_UPDATEDISASMDIALOG,
|
IDM_UPDATEDISASMDIALOG,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user