Save States: Refactoring - everything is now saved in size-defined blocks (should no longer need to break compatibility in the future)

This commit is contained in:
Souryo 2016-06-02 20:20:26 -04:00
parent 4eb5b11607
commit 4a784ff87a
69 changed files with 315 additions and 543 deletions

View file

@ -226,7 +226,7 @@ void APU::StreamState(bool saving)
_currentCycle = 0;
}
Stream<NesModel>(_nesModel);
Stream(_nesModel);
Stream(_squareChannel[0].get());
Stream(_squareChannel[1].get());
Stream(_triangleChannel.get());

View file

@ -60,12 +60,7 @@ public:
{
ApuLengthCounter::StreamState(saving);
Stream<bool>(_constantVolume);
Stream<uint8_t>(_volume);
Stream<uint8_t>(_envelopeCounter);
Stream<bool>(_start);
Stream<int8_t>(_divider);
Stream<uint8_t>(_counter);
Stream(_constantVolume, _volume, _envelopeCounter, _start, _divider, _counter);
}
void TickEnvelope()

View file

@ -64,15 +64,7 @@ public:
void StreamState(bool saving)
{
Stream<int32_t>(_nextIrqCycle);
Stream<int32_t>(_previousCycle);
Stream<uint32_t>(_currentStep);
Stream<uint32_t>(_stepMode);
Stream<bool>(_inhibitIRQ);
Stream<NesModel>(_nesModel);
Stream<uint8_t>(_blockFrameCounterTick, 0);
Stream<int8_t>(_writeDelayCounter, -1);
Stream<int16_t>(_newValue, -1);
Stream(_nextIrqCycle, _previousCycle, _currentStep, _stepMode, _inhibitIRQ, _nesModel, _blockFrameCounterTick, _writeDelayCounter, _newValue);
if(!saving) {
SetNesModel(_nesModel);

View file

@ -72,12 +72,7 @@ public:
{
BaseApuChannel::StreamState(saving);
Stream<bool>(_enabled);
Stream<bool>(_lengthCounterHalt);
Stream<bool>(_newHaltValue);
Stream<uint8_t>(_lengthCounter);
Stream<uint8_t>(_lengthCounterPreviousValue);
Stream<uint8_t>(_lengthCounterReloadValue);
Stream(_enabled, _lengthCounterHalt, _newHaltValue, _lengthCounter, _lengthCounterPreviousValue, _lengthCounterReloadValue);
}
bool GetStatus()

View file

@ -7,9 +7,7 @@
void ArkanoidController::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
Stream<uint32_t>(_stateBuffer);
Stream<bool>(_buttonPressed);
Stream<int32_t>(_xPosition);
Stream(_stateBuffer, _buttonPressed, _xPosition);
}
uint8_t ArkanoidController::GetPortOutput()

View file

@ -40,7 +40,6 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<uint8_t>(_prgBlock);
Stream<uint8_t>(_prgPage);
Stream(_prgBlock, _prgPage);
}
};

View file

@ -37,6 +37,6 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_bf9097Mode);
Stream(_bf9097Mode);
}
};

View file

@ -42,7 +42,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_enableMirroringControl);
Stream(_enableMirroringControl);
}
public:

View file

@ -50,10 +50,7 @@ public:
_previousCycle = 0;
}
Stream<int8_t>(_lastOutput);
Stream<uint16_t>(_timer);
Stream<uint16_t>(_period);
Stream<NesModel>(_nesModel);
Stream(_lastOutput, _timer, _period, _nesModel);
}
void SetNesModel(NesModel model)

View file

@ -21,7 +21,7 @@ BaseControlDevice::~BaseControlDevice()
void BaseControlDevice::StreamState(bool saving)
{
Stream<uint8_t>(_currentState);
Stream(_currentState);
}
uint8_t BaseControlDevice::GetPort()

View file

@ -17,15 +17,7 @@ protected:
void StreamState(bool saving)
{
Stream<uint8_t>(_speed);
Stream<uint8_t>(_gain);
Stream<bool>(_envelopeOff);
Stream<bool>(_volumeIncrease);
Stream<uint16_t>(_frequency);
Stream<uint32_t>(_timer);
Stream<uint8_t>(_masterSpeed);
Stream(_speed, _gain, _envelopeOff, _volumeIncrease, _frequency, _timer, _masterSpeed);
}
public:

View file

@ -272,17 +272,14 @@ void BaseMapper::RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr)
void BaseMapper::StreamState(bool saving)
{
StreamArray<uint8_t>(_chrRam, _chrRamSize);
Stream(_mirroringType,
ArrayInfo<uint8_t>{_chrRam, _chrRamSize},
ArrayInfo<uint8_t>{_workRam, GetWorkRamSize()},
ArrayInfo<uint8_t>{_saveRam, _saveRamSize},
ArrayInfo<uint32_t>{_prgPageNumbers, 64},
ArrayInfo<uint32_t>{_chrPageNumbers, 64},
ArrayInfo<uint8_t>{_nametableIndexes, 4});
Stream<MirroringType>(_mirroringType);
StreamArray<uint8_t>(_workRam, GetWorkRamSize());
StreamArray<uint8_t>(_saveRam, _saveRamSize);
StreamArray<uint32_t>(_prgPageNumbers, 64);
StreamArray<uint32_t>(_chrPageNumbers, 64);
StreamArray<uint8_t>(_nametableIndexes, 4);
if(!saving) {
for(uint16_t i = 0; i < 64; i++) {
if(_prgPageNumbers[i] != 0xEEEEEEEE) {

View file

@ -185,20 +185,6 @@ void CPU::StartDmcTransfer()
void CPU::StreamState(bool saving)
{
Stream<uint16_t>(_state.PC);
Stream<uint8_t>(_state.SP);
Stream<uint8_t>(_state.PS);
Stream<uint8_t>(_state.A);
Stream<uint8_t>(_state.X);
Stream<uint8_t>(_state.Y);
Stream<int32_t>(_cycleCount);
Stream<bool>(_state.NMIFlag);
Stream<uint32_t>(_state.IRQFlag);
Stream<int8_t>(_dmcCounter);
Stream<bool>(_dmcDmaRunning);
Stream<uint16_t>(_spriteDmaCounter);
Stream<bool>(_spriteDmaTransfer);
Stream(_state.PC, _state.SP, _state.PS, _state.A, _state.X, _state.Y, _cycleCount, _state.NMIFlag,
_state.IRQFlag, _dmcCounter, _dmcDmaRunning, _spriteDmaCounter, _spriteDmaTransfer);
}

View file

@ -217,16 +217,7 @@ void ControlManager::StreamState(bool saving)
}
}
Stream<bool>(_refreshState);
Stream<int32_t>(_mousePosition.X);
Stream<int32_t>(_mousePosition.Y);
Stream<NesModel>(nesModel);
Stream<ExpansionPortDevice>(expansionDevice);
Stream<ConsoleType>(consoleType);
for(int i = 0; i < 4; i++) {
Stream<ControllerType>(controllerTypes[i]);
}
Stream<bool>(hasFourScore);
Stream(_refreshState, _mousePosition.X, _mousePosition.Y, nesModel, expansionDevice, consoleType, ArrayInfo<ControllerType>{controllerTypes, 4}, hasFourScore);
if(!saving) {
EmulationSettings::SetNesModel(nesModel);

View file

@ -567,6 +567,7 @@
<ClCompile Include="NtscFilter.cpp" />
<ClCompile Include="ReverbFilter.cpp" />
<ClCompile Include="RomLoader.cpp" />
<ClCompile Include="Snapshotable.cpp" />
<ClCompile Include="SoundMixer.cpp" />
<ClCompile Include="StandardController.cpp" />
<ClCompile Include="MapperFactory.cpp" />

View file

@ -95,9 +95,6 @@
<ClInclude Include="UNROM.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="Snapshotable.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
<ClInclude Include="AXROM.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
@ -590,6 +587,9 @@
<ClInclude Include="ScaleFilter.h">
<Filter>VideoDecoder</Filter>
</ClInclude>
<ClInclude Include="Snapshotable.h">
<Filter>Nes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -736,5 +736,8 @@
<ClCompile Include="ScaleFilter.cpp">
<Filter>VideoDecoder</Filter>
</ClCompile>
<ClCompile Include="Snapshotable.cpp">
<Filter>Nes</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -108,22 +108,7 @@ void DeltaModulationChannel::Clock()
void DeltaModulationChannel::StreamState(bool saving)
{
BaseApuChannel::StreamState(saving);
Stream<uint16_t>(_sampleAddr);
Stream<uint16_t>(_sampleLength);
Stream<uint8_t>(_outputLevel);
Stream<bool>(_irqEnabled);
Stream<bool>(_loopFlag);
Stream<uint16_t>(_currentAddr);
Stream<uint16_t>(_bytesRemaining);
Stream<uint8_t>(_readBuffer);
Stream<bool>(_bufferEmpty);
Stream<uint8_t>(_shiftRegister);
Stream<uint8_t>(_bitsRemaining);
Stream<bool>(_silenceFlag);
Stream<bool>(_needToRun);
Stream(_sampleAddr, _sampleLength, _outputLevel, _irqEnabled, _loopFlag, _currentAddr, _bytesRemaining, _readBuffer, _bufferEmpty, _shiftRegister, _bitsRemaining, _silenceFlag, _needToRun);
}
bool DeltaModulationChannel::IrqPending(uint32_t cyclesToRun)

View file

@ -315,44 +315,12 @@ void FDS::StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<uint16_t>(_irqReloadValue);
Stream<uint16_t>(_irqCounter);
Stream<bool>(_irqEnabled);
Stream<bool>(_irqReloadEnabled);
Stream(_irqReloadValue, _irqCounter, _irqEnabled, _irqReloadEnabled, _diskRegEnabled, _soundRegEnabled, _writeDataReg, _motorOn, _resetTransfer,
_readMode, _crcControl, _diskReady, _diskIrqEnabled, _extConWriteReg, _badCrc, _endOfHead, _readWriteEnabled, _readDataReg, _diskWriteProtected,
_diskNumber, _newDiskNumber, _newDiskInsertDelay, _diskPosition, _delay, _previousCrcControlFlag, _gapEnded, _scanningDisk, _needIrq,
_transferComplete, _isDirty);
Stream<bool>(_diskRegEnabled);
Stream<bool>(_soundRegEnabled);
Stream<uint8_t>(_writeDataReg);
Stream<bool>(_motorOn);
Stream<bool>(_resetTransfer);
Stream<bool>(_readMode);
Stream<bool>(_crcControl);
Stream<bool>(_diskReady);
Stream<bool>(_diskIrqEnabled);
Stream<uint8_t>(_extConWriteReg);
Stream<bool>(_badCrc);
Stream<bool>(_endOfHead);
Stream<bool>(_readWriteEnabled);
Stream<uint8_t>(_readDataReg);
Stream<bool>(_diskWriteProtected);
Stream<uint32_t>(_diskNumber);
Stream<uint32_t>(_newDiskNumber);
Stream<uint32_t>(_newDiskInsertDelay);
Stream<uint32_t>(_diskPosition);
Stream<uint32_t>(_delay);
Stream<bool>(_previousCrcControlFlag);
Stream<bool>(_gapEnded);
Stream<bool>(_scanningDisk);
Stream<bool>(_needIrq);
Stream<bool>(_transferComplete);
Stream<bool>(_isDirty);
Stream(_audio.get());
}
FDS::FDS()

View file

@ -37,20 +37,8 @@ protected:
Stream(&_volume);
Stream(&_mod);
StreamArray<uint8_t>(_waveTable, 64);
Stream<bool>(_waveWriteEnabled);
Stream<bool>(_disableEnvelopes);
Stream<bool>(_haltWaveform);
Stream<uint8_t>(_masterVolume);
//Internal values
Stream<uint16_t>(_waveOverflowCounter);
Stream<int32_t>(_wavePitch);
Stream<uint8_t>(_wavePosition);
Stream<uint8_t>(_lastOutput);
Stream(_waveWriteEnabled, _disableEnvelopes, _haltWaveform, _masterVolume, _waveOverflowCounter, _wavePitch, _wavePosition, _lastOutput,
ArrayInfo<uint8_t>{_waveTable, 64});
}
public:

View file

@ -24,8 +24,7 @@ class IremG101 : public BaseMapper
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_prgRegs, 2);
Stream<uint8_t>(_prgMode);
Stream(_prgMode, _prgRegs[0], _prgRegs[1]);
}
void UpdatePrgMode()

View file

@ -25,9 +25,7 @@ protected:
void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_irqEnabled);
Stream<uint16_t>(_irqCounter);
Stream<uint16_t>(_irqReloadValue);
Stream(_irqEnabled, _irqCounter, _irqReloadValue);
}
virtual void ProcessCpuClock()

View file

@ -26,9 +26,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_prgFlag);
Stream<bool>(_chrFlag);
Stream(_prgFlag, _chrFlag);
}
void WriteRegister(uint16_t addr, uint8_t value)

View file

@ -32,14 +32,12 @@ class JalecoSs88006 : public BaseMapper
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_prgBanks, 3);
StreamArray<uint8_t>(_chrBanks, 8);
StreamArray<uint8_t>(_irqReloadValue, 4);
Stream<uint16_t>(_irqCounter);
Stream<uint8_t>(_irqCounterSize);
Stream<bool>(_irqEnabled);
BaseMapper::StreamState(saving);
Stream(_irqCounter, _irqCounterSize, _irqEnabled,
ArrayInfo<uint8_t>{_prgBanks, 3},
ArrayInfo<uint8_t>{_chrBanks, 8},
ArrayInfo<uint8_t>{_irqReloadValue, 4});
}
void SetMirroring(uint8_t value)

View file

@ -132,17 +132,8 @@ class MMC1 : public BaseMapper
protected:
void StreamState(bool saving)
{
Stream<uint8_t>(_state.Reg8000);
Stream<uint8_t>(_state.RegA000);
Stream<uint8_t>(_state.RegC000);
Stream<uint8_t>(_state.RegE000);
Stream<uint8_t>(_writeBuffer);
Stream<uint8_t>(_shiftCount);
Stream<int32_t>(_lastWriteCycle);
BaseMapper::StreamState(saving);
Stream(_state.Reg8000, _state.RegA000, _state.RegC000, _state.RegE000, _writeBuffer, _shiftCount, _lastWriteCycle);
}
virtual uint16_t GetPRGPageSize() { return 0x4000; }

View file

@ -45,13 +45,8 @@ class MMC2 : public BaseMapper
void StreamState(bool saving)
{
Stream<uint8_t>(_leftLatch);
Stream<uint8_t>(_rightLatch);
Stream<bool>(_needChrUpdate);
StreamArray<uint8_t>(_leftChrPage, 2);
StreamArray<uint8_t>(_rightChrPage, 2);
BaseMapper::StreamState(saving);
Stream(_leftLatch, _rightLatch, _needChrUpdate, _leftChrPage[0], _leftChrPage[1], _rightChrPage[0], _rightChrPage[1]);
}
void WriteRegister(uint16_t addr, uint8_t value)

View file

@ -142,30 +142,12 @@ class MMC3 : public BaseMapper
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_state.Reg8000);
Stream<uint8_t>(_state.RegA000);
Stream<uint8_t>(_state.RegA001);
Stream<uint8_t>(_currentRegister);
StreamArray<uint8_t>(_registers, 8);
Stream<uint8_t>(_chrMode);
Stream<uint8_t>(_prgMode);
Stream<uint8_t>(_irqReloadValue);
Stream<uint8_t>(_irqCounter);
Stream<bool>(_irqReload);
Stream<bool>(_irqEnabled);
Stream<uint32_t>(_lastCycle);
Stream<uint32_t>(_cyclesDown);
Stream<bool>(_wramEnabled);
Stream<bool>(_wramWriteProtected);
BaseMapper::StreamState(saving);
Stream(_state.Reg8000, _state.RegA000, _state.RegA001, _currentRegister, _chrMode, _prgMode,
_irqReloadValue, _irqCounter, _irqReload, _irqEnabled, _lastCycle, _cyclesDown,
_wramEnabled, _wramWriteProtected, ArrayInfo<uint8_t>{_registers, 8});
}
virtual uint16_t GetPRGPageSize() { return 0x2000; }
virtual uint16_t GetCHRPageSize() { return 0x0400; }

View file

@ -45,7 +45,6 @@ protected:
virtual void StreamState(bool saving)
{
MMC3::StreamState(saving);
Stream<uint8_t>(_prgReg);
Stream<uint8_t>(_chrReg);
Stream(_prgReg, _chrReg);
}
};

View file

@ -18,8 +18,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_chrSelection);
MMC3::StreamState(saving);
Stream(_chrSelection);
}
virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default)

View file

@ -36,6 +36,6 @@ private:
virtual void StreamState(bool saving)
{
MMC3::StreamState(saving);
Stream<uint8_t>(_prgReg);
Stream(_prgReg);
}
};

View file

@ -13,8 +13,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_selectedBlock);
MMC3::StreamState(saving);
Stream(_selectedBlock);
}
virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default)

View file

@ -13,8 +13,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_selectedBlock);
MMC3::StreamState(saving);
Stream(_selectedBlock);
}
virtual void Reset(bool softReset)

View file

@ -10,8 +10,8 @@ private:
protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_selectedBlock);
MMC3::StreamState(saving);
Stream(_selectedBlock);
}
virtual void Reset(bool softReset)

View file

@ -14,13 +14,12 @@ protected:
virtual void StreamState(bool saving)
{
StreamArray<uint8_t>(_reg, 4);
Stream<uint8_t>(_regIndex);
MMC3::StreamState(saving);
Stream(_regIndex, ArrayInfo<uint8_t>{_reg, 4});
if(_reg[3] & 0x40) {
RemoveRegisterRange(0x6000, 0x7FFF);
}
MMC3::StreamState(saving);
}
virtual void Reset(bool softReset)

View file

@ -13,8 +13,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_selectedBlock);
MMC3::StreamState(saving);
Stream(_selectedBlock);
}
virtual void Reset(bool softReset)

View file

@ -15,10 +15,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_selectedBlock);
Stream<uint8_t>(_prgReg);
Stream<uint8_t>(_prgMode);
MMC3::StreamState(saving);
Stream(_selectedBlock, _prgReg, _prgMode);
}
virtual void Reset(bool softReset)

View file

@ -13,8 +13,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint8_t>(_extraReg);
MMC3::StreamState(saving);
Stream(_extraReg);
}
virtual void Reset(bool softReset)

View file

@ -25,10 +25,8 @@ protected:
virtual void StreamState(bool saving)
{
Stream<uint16_t>(_firstRamBank);
Stream<uint16_t>(_lastRamBank);
Stream<uint16_t>(_chrRamSize);
MMC3::StreamState(saving);
Stream(_firstRamBank, _lastRamBank, _chrRamSize);
}
public:

View file

@ -317,47 +317,14 @@ protected:
void StreamState(bool saving)
{
Stream<uint8_t>(_prgRamProtect1);
Stream<uint8_t>(_prgRamProtect2);
Stream<uint8_t>(_fillModeTile);
Stream<uint8_t>(_fillModeColor);
Stream<bool>(_verticalSplitEnabled);
Stream<bool>(_verticalSplitRightSide);
Stream<uint8_t>(_verticalSplitDelimiterTile);
Stream<uint8_t>(_verticalSplitScroll);
Stream<uint8_t>(_verticalSplitBank);
Stream<uint8_t>(_multiplierValue1);
Stream<uint8_t>(_multiplierValue2);
Stream<uint8_t>(_nametableMapping);
Stream<uint8_t>(_extendedRamMode);
Stream<uint16_t>(_exAttributeLastNametableFetch);
Stream<int8_t>(_exAttrLastFetchCounter);
Stream<uint8_t>(_exAttrSelectedChrBank);
Stream<uint8_t>(_prgMode);
StreamArray<uint8_t>(_prgBanks, 5);
Stream<uint8_t>(_chrMode);
Stream<uint8_t>(_chrUpperBits);
StreamArray<uint16_t>(_chrBanks, 12);
Stream<uint16_t>(_lastChrReg);
Stream<bool>(_spriteFetch);
Stream<bool>(_largeSprites);
Stream<uint8_t>(_irqCounterTarget);
Stream<bool>(_irqEnabled);
Stream<int16_t>(_previousScanline);
Stream<uint8_t>(_irqCounter);
Stream<bool>(_irqPending);
Stream<bool>(_ppuInFrame);
BaseMapper::StreamState(saving);
Stream(_prgRamProtect1, _prgRamProtect2, _fillModeTile, _fillModeColor, _verticalSplitEnabled, _verticalSplitRightSide,
_verticalSplitDelimiterTile, _verticalSplitScroll, _verticalSplitBank, _multiplierValue1, _multiplierValue2,
_nametableMapping, _extendedRamMode, _exAttributeLastNametableFetch, _exAttrLastFetchCounter, _exAttrSelectedChrBank,
_prgMode, ArrayInfo<uint8_t>{_prgBanks, 5}, _chrMode, _chrUpperBits, ArrayInfo<uint16_t>{_chrBanks, 12}, _lastChrReg,
_spriteFetch, _largeSprites, _irqCounterTarget, _irqEnabled, _previousScanline, _irqCounter, _irqPending, _ppuInFrame);
if(!saving) {
UpdatePrgBanks();
}

View file

@ -22,7 +22,7 @@ protected:
void StreamState(bool saving)
{
MMC3::StreamState(saving);
Stream<uint8_t>(_currentReg);
Stream(_currentReg);
}
void WriteRegister(uint16_t addr, uint8_t value)

View file

@ -21,7 +21,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_prgMode1);
Stream(_prgMode1);
}
void WriteRegister(uint16_t addr, uint8_t value)

View file

@ -24,7 +24,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_registers, 2);
Stream(_registers[0], _registers[1]);
}
virtual void Reset(bool softReset)

View file

@ -20,7 +20,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_contraMode);
Stream(_contraMode);
}
virtual void Reset(bool softReset)

View file

@ -22,7 +22,7 @@ protected:
void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_registers, 2);
Stream(_registers[0], _registers[1]);
}
void UpdateState()

View file

@ -33,6 +33,6 @@ protected:
void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<uint8_t>(_resetCounter);
Stream(_resetCounter);
}
};

View file

@ -171,8 +171,7 @@ uint32_t MemoryManager::ToAbsoluteChrAddress(uint16_t vramAddr)
void MemoryManager::StreamState(bool saving)
{
StreamArray<uint8_t>(_internalRAM, MemoryManager::InternalRAMSize);
for(int i = 0; i < 2; i++) {
StreamArray<uint8_t>(_nametableRAM[i], MemoryManager::NameTableScreenSize);
}
Stream(ArrayInfo<uint8_t>{_internalRAM, MemoryManager::InternalRAMSize},
ArrayInfo<uint8_t>{_nametableRAM[0], MemoryManager::NameTableScreenSize},
ArrayInfo<uint8_t>{_nametableRAM[1], MemoryManager::NameTableScreenSize});
}

View file

@ -19,13 +19,7 @@ protected:
void StreamState(bool saving)
{
BaseFdsChannel::StreamState(saving);
Stream<int8_t>(_counter);
Stream<bool>(_modulationDisabled);
Stream<uint8_t>(_modTablePosition);
Stream<uint16_t>(_overflowCounter);
StreamArray<uint8_t>(_modTable, 64);
Stream(_counter, _modulationDisabled, _modTablePosition, _overflowCounter, ArrayInfo<uint8_t>{_modTable, 64});
}
public:

View file

@ -26,10 +26,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_registers, 5);
Stream<bool>(_toggle);
Stream<bool>(_autoSwitchCHR);
Stream(ArrayInfo<uint8_t>{_registers, 5}, _toggle, _autoSwitchCHR);
}
void InitMapper()

View file

@ -53,8 +53,7 @@ public:
{
ApuEnvelope::StreamState(saving);
Stream<uint16_t>(_shiftRegister);
Stream<bool>(_modeFlag);
Stream(_shiftRegister, _modeFlag);
}
void GetMemoryRanges(MemoryRanges &ranges)

View file

@ -883,94 +883,22 @@ void PPU::ExecStatic()
void PPU::StreamState(bool saving)
{
Stream<uint8_t>(_state.Control);
Stream<uint8_t>(_state.Mask);
Stream<uint8_t>(_state.Status);
Stream<uint32_t>(_state.SpriteRamAddr);
Stream<uint16_t>(_state.VideoRamAddr);
Stream<uint8_t>(_state.XScroll);
Stream<uint16_t>(_state.TmpVideoRamAddr);
Stream<bool>(_state.WriteToggle);
Stream<uint16_t>(_state.HighBitShift);
Stream<uint16_t>(_state.LowBitShift);
Stream<bool>(_flags.VerticalWrite);
Stream<uint16_t>(_flags.SpritePatternAddr);
Stream<uint16_t>(_flags.BackgroundPatternAddr);
Stream<bool>(_flags.LargeSprites);
Stream<bool>(_flags.VBlank);
Stream<bool>(_flags.Grayscale);
Stream<bool>(_flags.BackgroundMask);
Stream<bool>(_flags.SpriteMask);
Stream<bool>(_flags.BackgroundEnabled);
Stream<bool>(_flags.SpritesEnabled);
Stream<bool>(_flags.IntensifyRed);
Stream<bool>(_flags.IntensifyGreen);
Stream<bool>(_flags.IntensifyBlue);
Stream<uint8_t>(_paletteRamMask);
Stream<uint16_t>(_intensifyColorBits);
Stream<bool>(_statusFlags.SpriteOverflow);
Stream<bool>(_statusFlags.Sprite0Hit);
Stream<bool>(_statusFlags.VerticalBlank);
Stream<int32_t>(_scanline);
Stream<uint32_t>(_cycle);
Stream<uint32_t>(_frameCount);
Stream<uint8_t>(_memoryReadBuffer);
StreamArray<uint8_t>(_paletteRAM, 0x20);
StreamArray<uint8_t>(_spriteRAM, 0x100);
StreamArray<uint8_t>(_secondarySpriteRAM, 0x20);
Stream<uint8_t>(_currentTile.LowByte);
Stream<uint8_t>(_currentTile.HighByte);
Stream<uint32_t>(_currentTile.PaletteOffset);
Stream<uint8_t>(_nextTile.LowByte);
Stream<uint8_t>(_nextTile.HighByte);
Stream<uint32_t>(_nextTile.PaletteOffset);
Stream<uint16_t>(_nextTile.TileAddr);
Stream<uint8_t>(_previousTile.LowByte);
Stream<uint8_t>(_previousTile.HighByte);
Stream<uint32_t>(_previousTile.PaletteOffset);
Stream(_state.Control, _state.Mask, _state.Status, _state.SpriteRamAddr, _state.VideoRamAddr, _state.XScroll, _state.TmpVideoRamAddr, _state.WriteToggle,
_state.HighBitShift, _state.LowBitShift, _flags.VerticalWrite, _flags.SpritePatternAddr, _flags.BackgroundPatternAddr, _flags.LargeSprites, _flags.VBlank,
_flags.Grayscale, _flags.BackgroundMask, _flags.SpriteMask, _flags.BackgroundEnabled, _flags.SpritesEnabled, _flags.IntensifyRed, _flags.IntensifyGreen,
_flags.IntensifyBlue, _paletteRamMask, _intensifyColorBits, _statusFlags.SpriteOverflow, _statusFlags.Sprite0Hit, _statusFlags.VerticalBlank, _scanline,
_cycle, _frameCount, _memoryReadBuffer, _currentTile.LowByte, _currentTile.HighByte, _currentTile.PaletteOffset, _nextTile.LowByte, _nextTile.HighByte,
_nextTile.PaletteOffset, _nextTile.TileAddr, _previousTile.LowByte, _previousTile.HighByte, _previousTile.PaletteOffset, _spriteIndex, _spriteCount,
_secondaryOAMAddr, _sprite0Visible, _oamCopybuffer, _spriteInRange, _sprite0Added, _spriteAddrH, _spriteAddrL, _oamCopyDone, _nesModel, _spriteDmaAddr,
_spriteDmaCounter, _prevRenderingEnabled, _renderingEnabled, _openBus, _ignoreVramRead, _skipScrollingIncrement,
ArrayInfo<uint8_t>{_paletteRAM, 0x20},
ArrayInfo<uint8_t>{_spriteRAM, 0x100},
ArrayInfo<uint8_t>{_secondarySpriteRAM, 0x20},
ArrayInfo<int32_t>{_openBusDecayStamp, 8});
for(int i = 0; i < 64; i++) {
Stream<uint8_t>(_spriteTiles[i].SpriteX);
Stream<uint8_t>(_spriteTiles[i].LowByte);
Stream<uint8_t>(_spriteTiles[i].HighByte);
Stream<uint32_t>(_spriteTiles[i].PaletteOffset);
Stream<bool>(_spriteTiles[i].HorizontalMirror);
Stream<bool>(_spriteTiles[i].BackgroundPriority);
Stream(_spriteTiles[i].SpriteX, _spriteTiles[i].LowByte, _spriteTiles[i].HighByte, _spriteTiles[i].PaletteOffset, _spriteTiles[i].HorizontalMirror, _spriteTiles[i].BackgroundPriority);
}
Stream<uint32_t>(_spriteIndex);
Stream<uint32_t>(_spriteCount);
Stream<uint32_t>(_secondaryOAMAddr);
Stream<bool>(_sprite0Visible);
Stream<uint8_t>(_oamCopybuffer);
Stream<bool>(_spriteInRange);
Stream<bool>(_sprite0Added);
Stream<int32_t>();
Stream<uint8_t>(_spriteAddrH);
Stream<uint8_t>(_spriteAddrL);
Stream<bool>(_oamCopyDone);
Stream<NesModel>(_nesModel);
Stream<uint16_t>(_spriteDmaAddr);
Stream<uint16_t>(_spriteDmaCounter);
Stream<bool>(_prevRenderingEnabled);
Stream<bool>(_renderingEnabled);
Stream<uint8_t>(_openBus);
StreamArray<int32_t>(_openBusDecayStamp, 8);
Stream<uint32_t>(_ignoreVramRead);
Stream<bool>(_skipScrollingIncrement);
if(!saving) {
SetNesModel(_nesModel);

View file

@ -35,20 +35,8 @@ protected:
void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_irqEnabled);
Stream<bool>(_irqCycleMode);
Stream<bool>(_needReload);
Stream<uint8_t>(_needIrqDelay);
Stream<uint8_t>(_irqCounter);
Stream<uint8_t>(_irqReloadValue);
Stream<uint32_t>(_lastCycle);
Stream<uint32_t>(_cyclesDown);
Stream<uint8_t>(_cpuClockCounter);
Stream<uint8_t>(_currentRegister);
StreamArray<uint8_t>(_registers, 16);
Stream<bool>(_forceClock);
Stream(_irqEnabled, _irqCycleMode, _needReload, _needIrqDelay, _irqCounter, _irqReloadValue, _lastCycle,
_cyclesDown, _cpuClockCounter, _currentRegister, ArrayInfo<uint8_t>{_registers, 16}, _forceClock);
}
virtual void ProcessCpuClock()

View file

@ -8,7 +8,7 @@ private:
static string GetStateFilepath(int stateIndex);
public:
static const uint32_t FileFormatVersion = 2;
static const uint32_t FileFormatVersion = 3;
static uint64_t GetStateInfo(int stateIndex);
static void SaveState(int stateIndex);

101
Core/Snapshotable.cpp Normal file
View file

@ -0,0 +1,101 @@
#pragma once
#include "stdafx.h"
#include <algorithm>
#include "Snapshotable.h"
void Snapshotable::StreamStartBlock()
{
if(_inBlock) {
throw new std::runtime_error("Cannot start a new block before ending the last block");
}
_blockBuffer = new uint8_t[0xFFFFF];
if(!_saving) {
InternalStream(_blockSize);
InternalStream(ArrayInfo<uint8_t>{_blockBuffer, std::min((uint32_t)0xFFFFF, _blockSize)});
}
_blockPosition = 0;
_inBlock = true;
}
void Snapshotable::StreamEndBlock()
{
_inBlock = false;
if(_saving) {
InternalStream(_blockPosition);
InternalStream(ArrayInfo<uint8_t>{_blockBuffer, _blockPosition});
}
delete[] _blockBuffer;
_blockBuffer = nullptr;
}
void Snapshotable::Stream(Snapshotable* snapshotable)
{
stringstream stream;
if(_saving) {
snapshotable->SaveSnapshot(&stream);
uint32_t size = (uint32_t)stream.tellp();
stream.seekg(0, ios::beg);
stream.seekp(0, ios::beg);
uint8_t *buffer = new uint8_t[size];
stream.read((char*)buffer, size);
InternalStream(size);
InternalStream(ArrayInfo<uint8_t>{buffer, size});
delete[] buffer;
} else {
uint32_t size = 0;
InternalStream(size);
if(_position + size <= _streamSize) {
uint8_t *buffer = new uint8_t[size];
InternalStream(ArrayInfo<uint8_t>{buffer, size});
stream.write((char*)buffer, size);
stream.seekg(0, ios::beg);
stream.seekp(0, ios::beg);
snapshotable->LoadSnapshot(&stream);
delete[] buffer;
} else {
_position = _streamSize;
}
}
}
void Snapshotable::SaveSnapshot(ostream* file)
{
_stream = new uint8_t[0xFFFFF];
memset((char*)_stream, 0, 0xFFFFF);
_position = 0;
_saving = true;
StreamState(_saving);
file->write((char*)&_position, sizeof(_position));
file->write((char*)_stream, _position);
delete[] _stream;
if(_blockBuffer) {
throw new std::runtime_error("A call to StreamEndBlock is missing.");
}
}
void Snapshotable::LoadSnapshot(istream* file)
{
_stream = new uint8_t[0xFFFFF];
memset((char*)_stream, 0, 0xFFFFF);
_position = 0;
_saving = false;
file->read((char*)&_streamSize, sizeof(_streamSize));
file->read((char*)_stream, _streamSize);
StreamState(_saving);
delete[] _stream;
if(_blockBuffer) {
throw new std::runtime_error("A call to StreamEndBlock is missing.");
}
}

View file

@ -2,64 +2,62 @@
#include "stdafx.h"
template<typename T>
struct ArrayInfo
{
T* Array;
uint32_t ElementCount;
};
template<typename T>
struct ValueInfo
{
T* Value;
T DefaultValue;
};
template<typename T>
struct EmptyInfo
{
T Empty;
};
class Snapshotable
{
private:
uint8_t* _stream;
uint32_t _position;
uint32_t _streamSize;
bool _inBlock = false;
uint8_t* _blockBuffer = nullptr;
uint32_t _blockSize = 0;
uint32_t _blockPosition = 0;
bool _saving;
protected:
virtual void StreamState(bool saving) = 0;
void Stream(Snapshotable* snapshotable)
{
stringstream stream;
if(_saving) {
snapshotable->SaveSnapshot(&stream);
uint32_t size = (uint32_t)stream.tellp();
stream.seekg(0, ios::beg);
stream.seekp(0, ios::beg);
uint8_t *buffer = new uint8_t[size];
stream.read((char*)buffer, size);
Stream<uint32_t>(size);
StreamArray<uint8_t>(buffer, size);
delete[] buffer;
} else {
uint32_t size = 0;
Stream<uint32_t>(size);
if(_position + size <= _streamSize) {
uint8_t *buffer = new uint8_t[size];
StreamArray(buffer, size);
stream.write((char*)buffer, size);
stream.seekg(0, ios::beg);
stream.seekp(0, ios::beg);
snapshotable->LoadSnapshot(&stream);
delete[] buffer;
private:
template<typename T>
void StreamElement(T &value, T defaultValue = T())
{
if(_saving) {
uint8_t* bytes = (uint8_t*)&value;
int typeSize = sizeof(T);
for(int i = 0; i < typeSize; i++) {
if(_inBlock) {
_blockBuffer[_blockPosition++] = bytes[i];
} else {
_position = _streamSize;
_stream[_position++] = bytes[i];
}
}
}
template<typename T>
void Stream()
{
//Used to skip old values
_position += sizeof(T);
}
template<typename T>
void Stream(T &value, T defaultValue = T())
{
if(_saving) {
uint8_t* bytes = (uint8_t*)&value;
int typeSize = sizeof(T);
for(int i = 0; i < typeSize; i++) {
_stream[_position++] = bytes[i];
} else {
if(_inBlock) {
if(_blockPosition + sizeof(T) <= _blockSize) {
value = *((T*)(_blockBuffer + _blockPosition));
_blockPosition += sizeof(T);
} else {
value = defaultValue;
_blockPosition = _blockSize;
}
} else {
if(_position + sizeof(T) <= _streamSize) {
@ -71,55 +69,68 @@ class Snapshotable
}
}
}
}
template<typename T>
void StreamArray(T* value, uint32_t length)
{
uint32_t typeSize = sizeof(T);
if(_saving) {
uint8_t* bytes = (uint8_t*)value;
for(uint32_t i = 0, len = length*typeSize; i < len; i++) {
_stream[_position++] = bytes[i];
}
} else {
for(uint32_t i = 0, len = length*typeSize; i < len; i++) {
if(_position < _streamSize) {
((uint8_t*)value)[i] = _stream[_position];
_position++;
} else {
((uint8_t*)value)[i] = 0;
_position = _streamSize;
}
}
}
template<typename T>
void InternalStream(EmptyInfo<T> &info)
{
if(_inBlock) {
_blockPosition += sizeof(T);
} else {
_position += sizeof(T);
}
}
public:
void SaveSnapshot(ostream* file)
{
_stream = new uint8_t[0xFFFFF];
memset((char*)_stream, 0, 0xFFFFF);
_position = 0;
_saving = true;
StreamState(_saving);
file->write((char*)&_position, sizeof(_position));
file->write((char*)_stream, _position);
delete[] _stream;
template<typename T>
void InternalStream(ArrayInfo<T> &info)
{
T* pointer = info.Array;
for(uint32_t i = 0; i < info.ElementCount; i++) {
StreamElement<T>(*pointer);
pointer++;
}
}
void LoadSnapshot(istream* file)
{
_stream = new uint8_t[0xFFFFF];
memset((char*)_stream, 0, 0xFFFFF);
_position = 0;
_saving = false;
file->read((char*)&_streamSize, sizeof(_streamSize));
file->read((char*)_stream, _streamSize);
StreamState(_saving);
template<typename T>
void InternalStream(ValueInfo<T> &info)
{
StreamElement<T>(*info.Value, info.DefaultValue);
}
delete[] _stream;
}
template<typename T>
void InternalStream(T &value)
{
StreamElement<T>(value);
}
void RecursiveStream()
{
}
template<typename T, typename... T2>
void RecursiveStream(T &value, T2&... args)
{
InternalStream(value);
RecursiveStream(args...);
}
void StreamStartBlock();
void StreamEndBlock();
protected:
virtual void StreamState(bool saving) = 0;
void Stream(Snapshotable* snapshotable);
template<typename... T>
void Stream(T&... args)
{
StreamStartBlock();
RecursiveStream(args...);
StreamEndBlock();
}
public:
void SaveSnapshot(ostream* file);
void LoadSnapshot(istream* file);
};

View file

@ -24,17 +24,14 @@ SoundMixer::~SoundMixer()
void SoundMixer::StreamState(bool saving)
{
Stream<uint32_t>(_clockRate);
Stream<uint32_t>(_sampleRate);
Stream<AudioChannel>(_expansionAudioType);
Stream(_clockRate, _sampleRate, _expansionAudioType);
if(!saving) {
Reset();
UpdateRates();
}
Stream<int16_t>(_previousOutput);
StreamArray<int8_t>(_currentOutput, MaxChannelCount);
Stream(_previousOutput, ArrayInfo<int8_t>{_currentOutput, MaxChannelCount});
}
void SoundMixer::RegisterAudioDevice(IAudioDevice *audioDevice)

View file

@ -105,16 +105,7 @@ public:
{
ApuEnvelope::StreamState(saving);
Stream<uint16_t>(_realPeriod);
Stream<uint8_t>(_duty);
Stream<uint8_t>(_dutyPos);
Stream<bool>(_sweepEnabled);
Stream<uint8_t>(_sweepPeriod);
Stream<bool>(_sweepNegate);
Stream<uint8_t>(_sweepShift);
Stream<bool>(_reloadSweep);
Stream<uint8_t>(_sweepDivider);
Stream<uint32_t>(_sweepTargetPeriod);
Stream(_realPeriod, _duty, _dutyPos, _sweepEnabled, _sweepPeriod, _sweepNegate, _sweepShift, _reloadSweep, _sweepDivider, _sweepTargetPeriod);
}
void GetMemoryRanges(MemoryRanges &ranges)

View file

@ -8,8 +8,7 @@
void StandardController::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
Stream<uint32_t>(_stateBuffer);
Stream<uint32_t>(_stateBufferFamicom);
Stream(_stateBuffer, _stateBufferFamicom);
if(_additionalController) {
Stream(_additionalController.get());

View file

@ -22,9 +22,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_irqLatch);
Stream<bool>(_irqEnabled);
Stream<uint16_t>(_irqCounter);
Stream(_irqLatch, _irqEnabled, _irqCounter);
}
virtual void ProcessCpuClock()

View file

@ -14,11 +14,6 @@ protected:
SelectPRGPage(1, -1);
}
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
}
void WriteRegister(uint16_t addr, uint8_t value)
{
switch(addr & 0xF000) {

View file

@ -92,7 +92,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<uint8_t>(_ramPermission);
Stream(_ramPermission);
if(!saving) {
UpdateRamAccess();

View file

@ -110,9 +110,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_ramPermission, 3);
StreamArray<uint8_t>(_chrRegs, 6);
Stream<uint8_t>(_chrMode);
Stream(ArrayInfo<uint8_t>{_ramPermission, 3}, ArrayInfo<uint8_t>{_chrRegs, 6}, _chrMode);
if(!saving) {
UpdateRamAccess();

View file

@ -48,11 +48,7 @@ public:
{
ApuLengthCounter::StreamState(saving);
Stream<uint8_t>(_linearCounter);
Stream<uint8_t>(_linearCounterReload);
Stream<bool>(_linearReloadFlag);
Stream<bool>(_linearControlFlag);
Stream<uint8_t>(_sequencePosition);
Stream(_linearCounter, _linearCounterReload, _linearReloadFlag, _linearControlFlag, _sequencePosition);
}
void GetMemoryRanges(MemoryRanges &ranges)

View file

@ -6,11 +6,6 @@
class TxSRom : public MMC3
{
protected:
virtual void StreamState(bool saving)
{
MMC3::StreamState(saving);
}
void UpdateMirroring()
{
//This is disabled, 8001 writes are used to setup mirroring instead

View file

@ -25,7 +25,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
StreamArray<uint8_t>(_chrBanks, 2);
Stream(ArrayInfo<uint8_t>{ _chrBanks, 2 });
}
void WriteRegister(uint16_t addr, uint8_t value)

View file

@ -188,17 +188,7 @@ class VRC2_4 : public BaseMapper
void StreamState(bool saving)
{
Stream<uint8_t>(_prgReg0);
Stream<uint8_t>(_prgReg1);
Stream<uint8_t>(_prgMode);
StreamArray<uint8_t>(_loCHRRegs, 8);
StreamArray<uint8_t>(_hiCHRRegs, 8);
Stream<bool>(_hasIRQ);
Stream(_irq);
BaseMapper::StreamState(saving);
Stream(_prgReg0, _prgReg1, _prgMode, ArrayInfo<uint8_t>{_loCHRRegs, 8}, ArrayInfo<uint8_t>{_hiCHRRegs, 8}, _hasIRQ, _irq);
}
};

View file

@ -25,11 +25,7 @@ protected:
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream<bool>(_irqEnableOnAck);
Stream<bool>(_smallCounter);
Stream<bool>(_irqEnabled);
Stream<uint16_t>(_irqCounter);
Stream<uint16_t>(_irqReload);
Stream(_irqEnableOnAck, _smallCounter, _irqEnabled, _irqCounter, _irqReload);
}
virtual void ProcessCpuClock()

View file

@ -34,8 +34,7 @@ protected:
{
BaseMapper::StreamState(saving);
Stream(_irq);
Stream<uint8_t>(_bankingMode);
StreamArray<uint8_t>(_chrRegisters, 8);
Stream(_bankingMode, ArrayInfo<uint8_t>{_chrRegisters, 8});
if(!saving) {
UpdatePrgRamAccess();

View file

@ -32,8 +32,7 @@ protected:
{
BaseMapper::StreamState(saving);
Stream(_irq);
Stream<uint8_t>(_controlFlags);
StreamArray<uint8_t>(_chrRegisters, 8);
Stream(_controlFlags, ArrayInfo<uint8_t>{_chrRegisters, 8});
if(!saving) {
UpdatePrgRamAccess();

View file

@ -15,12 +15,7 @@ private:
protected:
void StreamState(bool saving)
{
Stream<uint8_t>(_irqReloadValue);
Stream<uint8_t>(_irqCounter);
Stream<int16_t>(_irqPrescalerCounter);
Stream<bool>(_irqEnabled);
Stream<bool>(_irqEnabledAfterAck);
Stream<bool>(_irqCycleMode);
Stream(_irqReloadValue, _irqCounter, _irqPrescalerCounter, _irqEnabled, _irqEnabledAfterAck, _irqCycleMode);
}
public:

View file

@ -19,9 +19,7 @@ struct ZapperButtonState
void Zapper::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
Stream<int32_t>(_xPosition);
Stream<int32_t>(_yPosition);
Stream<bool>(_pulled);
Stream(_xPosition, _yPosition, _pulled);
}
uint32_t Zapper::GetNetPlayState()