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
This commit is contained in:
hrydgard 2008-08-30 13:06:17 +00:00
parent ff0a613427
commit 5ac5a04982
12 changed files with 119 additions and 24 deletions

View File

@ -413,15 +413,11 @@ EState GetState()
} }
void SaveState() { void SaveState() {
CCPU::EnableStepping(true);
State_Save("state.dlp"); State_Save("state.dlp");
CCPU::EnableStepping(false);
} }
void LoadState() { void LoadState() {
CCPU::EnableStepping(true);
State_Load("state.dlp"); State_Load("state.dlp");
CCPU::EnableStepping(false);
} }
const SCoreStartupParameter& GetStartupParameter() const SCoreStartupParameter& GetStartupParameter()

View File

@ -89,6 +89,7 @@ namespace HW
void DoState(PointerWrap &p) void DoState(PointerWrap &p)
{ {
Memory::DoState(p);
PixelEngine::DoState(p); PixelEngine::DoState(p);
CommandProcessor::DoState(p); CommandProcessor::DoState(p);
VideoInterface::DoState(p); VideoInterface::DoState(p);

View File

@ -18,6 +18,7 @@
#include "Common.h" #include "Common.h"
#include "MemoryUtil.h" #include "MemoryUtil.h"
#include "MemArena.h" #include "MemArena.h"
#include "ChunkFile.h"
#include "Memmap.h" #include "Memmap.h"
#include "../Core.h" #include "../Core.h"
@ -143,7 +144,6 @@ template <class T, u8* P> void HWCALL HW_Write_Memory(T _Data, const u32 _Addres
#define AUDIO_START 0x1B #define AUDIO_START 0x1B
#define GP_START 0x20 #define GP_START 0x20
void InitHWMemFuncs() void InitHWMemFuncs()
{ {
for (int i = 0; i < NUMHWMEMFUN; i++) for (int i = 0; i < NUMHWMEMFUN; i++)
@ -523,6 +523,15 @@ bool Init()
return true; 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() bool Shutdown()
{ {

View File

@ -370,6 +370,7 @@ namespace Jit64
js.fifoBytesThisBlock = 0; js.fifoBytesThisBlock = 0;
js.curBlock = &b; js.curBlock = &b;
js.blockSetsQuantizers = false; js.blockSetsQuantizers = false;
js.block_flags = 0;
//Analyze the block, collect all instructions it is made of (including inlining, //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. //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.compilerPC = ops[i].address;
js.op = &ops[i]; js.op = &ops[i];
js.instructionNumber = i; js.instructionNumber = i;
if (i == (int)size - 1) js.isLastInstruction = true; if (i == (int)size - 1)
js.isLastInstruction = true;
// const GekkoOpInfo *info = GetOpInfo(); // const GekkoOpInfo *info = GetOpInfo();
// if (js.isLastInstruction) // if (js.isLastInstruction)
@ -435,6 +437,7 @@ namespace Jit64
} }
js.compilerPC += 4; js.compilerPC += 4;
b.flags = js.block_flags;
b.codeSize = (u32)(GetCodePtr() - start); b.codeSize = (u32)(GetCodePtr() - start);
b.originalSize = js.compilerPC - emaddress; b.originalSize = js.compilerPC - emaddress;
return normalEntry; return normalEntry;

View File

@ -48,6 +48,7 @@ namespace Jit64
int blockSize; int blockSize;
int instructionNumber; int instructionNumber;
int downcountAmount; int downcountAmount;
int block_flags;
bool isLastInstruction; bool isLastInstruction;
bool blockSetsQuantizers; bool blockSetsQuantizers;

View File

@ -118,6 +118,15 @@ namespace Jit64
SetCodePtr(codeCache); 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() void ResetCache()
{ {
ShutdownCache(); ShutdownCache();
@ -338,8 +347,11 @@ namespace Jit64
//for something else, then it's fine. //for something else, then it's fine.
LOG(MASTER_LOG, "WARNING - ClearCache detected code overwrite @ %08x", blocks[blocknum].originalAddress); 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(); u8 *prev_code = GetWritableCodePtr();
// Spurious entrances from previously linked blocks can only come through checkedEntry // Spurious entrances from previously linked blocks can only come through checkedEntry
SetCodePtr((u8*)b.checkedEntry); SetCodePtr((u8*)b.checkedEntry);

View File

@ -28,6 +28,18 @@ namespace Jit64
//Code pointers are stored separately, they will be accessed much more frequently //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 // TODO(ector) - optimize this struct for size
struct JitBlock struct JitBlock
{ {
@ -42,6 +54,7 @@ namespace Jit64
int runCount; // for profiling. int runCount; // for profiling.
const u8 *checkedEntry; const u8 *checkedEntry;
bool invalid; bool invalid;
int flags;
}; };
void PrintStats(); void PrintStats();
@ -62,6 +75,9 @@ namespace Jit64
u8 **GetCodePointers(); u8 **GetCodePointers();
u8 *Jit(u32 emaddress); u8 *Jit(u32 emaddress);
void DestroyBlocksWithFlag(BlockFlag death_flag);
void LinkBlocks(); void LinkBlocks();
void ClearCache(); void ClearCache();

View File

@ -107,6 +107,8 @@ const double GC_ALIGNED16(m_dequantizeTableD[]) =
void psq_st(UGeckoInstruction inst) void psq_st(UGeckoInstruction inst)
{ {
INSTRUCTION_START; INSTRUCTION_START;
js.block_flags |= BLOCK_USE_GQR0 << inst.I;
if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers) if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers)
{ {
Default(inst); Default(inst);
@ -118,6 +120,7 @@ void psq_st(UGeckoInstruction inst)
Default(inst); Default(inst);
return; return;
} }
const UGQR gqr(rSPR(SPR_GQR0 + inst.I)); const UGQR gqr(rSPR(SPR_GQR0 + inst.I));
const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE); const EQuantizeType stType = static_cast<EQuantizeType>(gqr.ST_TYPE);
int stScale = gqr.ST_SCALE; 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) void psq_l(UGeckoInstruction inst)
{ {
INSTRUCTION_START; INSTRUCTION_START;
js.block_flags |= BLOCK_USE_GQR0 << inst.I;
if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers) if (js.blockSetsQuantizers || !Core::GetStartupParameter().bOptimizeQuantizers)
{ {
Default(inst); Default(inst);
return; return;
} }
const UGQR gqr(rSPR(SPR_GQR0 + inst.I)); const UGQR gqr(rSPR(SPR_GQR0 + inst.I));
const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE); const EQuantizeType ldType = static_cast<EQuantizeType>(gqr.LD_TYPE);
int ldScale = gqr.LD_SCALE; int ldScale = gqr.LD_SCALE;

View File

@ -22,6 +22,8 @@
#include "../PowerPC.h" #include "../PowerPC.h"
#include "../PPCTables.h" #include "../PPCTables.h"
#include "x64Emitter.h" #include "x64Emitter.h"
#include "ABI.h"
#include "Thunk.h"
#include "Jit.h" #include "Jit.h"
#include "JitCache.h" #include "JitCache.h"
@ -55,7 +57,16 @@ namespace Jit64
case SPR_GQR0 + 7: case SPR_GQR0 + 7:
js.blockSetsQuantizers = true; js.blockSetsQuantizers = true;
// Prevent recompiler from compiling in old quantizer values. // 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; break;
// TODO - break block if quantizers are written to. // TODO - break block if quantizers are written to.
default: default:

View File

@ -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 "Common.h"
#include "State.h" #include "State.h"
#include "CoreTiming.h" #include "CoreTiming.h"
#include "HW/HW.h" #include "HW/HW.h"
#include "PowerPC/PowerPC.h" #include "PowerPC/PowerPC.h"
#include "PowerPC/Jit64/JitCache.h"
#include "Plugins/Plugin_Video.h" #include "Plugins/Plugin_Video.h"
#include "Plugins/Plugin_DSP.h"
#include <string> #include <string>
@ -18,11 +37,14 @@ void DoState(PointerWrap &p)
{ {
PowerPC::DoState(p); PowerPC::DoState(p);
HW::DoState(p); HW::DoState(p);
CoreTiming::DoState(p);
PluginVideo::Video_DoState(p.GetPPtr(), p.GetMode()); PluginVideo::Video_DoState(p.GetPPtr(), p.GetMode());
} }
void SaveStateCallback(u64 userdata, int cyclesLate) void SaveStateCallback(u64 userdata, int cyclesLate)
{ {
Jit64::ClearCache();
u8 *ptr = 0; u8 *ptr = 0;
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
DoState(p); DoState(p);
@ -39,7 +61,8 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
void LoadStateCallback(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"); FILE *f = fopen(cur_filename.c_str(), "r");
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
int sz = ftell(f); int sz = ftell(f);

View File

@ -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 #ifndef _STATE_H
#define _STATE_H #define _STATE_H
// None of these happen instantly - they get scheduled as an event.
void State_Init(); void State_Init();
void State_Shutdown(); void State_Shutdown();
// These don't happen instantly - they get scheduled as events.
void State_Save(const char *filename); void State_Save(const char *filename);
void State_Load(const char *filename); void State_Load(const char *filename);

View File

@ -170,24 +170,25 @@ void CFrame::CreateMenu()
fileMenu->Append(wxID_OPEN, _T("&Open...")); fileMenu->Append(wxID_OPEN, _T("&Open..."));
fileMenu->Append(wxID_REFRESH, _T("&Refresh")); fileMenu->Append(wxID_REFRESH, _T("&Refresh"));
fileMenu->Append(IDM_BROWSE, _T("&Browse for ISOs...")); 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->AppendSeparator();
fileMenu->Append(wxID_EXIT, _T("E&xit"), _T("")); fileMenu->Append(wxID_EXIT, _T("E&xit"), _T(""));
m_pMenuBar->Append(fileMenu, _T("&File")); 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 // options menu
wxMenu* pOptionsMenu = new wxMenu; wxMenu* pOptionsMenu = new wxMenu;
m_pPluginOptions = new wxMenuItem(pOptionsMenu, IDM_PLUGIN_OPTIONS, _T("&Select plugins")); m_pPluginOptions = new wxMenuItem(pOptionsMenu, IDM_PLUGIN_OPTIONS, _T("&Select plugins"));