diff --git a/Source/Core/Common/Common.vcproj b/Source/Core/Common/Common.vcproj
index bdd518410d..6723ceb5ea 100644
--- a/Source/Core/Common/Common.vcproj
+++ b/Source/Core/Common/Common.vcproj
@@ -455,6 +455,14 @@
RelativePath=".\Src\ABI.h"
>
+
+
+
+
diff --git a/Source/Core/Common/Src/ChunkFile.cpp b/Source/Core/Common/Src/ChunkFile.cpp
new file mode 100644
index 0000000000..48f4498fef
--- /dev/null
+++ b/Source/Core/Common/Src/ChunkFile.cpp
@@ -0,0 +1,175 @@
+// 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 "ChunkFile.h"
+
+#include
+
+// Not using file mapping, just bog standard fopen and friends. We trust them to be fast
+// enough to not be the bottleneck.
+
+ChunkFile::ChunkFile(const char *filename, ChunkFileMode _mode)
+{
+ mode = _mode;
+ data = 0;
+
+ didFail = false;
+ f = fopen(filename, mode == MODE_WRITE ? "wb" : "rb");
+ if (!f) {
+ didFail = true;
+ return;
+ }
+
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ eof = size;
+
+ stack_ptr = 0;
+}
+
+ChunkFile::~ChunkFile()
+{
+ if (f)
+ fclose(f);
+}
+
+int ChunkFile::ReadInt()
+{
+ int x;
+ fread(&x, 4, 1, f);
+ return x;
+}
+
+void ChunkFile::WriteInt(int x)
+{
+ fwrite(&x, 4, 1, f);
+}
+
+bool ChunkFile::Do(void *ptr, int size)
+{
+ int sz;
+ switch (mode) {
+ case MODE_READ:
+ sz = ReadInt();
+ if (sz != size)
+ return false;
+ fread(ptr, size, 1, f);
+ fseek(f, ((size + 3) & ~3) - size, SEEK_CUR);
+ break;
+ case MODE_WRITE:
+ WriteInt(size);
+ fwrite(ptr, size, 1, f);
+ fseek(f, ((size + 3) & ~3) - size, SEEK_CUR);
+ break;
+ case MODE_VERIFY:
+ sz = ReadInt();
+ if (sz != size)
+ return false;
+ fseek(f, (size + 3) & ~3, SEEK_CUR);
+ break;
+ }
+ return true;
+}
+
+//let's get into the business
+bool ChunkFile::Descend(const char *cid)
+{
+ int id = *((int*)cid);
+ if (mode == MODE_READ)
+ {
+ bool found = false;
+ int startPos = ftell(f);
+ ChunkInfo temp = stack[stack_ptr];
+
+ //save information to restore after the next Ascend
+ stack[stack_ptr].parentStartLocation = startPos;
+ stack[stack_ptr].parentEOF = eof;
+
+ int firstID = 0;
+ //let's search through children..
+ while (ftell(f) < eof)
+ {
+ stack[stack_ptr].ID = ReadInt();
+ if (firstID == 0)
+ firstID = stack[stack_ptr].ID|1;
+ stack[stack_ptr].length = ReadInt();
+ stack[stack_ptr].startLocation = ftell(f);
+ if (stack[stack_ptr].ID == id)
+ {
+ found = true;
+ break;
+ }
+ else
+ {
+ fseek(f, stack[stack_ptr].length, SEEK_CUR); //try next block
+ }
+ }
+
+ //if we found nothing, return false so the caller can skip this
+ if (!found)
+ {
+ stack[stack_ptr] = temp;
+ fseek(f, stack[stack_ptr].parentStartLocation, SEEK_SET);
+ return false;
+ }
+
+ //descend into it
+ //pos was set inside the loop above
+ eof = stack[stack_ptr].startLocation + stack[stack_ptr].length;
+ stack_ptr++;
+ return true;
+ }
+ else
+ {
+ //write a chunk id, and prepare for filling in length later
+ WriteInt(id);
+ WriteInt(0); //will be filled in by Ascend
+ stack[stack_ptr].startLocation = ftell(f);
+ stack_ptr++;
+ return true;
+ }
+}
+
+//let's ascend out
+void ChunkFile::Ascend()
+{
+ if (mode == MODE_READ)
+ {
+ //ascend, and restore information
+ stack_ptr--;
+ fseek(f, stack[stack_ptr].parentStartLocation, SEEK_SET);
+ eof = stack[stack_ptr].parentEOF;
+ }
+ else
+ {
+ stack_ptr--;
+ //now fill in the written length automatically
+ int posNow = ftell(f);
+ fseek(f, stack[stack_ptr].startLocation - 4, SEEK_SET);
+ WriteInt(posNow - stack[stack_ptr].startLocation);
+ fseek(f, posNow, SEEK_SET);
+ }
+}
+
+int ChunkFile::GetCurrentChunkSize()
+{
+ if (stack_ptr)
+ return stack[stack_ptr - 1].length;
+ else
+ return 0;
+}
diff --git a/Source/Core/Common/Src/ChunkFile.h b/Source/Core/Common/Src/ChunkFile.h
new file mode 100644
index 0000000000..44c7719ada
--- /dev/null
+++ b/Source/Core/Common/Src/ChunkFile.h
@@ -0,0 +1,109 @@
+// 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 _CHUNKFILE_H
+#define _CHUNKFILE_H
+
+// Class to read/write/verify hierarchical binary file formats.
+// Grabbed from one of my older projects and modified heavily.
+// Works more like a RIFF file than a Google Protocol Buffer, for example.
+
+#include "Common.h"
+
+#include
+#include
+
+
+
+
diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp
index bbe2d30593..8adc9313b9 100644
--- a/Source/Core/Core/Src/CoreTiming.cpp
+++ b/Source/Core/Core/Src/CoreTiming.cpp
@@ -61,7 +61,7 @@ int RegisterEvent(const char *name, TimedCallback callback)
type.name = name;
type.callback = callback;
event_types.push_back(type);
- return event_types.size() - 1;
+ return (int)event_types.size() - 1;
}
void UnregisterAllEvents()
@@ -71,6 +71,18 @@ void UnregisterAllEvents()
event_types.clear();
}
+void DoState(ChunkFile &f)
+{
+ externalEventSection.Enter();
+ f.Descend("TIME");
+ f.Do(downcount);
+ f.Do(slicelength);
+ f.Do(maxSliceLength);
+ f.Do(globalTimer);
+ f.Do(idledCycles);
+ f.Ascend();
+ externalEventSection.Leave();
+}
u64 GetTicks()
{
diff --git a/Source/Core/Core/Src/CoreTiming.h b/Source/Core/Core/Src/CoreTiming.h
index 5139df3586..bdd0d6682c 100644
--- a/Source/Core/Core/Src/CoreTiming.h
+++ b/Source/Core/Core/Src/CoreTiming.h
@@ -25,6 +25,7 @@
// callback. You then schedule events using the type id you get back.
#include "Common.h"
+#include "ChunkFile.h"
namespace CoreTiming
{
@@ -34,6 +35,7 @@ typedef void (*TimedCallback)(u64 userdata, int cyclesLate);
u64 GetTicks();
u64 GetIdleTicks();
+void DoState(ChunkFile &f);
// The int that the callbacks get is how many cycles late it was.
// So to schedule a new event on a regular basis:
// inside callback:
diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp
index 424fb58599..3f7347bd35 100644
--- a/Source/Core/Core/Src/HW/AudioInterface.cpp
+++ b/Source/Core/Core/Src/HW/AudioInterface.cpp
@@ -87,18 +87,29 @@ struct SAudioRegister
u32 m_InterruptTiming;
};
-SAudioRegister g_AudioRegister;
+// STATE_TO_SAVE
+static SAudioRegister g_AudioRegister;
+static u64 g_LastCPUTime = 0;
+static int g_SampleRate = 32000;
+static int g_DSPSampleRate = 32000;
+static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
+
+void DoState(ChunkFile &f)
+{
+ f.Descend("AI ");
+ f.Do(g_AudioRegister);
+ f.Do(g_LastCPUTime);
+ f.Do(g_SampleRate);
+ f.Do(g_DSPSampleRate);
+ f.Do(g_CPUCyclesPerSample);
+ f.Ascend();
+}
void GenerateAudioInterrupt();
void UpdateInterrupts();
void IncreaseSampleCount(const u32 _uAmount);
void ReadStreamBlock(short* _pPCM);
-static u64 g_LastCPUTime = 0;
-static int g_SampleRate = 32000;
-static int g_DSPSampleRate = 32000;
-static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
-
void Init()
{
g_AudioRegister.m_SampleCounter = 0;
diff --git a/Source/Core/Core/Src/HW/AudioInterface.h b/Source/Core/Core/Src/HW/AudioInterface.h
index 85ca1a4231..b6adf54fcc 100644
--- a/Source/Core/Core/Src/HW/AudioInterface.h
+++ b/Source/Core/Core/Src/HW/AudioInterface.h
@@ -20,32 +20,28 @@
#ifndef _AUDIOINTERFACE_H
#define _AUDIOINTERFACE_H
+class ChunkFile;
+
namespace AudioInterface
{
-// Init
void Init();
-
-// Shutdown
void Shutdown();
+void DoState(ChunkFile &f);
-// Update
void Update();
// Calls by DSP plugin
unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples);
-// Read32
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
-
-// Write32
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
-// Get the Audio Rate (48000 or 32000)
+// Get the audio rates (48000 or 32000 only)
u32 GetAISampleRate();
u32 GetDSPSampleRate();
-} // end of namespace AudioInterface
+} // namespace
#endif
diff --git a/Source/Core/Core/Src/HW/CommandProcessor.cpp b/Source/Core/Core/Src/HW/CommandProcessor.cpp
index 99fa6967a9..eb7c3358a9 100644
--- a/Source/Core/Core/Src/HW/CommandProcessor.cpp
+++ b/Source/Core/Core/Src/HW/CommandProcessor.cpp
@@ -105,6 +105,20 @@ u16 m_tokenReg;
CPFifo fifo; //This one is shared between gfx thread and emulator thread
+void DoState(ChunkFile &f)
+{
+ f.Descend("CP ");
+ f.Do(m_CPStatusReg);
+ f.Do(m_CPCtrlReg);
+ f.Do(m_CPClearReg);
+ f.Do(m_bboxleft);
+ f.Do(m_bboxtop);
+ f.Do(m_bboxright);
+ f.Do(m_bboxbottom);
+ f.Do(m_tokenReg);
+ f.Do(fifo);
+ f.Ascend();
+}
// function
void UpdateFifoRegister();
diff --git a/Source/Core/Core/Src/HW/CommandProcessor.h b/Source/Core/Core/Src/HW/CommandProcessor.h
index 46991c8081..6775f631d0 100644
--- a/Source/Core/Core/Src/HW/CommandProcessor.h
+++ b/Source/Core/Core/Src/HW/CommandProcessor.h
@@ -18,6 +18,9 @@
#ifndef _COMMANDPROCESSOR_H
#define _COMMANDPROCESSOR_H
+#include "Common.h"
+class ChunkFile;
+
#ifdef _WIN32
#include
#endif
@@ -79,6 +82,7 @@ extern CPFifo fifo;
// Init
void Init();
void Shutdown();
+void DoState(ChunkFile &f);
// Read
void HWCALL Read16(u16& _rReturnValue, const u32 _Address);
diff --git a/Source/Core/Core/Src/HW/DSP.cpp b/Source/Core/Core/Src/HW/DSP.cpp
index 2b40ea7d8a..0ce6a4844f 100644
--- a/Source/Core/Core/Src/HW/DSP.cpp
+++ b/Source/Core/Core/Src/HW/DSP.cpp
@@ -175,6 +175,19 @@ u16 g_AR_MODE = 0x43; // 0x23 -> Zelda standard mode (standard ARAM access ??)
// 0x43 -> written by OSAudioInit at the UCode upload (upload UCode)
// 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ??
+void DoState(ChunkFile &f)
+{
+ f.Descend("DSP ");
+ f.Do(g_ARAM, ARAM_SIZE);
+ f.Do(g_dspState);
+ f.Do(g_audioDMA);
+ f.Do(g_arDMA);
+ f.Do(g_AR_READY_FLAG);
+ f.Do(g_AR_MODE);
+ f.Ascend();
+}
+
+
void UpdateInterrupts();
void Update_ARAM_DMA();
void WriteARAM(u8 _iValue, u32 _iAddress);
diff --git a/Source/Core/Core/Src/HW/DSP.h b/Source/Core/Core/Src/HW/DSP.h
index a139c9bef6..73ddaf8395 100644
--- a/Source/Core/Core/Src/HW/DSP.h
+++ b/Source/Core/Core/Src/HW/DSP.h
@@ -19,6 +19,7 @@
#define _DSPINTERFACE_H
#include "Common.h"
+class ChunkFile;
namespace DSP
{
@@ -32,6 +33,8 @@ enum DSPInterruptType
void Init();
void Shutdown();
+void DoState(ChunkFile &f);
+
void GenerateDSPInterrupt(DSPInterruptType _DSPInterruptType, bool _bSet = true);
void GenerateDSPInterruptFromPlugin(DSPInterruptType _DSPInterruptType, bool _bSet = true);
diff --git a/Source/Core/Core/Src/HW/DVDInterface.cpp b/Source/Core/Core/Src/HW/DVDInterface.cpp
index f03d1c646c..ae638557fc 100644
--- a/Source/Core/Core/Src/HW/DVDInterface.cpp
+++ b/Source/Core/Core/Src/HW/DVDInterface.cpp
@@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+#include "Common.h"
+#include "ChunkFile.h"
+
#include "StreamADPCM.H"
#include "DVDInterface.h"
@@ -44,7 +47,7 @@ namespace DVDInterface
20993: 00000000 DVD (zzz_80146e44 ??, 0x80146fcc) : DVD(r): 0xcc006018
After this, Cubivore infinitely calls DVDGetDriveStatus, which does not even
- bother to check any DVD regs
+ bother to check any DVD regs. Waiting for interrupt?
*/
// internal hardware addresses
@@ -69,7 +72,7 @@ enum DVDInterruptType
INT_DEINT = 0,
INT_TCINT = 1,
INT_BRKINT = 2,
- INT_CVRINT
+ INT_CVRINT = 3,
};
// DI Status Register
@@ -78,14 +81,14 @@ union UDISR
u32 Hex;
struct
{
- unsigned BREAK : 1; // Stop the Device + Interrupt
- unsigned DEINITMASK : 1; // Access Device Error Int Mask
- unsigned DEINT : 1; // Access Device Error Int
- unsigned TCINTMASK : 1; // Transfer Complete Int Mask
- unsigned TCINT : 1; // Transfer Complete Int
- unsigned BRKINTMASK : 1;
- unsigned BRKINT : 1; // w 1: clear brkint
- unsigned : 25;
+ unsigned BREAK : 1; // Stop the Device + Interrupt
+ unsigned DEINITMASK : 1; // Access Device Error Int Mask
+ unsigned DEINT : 1; // Access Device Error Int
+ unsigned TCINTMASK : 1; // Transfer Complete Int Mask
+ unsigned TCINT : 1; // Transfer Complete Int
+ unsigned BRKINTMASK : 1;
+ unsigned BRKINT : 1; // w 1: clear brkint
+ unsigned : 25;
};
UDISR() {Hex = 0;}
UDISR(u32 _hex) {Hex = _hex;}
@@ -97,10 +100,10 @@ union UDICVR
u32 Hex;
struct
{
- unsigned CVR : 1; // 0: Cover closed 1: Cover open
- unsigned CVRINTMASK : 1; // 1: Interrupt enabled;
- unsigned CVRINT : 1; // 1: Interrupt clear
- unsigned : 29;
+ unsigned CVR : 1; // 0: Cover closed 1: Cover open
+ unsigned CVRINTMASK : 1; // 1: Interrupt enabled;
+ unsigned CVRINT : 1; // 1: Interrupt clear
+ unsigned : 29;
};
UDICVR() {Hex = 0;}
UDICVR(u32 _hex) {Hex = _hex;}
@@ -170,11 +173,19 @@ struct DVDMemStruct
u32 AudioLength;
};
+// STATE_TO_SAVE
DVDMemStruct dvdMem;
+u32 g_ErrorCode = 0x00;
+bool g_bDiscInside = true;
-// helper
-u32 g_ErrorCode = 0x00;
-bool g_bDiscInside = true;
+void DoState(ChunkFile &f)
+{
+ f.Descend("DI ");
+ f.Do(dvdMem);
+ f.Do(g_ErrorCode);
+ f.Do(g_bDiscInside);
+ f.Ascend();
+}
void UpdateInterrupts();
void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt);
diff --git a/Source/Core/Core/Src/HW/DVDInterface.h b/Source/Core/Core/Src/HW/DVDInterface.h
index 8f9035f8ec..e16bf92604 100644
--- a/Source/Core/Core/Src/HW/DVDInterface.h
+++ b/Source/Core/Core/Src/HW/DVDInterface.h
@@ -19,13 +19,14 @@
#define _DVDINTERFACE_H
#include "Common.h"
+class ChunkFile;
namespace DVDInterface
{
-// Init
void Init();
void Shutdown();
+void DoState(ChunkFile &f);
void SetDiscInside(bool _DiscInside);
diff --git a/Source/Core/Core/Src/HW/EXI.cpp b/Source/Core/Core/Src/HW/EXI.cpp
index 67fed625f3..bc464f3bd9 100644
--- a/Source/Core/Core/Src/HW/EXI.cpp
+++ b/Source/Core/Core/Src/HW/EXI.cpp
@@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+#include "Common.h"
+#include "ChunkFile.h"
+
#include "PeripheralInterface.h"
#include "../PowerPC/PowerPC.h"
@@ -50,6 +53,13 @@ void Shutdown()
g_Channels = 0;
}
+void DoState(ChunkFile &f)
+{
+ f.Descend("EXI ");
+ // TODO: descend all the devices recursively.
+ f.Ascend();
+}
+
void Update()
{
g_Channels[0].Update();
diff --git a/Source/Core/Core/Src/HW/EXI.h b/Source/Core/Core/Src/HW/EXI.h
index c5f6fe5523..6a93a46751 100644
--- a/Source/Core/Core/Src/HW/EXI.h
+++ b/Source/Core/Core/Src/HW/EXI.h
@@ -18,12 +18,15 @@
#define _EXIINTERFACE_H
#include "Common.h"
+class ChunkFile;
namespace ExpansionInterface
{
void Init();
void Shutdown();
+void DoState(ChunkFile &f);
+
void Update();
void UpdateInterrupts();
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
index 969f664e34..8d9425a2e3 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
@@ -289,7 +289,7 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
break;
case cmdSetInterrupt:
- if (m_uPosition==1)
+ if (m_uPosition == 1)
{
interruptSwitch = byte;
}
diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp
index 02b462e292..067dd25f2a 100644
--- a/Source/Core/Core/Src/HW/GPFifo.cpp
+++ b/Source/Core/Core/Src/HW/GPFifo.cpp
@@ -15,13 +15,15 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
-#include "GPFifo.h"
-
+#include "Common.h"
+#include "ChunkFile.h"
#include "PeripheralInterface.h"
#include "CommandProcessor.h"
#include "Memmap.h"
#include "../PowerPC/PowerPC.h"
+#include "GPFifo.h"
+
namespace GPFifo
{
@@ -42,6 +44,14 @@ u8 GC_ALIGNED32(m_gatherPipe[GATHER_PIPE_SIZE*16]); //more room, for the fastmod
// pipe counter
u32 m_gatherPipeCount = 0;
+void DoState(ChunkFile &f)
+{
+ f.Descend("FIFO");
+ f.Do(m_gatherPipe);
+ f.Do(m_gatherPipeCount);
+ f.Ascend();
+}
+
void Init()
{
ResetGatherPipe();
diff --git a/Source/Core/Core/Src/HW/GPFifo.h b/Source/Core/Core/Src/HW/GPFifo.h
index b3377aeeed..a3d5dd025c 100644
--- a/Source/Core/Core/Src/HW/GPFifo.h
+++ b/Source/Core/Core/Src/HW/GPFifo.h
@@ -19,6 +19,7 @@
#define _GPFIFO_H
#include "Common.h"
+class ChunkFile;
namespace GPFifo
{
@@ -35,6 +36,7 @@ extern u32 m_gatherPipeCount;
// Init
void Init();
+void DoState(ChunkFile &f);
// ResetGatherPipe
void ResetGatherPipe();
diff --git a/Source/Core/Core/Src/HW/HW.cpp b/Source/Core/Core/Src/HW/HW.cpp
index 828f438fcf..97f88eaf21 100644
--- a/Source/Core/Core/Src/HW/HW.cpp
+++ b/Source/Core/Core/Src/HW/HW.cpp
@@ -37,6 +37,7 @@
#include "../CoreTiming.h"
#include "SystemTimers.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
+#include "../State.h"
#define CURVERSION 0x0001
@@ -45,7 +46,10 @@ namespace HW
void Init()
{
Thunk_Init(); // not really hw, but this way we know it's inited first :P
+ State_Init();
+
// Init the whole Hardware
+ AudioInterface::Init();
PixelEngine::Init();
CommandProcessor::Init();
VideoInterface::Init();
@@ -72,11 +76,32 @@ namespace HW
DSP::Shutdown();
Memory::Shutdown();
SerialInterface::Shutdown();
+ AudioInterface::Shutdown();
WII_IPC_HLE_Interface::Shutdown();
WII_IPCInterface::Shutdown();
+
+ State_Shutdown();
Thunk_Shutdown();
-
+
CoreTiming::UnregisterAllEvents();
}
+
+ void DoState(ChunkFile &f)
+ {
+ f.Descend("HWst");
+ PixelEngine::DoState(f);
+ CommandProcessor::DoState(f);
+ VideoInterface::DoState(f);
+ SerialInterface::DoState(f);
+ CPeripheralInterface::DoState(f);
+ DSP::DoState(f);
+ DVDInterface::DoState(f);
+ GPFifo::DoState(f);
+ ExpansionInterface::DoState(f);
+ AudioInterface::DoState(f);
+ CoreTiming::DoState(f);
+ WII_IPCInterface::DoState(f);
+ f.Ascend();
+ }
}
diff --git a/Source/Core/Core/Src/HW/HW.h b/Source/Core/Core/Src/HW/HW.h
index caa718a845..57c78eec48 100644
--- a/Source/Core/Core/Src/HW/HW.h
+++ b/Source/Core/Core/Src/HW/HW.h
@@ -19,15 +19,13 @@
#define _HW_H
#include "Common.h"
+#include "ChunkFile.h"
namespace HW
{
void Init();
void Shutdown();
- /*
- void LoadState(const char* _szFilename);
- void SaveState(const char* _szFilename);
- */
+ void DoState(ChunkFile &f);
}
#endif
diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h
index 5fcbb8dfe0..87bd93c558 100644
--- a/Source/Core/Core/Src/HW/Memmap.h
+++ b/Source/Core/Core/Src/HW/Memmap.h
@@ -21,6 +21,8 @@
#include "Common.h"
+class ChunkFile;
+
typedef void (HWCALL *writeFn8 )(const u8, const u32);
typedef void (HWCALL *writeFn16)(const u16,const u32);
typedef void (HWCALL *writeFn32)(const u32,const u32);
@@ -63,6 +65,8 @@ namespace Memory
bool IsInitialized();
bool Init();
bool Shutdown();
+ void DoState(ChunkFile &f);
+
void Clear();
bool AreMemoryBreakpointsActivated();
diff --git a/Source/Core/Core/Src/HW/MemoryInterface.cpp b/Source/Core/Core/Src/HW/MemoryInterface.cpp
index a4bc58ade0..8ec6717f10 100644
--- a/Source/Core/Core/Src/HW/MemoryInterface.cpp
+++ b/Source/Core/Core/Src/HW/MemoryInterface.cpp
@@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+#include "Common.h"
+#include "ChunkFile.h"
+
#include "../PowerPC/PowerPC.h"
#include "MemoryInterface.h"
@@ -47,6 +50,13 @@ struct MIMemStruct
// STATE_TO_SAVE
static MIMemStruct miMem;
+void DoState(ChunkFile &f)
+{
+ f.Descend("MI ");
+ f.Do(miMem);
+ f.Ascend();
+}
+
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
//0x30 -> 0x5a : gp memory metrics
diff --git a/Source/Core/Core/Src/HW/MemoryInterface.h b/Source/Core/Core/Src/HW/MemoryInterface.h
index fdd4768214..b02c083208 100644
--- a/Source/Core/Core/Src/HW/MemoryInterface.h
+++ b/Source/Core/Core/Src/HW/MemoryInterface.h
@@ -17,8 +17,13 @@
#ifndef _MEMORYINTERFACE_H
#define _MEMORYINTERFACE_H
+#include "Common.h"
+class ChunkFile;
+
namespace MemoryInterface
{
+void DoState(ChunkFile &f);
+
void HWCALL Read16(u16& _uReturnValue, const u32 _iAddress);
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
diff --git a/Source/Core/Core/Src/HW/PeripheralInterface.cpp b/Source/Core/Core/Src/HW/PeripheralInterface.cpp
index 69d78d659d..cf0f535a6a 100644
--- a/Source/Core/Core/Src/HW/PeripheralInterface.cpp
+++ b/Source/Core/Core/Src/HW/PeripheralInterface.cpp
@@ -16,6 +16,8 @@
// http://code.google.com/p/dolphin-emu/
#include
+#include "Common.h"
+#include "ChunkFile.h"
#include "../PowerPC/PowerPC.h"
#include "../HW/CPU.h"
@@ -31,6 +33,17 @@ u32 CPeripheralInterface::Fifo_CPUBase;
u32 CPeripheralInterface::Fifo_CPUEnd;
u32 CPeripheralInterface::Fifo_CPUWritePointer;
+void CPeripheralInterface::DoState(ChunkFile &f)
+{
+ f.Descend("PI ");
+ f.Do(m_InterruptMask);
+ f.Do(m_InterruptCause);
+ f.Do(Fifo_CPUBase);
+ f.Do(Fifo_CPUEnd);
+ f.Do(Fifo_CPUWritePointer);
+ f.Ascend();
+}
+
void CPeripheralInterface::Init()
{
m_InterruptMask = 0;
diff --git a/Source/Core/Core/Src/HW/PeripheralInterface.h b/Source/Core/Core/Src/HW/PeripheralInterface.h
index c792f3ca69..bf3abbd00b 100644
--- a/Source/Core/Core/Src/HW/PeripheralInterface.h
+++ b/Source/Core/Core/Src/HW/PeripheralInterface.h
@@ -19,6 +19,8 @@
#define _PERIPHERALINTERFACE_H
#include "Common.h"
+class ChunkFile;
+
//
// PERIPHERALINTERFACE
// Handles communication with cpu services like the write gatherer used for fifos, and interrupts
@@ -96,6 +98,7 @@ public:
static u32 Fifo_CPUWritePointer;
static void Init();
+ static void DoState(ChunkFile &f);
static void SetInterrupt(InterruptCause _causemask, bool _bSet=true);
diff --git a/Source/Core/Core/Src/HW/PixelEngine.cpp b/Source/Core/Core/Src/HW/PixelEngine.cpp
index 78c990e303..20051b0b42 100644
--- a/Source/Core/Core/Src/HW/PixelEngine.cpp
+++ b/Source/Core/Core/Src/HW/PixelEngine.cpp
@@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+#include "Common.h"
+#include "ChunkFile.h"
+
#include "PixelEngine.h"
#include "../CoreTiming.h"
@@ -60,6 +63,16 @@ static bool g_bSignalFinishInterrupt;
int et_SetTokenOnMainThread;
int et_SetFinishOnMainThread;
+void DoState(ChunkFile &f)
+{
+ f.Descend("PE ");
+ f.Do(g_ctrlReg);
+ f.Do(g_token);
+ f.Do(g_bSignalTokenInterrupt);
+ f.Do(g_bSignalFinishInterrupt);
+ f.Ascend();
+}
+
void UpdateInterrupts();
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
diff --git a/Source/Core/Core/Src/HW/PixelEngine.h b/Source/Core/Core/Src/HW/PixelEngine.h
index 299afee818..af6b1301b3 100644
--- a/Source/Core/Core/Src/HW/PixelEngine.h
+++ b/Source/Core/Core/Src/HW/PixelEngine.h
@@ -18,10 +18,12 @@
#define _PIXELENGINE_H
#include "Common.h"
+class ChunkFile;
namespace PixelEngine
{
void Init();
+void DoState(ChunkFile &f);
// Read
void HWCALL Read16(u16& _uReturnValue, const u32 _iAddress);
diff --git a/Source/Core/Core/Src/HW/SerialInterface.cpp b/Source/Core/Core/Src/HW/SerialInterface.cpp
index 184a7e49e4..aa504ab205 100644
--- a/Source/Core/Core/Src/HW/SerialInterface.cpp
+++ b/Source/Core/Core/Src/HW/SerialInterface.cpp
@@ -17,6 +17,9 @@
#include
+#include "Common.h"
+#include "ChunkFile.h"
+
#include "SerialInterface.h"
#include "SerialInterface_Devices.h"
@@ -215,6 +218,18 @@ static USIStatusReg g_StatusReg;
static USIEXIClockCount g_EXIClockCount;
static u8 g_SIBuffer[128];
+void DoState(ChunkFile &f)
+{
+ f.Descend("SI ");
+ f.Do(g_Channel);
+ f.Do(g_Poll);
+ f.Do(g_ComCSR);
+ f.Do(g_StatusReg);
+ f.Do(g_EXIClockCount);
+ f.Do(g_SIBuffer);
+ f.Ascend();
+}
+
static void GenerateSIInterrupt(SIInterruptType _SIInterrupt);
void RunSIBuffer();
void UpdateInterrupts();
@@ -228,10 +243,10 @@ void Init()
g_Channel[i].m_InLo.Hex = 0;
}
- unsigned int AttachedPasMask = PluginPAD::PAD_GetAttachedPads();
- for (int i=0; i<4; i++)
+ unsigned int AttachedPadMask = PluginPAD::PAD_GetAttachedPads();
+ for (int i = 0; i < 4; i++)
{
- if (AttachedPasMask & (1 << i))
+ if (AttachedPadMask & (1 << i))
g_Channel[i].m_pDevice = new CSIDevice_GCController(i);
else
g_Channel[i].m_pDevice = new CSIDevice_Dummy(i);
@@ -246,7 +261,7 @@ void Init()
void Shutdown()
{
- for (int i=0; i
#include "Common.h"
-#include "WII_IPC.h"
+#include "ChunkFile.h"
#include "CPU.h"
#include "Memmap.h"
#include "PeripheralInterface.h"
#include "../IPC_HLE/WII_IPC_HLE.h"
+#include "WII_IPC.h"
namespace WII_IPCInterface
{
@@ -92,6 +93,17 @@ u32 g_Address = 0;
u32 g_Reply = 0;
u32 g_SensorBarPower = 0;
+void DoState(ChunkFile &f)
+{
+ f.Descend("WIPC");
+ f.Do(g_IPC_Status);
+ f.Do(g_IPC_Config);
+ f.Do(g_IPC_Control);
+ f.Do(g_Address);
+ f.Do(g_Reply);
+ f.Do(g_SensorBarPower);
+ f.Ascend();
+}
void UpdateInterrupts();
diff --git a/Source/Core/Core/Src/HW/WII_IPC.h b/Source/Core/Core/Src/HW/WII_IPC.h
index f63b17acfd..2905a94296 100644
--- a/Source/Core/Core/Src/HW/WII_IPC.h
+++ b/Source/Core/Core/Src/HW/WII_IPC.h
@@ -17,18 +17,17 @@
#ifndef _WII_IPC_H_
#define _WII_IPC_H_
+#include "Common.h"
+class ChunkFile;
+
namespace WII_IPCInterface
{
-// Init
void Init();
-
-// Shutdown
void Shutdown();
+void DoState(ChunkFile &f);
-// Update
void Update();
-
bool IsReady();
void GenerateReply(u32 _AnswerAddress);
void GenerateAck(u32 _AnswerAddress);
diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp
index c1f7d3af6f..95a7b66257 100644
--- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp
+++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp
@@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+#include "Common.h"
+#include "ChunkFile.h"
+
#include "../HW/Memmap.h"
#include "../HW/CPU.h"
#include "../Core.h"
@@ -29,10 +32,19 @@
namespace PowerPC
{
+ // STATE_TO_SAVE
PowerPCState GC_ALIGNED16(ppcState);
+ volatile CPUState state = CPU_STEPPING;
+
ICPUCore* m_pCore = NULL;
- volatile CPUState state = CPU_STEPPING;
+ void DoState(ChunkFile &f)
+ {
+ f.Descend("PPC ");
+ f.Do(ppcState);
+ f.Do(state);
+ f.Ascend();
+ }
void ResetRegisters()
{
diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h
index 077b0b0e0d..5ec369679e 100644
--- a/Source/Core/Core/Src/PowerPC/PowerPC.h
+++ b/Source/Core/Core/Src/PowerPC/PowerPC.h
@@ -29,6 +29,8 @@
#include "Gekko.h"
#include "ICPUCore.h"
+class ChunkFile;
+
namespace PowerPC
{
enum ECoreType
@@ -85,6 +87,8 @@ namespace PowerPC
void Init();
void Shutdown();
+ void DoState(ChunkFile &f);
+
void SetCore(ECoreType _coreType);
ICPUCore& GetCore();
diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript
index 999d94b294..147eddd6ae 100644
--- a/Source/Core/Core/Src/SConscript
+++ b/Source/Core/Core/Src/SConscript
@@ -4,11 +4,12 @@ files = ["Console.cpp",
"Core.cpp",
"CoreTiming.cpp",
"CoreParameter.cpp",
- "LogManager.cpp",
- "PatchEngine.cpp",
- "MemTools.cpp",
- "Tracer.cpp",
"Host.cpp",
+ "LogManager.cpp",
+ "MemTools.cpp",
+ "PatchEngine.cpp",
+ "State.cpp",
+ "Tracer.cpp",
"VolumeHandler.cpp",
"Boot/Boot.cpp",
"Boot/Boot_DOL.cpp",
diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp
new file mode 100644
index 0000000000..a5d96db903
--- /dev/null
+++ b/Source/Core/Core/Src/State.cpp
@@ -0,0 +1,54 @@
+#include "Common.h"
+
+#include "State.h"
+#include "CoreTiming.h"
+#include "HW/HW.h"
+#include "PowerPC/PowerPC.h"
+
+static int ev_Save;
+static int ev_Load;
+
+static std::string cur_filename;
+
+void DoState(ChunkFile &f)
+{
+ f.Descend("DOLP");
+ PowerPC::DoState(f);
+ HW::DoState(f);
+ f.Ascend();
+}
+
+void SaveStateCallback(u64 userdata, int cyclesLate)
+{
+ ChunkFile f(cur_filename.c_str(), ChunkFile::MODE_WRITE);
+ DoState(f);
+}
+
+void LoadStateCallback(u64 userdata, int cyclesLate)
+{
+ ChunkFile f(cur_filename.c_str(), ChunkFile::MODE_READ);
+ DoState(f);
+}
+
+void State_Init()
+{
+ ev_Load = CoreTiming::RegisterEvent("LoadState", &LoadStateCallback);
+ ev_Save = CoreTiming::RegisterEvent("SaveState", &SaveStateCallback);
+}
+
+void State_Shutdown()
+{
+ // nothing to do, here for consistency.
+}
+
+void SaveState(const char *filename)
+{
+ cur_filename = filename;
+ CoreTiming::ScheduleEvent_Threadsafe(0, ev_Save);
+}
+
+void LoadState(const char *filename)
+{
+ cur_filename = filename;
+ CoreTiming::ScheduleEvent_Threadsafe(0, ev_Load);
+}
\ No newline at end of file
diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h
new file mode 100644
index 0000000000..5fe743d5e1
--- /dev/null
+++ b/Source/Core/Core/Src/State.h
@@ -0,0 +1,12 @@
+#ifndef _STATE_H
+#define _STATE_H
+
+// None of these happen instantly - they get scheduled as an event.
+
+void State_Init();
+void State_Shutdown();
+
+void State_Save();
+void State_Load();
+
+#endif