project64/Source/Project64-core/N64System/Recompiler/RecompilerClass.cpp

1144 lines
35 KiB
C++
Raw Normal View History

2016-01-27 09:11:59 +00:00
#include "stdafx.h"
#include <Project64-core/N64System/Recompiler/RecompilerClass.h>
#include <Project64-core/N64System/SystemGlobals.h>
#include <Project64-core/N64System/Recompiler/RecompilerCodeLog.h>
2016-01-27 09:11:59 +00:00
#include <Project64-core/N64System/N64Class.h>
#include <Project64-core/N64System/Interpreter/InterpreterCPU.h>
#include <Project64-core/ExceptionHandler.h>
CRecompiler::CRecompiler(CMipsMemoryVM & MMU, CRegisters & Registers, bool & EndEmulation) :
m_MMU(MMU),
m_Registers(Registers),
m_EndEmulation(EndEmulation),
m_MemoryStack(0),
PROGRAM_COUNTER(Registers.m_PROGRAM_COUNTER)
2016-01-27 09:11:59 +00:00
{
2016-09-26 11:10:11 +00:00
CFunctionMap::AllocateMemory();
ResetMemoryStackPos();
2016-01-27 09:11:59 +00:00
}
CRecompiler::~CRecompiler()
{
ResetRecompCode(false);
}
void CRecompiler::Run()
{
WriteTrace(TraceRecompiler, TraceDebug, "Start");
if (bRecordRecompilerAsm())
2016-01-27 09:11:59 +00:00
{
Start_Recompiler_Log();
2016-01-27 09:11:59 +00:00
}
if (!CRecompMemory::AllocateMemory())
{
WriteTrace(TraceRecompiler, TraceError, "AllocateMemory failed");
return;
}
if (!CFunctionMap::AllocateMemory())
{
WriteTrace(TraceRecompiler, TraceError, "AllocateMemory failed");
return;
}
m_EndEmulation = false;
#ifdef legacycode
*g_MemoryStack = (uint32_t)(RDRAM + (_GPR[29].W[0] & 0x1FFFFFFF));
2016-01-27 09:11:59 +00:00
#endif
__except_try()
{
if (g_System->LookUpMode() == FuncFind_VirtualLookup)
{
if (g_System->bSMM_ValidFunc())
{
RecompilerMain_VirtualTable_validate();
}
else
{
RecompilerMain_VirtualTable();
}
}
else if (g_System->LookUpMode() == FuncFind_ChangeMemory)
{
RecompilerMain_ChangeMemory();
}
else
{
if (g_System->bUseTlb())
{
if (g_System->bSMM_ValidFunc())
{
RecompilerMain_Lookup_validate_TLB();
}
else
{
RecompilerMain_Lookup_TLB();
}
}
else
{
if (g_System->bSMM_ValidFunc())
{
RecompilerMain_Lookup_validate();
}
else
{
RecompilerMain_Lookup();
}
}
}
}
__except_catch()
2016-01-27 09:11:59 +00:00
{
g_Notify->DisplayError(MSG_UNKNOWN_MEM_ACTION);
}
WriteTrace(TraceRecompiler, TraceDebug, "Done");
2016-01-27 09:11:59 +00:00
}
void CRecompiler::RecompilerMain_VirtualTable()
{
bool & Done = m_EndEmulation;
uint32_t & PC = PROGRAM_COUNTER;
while (!Done)
{
if (!m_MMU.ValidVaddr(PC))
2016-01-27 09:11:59 +00:00
{
m_Registers.DoTLBReadMiss(false, PC);
if (!m_MMU.ValidVaddr(PC))
2016-01-27 09:11:59 +00:00
{
g_Notify->DisplayError(stdstr_f("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PC).c_str());
return;
}
continue;
}
PCCompiledFunc_TABLE & table = FunctionTable()[PC >> 0xC];
uint32_t TableEntry = (PC & 0xFFF) >> 2;
if (table)
{
CCompiledFunc * info = table[TableEntry];
if (info != NULL)
{
(info->Function())();
continue;
}
}
CCompiledFunc * info = CompileCode();
2016-01-27 09:11:59 +00:00
if (info == NULL || m_EndEmulation)
{
break;
}
if (table == NULL)
{
table = new PCCompiledFunc[(0x1000 >> 2)];
if (table == NULL)
{
WriteTrace(TraceRecompiler, TraceError, "failed to allocate PCCompiledFunc");
g_Notify->FatalError(MSG_MEM_ALLOC_ERROR);
}
2016-10-04 19:58:11 +00:00
memset(table, 0, sizeof(PCCompiledFunc)* (0x1000 >> 2));
2016-01-27 09:11:59 +00:00
if (g_System->bSMM_Protect())
{
WriteTrace(TraceRecompiler, TraceError, "Create Table (%X): Index = %d", table, PC >> 0xC);
m_MMU.ProtectMemory(PC & ~0xFFF, PC | 0xFFF);
2016-01-27 09:11:59 +00:00
}
}
table[TableEntry] = info;
(info->Function())();
}
}
void CRecompiler::RecompilerMain_VirtualTable_validate()
{
g_Notify->BreakPoint(__FILE__, __LINE__);
2016-11-27 20:34:02 +00:00
#ifdef legacycode
PCCompiledFunc_TABLE * m_FunctionTable = m_Functions.GetFunctionTable();
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
while (!m_EndEmulation)
2016-01-27 09:11:59 +00:00
{
2016-11-27 20:34:02 +00:00
if (NextInstruction == DELAY_SLOT)
{
CCompiledFunc * Info = m_FunctionsDelaySlot.FindFunction(PROGRAM_COUNTER);
//Find Block on hash table
if (Info == NULL)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
#ifdef legacycode
if (!g_TLB->ValidVaddr(PROGRAM_COUNTER))
{
DoTLBMiss(NextInstruction == DELAY_SLOT, PROGRAM_COUNTER);
NextInstruction = NORMAL;
if (!g_TLB->ValidVaddr(PROGRAM_COUNTER))
{
g_Notify->DisplayError("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PROGRAM_COUNTER);
return;
}
continue;
}
#endif
//Find Block on hash table
Info = CompileDelaySlot(PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
if (Info == NULL || EndEmulation())
{
break;
}
}
const uint8_t * Block = Info->FunctionAddr();
if ((*Info->MemLocation[0] != Info->MemContents[0]) ||
(*Info->MemLocation[1] != Info->MemContents[1]))
{
ClearRecompCode_Virt((Info->VStartPC() - 0x1000) & ~0xFFF, 0x2000, Remove_ValidateFunc);
NextInstruction = DELAY_SLOT;
Info = NULL;
continue;
}
_asm {
pushad
call Block
popad
}
continue;
}
PCCompiledFunc_TABLE table = m_FunctionTable[PROGRAM_COUNTER >> 0xC];
if (table)
{
CCompiledFunc * info = table[(PROGRAM_COUNTER & 0xFFF) >> 2];
if (info != NULL)
{
if ((*info->MemLocation[0] != info->MemContents[0]) ||
(*info->MemLocation[1] != info->MemContents[1]))
{
ClearRecompCode_Virt((info->VStartPC() - 0x1000) & ~0xFFF, 0x3000, Remove_ValidateFunc);
info = NULL;
continue;
}
const uint8_t * Block = info->FunctionAddr();
_asm {
pushad
call Block
popad
}
continue;
}
}
g_Notify->BreakPoint(__FILE__, __LINE__);
#ifdef legacycode
if (!g_TLB->ValidVaddr(PROGRAM_COUNTER))
{
DoTLBMiss(NextInstruction == DELAY_SLOT, PROGRAM_COUNTER);
NextInstruction = NORMAL;
if (!g_TLB->ValidVaddr(PROGRAM_COUNTER))
{
g_Notify->DisplayError("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PROGRAM_COUNTER);
return;
}
}
#endif
CCompiledFunc * info = CompileCode();
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
if (info == NULL || EndEmulation())
{
break;
}
2016-01-27 09:11:59 +00:00
}
2016-11-27 20:34:02 +00:00
while (!m_EndEmulation)
2016-01-27 09:11:59 +00:00
{
if (!m_MMU.ValidVaddr(PROGRAM_COUNTER))
2016-11-27 20:34:02 +00:00
{
DoTLBMiss(NextInstruction == DELAY_SLOT, PROGRAM_COUNTER);
NextInstruction = NORMAL;
if (!m_MMU.ValidVaddr(PROGRAM_COUNTER))
2016-11-27 20:34:02 +00:00
{
g_Notify->DisplayError("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PROGRAM_COUNTER);
return;
}
}
if (NextInstruction == DELAY_SLOT)
{
CCompiledFunc * Info = m_FunctionsDelaySlot.FindFunction(PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
//Find Block on hash table
if (Info == NULL)
{
Info = CompileDelaySlot(PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
if (Info == NULL || EndEmulation())
{
break;
}
}
if (bSMM_ValidFunc())
{
if ((*Info->MemLocation[0] != Info->MemContents[0]) ||
(*Info->MemLocation[1] != Info->MemContents[1]))
{
ClearRecompCode_Virt((Info->StartPC() - 0x1000) & ~0xFFF, 0x2000, Remove_ValidateFunc);
NextInstruction = DELAY_SLOT;
Info = NULL;
continue;
}
}
const uint8_t * Block = Info->FunctionAddr();
_asm {
pushad
call Block
popad
}
continue;
}
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
CCompiledFunc * Info = m_Functions.FindFunction(PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
//Find Block on hash table
if (Info == NULL)
{
Info = CompileCode();
2016-01-27 09:11:59 +00:00
2016-11-27 20:34:02 +00:00
if (Info == NULL || EndEmulation())
{
break;
}
}
if (bSMM_ValidFunc())
{
if ((*Info->MemLocation[0] != Info->MemContents[0]) ||
(*Info->MemLocation[1] != Info->MemContents[1]))
{
ClearRecompCode_Virt((Info->StartPC() - 0x1000) & ~0xFFF, 0x3000, Remove_ValidateFunc);
Info = NULL;
continue;
}
}
const uint8_t * Block = Info->FunctionAddr();
_asm {
pushad
call Block
popad
}
2016-01-27 09:11:59 +00:00
}
2016-11-27 20:34:02 +00:00
#endif
2016-01-27 09:11:59 +00:00
}
void CRecompiler::RecompilerMain_Lookup()
{
while (!m_EndEmulation)
{
uint32_t PhysicalAddr = PROGRAM_COUNTER & 0x1FFFFFFF;
if (PhysicalAddr < g_System->RdramSize())
{
CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2];
if (info == NULL)
{
info = CompileCode();
2016-01-27 09:11:59 +00:00
if (info == NULL || m_EndEmulation)
{
break;
}
if (g_System->bSMM_Protect())
{
m_MMU.ProtectMemory(PROGRAM_COUNTER & ~0xFFF, PROGRAM_COUNTER | 0xFFF);
2016-01-27 09:11:59 +00:00
}
JumpTable()[PhysicalAddr >> 2] = info;
}
(info->Function())();
}
else
{
uint32_t opsExecuted = 0;
while (m_MMU.TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize())
2016-01-27 09:11:59 +00:00
{
CInterpreterCPU::ExecuteOps(g_System->CountPerOp());
opsExecuted += g_System->CountPerOp();
}
if (g_SyncSystem)
{
g_System->UpdateSyncCPU(g_SyncSystem, opsExecuted);
g_System->SyncCPU(g_SyncSystem);
}
}
}
/*
uint32_t Addr;
CCompiledFunc * Info;
//const uint8_t * Block;
while(!m_EndEmulation)
{
2016-11-27 20:34:02 +00:00
if (bUseTlb())
2016-01-27 09:11:59 +00:00
{
g_Notify->BreakPoint(__FILE__, __LINE__);
#ifdef legacycode
if (!g_TLB->TranslateVaddr(PROGRAM_COUNTER, Addr))
{
DoTLBMiss(NextInstruction == DELAY_SLOT,PROGRAM_COUNTER);
NextInstruction = NORMAL;
if (!TranslateVaddr(PROGRAM_COUNTER, &Addr)) {
g_Notify->DisplayError("Failed to translate PC to a PAddr: %X\n\nEmulation stopped",PROGRAM_COUNTER);
return;
}
}
#endif
} else {
Addr = PROGRAM_COUNTER & 0x1FFFFFFF;
}*/
/* if (NextInstruction == DELAY_SLOT) {
CCompiledFunc * Info = m_FunctionsDelaySlot.FindFunction(PROGRAM_COUNTER);
//Find Block on hash table
if (Info == NULL)
{
Info = CompileDelaySlot(PROGRAM_COUNTER);
if (Info == NULL || EndEmulation())
{
break;
}
}
if (bSMM_ValidFunc())
{
if ((*Info->MemLocation[0] != Info->MemContents[0]) ||
(*Info->MemLocation[1] != Info->MemContents[1]))
{
ClearRecompCode_Virt((Info->VStartPC() - 0x1000) & ~0xFFF,0x2000,Remove_ValidateFunc);
NextInstruction = DELAY_SLOT;
Info = NULL;
continue;
}
}
const uint8_t * Block = Info->FunctionAddr();
_asm {
pushad
call Block
popad
}
continue;
}
__try {
if (Addr > 0x10000000)
{
if (bRomInMemory())
{
if (Addr > 0x20000000)
{
WriteTraceF(TraceDebug,"Executing from non mapped space .1 PC: %X Addr: %X",PROGRAM_COUNTER, Addr);
g_Notify->DisplayError(GS(MSG_NONMAPPED_SPACE));
break;
}
Info = (CCompiledFunc *)*(JumpTable + (Addr >> 2));
} else {
if (PROGRAM_COUNTER >= 0xB0000000 && PROGRAM_COUNTER < (RomFileSize | 0xB0000000)) {
while (PROGRAM_COUNTER >= 0xB0000000 && PROGRAM_COUNTER < (RomFileSize | 0xB0000000)) {
ExecuteInterpreterOpCode();
}
continue;
} else {
WriteTraceF(TraceDebug,"Executing from non mapped space .1 PC: %X Addr: %X",PROGRAM_COUNTER, Addr);
g_Notify->DisplayError(GS(MSG_NONMAPPED_SPACE));
break;
}
}
} else {
Info = (CCompiledFunc *)*(JumpTable + (Addr >> 2));
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
if (PROGRAM_COUNTER >= 0xB0000000 && PROGRAM_COUNTER < (RomFileSize | 0xB0000000)) {
while (PROGRAM_COUNTER >= 0xB0000000 && PROGRAM_COUNTER < (RomFileSize | 0xB0000000)) {
ExecuteInterpreterOpCode();
}
continue;
} else {
WriteTraceF(TraceDebug,"Executing from non mapped space .2 PC: %X Addr: %X",PROGRAM_COUNTER, Addr);
g_Notify->DisplayError(GS(MSG_NONMAPPED_SPACE));
return;
}
}
if (Info == NULL)
{
Info = CompileCode();
2016-01-27 09:11:59 +00:00
if (Info == NULL || EndEmulation())
{
break;
}
*(JumpTable + (Addr >> 2)) = (void *)Info;
// if (SelfModCheck == ModCode_ProtectedMemory) {
// VirtualProtect(RDRAM + Addr, 4, PAGE_READONLY, &OldProtect);
// }
}
if (bSMM_ValidFunc())
{
if ((*Info->MemLocation[0] != Info->MemContents[0]) ||
(*Info->MemLocation[1] != Info->MemContents[1]))
{
ClearRecompCode_Virt((Info->VStartPC() - 0x1000) & ~0xFFF,0x3000,Remove_ValidateFunc);
Info = NULL;
continue;
}
}
g_Notify->BreakPoint(__FILE__, __LINE__);
#ifdef legacycode
if (Profiling && IndvidualBlock) {
static uint32_t ProfAddress = 0;
if ((PROGRAM_COUNTER & ~0xFFF) != ProfAddress) {
char Label[100];
ProfAddress = PROGRAM_COUNTER & ~0xFFF;
sprintf(Label,"PC: %X to %X",ProfAddress,ProfAddress+ 0xFFC);
// StartTimer(Label);
}
2016-11-27 20:34:02 +00:00
if (PROGRAM_COUNTER >= 0x800DD000 && PROGRAM_COUNTER <= 0x800DDFFC) {
2016-01-27 09:11:59 +00:00
char Label[100];
sprintf(Label,"PC: %X Block: %X",PROGRAM_COUNTER,Block);
StartTimer(Label);
2016-11-27 20:34:02 +00:00
}
2016-01-27 09:11:59 +00:00
// } else if ((Profiling || ShowCPUPer) && ProfilingLabel[0] == 0) {
// StartTimer("r4300i Running");
2016-11-27 20:34:02 +00:00
}
2016-01-27 09:11:59 +00:00
#endif
const uint8_t * Block = Info->FunctionAddr();
_asm {
pushad
call Block
popad
}
}*/
}
void CRecompiler::RecompilerMain_Lookup_TLB()
{
uint32_t PhysicalAddr;
while (!m_EndEmulation)
{
if (!m_MMU.TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr))
2016-01-27 09:11:59 +00:00
{
m_Registers.DoTLBReadMiss(false, PROGRAM_COUNTER);
if (!m_MMU.TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr))
2016-01-27 09:11:59 +00:00
{
g_Notify->DisplayError(stdstr_f("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PROGRAM_COUNTER).c_str());
m_EndEmulation = true;
}
continue;
}
if (PhysicalAddr < g_System->RdramSize())
{
CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2];
if (info == NULL)
{
info = CompileCode();
2016-01-27 09:11:59 +00:00
if (info == NULL || m_EndEmulation)
{
break;
}
if (g_System->bSMM_Protect())
{
m_MMU.ProtectMemory(PROGRAM_COUNTER & ~0xFFF, PROGRAM_COUNTER | 0xFFF);
2016-01-27 09:11:59 +00:00
}
JumpTable()[PhysicalAddr >> 2] = info;
}
(info->Function())();
}
else
{
uint32_t opsExecuted = 0;
while (m_MMU.TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize())
2016-01-27 09:11:59 +00:00
{
CInterpreterCPU::ExecuteOps(g_System->CountPerOp());
opsExecuted += g_System->CountPerOp();
}
if (g_SyncSystem)
{
g_System->UpdateSyncCPU(g_SyncSystem, opsExecuted);
g_System->SyncCPU(g_SyncSystem);
}
}
}
}
void CRecompiler::RecompilerMain_Lookup_validate()
{
while (!m_EndEmulation)
{
uint32_t PhysicalAddr = PROGRAM_COUNTER & 0x1FFFFFFF;
if (PhysicalAddr < g_System->RdramSize())
{
CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2];
if (info == NULL)
{
info = CompileCode();
2016-01-27 09:11:59 +00:00
if (info == NULL || m_EndEmulation)
{
break;
}
if (g_System->bSMM_Protect())
{
m_MMU.ProtectMemory(PROGRAM_COUNTER & ~0xFFF, PROGRAM_COUNTER | 0xFFF);
2016-01-27 09:11:59 +00:00
}
JumpTable()[PhysicalAddr >> 2] = info;
}
else
{
if (*(info->MemLocation(0)) != info->MemContents(0) ||
*(info->MemLocation(1)) != info->MemContents(1))
{
ClearRecompCode_Virt((info->EnterPC() - 0x1000) & ~0xFFF, 0x3000, Remove_ValidateFunc);
info = NULL;
continue;
}
}
(info->Function())();
}
else
{
uint32_t opsExecuted = 0;
while (m_MMU.TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize())
2016-01-27 09:11:59 +00:00
{
CInterpreterCPU::ExecuteOps(g_System->CountPerOp());
opsExecuted += g_System->CountPerOp();
}
if (g_SyncSystem)
{
g_System->UpdateSyncCPU(g_SyncSystem, opsExecuted);
g_System->SyncCPU(g_SyncSystem);
}
}
}
}
void CRecompiler::RecompilerMain_Lookup_validate_TLB()
{
WriteTrace(TraceRecompiler, TraceInfo, "Start");
bool & Done = m_EndEmulation;
uint32_t & PC = PROGRAM_COUNTER;
2016-01-27 09:11:59 +00:00
uint32_t PhysicalAddr;
while (!Done)
2016-01-27 09:11:59 +00:00
{
if (!m_MMU.TranslateVaddr(PC, PhysicalAddr))
2016-01-27 09:11:59 +00:00
{
m_Registers.DoTLBReadMiss(false, PC);
if (!m_MMU.TranslateVaddr(PC, PhysicalAddr))
2016-01-27 09:11:59 +00:00
{
g_Notify->DisplayError(stdstr_f("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PC).c_str());
Done = true;
2016-01-27 09:11:59 +00:00
}
continue;
}
if (PhysicalAddr < g_System->RdramSize())
{
CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2];
if (info == NULL)
{
info = CompileCode();
2016-01-27 09:11:59 +00:00
if (info == NULL || m_EndEmulation)
{
break;
}
if (g_System->bSMM_Protect())
{
m_MMU.ProtectMemory(PC & ~0xFFF, PC | 0xFFF);
2016-01-27 09:11:59 +00:00
}
JumpTable()[PhysicalAddr >> 2] = info;
}
else
{
if (*(info->MemLocation(0)) != info->MemContents(0) ||
*(info->MemLocation(1)) != info->MemContents(1))
{
if (PhysicalAddr > 0x1000)
{
ClearRecompCode_Phys((PhysicalAddr - 0x1000) & ~0xFFF, 0x3000, Remove_ValidateFunc);
}
else
{
ClearRecompCode_Phys(0, 0x2000, Remove_ValidateFunc);
}
info = JumpTable()[PhysicalAddr >> 2];
if (info != NULL)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
info = NULL;
}
continue;
}
}
2016-10-02 21:46:05 +00:00
if (bRecordExecutionTimes())
{
2016-10-04 19:58:11 +00:00
uint64_t PreNonCPUTime = g_System->m_CPU_Usage.NonCPUTime();
2016-10-02 21:46:05 +00:00
HighResTimeStamp StartTime, EndTime;
StartTime.SetToNow();
(info->Function())();
EndTime.SetToNow();
2016-10-04 19:58:11 +00:00
uint64_t PostNonCPUTime = g_System->m_CPU_Usage.NonCPUTime();
2016-10-02 21:46:05 +00:00
uint64_t TimeTaken = EndTime.GetMicroSeconds() - StartTime.GetMicroSeconds();
2016-10-04 19:58:11 +00:00
if (PostNonCPUTime >= PreNonCPUTime)
{
TimeTaken -= PostNonCPUTime - PreNonCPUTime;
}
else
{
TimeTaken -= PostNonCPUTime;
}
2016-10-02 21:46:05 +00:00
FUNCTION_PROFILE::iterator itr = m_BlockProfile.find(info->Function());
if (itr == m_BlockProfile.end())
{
FUNCTION_PROFILE_DATA data = { 0 };
data.Address = info->EnterPC();
std::pair<FUNCTION_PROFILE::iterator, bool> res = m_BlockProfile.insert(FUNCTION_PROFILE::value_type(info->Function(), data));
itr = res.first;
}
2016-10-04 19:58:11 +00:00
WriteTrace(TraceN64System, TraceNotice, "EndTime: %X StartTime: %X TimeTaken: %X", (uint32_t)(EndTime.GetMicroSeconds() & 0xFFFFFFFF), (uint32_t)(StartTime.GetMicroSeconds() & 0xFFFFFFFF), (uint32_t)TimeTaken);
2016-10-02 21:46:05 +00:00
itr->second.TimeTaken += TimeTaken;
}
else
{
(info->Function())();
}
2016-01-27 09:11:59 +00:00
}
else
{
uint32_t opsExecuted = 0;
while (m_MMU.TranslateVaddr(PC, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize())
2016-01-27 09:11:59 +00:00
{
CInterpreterCPU::ExecuteOps(g_System->CountPerOp());
opsExecuted += g_System->CountPerOp();
}
if (g_SyncSystem)
{
g_System->UpdateSyncCPU(g_SyncSystem, opsExecuted);
g_System->SyncCPU(g_SyncSystem);
}
}
}
WriteTrace(TraceRecompiler, TraceDebug, "Done");
2016-01-27 09:11:59 +00:00
}
void CRecompiler::Reset()
{
2016-09-26 11:10:11 +00:00
WriteTrace(TraceRecompiler, TraceDebug, "start");
2016-01-27 09:11:59 +00:00
ResetRecompCode(true);
ResetMemoryStackPos();
2016-09-26 11:10:11 +00:00
WriteTrace(TraceRecompiler, TraceDebug, "Done");
2016-01-27 09:11:59 +00:00
}
void CRecompiler::ResetRecompCode(bool bAllocate)
{
2016-09-26 11:10:11 +00:00
WriteTrace(TraceRecompiler, TraceDebug, "start");
2016-01-27 09:11:59 +00:00
CRecompMemory::Reset();
CFunctionMap::Reset(bAllocate);
for (CCompiledFuncList::iterator iter = m_Functions.begin(); iter != m_Functions.end(); iter++)
{
CCompiledFunc * Func = iter->second;
while (Func != NULL)
{
CCompiledFunc * CurrentFunc = Func;
Func = Func->Next();
delete CurrentFunc;
}
}
m_Functions.clear();
2016-09-26 11:10:11 +00:00
WriteTrace(TraceRecompiler, TraceDebug, "Done");
2016-01-27 09:11:59 +00:00
}
void CRecompiler::RecompilerMain_ChangeMemory()
{
g_Notify->BreakPoint(__FILE__, __LINE__);
#ifdef legacycode
uint32_t Value, Addr;
uint8_t * Block;
while (!EndEmulation())
2016-01-27 09:11:59 +00:00
{
if (UseTlb)
{
if (!TranslateVaddr(PROGRAM_COUNTER, &Addr))
{
DoTLBMiss(NextInstruction == DELAY_SLOT, PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
NextInstruction = NORMAL;
if (!TranslateVaddr(PROGRAM_COUNTER, &Addr))
{
g_Notify->DisplayError("Failed to translate PC to a PAddr: %X\n\nEmulation stopped", PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
ExitThread(0);
}
}
}
else
{
2016-01-27 09:11:59 +00:00
Addr = PROGRAM_COUNTER & 0x1FFFFFFF;
}
if (NextInstruction == DELAY_SLOT)
{
__try
{
Value = (uint32_t)(*(DelaySlotTable + (Addr >> 12)));
}
__except (EXCEPTION_EXECUTE_HANDLER)
2016-01-27 09:11:59 +00:00
{
g_Notify->DisplayError("Executing Delay Slot from non maped space\nPROGRAM_COUNTER = 0x%X", PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
ExitThread(0);
}
if ((Value >> 16) == 0x7C7C)
2016-01-27 09:11:59 +00:00
{
uint32_t Index = (Value & 0xFFFF);
Block = (uint8_t *)OrigMem[Index].CompiledLocation;
if (OrigMem[Index].PAddr != Addr) { Block = NULL; }
if (OrigMem[Index].VAddr != PROGRAM_COUNTER) { Block = NULL; }
if (Index >= TargetIndex) { Block = NULL; }
}
else
{
Block = NULL;
}
if (Block == NULL)
{
uint32_t MemValue;
Block = CompileDelaySlot();
Value = 0x7C7C0000;
Value += (uint16_t)(TargetIndex);
MemValue = *(uint32_t *)(RDRAM + Addr);
if ((MemValue >> 16) == 0x7C7C)
2016-01-27 09:11:59 +00:00
{
MemValue = OrigMem[(MemValue & 0xFFFF)].OriginalValue;
}
OrigMem[(uint16_t)(TargetIndex)].OriginalValue = MemValue;
OrigMem[(uint16_t)(TargetIndex)].CompiledLocation = Block;
OrigMem[(uint16_t)(TargetIndex)].PAddr = Addr;
OrigMem[(uint16_t)(TargetIndex)].VAddr = PROGRAM_COUNTER;
TargetIndex += 1;
*(DelaySlotTable + (Addr >> 12)) = (void *)Value;
NextInstruction = NORMAL;
}
_asm
{
pushad
call Block
popad
}
continue;
}
__try
{
Value = *(uint32_t *)(RDRAM + Addr);
if ((Value >> 16) == 0x7C7C)
2016-01-27 09:11:59 +00:00
{
uint32_t Index = (Value & 0xFFFF);
Block = (uint8_t *)OrigMem[Index].CompiledLocation;
if (OrigMem[Index].PAddr != Addr) { Block = NULL; }
if (OrigMem[Index].VAddr != PROGRAM_COUNTER) { Block = NULL; }
if (Index >= TargetIndex) { Block = NULL; }
}
else
{
Block = NULL;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
2016-01-27 09:11:59 +00:00
{
g_Notify->DisplayError(GS(MSG_NONMAPPED_SPACE));
ExitThread(0);
}
if (Block == NULL)
{
uint32_t MemValue;
__try
{
Block = Compiler4300iBlock();
}
__except (EXCEPTION_EXECUTE_HANDLER)
2016-01-27 09:11:59 +00:00
{
ResetRecompCode();
Block = Compiler4300iBlock();
}
if (EndEmulation())
{
continue;
}
if (TargetIndex == MaxOrigMem)
{
ResetRecompCode();
continue;
}
Value = 0x7C7C0000;
Value += (uint16_t)(TargetIndex);
MemValue = *(uint32_t *)(RDRAM + Addr);
if ((MemValue >> 16) == 0x7C7C)
2016-01-27 09:11:59 +00:00
{
MemValue = OrigMem[(MemValue & 0xFFFF)].OriginalValue;
}
OrigMem[(uint16_t)(TargetIndex)].OriginalValue = MemValue;
OrigMem[(uint16_t)(TargetIndex)].CompiledLocation = Block;
OrigMem[(uint16_t)(TargetIndex)].PAddr = Addr;
OrigMem[(uint16_t)(TargetIndex)].VAddr = PROGRAM_COUNTER;
TargetIndex += 1;
*(uint32_t *)(RDRAM + Addr) = Value;
NextInstruction = NORMAL;
}
if (Profiling && IndvidualBlock)
{
static uint32_t ProfAddress = 0;
/*if ((PROGRAM_COUNTER & ~0xFFF) != ProfAddress)
{
char Label[100];
ProfAddress = PROGRAM_COUNTER & ~0xFFF;
sprintf(Label,"PC: %X to %X",ProfAddress,ProfAddress+ 0xFFC);
StartTimer(Label);
}*/
/*if (PROGRAM_COUNTER >= 0x800DD000 && PROGRAM_COUNTER <= 0x800DDFFC)
{
char Label[100];
sprintf(Label,"PC: %X Block: %X",PROGRAM_COUNTER,Block);
StartTimer(Label);
}*/
// } else if ((Profiling || ShowCPUPer) && ProfilingLabel[0] == 0) {
// StartTimer("r4300i Running");
}
_asm
{
pushad
call Block
popad
}
} // end for(;;)
#endif
}
CCompiledFunc * CRecompiler::CompileCode()
2016-01-27 09:11:59 +00:00
{
WriteTrace(TraceRecompiler, TraceDebug, "Start (PC: %X)", PROGRAM_COUNTER);
2016-01-27 09:11:59 +00:00
uint32_t pAddr = 0;
if (!m_MMU.TranslateVaddr(PROGRAM_COUNTER, pAddr))
2016-01-27 09:11:59 +00:00
{
WriteTrace(TraceRecompiler, TraceError, "Failed to translate %X", PROGRAM_COUNTER);
return NULL;
}
CCompiledFuncList::iterator iter = m_Functions.find(PROGRAM_COUNTER);
if (iter != m_Functions.end())
{
WriteTrace(TraceRecompiler, TraceInfo, "exisiting functions for address (Program Counter: %X pAddr: %X)", PROGRAM_COUNTER, pAddr);
2016-01-27 09:11:59 +00:00
for (CCompiledFunc * Func = iter->second; Func != NULL; Func = Func->Next())
{
uint32_t PAddr;
if (m_MMU.TranslateVaddr(Func->MinPC(), PAddr))
2016-01-27 09:11:59 +00:00
{
MD5Digest Hash;
MD5(m_MMU.Rdram() + PAddr, (Func->MaxPC() - Func->MinPC()) + 4).get_digest(Hash);
2016-01-27 09:11:59 +00:00
if (memcmp(Hash.digest, Func->Hash().digest, sizeof(Hash.digest)) == 0)
{
WriteTrace(TraceRecompiler, TraceInfo, "Using extisting compiled code (Program Counter: %X pAddr: %X)", PROGRAM_COUNTER, pAddr);
2016-01-27 09:11:59 +00:00
return Func;
}
}
}
}
CheckRecompMem();
//uint32_t StartTime = timeGetTime();
WriteTrace(TraceRecompiler, TraceDebug, "Compile Block-Start: Program Counter: %X pAddr: %X", PROGRAM_COUNTER, pAddr);
2016-01-27 09:11:59 +00:00
2016-06-28 11:22:30 +00:00
CCodeBlock CodeBlock(PROGRAM_COUNTER, *g_RecompPos);
2016-01-27 09:11:59 +00:00
if (!CodeBlock.Compile())
{
return NULL;
}
if (bShowRecompMemSize())
{
ShowMemUsed();
}
CCompiledFunc * Func = new CCompiledFunc(CodeBlock);
std::pair<CCompiledFuncList::iterator, bool> ret = m_Functions.insert(CCompiledFuncList::value_type(Func->EnterPC(), Func));
2016-01-27 09:11:59 +00:00
if (ret.second == false)
{
Func->SetNext(ret.first->second->Next());
ret.first->second->SetNext(Func);
}
if (g_ModuleLogLevel[TraceRecompiler] >= TraceDebug)
{
WriteTrace(TraceRecompiler, TraceDebug, "info->Function() = %X", Func->Function());
std::string dumpline;
uint32_t start_address = (uint32_t)(Func->Function()) & ~1;
for (uint8_t * ptr = (uint8_t *)start_address; ptr < CodeBlock.CompiledLocationEnd(); ptr++)
{
if (dumpline.empty())
{
dumpline += stdstr_f("%X: ", ptr);
}
dumpline += stdstr_f(" %02X", *ptr);
if ((((uint32_t)ptr - start_address) + 1) % 30 == 0)
{
WriteTrace(TraceRecompiler, TraceDebug, "%s", dumpline.c_str());
dumpline.clear();
}
}
if (!dumpline.empty())
{
WriteTrace(TraceRecompiler, TraceDebug, "%s", dumpline.c_str());
}
}
WriteTrace(TraceRecompiler, TraceVerbose, "Done");
2016-01-27 09:11:59 +00:00
return Func;
}
void CRecompiler::ClearRecompCode_Phys(uint32_t Address, int length, REMOVE_REASON Reason)
{
if (g_System->LookUpMode() == FuncFind_VirtualLookup)
{
ClearRecompCode_Virt(Address + 0x80000000, length, Reason);
ClearRecompCode_Virt(Address + 0xA0000000, length, Reason);
if (g_System->bUseTlb())
{
uint32_t VAddr, Index = 0;
while (g_TLB->PAddrToVAddr(Address, VAddr, Index))
{
WriteTrace(TraceRecompiler, TraceInfo, "ClearRecompCode Vaddr %X len: %d", VAddr, length);
2016-01-27 09:11:59 +00:00
ClearRecompCode_Virt(VAddr, length, Reason);
}
}
}
else if (g_System->LookUpMode() == FuncFind_PhysicalLookup)
{
if (Address < g_System->RdramSize())
{
int ClearLen = ((length + 3) & ~3);
if (Address + ClearLen > g_System->RdramSize())
{
g_Notify->BreakPoint(__FILE__, __LINE__);
ClearLen = g_System->RdramSize() - Address;
}
WriteTrace(TraceRecompiler, TraceInfo, "Reseting Jump Table, Addr: %X len: %d", Address, ClearLen);
2016-01-27 09:11:59 +00:00
memset((uint8_t *)JumpTable() + Address, 0, ClearLen);
if (g_System->bSMM_Protect())
{
m_MMU.UnProtectMemory(Address + 0x80000000, Address + 0x80000004);
2016-01-27 09:11:59 +00:00
}
}
else
{
WriteTrace(TraceRecompiler, TraceInfo, "Ignoring reset of Jump Table, Addr: %X len: %d", Address, ((length + 3) & ~3));
2016-01-27 09:11:59 +00:00
}
}
}
void CRecompiler::ClearRecompCode_Virt(uint32_t Address, int length, REMOVE_REASON Reason)
{
2016-09-26 11:10:11 +00:00
uint32_t AddressIndex, WriteStart;
int DataInBlock, DataToWrite, DataLeft;
2016-01-27 09:11:59 +00:00
switch (g_System->LookUpMode())
{
case FuncFind_VirtualLookup:
2016-09-26 11:10:11 +00:00
AddressIndex = Address >> 0xC;
WriteStart = (Address & 0xFFC);
length = ((length + 3) & ~0x3);
2016-01-27 09:11:59 +00:00
2016-09-26 11:10:11 +00:00
DataInBlock = 0x1000 - WriteStart;
DataToWrite = length < DataInBlock ? length : DataInBlock;
DataLeft = length - DataToWrite;
2016-01-27 09:11:59 +00:00
2016-09-26 11:10:11 +00:00
{
PCCompiledFunc_TABLE & table = FunctionTable()[AddressIndex];
if (table)
{
WriteTrace(TraceRecompiler, TraceError, "Delete Table (%X): Index = %d", table, AddressIndex);
delete table;
table = NULL;
m_MMU.UnProtectMemory(Address, Address + length);
}
2016-01-27 09:11:59 +00:00
if (DataLeft > 0)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
}
2016-01-27 09:11:59 +00:00
}
break;
2016-01-27 09:11:59 +00:00
case FuncFind_PhysicalLookup:
2016-11-18 19:49:24 +00:00
{
uint32_t pAddr = 0;
if (m_MMU.TranslateVaddr(Address, pAddr))
2016-11-18 19:49:24 +00:00
{
ClearRecompCode_Phys(pAddr, length, Reason);
}
}
break;
2016-01-27 09:11:59 +00:00
default:
g_Notify->BreakPoint(__FILE__, __LINE__);
}
}
void CRecompiler::ResetMemoryStackPos()
{
if (m_Registers.m_GPR[29].UW[0] == 0)
{
m_MemoryStack = 0;
return;
}
uint32_t pAddr = 0;
if (m_MMU.TranslateVaddr(m_Registers.m_GPR[29].UW[0], pAddr))
2016-01-27 09:11:59 +00:00
{
m_MemoryStack = (uint32_t)(m_MMU.Rdram() + pAddr);
2016-01-27 09:11:59 +00:00
}
else
{
WriteTrace(TraceRecompiler, TraceError, "Failed to translate SP address (%s)", m_Registers.m_GPR[29].UW[0]);
g_Notify->BreakPoint(__FILE__, __LINE__);
}
2016-10-02 21:46:05 +00:00
}
void CRecompiler::DumpFunctionTimes()
{
CPath LogFileName(g_Settings->LoadStringVal(Directory_Log).c_str(), "FunctionTimes.csv");
CLog Log;
Log.Open(LogFileName);
for (FUNCTION_PROFILE::iterator itr = m_BlockProfile.begin(); itr != m_BlockProfile.end(); itr++)
{
Log.LogF("%X,0x%X,%d\r\n", (uint32_t)itr->first, itr->second.Address, (uint32_t)itr->second.TimeTaken);
}
}
void CRecompiler::ResetFunctionTimes()
{
m_BlockProfile.clear();
2016-10-04 19:58:11 +00:00
}