From 5ac5a0498222cc26b5437cc460745239291d5229 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sat, 30 Aug 2008 13:06:17 +0000 Subject: [PATCH] More state save code, "proper" fix for the quantizer problem git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@382 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/Core.cpp | 4 --- Source/Core/Core/Src/HW/HW.cpp | 1 + Source/Core/Core/Src/HW/Memmap.cpp | 11 +++++++- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 5 +++- Source/Core/Core/Src/PowerPC/Jit64/Jit.h | 1 + .../Core/Core/Src/PowerPC/Jit64/JitCache.cpp | 14 +++++++++- Source/Core/Core/Src/PowerPC/Jit64/JitCache.h | 16 +++++++++++ .../Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp | 6 +++++ .../Src/PowerPC/Jit64/Jit_SystemRegisters.cpp | 13 ++++++++- Source/Core/Core/Src/State.cpp | 25 ++++++++++++++++- Source/Core/Core/Src/State.h | 20 ++++++++++++-- Source/Core/DolphinWX/src/Frame.cpp | 27 ++++++++++--------- 12 files changed, 119 insertions(+), 24 deletions(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index f2ec671444..516ad809c3 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -413,15 +413,11 @@ EState GetState() } void SaveState() { - CCPU::EnableStepping(true); State_Save("state.dlp"); - CCPU::EnableStepping(false); } void LoadState() { - CCPU::EnableStepping(true); State_Load("state.dlp"); - CCPU::EnableStepping(false); } const SCoreStartupParameter& GetStartupParameter() diff --git a/Source/Core/Core/Src/HW/HW.cpp b/Source/Core/Core/Src/HW/HW.cpp index 3aac2ce66b..a132670db9 100644 --- a/Source/Core/Core/Src/HW/HW.cpp +++ b/Source/Core/Core/Src/HW/HW.cpp @@ -89,6 +89,7 @@ namespace HW void DoState(PointerWrap &p) { + Memory::DoState(p); PixelEngine::DoState(p); CommandProcessor::DoState(p); VideoInterface::DoState(p); diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index 40f98c56e4..1c183f7955 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -18,6 +18,7 @@ #include "Common.h" #include "MemoryUtil.h" #include "MemArena.h" +#include "ChunkFile.h" #include "Memmap.h" #include "../Core.h" @@ -143,7 +144,6 @@ template void HWCALL HW_Write_Memory(T _Data, const u32 _Addres #define AUDIO_START 0x1B #define GP_START 0x20 - void InitHWMemFuncs() { for (int i = 0; i < NUMHWMEMFUN; i++) @@ -523,6 +523,15 @@ bool Init() return true; } +void DoState(PointerWrap &p) +{ + bool wii = Core::GetStartupParameter().bWii; + p.DoArray(m_pRAM, RAM_SIZE); + p.DoArray(m_pEFB, EFB_SIZE); + p.DoArray(m_pL1Cache, L1_CACHE_SIZE); + if (wii) + p.DoArray(m_pEXRAM, EXRAM_SIZE); +} bool Shutdown() { diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 6b0e0b5eb6..c94b29e599 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -370,6 +370,7 @@ namespace Jit64 js.fifoBytesThisBlock = 0; js.curBlock = &b; js.blockSetsQuantizers = false; + js.block_flags = 0; //Analyze the block, collect all instructions it is made of (including inlining, //if that is enabled), reorder instructions for optimal performance, and join joinable instructions. @@ -415,7 +416,8 @@ namespace Jit64 js.compilerPC = ops[i].address; js.op = &ops[i]; js.instructionNumber = i; - if (i == (int)size - 1) js.isLastInstruction = true; + if (i == (int)size - 1) + js.isLastInstruction = true; // const GekkoOpInfo *info = GetOpInfo(); // if (js.isLastInstruction) @@ -435,6 +437,7 @@ namespace Jit64 } js.compilerPC += 4; + b.flags = js.block_flags; b.codeSize = (u32)(GetCodePtr() - start); b.originalSize = js.compilerPC - emaddress; return normalEntry; diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index 83b47d9d61..fda7686941 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -48,6 +48,7 @@ namespace Jit64 int blockSize; int instructionNumber; int downcountAmount; + int block_flags; bool isLastInstruction; bool blockSetsQuantizers; diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp index e897e96afa..b4f5f88a9e 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp @@ -118,6 +118,15 @@ namespace Jit64 SetCodePtr(codeCache); } + void DestroyBlocksWithFlag(BlockFlag death_flag) + { + for (int i = 0; i < numBlocks; i++) { + if (blocks[i].flags & death_flag) { + DestroyBlock(i, false); + } + } + } + void ResetCache() { ShutdownCache(); @@ -338,8 +347,11 @@ namespace Jit64 //for something else, then it's fine. LOG(MASTER_LOG, "WARNING - ClearCache detected code overwrite @ %08x", blocks[blocknum].originalAddress); } - // TODO: Unlink block. + // We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher. + // Not entirely ideal, but .. pretty good. + + // TODO - make sure that the below stuff really is safe. u8 *prev_code = GetWritableCodePtr(); // Spurious entrances from previously linked blocks can only come through checkedEntry SetCodePtr((u8*)b.checkedEntry); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.h b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.h index d7382f15ad..ea7c86d8b0 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.h @@ -28,6 +28,18 @@ namespace Jit64 //Code pointers are stored separately, they will be accessed much more frequently + enum BlockFlag + { + BLOCK_USE_GQR0 = 0x1, + BLOCK_USE_GQR1 = 0x2, + BLOCK_USE_GQR2 = 0x4, + BLOCK_USE_GQR3 = 0x8, + BLOCK_USE_GQR4 = 0x10, + BLOCK_USE_GQR5 = 0x20, + BLOCK_USE_GQR6 = 0x40, + BLOCK_USE_GQR7 = 0x80, + }; + // TODO(ector) - optimize this struct for size struct JitBlock { @@ -42,6 +54,7 @@ namespace Jit64 int runCount; // for profiling. const u8 *checkedEntry; bool invalid; + int flags; }; void PrintStats(); @@ -62,6 +75,9 @@ namespace Jit64 u8 **GetCodePointers(); u8 *Jit(u32 emaddress); + + void DestroyBlocksWithFlag(BlockFlag death_flag); + void LinkBlocks(); void ClearCache(); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp index 00ea2d2d80..429f9e3655 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -107,6 +107,8 @@ const double GC_ALIGNED16(m_dequantizeTableD[]) = void psq_st(UGeckoInstruction inst) { INSTRUCTION_START; + js.block_flags |= BLOCK_USE_GQR0 << inst.I; + if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers) { Default(inst); @@ -118,6 +120,7 @@ void psq_st(UGeckoInstruction inst) Default(inst); return; } + const UGQR gqr(rSPR(SPR_GQR0 + inst.I)); const EQuantizeType stType = static_cast(gqr.ST_TYPE); int stScale = gqr.ST_SCALE; @@ -281,11 +284,14 @@ const u8 GC_ALIGNED16(pbswapShuffleNoop[16]) = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 void psq_l(UGeckoInstruction inst) { INSTRUCTION_START; + js.block_flags |= BLOCK_USE_GQR0 << inst.I; + if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers) { Default(inst); return; } + const UGQR gqr(rSPR(SPR_GQR0 + inst.I)); const EQuantizeType ldType = static_cast(gqr.LD_TYPE); int ldScale = gqr.LD_SCALE; diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp index 8b3bab2b1a..959fa55cea 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -22,6 +22,8 @@ #include "../PowerPC.h" #include "../PPCTables.h" #include "x64Emitter.h" +#include "ABI.h" +#include "Thunk.h" #include "Jit.h" #include "JitCache.h" @@ -55,7 +57,16 @@ namespace Jit64 case SPR_GQR0 + 7: js.blockSetsQuantizers = true; // Prevent recompiler from compiling in old quantizer values. - // TODO - actually save the set state and use it in following quantizer ops. + // If the value changed, destroy all blocks using this quantizer + // This will create a little bit of block churn, but hopefully not too bad. + { + MOV(32, R(EAX), M(&PowerPC::ppcState.spr[iIndex])); // Load old value + CMP(32, R(EAX), gpr.R(inst.RD)); + FixupBranch skip_destroy = J_CC(CC_E, false); + int gqr = iIndex - SPR_GQR0; + ABI_CallFunctionC(ProtectFunction(&Jit64::DestroyBlocksWithFlag, 1), (u32)BLOCK_USE_GQR0 << gqr); + SetJumpTarget(skip_destroy); + } break; // TODO - break block if quantizers are written to. default: diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index e27007c9bb..5215c5ea87 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -1,11 +1,30 @@ +// 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 "Common.h" #include "State.h" #include "CoreTiming.h" #include "HW/HW.h" #include "PowerPC/PowerPC.h" +#include "PowerPC/Jit64/JitCache.h" #include "Plugins/Plugin_Video.h" +#include "Plugins/Plugin_DSP.h" #include @@ -18,11 +37,14 @@ void DoState(PointerWrap &p) { PowerPC::DoState(p); HW::DoState(p); + CoreTiming::DoState(p); PluginVideo::Video_DoState(p.GetPPtr(), p.GetMode()); } void SaveStateCallback(u64 userdata, int cyclesLate) { + Jit64::ClearCache(); + u8 *ptr = 0; PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); DoState(p); @@ -39,7 +61,8 @@ void SaveStateCallback(u64 userdata, int cyclesLate) void LoadStateCallback(u64 userdata, int cyclesLate) { - // ChunkFile f(cur_filename.c_str(), ChunkFile::MODE_READ); + Jit64::ClearCache(); + FILE *f = fopen(cur_filename.c_str(), "r"); fseek(f, 0, SEEK_END); int sz = ftell(f); diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h index 2fd5fe091a..e2800ff240 100644 --- a/Source/Core/Core/Src/State.h +++ b/Source/Core/Core/Src/State.h @@ -1,11 +1,27 @@ +// 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 _STATE_H #define _STATE_H -// None of these happen instantly - they get scheduled as an event. - void State_Init(); void State_Shutdown(); +// These don't happen instantly - they get scheduled as events. void State_Save(const char *filename); void State_Load(const char *filename); diff --git a/Source/Core/DolphinWX/src/Frame.cpp b/Source/Core/DolphinWX/src/Frame.cpp index ffade630ae..c9b926c58e 100644 --- a/Source/Core/DolphinWX/src/Frame.cpp +++ b/Source/Core/DolphinWX/src/Frame.cpp @@ -170,24 +170,25 @@ void CFrame::CreateMenu() fileMenu->Append(wxID_OPEN, _T("&Open...")); fileMenu->Append(wxID_REFRESH, _T("&Refresh")); fileMenu->Append(IDM_BROWSE, _T("&Browse for ISOs...")); - fileMenu->AppendSeparator(); - m_pMenuItemPlay = new wxMenuItem(fileMenu, IDM_PLAY, _T("&Play")); - fileMenu->Append(m_pMenuItemPlay); - m_pMenuItemStop = new wxMenuItem(fileMenu, IDM_STOP, _T("&Stop")); - fileMenu->Append(m_pMenuItemStop); - - fileMenu->AppendSeparator(); - m_pMenuItemLoad = new wxMenuItem(fileMenu, IDM_LOADSTATE, _T("&Load State... (AKA Russian Roulette)")); - fileMenu->Append(m_pMenuItemLoad); - m_pMenuItemLoad->Enable(false); - m_pMenuItemSave = new wxMenuItem(fileMenu, IDM_SAVESTATE, _T("Sa&ve State... (Use at your own risk)")); - fileMenu->Append(m_pMenuItemSave); - m_pMenuItemSave->Enable(false); fileMenu->AppendSeparator(); fileMenu->Append(wxID_EXIT, _T("E&xit"), _T("")); m_pMenuBar->Append(fileMenu, _T("&File")); + // emulation menu + wxMenu* emulationMenu = new wxMenu; + m_pMenuItemPlay = new wxMenuItem(fileMenu, IDM_PLAY, _T("&Play")); + emulationMenu->Append(m_pMenuItemPlay); + m_pMenuItemStop = new wxMenuItem(fileMenu, IDM_STOP, _T("&Stop")); + emulationMenu->Append(m_pMenuItemStop); + emulationMenu->AppendSeparator(); + + m_pMenuItemLoad = new wxMenuItem(fileMenu, IDM_LOADSTATE, _T("&Load State")); + emulationMenu->Append(m_pMenuItemLoad); + m_pMenuItemSave = new wxMenuItem(fileMenu, IDM_SAVESTATE, _T("Sa&ve State")); + emulationMenu->Append(m_pMenuItemSave); + m_pMenuBar->Append(emulationMenu, _T("&Emulation")); + // options menu wxMenu* pOptionsMenu = new wxMenu; m_pPluginOptions = new wxMenuItem(pOptionsMenu, IDM_PLUGIN_OPTIONS, _T("&Select plugins"));