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 +#include + +//TO REMEMBER WHEN USING: + +//EITHER a chunk contains ONLY data +//OR it contains ONLY other chunks +//otherwise the scheme breaks... + +class ChunkFile +{ +public: + enum ChunkFileMode + { + MODE_READ, + MODE_WRITE, + MODE_VERIFY, + }; +private: + struct ChunkInfo + { + int startLocation; + int parentStartLocation; + int parentEOF; + unsigned int ID; + int length; + }; + + ChunkInfo stack[8]; + int stack_ptr; + + char *data; + int size; + int eof; + + ChunkFileMode mode; + FILE *f; + bool didFail; + + // Used for internal bookkeeping only. + int ReadInt(); + void WriteInt(int x); + +public: + + ChunkFile(const char *filename, ChunkFileMode mode); + ~ChunkFile(); + + // Only pass 4-character IDs. + bool Descend(const char *id); + void Ascend(); + + //void Do(int &i); + //bool Do(std::string &s); + bool Do(void *ptr, int size); + + // Future + // bool DoCompressed(void *ptr, int size) + + // Store maps to file. Very useful. + template + void Do(std::map &x) { + + } + + // Store vectors. + template + void Do(std::vector &x) { + + } + + // Handle everything else + template + void Do(T &x) { + Do((void *)&x, sizeof(x)); + } + + int GetCurrentChunkSize(); + bool failed() {return didFail;} +}; + +#endif \ No newline at end of file diff --git a/Source/Core/Common/Src/SConscript b/Source/Core/Common/Src/SConscript index 5f215ab564..52a4fe3335 100644 --- a/Source/Core/Common/Src/SConscript +++ b/Source/Core/Common/Src/SConscript @@ -2,6 +2,7 @@ Import('env') files = ["ABI.cpp", "Common.cpp", + "ChunkFile.cpp", "CPUDetect.cpp", "DynamicLibrary.cpp", "Hash.cpp", diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index 3a7e322e21..d50aab1792 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -1174,6 +1174,14 @@ RelativePath=".\Src\SConscript" > + + + + 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