From 6c0c97cffe4326ed648cf3426d7311188f0b59ec Mon Sep 17 00:00:00 2001 From: "sl1nk3.s" Date: Sun, 1 Nov 2009 01:24:30 +0000 Subject: [PATCH] Fixed TLB games support for the iCache, games using the TLB Hack should now work as before (fixes issue 1218) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4492 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/HW/Memmap.cpp | 33 +++++++++++++++---- .../Interpreter/Interpreter_FloatingPoint.cpp | 1 + Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp | 16 ++++++++- .../Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp | 16 ++++++++- .../Core/Src/PowerPC/JitCommon/JitCache.cpp | 28 +++++++++++++--- .../Core/Src/PowerPC/JitCommon/JitCache.h | 3 ++ Source/Core/Core/Src/PowerPC/PPCCache.cpp | 19 ++++++++--- Source/Core/Core/Src/PowerPC/PPCCache.h | 2 ++ Source/Core/Core/Src/State.cpp | 14 +++++--- Source/Core/DolphinWX/Src/Frame.cpp | 9 ++--- Source/Core/DolphinWX/Src/Frame.h | 1 + Source/Core/DolphinWX/Src/FrameTools.cpp | 10 ++++-- 12 files changed, 125 insertions(+), 27 deletions(-) diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index 91118f5379..f1b063d556 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -50,7 +50,6 @@ may be redirected here (for example to Read_U32()). - // Declarations and definitions // ---------------- namespace Memory @@ -539,6 +538,7 @@ u32 Read_Opcode_JIT(const u32 _Address) { #ifdef JIT_UNLIMITED_ICACHE if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 && + (_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) { PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); @@ -546,10 +546,15 @@ u32 Read_Opcode_JIT(const u32 _Address) } u8* iCache; u32 addr; - if (_Address & JIT_ICACHE_EXRAM_BIT) + if (_Address & JIT_ICACHE_VMEM_BIT) + { + iCache = jit.GetBlockCache()->GetICacheVMEM(); + addr = _Address & JIT_ICACHE_MASK; + } + else if (_Address & JIT_ICACHE_EXRAM_BIT) { iCache = jit.GetBlockCache()->GetICacheEx(); - addr = _Address & JIT_ICACHEEX_MASK; + addr = _Address & JIT_ICACHEEX_MASK; } else { @@ -587,6 +592,7 @@ u32 Read_Opcode_JIT_LC(const u32 _Address) { #ifdef JIT_UNLIMITED_ICACHE if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 && + (_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) { PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); @@ -594,10 +600,15 @@ u32 Read_Opcode_JIT_LC(const u32 _Address) } u8* iCache; u32 addr; - if (_Address & JIT_ICACHE_EXRAM_BIT) + if (_Address & JIT_ICACHE_VMEM_BIT) + { + iCache = jit.GetBlockCache()->GetICacheVMEM(); + addr = _Address & JIT_ICACHE_MASK; + } + else if (_Address & JIT_ICACHE_EXRAM_BIT) { iCache = jit.GetBlockCache()->GetICacheEx(); - addr = _Address & JIT_ICACHEEX_MASK; + addr = _Address & JIT_ICACHEEX_MASK; } else { @@ -624,7 +635,11 @@ u32 Read_Opcode_JIT_LC(const u32 _Address) void Write_Opcode_JIT(const u32 _Address, const u32 _Value) { #ifdef JIT_UNLIMITED_ICACHE - if (_Address & JIT_ICACHE_EXRAM_BIT) + if (_Address & JIT_ICACHE_VMEM_BIT) + { + *(u32*)(jit.GetBlockCache()->GetICacheVMEM() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value); + } + else if (_Address & JIT_ICACHE_EXRAM_BIT) { *(u32*)(jit.GetBlockCache()->GetICacheEx() + (_Address & JIT_ICACHEEX_MASK)) = Common::swap32(_Value); } @@ -790,7 +805,7 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) } else { - // (comment for old implementation) : F|RES: rouge squadron and other games use the TLB ... so this cant work + // (comment for old implementation) : F|RES: rogue squadron and other games use the TLB ... so this cant work // fixed implementation: for (u32 i = 0; i < _iLength; i++) @@ -894,6 +909,10 @@ u8 *GetPointer(const u32 _Address) else return 0; + case 0x7E: + case 0x7F: + return (u8*)(((char*)m_pFakeVMEM) + (_Address & RAM_MASK)); + case 0xE0: if (_Address < (0xE0000000 + L1_CACHE_SIZE)) return GetCachePtr() + (_Address & L1_CACHE_MASK); diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index b9e006ab85..018bcfe0e0 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -45,6 +45,7 @@ namespace Interpreter void UpdateSSEState(); // Extremely rare - actually, never seen. +// Star Wars : Rogue Leader spams that at some point :| void Helper_UpdateCR1(double _fValue) { // Should just update exception flags, not do any compares. diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp index 9520d653d0..67567e9931 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp @@ -159,6 +159,8 @@ void AsmRoutineManager::Generate() SetJumpTarget(needinst); #ifdef JIT_UNLIMITED_ICACHE + TEST(32, R(EAX), Imm32(JIT_ICACHE_VMEM_BIT)); + FixupBranch vmem = J_CC(CC_NZ); TEST(32, R(EAX), Imm32(JIT_ICACHE_EXRAM_BIT)); FixupBranch exram = J_CC(CC_NZ); @@ -179,9 +181,21 @@ void AsmRoutineManager::Generate() #else MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICacheEx())); MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); -#endif +#endif + + FixupBranch getinst2 = J(); + SetJumpTarget(vmem); + + AND(32, R(EAX), Imm32(JIT_ICACHE_MASK)); +#ifdef _M_IX86 + MOV(32, R(EAX), MDisp(EAX, (u32)jit.GetBlockCache()->GetICacheVMEM())); +#else + MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICacheVMEM())); + MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); +#endif SetJumpTarget(getinst); + SetJumpTarget(getinst2); #else #ifdef _M_IX86 AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp index e070347492..329e103524 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp @@ -164,6 +164,8 @@ void AsmRoutineManager::Generate() SetJumpTarget(needinst); #ifdef JIT_UNLIMITED_ICACHE + TEST(32, R(EAX), Imm32(JIT_ICACHE_VMEM_BIT)); + FixupBranch vmem = J_CC(CC_NZ); TEST(32, R(EAX), Imm32(JIT_ICACHE_EXRAM_BIT)); FixupBranch exram = J_CC(CC_NZ); @@ -184,9 +186,21 @@ void AsmRoutineManager::Generate() #else MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICacheEx())); MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); -#endif +#endif + + FixupBranch getinst2 = J(); + SetJumpTarget(vmem); + + AND(32, R(EAX), Imm32(JIT_ICACHE_MASK)); +#ifdef _M_IX86 + MOV(32, R(EAX), MDisp(EAX, (u32)jit.GetBlockCache()->GetICacheVMEM())); +#else + MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICacheVMEM())); + MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); +#endif SetJumpTarget(getinst); + SetJumpTarget(getinst2); #else #ifdef _M_IX86 AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index e88dfda57d..bf890f2f05 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -86,21 +86,23 @@ bool JitBlock::ContainsAddress(u32 em_address) blocks = new JitBlock[MAX_NUM_BLOCKS]; blockCodePointers = new const u8*[MAX_NUM_BLOCKS]; #ifdef JIT_UNLIMITED_ICACHE - if (iCache == 0 && iCacheEx == 0) + if (iCache == 0 && iCacheEx == 0 && iCacheVMEM == 0) { iCache = new u8[JIT_ICACHE_SIZE]; iCacheEx = new u8[JIT_ICACHEEX_SIZE]; + iCacheVMEM = new u8[JIT_ICACHE_SIZE]; } else { PanicAlert("JitBlockCache::Init() - iCache is already initialized"); } - if (iCache == 0 || iCacheEx == 0) + if (iCache == 0 || iCacheEx == 0 || iCacheVMEM == 0) { PanicAlert("JitBlockCache::Init() - unable to allocate iCache"); } memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); memset(iCacheEx, JIT_ICACHE_INVALID_BYTE, JIT_ICACHEEX_SIZE); + memset(iCacheVMEM, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); #endif Clear(); } @@ -116,6 +118,9 @@ bool JitBlock::ContainsAddress(u32 em_address) if (iCacheEx != 0) delete [] iCacheEx; iCacheEx = 0; + if (iCacheVMEM != 0) + delete [] iCacheVMEM; + iCacheVMEM = 0; #endif blocks = 0; blockCodePointers = 0; @@ -238,6 +243,11 @@ bool JitBlock::ContainsAddress(u32 em_address) { return iCacheEx; } + + u8* JitBlockCache::GetICacheVMEM() + { + return iCacheVMEM; + } #endif int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr) @@ -246,7 +256,11 @@ bool JitBlock::ContainsAddress(u32 em_address) return -1; #ifdef JIT_UNLIMITED_ICACHE u32 inst; - if (addr & JIT_ICACHE_EXRAM_BIT) + if (addr & JIT_ICACHE_VMEM_BIT) + { + inst = *(u32*)(iCacheVMEM + (addr & JIT_ICACHE_MASK)); + } + else if (addr & JIT_ICACHE_EXRAM_BIT) { inst = *(u32*)(iCacheEx + (addr & JIT_ICACHEEX_MASK)); } @@ -394,11 +408,17 @@ bool JitBlock::ContainsAddress(u32 em_address) // invalidate iCache. // icbi can be called with any address, so we sholud check if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000 && + (address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area (address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (address & ~JIT_ICACHEEX_MASK) != 0x10000000) { return; } - if (address & JIT_ICACHE_EXRAM_BIT) + if (address & JIT_ICACHE_VMEM_BIT) + { + u32 cacheaddr = address & JIT_ICACHE_MASK; + memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + } + else if (address & JIT_ICACHE_EXRAM_BIT) { u32 cacheaddr = address & JIT_ICACHEEX_MASK; memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h index a402eae75d..e72bb6b4e9 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h @@ -37,6 +37,7 @@ #define JIT_ICACHEEX_SIZE 0x4000000 #define JIT_ICACHEEX_MASK 0x3ffffff #define JIT_ICACHE_EXRAM_BIT 0x10000000 +#define JIT_ICACHE_VMEM_BIT 0x20000000 // this corresponds to opcode 5 which is invalid in PowerPC #define JIT_ICACHE_INVALID_BYTE 0x14 #define JIT_ICACHE_INVALID_WORD 0x14141414 @@ -89,6 +90,7 @@ class JitBlockCache #ifdef JIT_UNLIMITED_ICACHE u8 *iCache; u8 *iCacheEx; + u8 *iCacheVMEM; #endif int MAX_NUM_BLOCKS; @@ -116,6 +118,7 @@ public: #ifdef JIT_UNLIMITED_ICACHE u8 *GetICache(); u8 *GetICacheEx(); + u8 *GetICacheVMEM(); #endif // Fast way to get a block. Only works on the first ppc instruction of a block. diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp index 0494e5f45a..0af5e3e97f 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp @@ -72,6 +72,7 @@ namespace PowerPC #ifdef FAST_ICACHE memset(lookup_table, 0xff, sizeof(lookup_table)); memset(lookup_table_ex, 0xff, sizeof(lookup_table_ex)); + memset(lookup_table_vmem, 0xff, sizeof(lookup_table_vmem)); #endif } @@ -85,7 +86,9 @@ namespace PowerPC for (int i = 0; i < 8; i++) if (valid[set] & (1<> 12)) + if (tags[set][i] & (ICACHE_VMEM_BIT >> 12)) + lookup_table_vmem[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; + else if (tags[set][i] & (ICACHE_EXRAM_BIT >> 12)) lookup_table_ex[((tags[set][i] << 7) | set) & 0x1fffff] = 0xff; else lookup_table[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; @@ -102,7 +105,11 @@ namespace PowerPC u32 tag = addr >> 12; #ifdef FAST_ICACHE u32 t; - if (addr & ICACHE_EXRAM_BIT) + if (addr & ICACHE_VMEM_BIT) + { + t = lookup_table_vmem[(addr>>5) & 0xfffff]; + } + else if (addr & ICACHE_EXRAM_BIT) { t = lookup_table_ex[(addr>>5) & 0x1fffff]; } @@ -134,12 +141,16 @@ namespace PowerPC #ifdef FAST_ICACHE if (valid[set] & (1<> 12)) + if (tags[set][t] & (ICACHE_VMEM_BIT >> 12)) + lookup_table_vmem[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; + else if (tags[set][t] & (ICACHE_EXRAM_BIT >> 12)) lookup_table_ex[((tags[set][t] << 7) | set) & 0x1fffff] = 0xff; else lookup_table[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; } - if (addr & ICACHE_EXRAM_BIT) + if (addr & ICACHE_VMEM_BIT) + lookup_table_vmem[(addr>>5) & 0xfffff] = t; + else if (addr & ICACHE_EXRAM_BIT) lookup_table_ex[(addr>>5) & 0x1fffff] = t; else lookup_table[(addr>>5) & 0xfffff] = t; diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.h b/Source/Core/Core/Src/PowerPC/PPCCache.h index 559afc0c6c..d00986cf87 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.h +++ b/Source/Core/Core/Src/PowerPC/PPCCache.h @@ -31,6 +31,7 @@ namespace PowerPC const u32 ICACHE_BLOCK_SIZE = 8; const u32 ICACHE_EXRAM_BIT = 0x10000000; + const u32 ICACHE_VMEM_BIT = 0x20000000; struct InstructionCache { @@ -45,6 +46,7 @@ namespace PowerPC #ifdef FAST_ICACHE u8 lookup_table[1<<20]; u8 lookup_table_ex[1<<21]; + u8 lookup_table_vmem[1<<20]; #endif InstructionCache(); diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index d920a2d801..d9acf65472 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -72,7 +72,7 @@ static Common::Thread *saveThread = NULL; // Don't forget to increase this after doing changes on the savestate system -#define STATE_VERSION 1 +#define STATE_VERSION 2 void DoState(PointerWrap &p) @@ -81,7 +81,8 @@ void DoState(PointerWrap &p) p.Do(cookie); if (cookie != 0xBAADBABE + STATE_VERSION) { - PanicAlert("Savestate version mismatch !\nSorry, you can't load states from other revisions."); + //PanicAlert("Savestate version mismatch !\nSorry, you can't load states from other revisions."); + p.SetMode(PointerWrap::MODE_MEASURE); return; } // Begin with video plugin, so that it gets a chance to clear it's caches and writeback modified things to RAM @@ -97,6 +98,7 @@ void DoState(PointerWrap &p) #ifdef JIT_UNLIMITED_ICACHE p.DoVoid(jit.GetBlockCache()->GetICache(), JIT_ICACHE_SIZE); p.DoVoid(jit.GetBlockCache()->GetICacheEx(), JIT_ICACHEEX_SIZE); + p.DoVoid(jit.GetBlockCache()->GetICacheVMEM(), JIT_ICACHE_SIZE); #endif } @@ -345,9 +347,13 @@ void LoadStateCallback(u64 userdata, int cyclesLate) u8 *ptr = buffer; PointerWrap p(&ptr, PointerWrap::MODE_READ); DoState(p); - delete [] buffer; - Core::DisplayMessage(StringFromFormat("Loaded state from %s", cur_filename.c_str()).c_str(), 2000); + if (p.GetMode() == PointerWrap::MODE_READ) + Core::DisplayMessage(StringFromFormat("Loaded state from %s", cur_filename.c_str()).c_str(), 2000); + else + Core::DisplayMessage("Unable to Load : Can't load state from other revisions !", 4000); + + delete [] buffer; } void State_Init() diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index b98f796544..81dcab21da 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -659,7 +659,10 @@ void CFrame::OnKeyDown(wxKeyEvent& event) // Toggle fullscreen if (event.GetKeyCode() == WXK_ESCAPE || (event.GetKeyCode() == WXK_RETURN && event.GetModifiers() == wxMOD_ALT)) { - DoFullscreen(!IsFullScreen()); + // If a modal dialog is open, this will still process the keyboard events, and may cause + // the main window to become unresponsive, so we have to avoid that. + if ((bRenderToMain || Core::GetState() != Core::CORE_RUN) && !m_bModalDialogOpen) + DoFullscreen(!IsFullScreen()); // We do that to avoid the event to be double processed (which would cause the window to be stuck in fullscreen) event.StopPropagation(); @@ -832,9 +835,7 @@ wxAuiNotebook* CFrame::CreateEmptyNotebook() void CFrame::DoFullscreen(bool bF) { // Only switch this to fullscreen if we're rendering to main OR if we're not running a game - // AND if this is the active window, as it could cause the main window to become unresponsive - // if we're switching to fullscreen while a modal dialog is open - if ((bRenderToMain || Core::GetState() != Core::CORE_RUN) && this->IsActive()) + if (bRenderToMain || Core::GetState() != Core::CORE_RUN) { ShowFullScreen(bF); diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 65756e7ea9..686420a36d 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -194,6 +194,7 @@ class CFrame : public wxFrame bool m_bEdit; bool m_bTabSplit; bool m_bNoDocking; + bool m_bModalDialogOpen; char **drives; diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 4a61237426..3be39eb640 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -665,9 +665,11 @@ void CFrame::OnReset(wxCommandEvent& WXUNUSED (event)) void CFrame::OnConfigMain(wxCommandEvent& WXUNUSED (event)) { + m_bModalDialogOpen = true; CConfigMain ConfigMain(this); if (ConfigMain.ShowModal() == wxID_OK) m_GameListCtrl->Update(); + m_bModalDialogOpen = false; } void CFrame::OnPluginGFX(wxCommandEvent& WXUNUSED (event)) @@ -712,8 +714,10 @@ void CFrame::OnHelp(wxCommandEvent& event) { case IDM_HELPABOUT: { - AboutDolphin frame(this); - frame.ShowModal(); + m_bModalDialogOpen = true; + AboutDolphin frame(this); + frame.ShowModal(); + m_bModalDialogOpen = false; break; } case IDM_HELPWEBSITE: @@ -756,8 +760,10 @@ void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event)) void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event)) { +m_bModalDialogOpen = true; CMemcardManager MemcardManager(this); MemcardManager.ShowModal(); +m_bModalDialogOpen = false; } void CFrame::OnShow_CheatsWindow(wxCommandEvent& WXUNUSED (event))