/**************************************************************************** * * * Project 64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" CRecompiler::CRecompiler(CRegisters & Registers, CProfiling & Profile, bool & EndEmulation ) : m_Registers(Registers), m_Profile(Profile), m_EndEmulation(EndEmulation), PROGRAM_COUNTER(Registers.m_PROGRAM_COUNTER) { if (g_MMU != NULL) { ResetMemoryStackPos(); } } CRecompiler::~CRecompiler() { ResetRecompCode(false); } void CRecompiler::Run() { CoInitialize(NULL); if (bLogX86Code()) { Start_x86_Log(); } if (!CRecompMemory::AllocateMemory()) { WriteTrace(TraceError,__FUNCTION__ ": AllocateMemory failed"); return; } if (!CFunctionMap::AllocateMemory()) { WriteTrace(TraceError,__FUNCTION__ ": AllocateMemory failed"); return; } m_EndEmulation = false; #ifdef tofix *g_MemoryStack = (DWORD)(RDRAM+(_GPR[29].W[0] & 0x1FFFFFFF)); #endif __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( g_MMU->MemoryFilter( GetExceptionCode(), GetExceptionInformation()) ) { g_Notify->DisplayError(MSG_UNKNOWN_MEM_ACTION); } } void CRecompiler::RecompilerMain_VirtualTable() { bool & Done = m_EndEmulation; DWORD & PC = PROGRAM_COUNTER; while(!Done) { if (!g_TransVaddr->ValidVaddr(PC)) { m_Registers.DoTLBReadMiss(false,PC); if (!g_TransVaddr->ValidVaddr(PC)) { g_Notify->DisplayError(L"Failed to translate PC to a PAddr: %X\n\nEmulation stopped",PC); return; } continue; } PCCompiledFunc_TABLE & table = FunctionTable()[PC >> 0xC]; DWORD TableEntry = (PC & 0xFFF) >> 2; if (table) { CCompiledFunc * info = table[TableEntry]; if (info != NULL) { (info->Function())(); continue; } } CCompiledFunc * info = CompilerCode(); if (info == NULL || m_EndEmulation) { break; } if (table == NULL) { table = new PCCompiledFunc[(0x1000 >> 2)]; if (table == NULL) { WriteTrace(TraceError,__FUNCTION__ ": failed to allocate PCCompiledFunc"); g_Notify->FatalError(MSG_MEM_ALLOC_ERROR); } memset(table,0,sizeof(PCCompiledFunc) * (0x1000 >> 2)); if (g_System->bSMM_Protect()) { WriteTraceF(TraceError,__FUNCTION__ ": Create Table (%X): Index = %d",table, PC >> 0xC); g_MMU->ProtectMemory(PC & ~0xFFF,PC | 0xFFF); } } table[TableEntry] = info; (info->Function())(); } } void CRecompiler::RecompilerMain_VirtualTable_validate() { g_Notify->BreakPoint(__FILEW__,__LINE__); /* PCCompiledFunc_TABLE * m_FunctionTable = m_Functions.GetFunctionTable(); while(!m_EndEmulation) { /*if (NextInstruction == DELAY_SLOT) { CCompiledFunc * Info = m_FunctionsDelaySlot.FindFunction(PROGRAM_COUNTER); //Find Block on hash table if (Info == NULL) { g_Notify->BreakPoint(__FILEW__,__LINE__); #ifdef tofix if (!g_TLB->ValidVaddr(PROGRAM_COUNTER)) { DoTLBMiss(NextInstruction == DELAY_SLOT,PROGRAM_COUNTER); NextInstruction = NORMAL; if (!g_TLB->ValidVaddr(PROGRAM_COUNTER)) { g_Notify->DisplayError(L"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); if (Info == NULL || EndEmulation()) { break; } } const BYTE * 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 BYTE * Block = info->FunctionAddr(); _asm { pushad call Block popad } continue; } } g_Notify->BreakPoint(__FILEW__,__LINE__); #ifdef tofix if (!g_TLB->ValidVaddr(PROGRAM_COUNTER)) { DoTLBMiss(NextInstruction == DELAY_SLOT,PROGRAM_COUNTER); NextInstruction = NORMAL; if (!g_TLB->ValidVaddr(PROGRAM_COUNTER)) { g_Notify->DisplayError(L"Failed to translate PC to a PAddr: %X\n\nEmulation stopped",PROGRAM_COUNTER); return; } } #endif CCompiledFunc * info = CompilerCode(); if (info == NULL || EndEmulation()) { break; } } /* while(!m_EndEmulation) { if (!g_MMU->ValidVaddr(PROGRAM_COUNTER)) { DoTLBMiss(NextInstruction == DELAY_SLOT,PROGRAM_COUNTER); NextInstruction = NORMAL; if (!g_MMU->ValidVaddr(PROGRAM_COUNTER)) { g_Notify->DisplayError(L"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); //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->StartPC() - 0x1000) & ~0xFFF,0x2000,Remove_ValidateFunc); NextInstruction = DELAY_SLOT; Info = NULL; continue; } } const BYTE * Block = Info->FunctionAddr(); _asm { pushad call Block popad } continue; } CCompiledFunc * Info = m_Functions.FindFunction(PROGRAM_COUNTER); //Find Block on hash table if (Info == NULL) { Info = CompilerCode(); 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 BYTE * Block = Info->FunctionAddr(); _asm { pushad call Block popad } } */ } void CRecompiler::RecompilerMain_Lookup() { while(!m_EndEmulation) { DWORD PhysicalAddr = PROGRAM_COUNTER & 0x1FFFFFFF; if (PhysicalAddr < g_System->RdramSize()) { CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2]; if (info == NULL) { info = CompilerCode(); if (info == NULL || m_EndEmulation) { break; } if (g_System->bSMM_Protect()) { g_MMU->ProtectMemory(PROGRAM_COUNTER & ~0xFFF,PROGRAM_COUNTER | 0xFFF); } JumpTable()[PhysicalAddr >> 2] = info; } (info->Function())(); } else { DWORD opsExecuted = 0; while (g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize()) { CInterpreterCPU::ExecuteOps(g_System->CountPerOp()); opsExecuted += g_System->CountPerOp(); } if (g_SyncSystem) { g_System->UpdateSyncCPU(g_SyncSystem,opsExecuted); g_System->SyncCPU(g_SyncSystem); } } } /* DWORD Addr; CCompiledFunc * Info; //const BYTE * Block; while(!m_EndEmulation) { /*if (bUseTlb()) { g_Notify->BreakPoint(__FILEW__,__LINE__); #ifdef tofix if (!g_TLB->TranslateVaddr(PROGRAM_COUNTER, Addr)) { DoTLBMiss(NextInstruction == DELAY_SLOT,PROGRAM_COUNTER); NextInstruction = NORMAL; if (!TranslateVaddr(PROGRAM_COUNTER, &Addr)) { g_Notify->DisplayError(L"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 BYTE * 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 = CompilerCode(); 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(__FILEW__,__LINE__); #ifdef tofix if (Profiling && IndvidualBlock) { static DWORD 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"); /* } #endif const BYTE * Block = Info->FunctionAddr(); _asm { pushad call Block popad } }*/ } void CRecompiler::RecompilerMain_Lookup_TLB() { DWORD PhysicalAddr; while(!m_EndEmulation) { if (!g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr)) { m_Registers.DoTLBReadMiss(false,PROGRAM_COUNTER); if (!g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr)) { g_Notify->DisplayError(L"Failed to translate PC to a PAddr: %X\n\nEmulation stopped",PROGRAM_COUNTER); m_EndEmulation = true; } continue; } if (PhysicalAddr < g_System->RdramSize()) { CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2]; if (info == NULL) { info = CompilerCode(); if (info == NULL || m_EndEmulation) { break; } if (g_System->bSMM_Protect()) { g_MMU->ProtectMemory(PROGRAM_COUNTER & ~0xFFF,PROGRAM_COUNTER | 0xFFF); } JumpTable()[PhysicalAddr >> 2] = info; } (info->Function())(); } else { DWORD opsExecuted = 0; while (g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize()) { 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) { DWORD PhysicalAddr = PROGRAM_COUNTER & 0x1FFFFFFF; if (PhysicalAddr < g_System->RdramSize()) { CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2]; if (info == NULL) { info = CompilerCode(); if (info == NULL || m_EndEmulation) { break; } if (g_System->bSMM_Protect()) { g_MMU->ProtectMemory(PROGRAM_COUNTER & ~0xFFF,PROGRAM_COUNTER | 0xFFF); } 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 { DWORD opsExecuted = 0; while (g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize()) { 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() { DWORD PhysicalAddr; while(!m_EndEmulation) { if (!g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr)) { m_Registers.DoTLBReadMiss(false,PROGRAM_COUNTER); if (!g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr)) { g_Notify->DisplayError(L"Failed to translate PC to a PAddr: %X\n\nEmulation stopped",PROGRAM_COUNTER); m_EndEmulation = true; } continue; } if (PhysicalAddr < g_System->RdramSize()) { CCompiledFunc * info = JumpTable()[PhysicalAddr >> 2]; if (info == NULL) { info = CompilerCode(); if (info == NULL || m_EndEmulation) { break; } if (g_System->bSMM_Protect()) { g_MMU->ProtectMemory(PROGRAM_COUNTER & ~0xFFF,PROGRAM_COUNTER | 0xFFF); } 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(__FILEW__,__LINE__); info = NULL; } continue; } } (info->Function())(); } else { DWORD opsExecuted = 0; while (g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER, PhysicalAddr) && PhysicalAddr >= g_System->RdramSize()) { 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::Reset() { ResetRecompCode(true); ResetMemoryStackPos(); } void CRecompiler::ResetRecompCode( bool bAllocate ) { 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(); } void CRecompiler::RecompilerMain_ChangeMemory() { g_Notify->BreakPoint(__FILEW__,__LINE__); #ifdef tofix DWORD Value, Addr; BYTE * Block; while(!EndEmulation()) { if (UseTlb) { if (!TranslateVaddr(PROGRAM_COUNTER, &Addr)) { DoTLBMiss(NextInstruction == DELAY_SLOT,PROGRAM_COUNTER); NextInstruction = NORMAL; if (!TranslateVaddr(PROGRAM_COUNTER, &Addr)) { g_Notify->DisplayError(L"Failed to translate PC to a PAddr: %X\n\nEmulation stopped",PROGRAM_COUNTER); ExitThread(0); } } } else { Addr = PROGRAM_COUNTER & 0x1FFFFFFF; } if (NextInstruction == DELAY_SLOT) { __try { Value = (DWORD)(*(DelaySlotTable + (Addr >> 12))); } __except(EXCEPTION_EXECUTE_HANDLER) { g_Notify->DisplayError(L"Executing Delay Slot from non maped space\nPROGRAM_COUNTER = 0x%X",PROGRAM_COUNTER); ExitThread(0); } if ( (Value >> 16) == 0x7C7C) { DWORD Index = (Value & 0xFFFF); Block = (BYTE *)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) { DWORD MemValue; Block = CompileDelaySlot(); Value = 0x7C7C0000; Value += (WORD)(TargetIndex); MemValue = *(DWORD *)(RDRAM + Addr); if ( (MemValue >> 16) == 0x7C7C) { MemValue = OrigMem[(MemValue & 0xFFFF)].OriginalValue; } OrigMem[(WORD)(TargetIndex)].OriginalValue = MemValue; OrigMem[(WORD)(TargetIndex)].CompiledLocation = Block; OrigMem[(WORD)(TargetIndex)].PAddr = Addr; OrigMem[(WORD)(TargetIndex)].VAddr = PROGRAM_COUNTER; TargetIndex += 1; *(DelaySlotTable + (Addr >> 12)) = (void *)Value; NextInstruction = NORMAL; } _asm { pushad call Block popad } continue; } __try { Value = *(DWORD *)(RDRAM + Addr); if ( (Value >> 16) == 0x7C7C) { DWORD Index = (Value & 0xFFFF); Block = (BYTE *)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) { g_Notify->DisplayError(GS(MSG_NONMAPPED_SPACE)); ExitThread(0); } if (Block == NULL) { DWORD MemValue; __try { Block = Compiler4300iBlock(); } __except(EXCEPTION_EXECUTE_HANDLER) { ResetRecompCode(); Block = Compiler4300iBlock(); } if (EndEmulation()) { continue; } if (TargetIndex == MaxOrigMem) { ResetRecompCode(); continue; } Value = 0x7C7C0000; Value += (WORD)(TargetIndex); MemValue = *(DWORD *)(RDRAM + Addr); if ( (MemValue >> 16) == 0x7C7C) { MemValue = OrigMem[(MemValue & 0xFFFF)].OriginalValue; } OrigMem[(WORD)(TargetIndex)].OriginalValue = MemValue; OrigMem[(WORD)(TargetIndex)].CompiledLocation = Block; OrigMem[(WORD)(TargetIndex)].PAddr = Addr; OrigMem[(WORD)(TargetIndex)].VAddr = PROGRAM_COUNTER; TargetIndex += 1; *(DWORD *)(RDRAM + Addr) = Value; NextInstruction = NORMAL; } if (Profiling && IndvidualBlock) { static DWORD 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::CompilerCode() { DWORD pAddr = 0; if (!g_TransVaddr->TranslateVaddr(PROGRAM_COUNTER,pAddr)) { WriteTraceF(TraceError,__FUNCTION__ ": Failed to translate %X",PROGRAM_COUNTER); return NULL; } CCompiledFuncList::iterator iter = m_Functions.find(PROGRAM_COUNTER); if (iter != m_Functions.end()) { for (CCompiledFunc * Func = iter->second; Func != NULL; Func = Func->Next()) { DWORD PAddr; if (g_TransVaddr->TranslateVaddr(Func->MinPC(),PAddr)) { MD5Digest Hash; MD5(g_MMU->Rdram() + PAddr,(Func->MaxPC() - Func->MinPC())+ 4).get_digest(Hash); if (memcmp(Hash.digest,Func->Hash().digest,sizeof(Hash.digest)) == 0) { return Func; } } } } CheckRecompMem(); //DWORD StartTime = timeGetTime(); WriteTraceF(TraceRecompiler,__FUNCTION__ ": Compile Block-Start: Program Counter: %X pAddr: %X",PROGRAM_COUNTER,pAddr); CCodeBlock CodeBlock(PROGRAM_COUNTER, RecompPos()); if (!CodeBlock.Compile()) { return NULL; } if (bShowRecompMemSize()) { ShowMemUsed(); } CCompiledFunc * Func = new CCompiledFunc(CodeBlock); CCompiledFuncList::_Pairib ret = m_Functions.insert(CCompiledFuncList::value_type(Func->EnterPC(),Func)); if (ret.second == false) { Func->SetNext(ret.first->second->Next()); ret.first->second->SetNext(Func); return Func; } return Func; } void CRecompiler::ClearRecompCode_Phys(DWORD 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()) { DWORD VAddr, Index = 0; while (g_TLB->PAddrToVAddr(Address,VAddr,Index)) { WriteTraceF(TraceRecompiler,__FUNCTION__ ": ClearRecompCode Vaddr %X len: %d",VAddr,length); 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(__FILEW__,__LINE__); ClearLen = g_System->RdramSize() - Address; } WriteTraceF(TraceRecompiler,__FUNCTION__ ": Reseting Jump Table, Addr: %X len: %d",Address,ClearLen); memset((BYTE *)JumpTable() + Address,0,ClearLen); if (g_System->bSMM_Protect()) { g_MMU->UnProtectMemory(Address + 0x80000000,Address + 0x80000004); } } else{ WriteTraceF(TraceRecompiler,__FUNCTION__ ": Ignoring reset of Jump Table, Addr: %X len: %d",Address,((length + 3) & ~3)); } } } void CRecompiler::ClearRecompCode_Virt(DWORD Address, int length,REMOVE_REASON Reason ) { switch (g_System->LookUpMode()) { case FuncFind_VirtualLookup: { DWORD AddressIndex = Address >> 0xC; DWORD WriteStart = (Address & 0xFFC); length = ((length + 3) & ~0x3); int DataInBlock = 0x1000 - WriteStart; int DataToWrite = length < DataInBlock ? length : DataInBlock; int DataLeft = length - DataToWrite; PCCompiledFunc_TABLE & table = FunctionTable()[AddressIndex]; if (table) { WriteTraceF(TraceError,__FUNCTION__ ": Delete Table (%X): Index = %d",table, AddressIndex); delete table; table = NULL; g_MMU->UnProtectMemory(Address,Address + length); } if (DataLeft > 0) { g_Notify->BreakPoint(__FILEW__,__LINE__); } } break; case FuncFind_PhysicalLookup: { DWORD pAddr = 0; if (g_TransVaddr->TranslateVaddr(Address,pAddr)) { ClearRecompCode_Phys(pAddr,length,Reason); } } break; default: g_Notify->BreakPoint(__FILEW__,__LINE__); } } void CRecompiler::ResetMemoryStackPos() { if (g_MMU == NULL) { g_Notify->BreakPoint(__FILEW__,__LINE__); return; } if (m_Registers.m_GPR[29].UW[0] == 0) { m_MemoryStack = NULL; return; } DWORD pAddr = 0; if (g_TransVaddr->TranslateVaddr(m_Registers.m_GPR[29].UW[0],pAddr)) { m_MemoryStack = (DWORD)(g_MMU->Rdram() + pAddr); } else { WriteTraceF(TraceError,__FUNCTION__ ": Failed to translate SP address (%s)",m_Registers.m_GPR[29].UW[0]); g_Notify->BreakPoint(__FILEW__,__LINE__); } }