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:
parent
ff0a613427
commit
5ac5a04982
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
Loading…
Reference in New Issue