New serialize framework. Delay maple dma xfer

New serialize framework. Refactor serialization into modules.
Maple dma xfer must not be executed immediately. Delay until interrupt
is raised.
Fixes Geist Force freeze at start.
This commit is contained in:
Flyinghead 2021-11-13 15:56:42 +01:00
parent e56ecfec40
commit 8f80bcb159
54 changed files with 1863 additions and 1860 deletions

View File

@ -652,8 +652,9 @@ target_sources(${PROJECT_NAME} PRIVATE
core/hw/naomi/naomi_roms.cpp core/hw/naomi/naomi_roms.cpp
core/hw/naomi/naomi_roms.h core/hw/naomi/naomi_roms.h
core/hw/naomi/naomi_roms_input.h core/hw/naomi/naomi_roms_input.h
core/hw/pvr/drkPvr.cpp
core/hw/pvr/helper_classes.h core/hw/pvr/helper_classes.h
core/hw/pvr/pvr.cpp
core/hw/pvr/pvr.h
core/hw/pvr/pvr_mem.cpp core/hw/pvr/pvr_mem.cpp
core/hw/pvr/pvr_mem.h core/hw/pvr/pvr_mem.h
core/hw/pvr/pvr_regs.cpp core/hw/pvr/pvr_regs.cpp
@ -890,6 +891,7 @@ target_sources(${PROJECT_NAME} PRIVATE
core/emulator.h core/emulator.h
core/nullDC.cpp core/nullDC.cpp
core/serialize.cpp core/serialize.cpp
core/serialize.h
core/stdclass.cpp core/stdclass.cpp
core/stdclass.h core/stdclass.h
core/types.h core/types.h

View File

@ -40,6 +40,8 @@
#include "rend/gui.h" #include "rend/gui.h"
#include "lua/lua.h" #include "lua/lua.h"
#include "network/naomi_network.h" #include "network/naomi_network.h"
#include "serialize.h"
#include "hw/pvr/pvr.h"
#include <chrono> #include <chrono>
settings_t settings; settings_t settings;
@ -327,7 +329,7 @@ void dc_reset(bool hard)
if (hard) if (hard)
_vmem_unprotect_vram(0, VRAM_SIZE); _vmem_unprotect_vram(0, VRAM_SIZE);
sh4_sched_reset(hard); sh4_sched_reset(hard);
libPvr_Reset(hard); pvr::reset(hard);
libAICA_Reset(hard); libAICA_Reset(hard);
libARM_Reset(hard); libARM_Reset(hard);
sh4_cpu.Reset(true); sh4_cpu.Reset(true);
@ -382,7 +384,7 @@ void Emulator::init()
// Default platform // Default platform
setPlatform(DC_PLATFORM_DREAMCAST); setPlatform(DC_PLATFORM_DREAMCAST);
libPvr_Init(); pvr::init();
libAICA_Init(); libAICA_Init();
libARM_Init(); libARM_Init();
mem_Init(); mem_Init();
@ -567,7 +569,7 @@ void Emulator::term()
reios_term(); reios_term();
libARM_Term(); libARM_Term();
libAICA_Term(); libAICA_Term();
libPvr_Term(); pvr::term();
mem_Term(); mem_Term();
_vmem_release(); _vmem_release();
@ -646,7 +648,7 @@ void Emulator::step()
stop(); stop();
} }
bool dc_loadstate(const void **data, u32 size) void dc_loadstate(Deserializer& deser)
{ {
custom_texture.Terminate(); custom_texture.Terminate();
#if FEAT_AREC == DYNAREC_JIT #if FEAT_AREC == DYNAREC_JIT
@ -657,17 +659,10 @@ bool dc_loadstate(const void **data, u32 size)
bm_Reset(); bm_Reset();
#endif #endif
u32 usedSize = 0; dc_deserialize(deser);
if (!dc_unserialize((void **)data, &usedSize))
return false;
if (size != usedSize)
WARN_LOG(SAVESTATE, "Savestate: loaded %d bytes but used %d", size, usedSize);
mmu_set_state(); mmu_set_state();
sh4_cpu.ResetCache(); sh4_cpu.ResetCache();
return true;
} }
void Emulator::setNetworkState(bool online) void Emulator::setNetworkState(bool online)
@ -821,4 +816,5 @@ void Emulator::vblank()
else if (!config::ThreadedRendering) else if (!config::ThreadedRendering)
sh4_cpu.Stop(); sh4_cpu.Stop();
} }
Emulator emu; Emulator emu;

View File

@ -26,17 +26,18 @@
#include <future> #include <future>
#include <string> #include <string>
#include <memory> #include <memory>
#include <utility>
void loadGameSpecificSettings(); void loadGameSpecificSettings();
void SaveSettings(); void SaveSettings();
int flycast_init(int argc, char* argv[]); int flycast_init(int argc, char* argv[]);
void dc_reset(bool hard); void dc_reset(bool hard); // for tests only
void flycast_term(); void flycast_term();
void dc_exit(); void dc_exit();
void dc_savestate(int index = 0); void dc_savestate(int index = 0);
void dc_loadstate(int index = 0); void dc_loadstate(int index = 0);
bool dc_loadstate(const void **data, unsigned size); void dc_loadstate(Deserializer& deser);
enum class Event { enum class Event {
Start, Start,

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "serialize.h"
namespace dsp namespace dsp
{ {
@ -28,35 +29,28 @@ struct DSPState
bool stopped; // DSP program is a no-op bool stopped; // DSP program is a no-op
bool dirty; // DSP program has changed bool dirty; // DSP program has changed
bool serialize(void **data, unsigned int *total_size) void serialize(Serializer& ser)
{ {
REICAST_S(TEMP); ser << TEMP;
REICAST_S(MEMS); ser << MEMS;
REICAST_S(MIXS); ser << MIXS;
REICAST_S(RBP); ser << RBP;
REICAST_S(RBL); ser << RBL;
REICAST_S(MDEC_CT); ser << MDEC_CT;
return true;
} }
bool deserialize(void **data, unsigned int *total_size, serialize_version_enum version) void deserialize(Deserializer& deser)
{ {
if (version < V18) deser.skip(4096 * 8, Deserializer::V18); // DynCode
REICAST_SKIP(4096 * 8); // DynCode deser >> TEMP;
REICAST_US(TEMP); deser >> MEMS;
REICAST_US(MEMS); deser >> MIXS;
REICAST_US(MIXS); deser >> RBP;
REICAST_US(RBP); deser >> RBL;
REICAST_US(RBL); deser.skip(44, Deserializer::V18);
if (version < V18) deser >> MDEC_CT;
REICAST_SKIP(44); deser.skip(33596 - 4096 * 8 - sizeof(TEMP) - sizeof(MEMS) - sizeof(MIXS) - 4 * 3 - 44,
REICAST_US(MDEC_CT); Deserializer::V18); // other dsp stuff
if (version < V18)
REICAST_SKIP(33596 - 4096 * 8 - sizeof(TEMP) - sizeof(MEMS) - sizeof(MIXS) - 4 * 3 - 44); // other dsp stuff
dirty = true;
return true;
} }
}; };

View File

@ -26,6 +26,7 @@
#include "oslib/audiostream.h" #include "oslib/audiostream.h"
#include "hw/gdrom/gdrom_if.h" #include "hw/gdrom/gdrom_if.h"
#include "cfg/option.h" #include "cfg/option.h"
#include "serialize.h"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@ -153,7 +154,17 @@ static void VolumePan(SampleType value, u32 vol, u32 pan, SampleType& outl, Samp
} }
} }
DSP_OUT_VOL_REG* dsp_out_vol; template<typename T>
static void clip(T& v, T min, T max) {
v = std::min(max, std::max(min, v));
}
template<typename T>
static void clip16(T& v) {
clip<T>(v, -32768, 32767);
}
const DSP_OUT_VOL_REG *dsp_out_vol = (DSP_OUT_VOL_REG *)&aica_reg[0x2000];
static int beepOn; static int beepOn;
static int beepPeriod; static int beepPeriod;
static int beepCounter; static int beepCounter;
@ -549,8 +560,8 @@ struct ChannelEx
__forceinline static void StepAll(SampleType& mixl, SampleType& mixr) __forceinline static void StepAll(SampleType& mixl, SampleType& mixr)
{ {
for (int i = 0; i < 64; i++) for (ChannelEx& channel : Chans)
Chans[i].Step(mixl, mixr); channel.Step(mixl, mixr);
} }
void SetAegState(_EG_state newstate) void SetAegState(_EG_state newstate)
@ -780,12 +791,12 @@ struct ChannelEx
if ((offset == 0x01 || size == 2) && ccd->KYONEX) if ((offset == 0x01 || size == 2) && ccd->KYONEX)
{ {
ccd->KYONEX=0; ccd->KYONEX=0;
for (int i = 0; i < 64; i++) for (ChannelEx& channel : Chans)
{ {
if (Chans[i].ccd->KYONB) if (channel.ccd->KYONB)
Chans[i].KEY_ON(); channel.KEY_ON();
else else
Chans[i].KEY_OFF(); channel.KEY_OFF();
} }
} }
break; break;
@ -1289,7 +1300,6 @@ void sgc_Init()
} }
for (int i=0;i<64;i++) for (int i=0;i<64;i++)
Chans[i].Init(i,aica_reg); Chans[i].Init(i,aica_reg);
dsp_out_vol=(DSP_OUT_VOL_REG*)&aica_reg[0x2000];
for (int s = 0; s < 8; s++) for (int s = 0; s < 8; s++)
{ {
@ -1400,8 +1410,8 @@ static SampleType vmuBeepSample()
} }
constexpr int CDDA_SIZE = 2352 / 2; constexpr int CDDA_SIZE = 2352 / 2;
s16 cdda_sector[CDDA_SIZE]; static s16 cdda_sector[CDDA_SIZE];
u32 cdda_index = CDDA_SIZE; static u32 cdda_index = CDDA_SIZE;
//no DSP for now in this version //no DSP for now in this version
void AICA_Sample32() void AICA_Sample32()
@ -1587,157 +1597,160 @@ void AICA_Sample()
WriteSample(mixr,mixl); WriteSample(mixr,mixl);
} }
bool channel_serialize(void **data, unsigned int *total_size) void channel_serialize(Serializer& ser)
{ {
int i = 0 ; for (const ChannelEx& channel : Chans)
int addr = 0 ;
for ( i = 0 ; i < 64 ; i++)
{ {
addr = Chans[i].SA - (&(aica_ram[0])) ; u32 addr = channel.SA - &aica_ram[0];
REICAST_S(addr); ser << addr;
REICAST_S(Chans[i].CA) ; ser << channel.CA;
REICAST_S(Chans[i].step) ; ser << channel.step;
REICAST_S(Chans[i].s0) ; ser << channel.s0;
REICAST_S(Chans[i].s1) ; ser << channel.s1;
REICAST_S(Chans[i].loop.looped) ; ser << channel.loop.looped;
REICAST_S(Chans[i].adpcm.last_quant) ; ser << channel.adpcm.last_quant;
REICAST_S(Chans[i].adpcm.loopstart_quant); ser << channel.adpcm.loopstart_quant;
REICAST_S(Chans[i].adpcm.loopstart_prev_sample); ser << channel.adpcm.loopstart_prev_sample;
REICAST_S(Chans[i].adpcm.in_loop); ser << channel.adpcm.in_loop;
REICAST_S(Chans[i].noise_state) ; ser << channel.noise_state;
REICAST_S(Chans[i].AEG.val) ; ser << channel.AEG.val;
REICAST_S(Chans[i].AEG.state) ; ser << channel.AEG.state;
REICAST_S(Chans[i].FEG.value); ser << channel.FEG.value;
REICAST_S(Chans[i].FEG.state); ser << channel.FEG.state;
REICAST_S(Chans[i].FEG.prev1); ser << channel.FEG.prev1;
REICAST_S(Chans[i].FEG.prev2); ser << channel.FEG.prev2;
REICAST_S(Chans[i].lfo.counter) ; ser << channel.lfo.counter;
REICAST_S(Chans[i].lfo.state) ; ser << channel.lfo.state;
REICAST_S(Chans[i].enabled) ; ser << channel.enabled;
} }
REICAST_S(beepOn); ser << beepOn;
REICAST_S(beepPeriod); ser << beepPeriod;
REICAST_S(beepCounter); ser << beepCounter;
ser << cdda_sector;
return true; ser << cdda_index;
} }
bool channel_unserialize(void **data, unsigned int *total_size, serialize_version_enum ver) void channel_deserialize(Deserializer& deser)
{ {
int i = 0 ; if (deser.version() < Deserializer::V7_LIBRETRO)
int addr = 0 ;
u32 dum;
bool old_format = (ver >= V5 && ver < V7) || ver < V8_LIBRETRO;
for ( i = 0 ; i < 64 ; i++)
{ {
Chans[i].quiet = true; deser.skip(4 * 16); // volume_lut
REICAST_US(addr); deser.skip(4 * 256 + 768); // tl_lut. Due to a previous bug this is not 4 * (256 + 768)
Chans[i].SA = addr + (&(aica_ram[0])) ; deser.skip(4 * 64); // AEG_ATT_SPS
deser.skip(4 * 64); // AEG_DSR_SPS
REICAST_US(Chans[i].CA) ; deser.skip(2); // pl
REICAST_US(Chans[i].step) ; deser.skip(2); // pr
if (old_format)
REICAST_US(dum); // Chans[i].update_rate
Chans[i].UpdatePitch();
REICAST_US(Chans[i].s0) ;
REICAST_US(Chans[i].s1) ;
REICAST_US(Chans[i].loop.looped);
if (old_format)
{
REICAST_US(dum); // Chans[i].loop.LSA
REICAST_US(dum); // Chans[i].loop.LEA
}
Chans[i].UpdateLoop();
REICAST_US(Chans[i].adpcm.last_quant) ;
if (!old_format)
{
REICAST_US(Chans[i].adpcm.loopstart_quant);
REICAST_US(Chans[i].adpcm.loopstart_prev_sample);
REICAST_US(Chans[i].adpcm.in_loop);
}
else
{
Chans[i].adpcm.in_loop = true;
Chans[i].adpcm.loopstart_quant = 0;
Chans[i].adpcm.loopstart_prev_sample = 0;
}
REICAST_US(Chans[i].noise_state) ;
if (old_format)
{
REICAST_US(dum); // Chans[i].VolMix.DLAtt
REICAST_US(dum); // Chans[i].VolMix.DRAtt
REICAST_US(dum); // Chans[i].VolMix.DSPAtt
}
Chans[i].UpdateAtts();
if (old_format)
REICAST_US(dum); // Chans[i].VolMix.DSPOut
Chans[i].UpdateDSPMIX();
REICAST_US(Chans[i].AEG.val) ;
REICAST_US(Chans[i].AEG.state) ;
Chans[i].SetAegState(Chans[i].AEG.state);
if (old_format)
{
REICAST_US(dum); // Chans[i].AEG.AttackRate
REICAST_US(dum); // Chans[i].AEG.Decay1Rate
REICAST_US(dum); // Chans[i].AEG.Decay2Rate
REICAST_US(dum); // Chans[i].AEG.Decay2Value
REICAST_US(dum); // Chans[i].AEG.ReleaseRate
}
Chans[i].UpdateAEG();
REICAST_US(Chans[i].FEG.value);
REICAST_US(Chans[i].FEG.state);
if (!old_format)
{
REICAST_US(Chans[i].FEG.prev1);
REICAST_US(Chans[i].FEG.prev2);
}
else
{
Chans[i].FEG.prev1 = 0;
Chans[i].FEG.prev2 = 0;
}
Chans[i].SetFegState(Chans[i].FEG.state);
Chans[i].UpdateFEG();
if (old_format)
{
u8 dumu8;
REICAST_US(dumu8); // Chans[i].step_stream_lut1
REICAST_US(dumu8); // Chans[i].step_stream_lut2
REICAST_US(dumu8); // Chans[i].step_stream_lut3
}
Chans[i].UpdateStreamStep();
REICAST_US(Chans[i].lfo.counter) ;
if (old_format)
REICAST_US(dum); // Chans[i].lfo.start_value
REICAST_US(Chans[i].lfo.state) ;
if (old_format)
{
u8 dumu8;
REICAST_US(dumu8); // Chans[i].lfo.alfo
REICAST_US(dumu8); // Chans[i].lfo.alfo_shft
REICAST_US(dumu8); // Chans[i].lfo.plfo
REICAST_US(dumu8); // Chans[i].lfo.plfo_shft
REICAST_US(dumu8); // Chans[i].lfo.alfo_calc_lut
REICAST_US(dumu8); // Chans[i].lfo.plfo_calc_lut
}
Chans[i].UpdateLFO(true);
REICAST_US(Chans[i].enabled) ;
if (old_format)
REICAST_US(dum); // Chans[i].ChannelNumber
Chans[i].quiet = false;
} }
if (ver >= V22)
bool old_format = (deser.version() >= Deserializer::V5 && deser.version() < Deserializer::V7) || deser.version() < Deserializer::V8_LIBRETRO;
for (ChannelEx& channel : Chans)
{ {
REICAST_US(beepOn); channel.quiet = true;
REICAST_US(beepPeriod); u32 addr;
REICAST_US(beepCounter); deser >> addr;
channel.SA = addr + &aica_ram[0];
deser >> channel.CA;
deser >> channel.step;
if (old_format)
deser.skip<u32>(); // channel.update_rate
channel.UpdatePitch();
deser >> channel.s0;
deser >> channel.s1;
deser >> channel.loop.looped;
if (old_format)
{
deser.skip<u32>(); // channel.loop.LSA
deser.skip<u32>(); // channel.loop.LEA
}
channel.UpdateLoop();
deser >> channel.adpcm.last_quant;
if (!old_format)
{
deser >> channel.adpcm.loopstart_quant;
deser >> channel.adpcm.loopstart_prev_sample;
deser >> channel.adpcm.in_loop;
}
else
{
channel.adpcm.in_loop = true;
channel.adpcm.loopstart_quant = 0;
channel.adpcm.loopstart_prev_sample = 0;
}
deser >> channel.noise_state;
if (old_format)
{
deser.skip<u32>(); // channel.VolMix.DLAtt
deser.skip<u32>(); // channel.VolMix.DRAtt
deser.skip<u32>(); // channel.VolMix.DSPAtt
}
channel.UpdateAtts();
if (old_format)
deser.skip<u32>(); // channel.VolMix.DSPOut
channel.UpdateDSPMIX();
deser >> channel.AEG.val;
deser >> channel.AEG.state;
channel.SetAegState(channel.AEG.state);
if (old_format)
{
deser.skip<u32>(); // channel.AEG.AttackRate
deser.skip<u32>(); // channel.AEG.Decay1Rate
deser.skip<u32>(); // channel.AEG.Decay2Rate
deser.skip<u32>(); // channel.AEG.Decay2Value
deser.skip<u32>(); // channel.AEG.ReleaseRate
}
channel.UpdateAEG();
deser >> channel.FEG.value;
deser >> channel.FEG.state;
if (!old_format)
{
deser >> channel.FEG.prev1;
deser >> channel.FEG.prev2;
}
else
{
channel.FEG.prev1 = 0;
channel.FEG.prev2 = 0;
}
channel.SetFegState(channel.FEG.state);
channel.UpdateFEG();
if (old_format)
{
deser.skip<u8>(); // channel.step_stream_lut1
deser.skip<u8>(); // channel.step_stream_lut2
deser.skip<u8>(); // channel.step_stream_lut3
}
channel.UpdateStreamStep();
deser >> channel.lfo.counter;
if (old_format)
deser.skip<u32>(); // channel.lfo.start_value
deser >> channel.lfo.state;
if (old_format)
{
deser.skip<u8>(); // channel.lfo.alfo
deser.skip<u8>(); // channel.lfo.alfo_shft
deser.skip<u8>(); // channel.lfo.plfo
deser.skip<u8>(); // channel.lfo.plfo_shft
deser.skip<u8>(); // channel.lfo.alfo_calc_lut
deser.skip<u8>(); // channel.lfo.plfo_calc_lut
}
channel.UpdateLFO(true);
deser >> channel.enabled;
if (old_format)
deser.skip<u32>(); // channel.ChannelNumber
channel.quiet = false;
}
if (deser.version() >= Deserializer::V22)
{
deser >> beepOn;
deser >> beepPeriod;
deser >> beepCounter;
} }
else else
{ {
@ -1745,6 +1758,11 @@ bool channel_unserialize(void **data, unsigned int *total_size, serialize_versio
beepPeriod = 0; beepPeriod = 0;
beepCounter = 0; beepCounter = 0;
} }
deser >> cdda_sector;
return true; deser >> cdda_index;
if (deser.version() < Deserializer::V9_LIBRETRO)
{
deser.skip(4 * 64); // mxlr
deser.skip(4); // samples_gen
}
} }

View File

@ -50,13 +50,10 @@ struct DSP_OUT_VOL_REG
u32 pad:16; u32 pad:16;
}; };
//#define SAMPLE_TYPE_SHIFT (8)
typedef s32 SampleType; typedef s32 SampleType;
void ReadCommonReg(u32 reg,bool byte); void ReadCommonReg(u32 reg,bool byte);
void WriteCommonReg8(u32 reg,u32 data); void WriteCommonReg8(u32 reg,u32 data);
#define clip(x,min,max) do { if ((x)<(min)) (x)=(min); else if ((x)>(max)) (x)=(max); } while (false) void channel_serialize(Serializer& ctx);
#define clip16(x) clip(x,-32768,32767) void channel_deserialize(Deserializer& ctx);
bool channel_serialize(void **data, unsigned int *total_size);
bool channel_unserialize(void **data, unsigned int *total_size, serialize_version_enum version);
void vmuBeep(int on, int period); void vmuBeep(int on, int period);

View File

@ -20,6 +20,7 @@
#include "rtl8139c.h" #include "rtl8139c.h"
#include "hw/holly/holly_intc.h" #include "hw/holly/holly_intc.h"
#include "network/picoppp.h" #include "network/picoppp.h"
#include "serialize.h"
static RTL8139State *rtl8139device; static RTL8139State *rtl8139device;
@ -231,27 +232,26 @@ void pci_dma_write(PCIDevice *dev, dma_addr_t addr, const void *buf, dma_addr_t
memcpy(&GAPS_ram[addr & GAPSPCI_RAM_MASK], buf, len); memcpy(&GAPS_ram[addr & GAPSPCI_RAM_MASK], buf, len);
} }
void bba_Serialize(void **data, unsigned int *total_size) void bba_Serialize(Serializer& ser)
{ {
REICAST_S(GAPS_regs); ser << GAPS_regs;
REICAST_S(GAPS_ram); ser << GAPS_ram;
REICAST_S(dmaOffset); ser << dmaOffset;
REICAST_S(interruptPending); ser << interruptPending;
rtl8139_serialize(rtl8139device, data, total_size); rtl8139_serialize(rtl8139device, ser);
} }
void bba_Unserialize(void **data, unsigned int *total_size) void bba_Deserialize(Deserializer& deser)
{ {
REICAST_US(GAPS_regs); deser >> GAPS_regs;
REICAST_US(GAPS_ram); deser >> GAPS_ram;
REICAST_US(dmaOffset); deser >> dmaOffset;
REICAST_US(interruptPending); deser >> interruptPending;
// returns true if the receiver is enabled and the network stack must be started // returns true if the receiver is enabled and the network stack must be started
if (rtl8139_unserialize(rtl8139device, data, total_size)) if (rtl8139_deserialize(rtl8139device, deser))
start_pico(); start_pico();
} }
#define POLYNOMIAL_BE 0x04c11db6 #define POLYNOMIAL_BE 0x04c11db6
uint32_t net_crc32(const uint8_t *p, int len) uint32_t net_crc32(const uint8_t *p, int len)

View File

@ -24,5 +24,5 @@ void bba_Term();
void bba_Reset(bool hard); void bba_Reset(bool hard);
u32 bba_ReadMem(u32 addr, u32 sz); u32 bba_ReadMem(u32 addr, u32 sz);
void bba_WriteMem(u32 addr, u32 data, u32 sz); void bba_WriteMem(u32 addr, u32 data, u32 sz);
void bba_Serialize(void **data, unsigned int *total_size); void bba_Serialize(Serializer& ser);
void bba_Unserialize(void **data, unsigned int *total_size); void bba_Deserialize(Deserializer& deser);

View File

@ -50,6 +50,7 @@
/* For crc32 */ /* For crc32 */
#include <zlib.h> #include <zlib.h>
#include "rtl8139c.h" #include "rtl8139c.h"
#include "serialize.h"
/* debug RTL8139 card */ /* debug RTL8139 card */
//#define DEBUG_RTL8139 1 //#define DEBUG_RTL8139 1
@ -2327,132 +2328,132 @@ void rtl8139_destroy(RTL8139State *state)
free(state); free(state);
} }
void rtl8139_serialize(RTL8139State *s, void **data, unsigned int *total_size) void rtl8139_serialize(RTL8139State *s, Serializer& ser)
{ {
REICAST_SA(s->parent_obj.config, 256); ser.serialize(s->parent_obj.config, 256);
REICAST_SA(s->parent_obj.cmask, 256); ser.serialize(s->parent_obj.cmask, 256);
REICAST_SA(s->parent_obj.wmask, 256); ser.serialize(s->parent_obj.wmask, 256);
REICAST_S(s->parent_obj.io_regions); ser << s->parent_obj.io_regions;
REICAST_S(s->phys); ser << s->phys;
REICAST_S(s->mult); ser << s->mult;
REICAST_S(s->TxStatus); ser << s->TxStatus;
REICAST_S(s->TxAddr); ser << s->TxAddr;
REICAST_S(s->RxBuf); ser << s->RxBuf;
REICAST_S(s->RxBufferSize); ser << s->RxBufferSize;
REICAST_S(s->RxBufPtr); ser << s->RxBufPtr;
REICAST_S(s->RxBufAddr); ser << s->RxBufAddr;
REICAST_S(s->IntrStatus); ser << s->IntrStatus;
REICAST_S(s->IntrMask); ser << s->IntrMask;
REICAST_S(s->TxConfig); ser << s->TxConfig;
REICAST_S(s->RxConfig); ser << s->RxConfig;
REICAST_S(s->RxMissed); ser << s->RxMissed;
REICAST_S(s->CSCR); ser << s->CSCR;
REICAST_S(s->Cfg9346); ser << s->Cfg9346;
REICAST_S(s->Config0); ser << s->Config0;
REICAST_S(s->Config1); ser << s->Config1;
REICAST_S(s->Config3); ser << s->Config3;
REICAST_S(s->Config4); ser << s->Config4;
REICAST_S(s->Config5); ser << s->Config5;
REICAST_S(s->clock_enabled); ser << s->clock_enabled;
REICAST_S(s->bChipCmdState); ser << s->bChipCmdState;
REICAST_S(s->MultiIntr); ser << s->MultiIntr;
REICAST_S(s->BasicModeCtrl); ser << s->BasicModeCtrl;
REICAST_S(s->BasicModeStatus); ser << s->BasicModeStatus;
REICAST_S(s->NWayAdvert); ser << s->NWayAdvert;
REICAST_S(s->NWayLPAR); ser << s->NWayLPAR;
REICAST_S(s->NWayExpansion); ser << s->NWayExpansion;
REICAST_S(s->conf.macaddr); ser << s->conf.macaddr;
REICAST_S(s->currTxDesc); ser << s->currTxDesc;
REICAST_S(s->eeprom.contents); ser << s->eeprom.contents;
REICAST_S(s->eeprom.mode); ser << s->eeprom.mode;
REICAST_S(s->eeprom.tick); ser << s->eeprom.tick;
REICAST_S(s->eeprom.address); ser << s->eeprom.address;
REICAST_S(s->eeprom.input); ser << s->eeprom.input;
REICAST_S(s->eeprom.output); ser << s->eeprom.output;
REICAST_S(s->eeprom.eecs); ser << s->eeprom.eecs;
REICAST_S(s->eeprom.eesk); ser << s->eeprom.eesk;
REICAST_S(s->eeprom.eedi); ser << s->eeprom.eedi;
REICAST_S(s->eeprom.eedo); ser << s->eeprom.eedo;
REICAST_S(s->TCTR); ser << s->TCTR;
REICAST_S(s->TimerInt); ser << s->TimerInt;
REICAST_S(s->TCTR_base); ser << s->TCTR_base;
} }
bool rtl8139_unserialize(RTL8139State *s, void **data, unsigned int *total_size) bool rtl8139_deserialize(RTL8139State *s, Deserializer& deser)
{ {
REICAST_USA(s->parent_obj.config, 256); deser.deserialize(s->parent_obj.config, 256);
REICAST_USA(s->parent_obj.cmask, 256); deser.deserialize(s->parent_obj.cmask, 256);
REICAST_USA(s->parent_obj.wmask, 256); deser.deserialize(s->parent_obj.wmask, 256);
REICAST_US(s->parent_obj.io_regions); deser >> s->parent_obj.io_regions;
REICAST_US(s->phys); deser >> s->phys;
REICAST_US(s->mult); deser >> s->mult;
REICAST_US(s->TxStatus); deser >> s->TxStatus;
REICAST_US(s->TxAddr); deser >> s->TxAddr;
REICAST_US(s->RxBuf); deser >> s->RxBuf;
REICAST_US(s->RxBufferSize); deser >> s->RxBufferSize;
REICAST_US(s->RxBufPtr); deser >> s->RxBufPtr;
REICAST_US(s->RxBufAddr); deser >> s->RxBufAddr;
REICAST_US(s->IntrStatus); deser >> s->IntrStatus;
REICAST_US(s->IntrMask); deser >> s->IntrMask;
REICAST_US(s->TxConfig); deser >> s->TxConfig;
REICAST_US(s->RxConfig); deser >> s->RxConfig;
REICAST_US(s->RxMissed); deser >> s->RxMissed;
REICAST_US(s->CSCR); deser >> s->CSCR;
REICAST_US(s->Cfg9346); deser >> s->Cfg9346;
REICAST_US(s->Config0); deser >> s->Config0;
REICAST_US(s->Config1); deser >> s->Config1;
REICAST_US(s->Config3); deser >> s->Config3;
REICAST_US(s->Config4); deser >> s->Config4;
REICAST_US(s->Config5); deser >> s->Config5;
REICAST_US(s->clock_enabled); deser >> s->clock_enabled;
REICAST_US(s->bChipCmdState); deser >> s->bChipCmdState;
REICAST_US(s->MultiIntr); deser >> s->MultiIntr;
REICAST_US(s->BasicModeCtrl); deser >> s->BasicModeCtrl;
REICAST_US(s->BasicModeStatus); deser >> s->BasicModeStatus;
REICAST_US(s->NWayAdvert); deser >> s->NWayAdvert;
REICAST_US(s->NWayLPAR); deser >> s->NWayLPAR;
REICAST_US(s->NWayExpansion); deser >> s->NWayExpansion;
REICAST_US(s->conf.macaddr); deser >> s->conf.macaddr;
REICAST_US(s->currTxDesc); deser >> s->currTxDesc;
REICAST_US(s->eeprom.contents); deser >> s->eeprom.contents;
REICAST_US(s->eeprom.mode); deser >> s->eeprom.mode;
REICAST_US(s->eeprom.tick); deser >> s->eeprom.tick;
REICAST_US(s->eeprom.address); deser >> s->eeprom.address;
REICAST_US(s->eeprom.input); deser >> s->eeprom.input;
REICAST_US(s->eeprom.output); deser >> s->eeprom.output;
REICAST_US(s->eeprom.eecs); deser >> s->eeprom.eecs;
REICAST_US(s->eeprom.eesk); deser >> s->eeprom.eesk;
REICAST_US(s->eeprom.eedi); deser >> s->eeprom.eedi;
REICAST_US(s->eeprom.eedo); deser >> s->eeprom.eedo;
REICAST_US(s->TCTR); deser >> s->TCTR;
REICAST_US(s->TimerInt); deser >> s->TimerInt;
REICAST_US(s->TCTR_base); deser >> s->TCTR_base;
return s->bChipCmdState & CmdRxEnb; return s->bChipCmdState & CmdRxEnb;
} }

View File

@ -214,5 +214,5 @@ ssize_t rtl8139_receive(RTL8139State *s, const uint8_t *buf, size_t size);
RTL8139State *rtl8139_init(NICConf *conf); RTL8139State *rtl8139_init(NICConf *conf);
void rtl8139_destroy(RTL8139State *state); void rtl8139_destroy(RTL8139State *state);
void rtl8139_serialize(RTL8139State *state, void **data, unsigned int *total_size); void rtl8139_serialize(RTL8139State *state, Serializer& ser);
bool rtl8139_unserialize(RTL8139State *state, void **data, unsigned int *total_size); bool rtl8139_deserialize(RTL8139State *state, Deserializer& deser);

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <cmath> #include <cmath>
#include "types.h" #include "types.h"
#include "serialize.h"
struct MemChip struct MemChip
{ {
@ -54,8 +55,8 @@ public:
void digest(u8 md5Digest[16]); void digest(u8 md5Digest[16]);
virtual void Reset() {} virtual void Reset() {}
virtual bool Serialize(void **data, unsigned int *total_size) { return true; } virtual void Serialize(Serializer& ser) const { }
virtual bool Unserialize(void **data, unsigned int *total_size) { return true; } virtual void Deserialize(Deserializer& deser) { }
}; };
struct WritableChip : MemChip struct WritableChip : MemChip
@ -106,16 +107,13 @@ struct SRamChip : WritableChip
} }
} }
bool Serialize(void **data, unsigned int *total_size) override void Serialize(Serializer& ser) const override
{ {
REICAST_SA(&this->data[write_protect_size], size - write_protect_size); ser.serialize(&this->data[write_protect_size], size - write_protect_size);
return true;
} }
void Deserialize(Deserializer& deser) override
bool Unserialize(void **data, unsigned int *total_size) override
{ {
REICAST_USA(&this->data[write_protect_size], size - write_protect_size); deser.deserialize(&this->data[write_protect_size], size - write_protect_size);
return true;
} }
}; };
@ -712,18 +710,16 @@ private:
return result; return result;
} }
bool Serialize(void **data, unsigned int *total_size) override void Serialize(Serializer& ser) const override
{ {
REICAST_S(state); ser << state;
REICAST_SA(&this->data[write_protect_size], size - write_protect_size); ser.serialize(&this->data[write_protect_size], size - write_protect_size);
return true;
} }
bool Unserialize(void **data, unsigned int *total_size) override void Deserialize(Deserializer& deser) override
{ {
REICAST_US(state); deser >> state;
REICAST_USA(&this->data[write_protect_size], size - write_protect_size); deser.deserialize(&this->data[write_protect_size], size - write_protect_size);
return true;
} }
void erase_partition(u32 part_id) void erase_partition(u32 part_id)

View File

@ -25,3 +25,8 @@ enum DiscType
Open=0x2, //tray is open :) Open=0x2, //tray is open :)
}; };
namespace gdrom
{
void serialize(Serializer& ser);
void deserialize(Deserializer& deser);
}

View File

@ -12,6 +12,7 @@
#include "hw/sh4/sh4_mem.h" #include "hw/sh4/sh4_mem.h"
#include "hw/sh4/sh4_sched.h" #include "hw/sh4/sh4_sched.h"
#include "imgread/common.h" #include "imgread/common.h"
#include "serialize.h"
int gdrom_schid; int gdrom_schid;
@ -1251,3 +1252,82 @@ void gdrom_reg_Reset(bool hard)
libCore_gdrom_disc_change(); libCore_gdrom_disc_change();
} }
namespace gdrom
{
void serialize(Serializer& ser)
{
ser << GD_HardwareInfo;
ser << sns_asc;
ser << sns_ascq;
ser << sns_key;
ser << packet_cmd;
ser << set_mode_offset;
ser << read_params;
ser << read_buff;
ser << pio_buff;
ser << set_mode_offset;
ser << ata_cmd;
ser << cdda;
ser << gd_state;
ser << gd_disk_type;
ser << data_write_mode;
ser << DriveSel;
ser << Error;
ser << IntReason;
ser << Features;
ser << SecCount;
ser << SecNumber;
ser << GDStatus;
ser << ByteCount;
}
void deserialize(Deserializer& deser)
{
deser >> GD_HardwareInfo;
deser >> sns_asc;
deser >> sns_ascq;
deser >> sns_key;
deser >> packet_cmd;
deser >> set_mode_offset;
deser >> read_params;
if (deser.version() >= Deserializer::V17)
deser >> read_buff;
else
{
deser >> packet_cmd;
read_buff.cache_size = 0;
// read_buff (old)
if (deser.version() < Deserializer::V9_LIBRETRO
|| (deser.version() >= Deserializer::V5 && deser.version() < Deserializer::V8))
deser.skip(4 + 4 + 2352 * 8192);
}
deser >> pio_buff;
deser >> set_mode_offset;
deser >> ata_cmd;
deser >> cdda;
if (deser.version() < Deserializer::V10)
cdda.status = (bool)cdda.status ? cdda_t::Playing : cdda_t::NoInfo;
deser >> gd_state;
deser >> gd_disk_type;
deser >> data_write_mode;
deser >> DriveSel;
deser >> Error;
deser >> IntReason;
deser >> Features;
deser >> SecCount;
deser >> SecNumber;
deser >> GDStatus;
deser >> ByteCount;
if (deser.version() >= Deserializer::V5_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO)
deser.skip<u32>(); // GDROM_TICK
}
}

View File

@ -1,6 +1,5 @@
#include "holly_intc.h" #include "holly_intc.h"
#include "sb.h" #include "sb.h"
#include "hw/maple/maple_if.h"
#include "hw/sh4/sh4_interrupts.h" #include "hw/sh4/sh4_interrupts.h"
/* /*
@ -9,7 +8,7 @@
*/ */
//asic_RLXXPending: Update the intc flags for pending interrupts //asic_RLXXPending: Update the intc flags for pending interrupts
void asic_RL6Pending() static void asic_RL6Pending()
{ {
bool t1=(SB_ISTNRM & SB_IML6NRM)!=0; bool t1=(SB_ISTNRM & SB_IML6NRM)!=0;
bool t2=(SB_ISTERR & SB_IML6ERR)!=0; bool t2=(SB_ISTERR & SB_IML6ERR)!=0;
@ -18,7 +17,7 @@ void asic_RL6Pending()
InterruptPend(sh4_IRL_9,t1|t2|t3); InterruptPend(sh4_IRL_9,t1|t2|t3);
} }
void asic_RL4Pending() static void asic_RL4Pending()
{ {
bool t1=(SB_ISTNRM & SB_IML4NRM)!=0; bool t1=(SB_ISTNRM & SB_IML4NRM)!=0;
bool t2=(SB_ISTERR & SB_IML4ERR)!=0; bool t2=(SB_ISTERR & SB_IML4ERR)!=0;
@ -27,7 +26,7 @@ void asic_RL4Pending()
InterruptPend(sh4_IRL_11,t1|t2|t3); InterruptPend(sh4_IRL_11,t1|t2|t3);
} }
void asic_RL2Pending() static void asic_RL2Pending()
{ {
bool t1=(SB_ISTNRM & SB_IML2NRM)!=0; bool t1=(SB_ISTNRM & SB_IML2NRM)!=0;
bool t2=(SB_ISTERR & SB_IML2ERR)!=0; bool t2=(SB_ISTERR & SB_IML2ERR)!=0;
@ -36,58 +35,28 @@ void asic_RL2Pending()
InterruptPend(sh4_IRL_13,t1|t2|t3); InterruptPend(sh4_IRL_13,t1|t2|t3);
} }
//Raise interrupt interface
void RaiseAsicNormal(HollyInterruptID inter)
{
if (inter==holly_SCANINT2)
maple_vblank();
u32 Interrupt = 1<<(u8)inter;
SB_ISTNRM |= Interrupt;
asic_RL2Pending();
asic_RL4Pending();
asic_RL6Pending();
}
void RaiseAsicExt(HollyInterruptID inter)
{
u32 Interrupt = 1<<(u8)inter;
SB_ISTEXT |= Interrupt;
asic_RL2Pending();
asic_RL4Pending();
asic_RL6Pending();
}
void RaiseAsicErr(HollyInterruptID inter)
{
u32 Interrupt = 1<<(u8)inter;
SB_ISTERR |= Interrupt;
asic_RL2Pending();
asic_RL4Pending();
asic_RL6Pending();
}
void asic_RaiseInterrupt(HollyInterruptID inter) void asic_RaiseInterrupt(HollyInterruptID inter)
{ {
u8 m=inter>>8; u8 type = inter >> 8;
switch(m) u32 mask = 1 << (u8)inter;
switch(type)
{ {
case 0: case 0:
RaiseAsicNormal(inter); SB_ISTNRM |= mask;
break; break;
case 1: case 1:
RaiseAsicExt(inter); SB_ISTEXT |= mask;
break; break;
case 2: case 2:
RaiseAsicErr(inter); SB_ISTERR |= mask;
break; break;
} }
asic_RL2Pending();
asic_RL4Pending();
asic_RL6Pending();
} }
u32 Read_SB_ISTNRM(u32 addr) static u32 Read_SB_ISTNRM(u32 addr)
{ {
/* Note that the two highest bits indicate /* Note that the two highest bits indicate
* the OR'ed result of all the bits in * the OR'ed result of all the bits in
@ -104,7 +73,7 @@ u32 Read_SB_ISTNRM(u32 addr)
return tmp; return tmp;
} }
void Write_SB_ISTNRM(u32 addr, u32 data) static void Write_SB_ISTNRM(u32 addr, u32 data)
{ {
/* writing a 1 clears the interrupt */ /* writing a 1 clears the interrupt */
SB_ISTNRM &= ~data; SB_ISTNRM &= ~data;
@ -116,18 +85,31 @@ void Write_SB_ISTNRM(u32 addr, u32 data)
void asic_CancelInterrupt(HollyInterruptID inter) void asic_CancelInterrupt(HollyInterruptID inter)
{ {
SB_ISTEXT&=~(1<<(u8)inter); u8 type = inter >> 8;
u32 mask = ~(1 << (u8)inter);
switch (type)
{
case 0:
SB_ISTNRM &= mask;
break;
case 1:
SB_ISTEXT &= mask;
break;
case 2:
SB_ISTERR &= mask;
break;
}
asic_RL2Pending(); asic_RL2Pending();
asic_RL4Pending(); asic_RL4Pending();
asic_RL6Pending(); asic_RL6Pending();
} }
void Write_SB_ISTEXT(u32 addr, u32 data) static void Write_SB_ISTEXT(u32 addr, u32 data)
{ {
//nothing happens -- asic_CancelInterrupt is used instead //nothing happens -- asic_CancelInterrupt is used instead
} }
void Write_SB_ISTERR(u32 addr, u32 data) static void Write_SB_ISTERR(u32 addr, u32 data)
{ {
SB_ISTERR &= ~data; SB_ISTERR &= ~data;
@ -136,58 +118,58 @@ void Write_SB_ISTERR(u32 addr, u32 data)
asic_RL6Pending(); asic_RL6Pending();
} }
void Write_SB_IML6NRM(u32 addr, u32 data) static void Write_SB_IML6NRM(u32 addr, u32 data)
{ {
SB_IML6NRM=data; SB_IML6NRM=data;
asic_RL6Pending(); asic_RL6Pending();
} }
void Write_SB_IML4NRM(u32 addr, u32 data) static void Write_SB_IML4NRM(u32 addr, u32 data)
{ {
SB_IML4NRM=data; SB_IML4NRM=data;
asic_RL4Pending(); asic_RL4Pending();
} }
void Write_SB_IML2NRM(u32 addr, u32 data) static void Write_SB_IML2NRM(u32 addr, u32 data)
{ {
SB_IML2NRM=data; SB_IML2NRM=data;
asic_RL2Pending(); asic_RL2Pending();
} }
void Write_SB_IML6EXT(u32 addr, u32 data) static void Write_SB_IML6EXT(u32 addr, u32 data)
{ {
SB_IML6EXT=data; SB_IML6EXT=data;
asic_RL6Pending(); asic_RL6Pending();
} }
void Write_SB_IML4EXT(u32 addr, u32 data) static void Write_SB_IML4EXT(u32 addr, u32 data)
{ {
SB_IML4EXT=data; SB_IML4EXT=data;
asic_RL4Pending(); asic_RL4Pending();
} }
void Write_SB_IML2EXT(u32 addr, u32 data) static void Write_SB_IML2EXT(u32 addr, u32 data)
{ {
SB_IML2EXT=data; SB_IML2EXT=data;
asic_RL2Pending(); asic_RL2Pending();
} }
void Write_SB_IML6ERR(u32 addr, u32 data) static void Write_SB_IML6ERR(u32 addr, u32 data)
{ {
SB_IML6ERR=data; SB_IML6ERR=data;
asic_RL6Pending(); asic_RL6Pending();
} }
void Write_SB_IML4ERR(u32 addr, u32 data) static void Write_SB_IML4ERR(u32 addr, u32 data)
{ {
SB_IML4ERR=data; SB_IML4ERR=data;
asic_RL4Pending(); asic_RL4Pending();
} }
void Write_SB_IML2ERR(u32 addr, u32 data) static void Write_SB_IML2ERR(u32 addr, u32 data)
{ {
SB_IML2ERR=data; SB_IML2ERR=data;

View File

@ -4,8 +4,11 @@
#include "hw/naomi/naomi_cart.h" #include "hw/naomi/naomi_cart.h"
#include "cfg/option.h" #include "cfg/option.h"
#include "stdclass.h" #include "stdclass.h"
#include "serialize.h"
MapleInputState mapleInputState[4]; MapleInputState mapleInputState[4];
extern bool maple_ddt_pending_reset;
extern std::vector<std::pair<u32, std::vector<u32>>> mapleDmaOut;
void (*MapleConfigMap::UpdateVibration)(u32 port, float power, float inclination, u32 duration_ms); void (*MapleConfigMap::UpdateVibration)(u32 port, float power, float inclination, u32 duration_ms);
@ -366,8 +369,16 @@ void mcfg_DestroyDevices()
} }
} }
void mcfg_SerializeDevices(void **data, unsigned int *total_size) void mcfg_SerializeDevices(Serializer& ser)
{ {
ser << maple_ddt_pending_reset;
ser << (u32)mapleDmaOut.size();
for (const auto& pair : mapleDmaOut)
{
ser << pair.first; // u32 address
ser << (u32)pair.second.size();
ser.serialize(pair.second.data(), pair.second.size());
}
for (int i = 0; i < MAPLE_PORTS; i++) for (int i = 0; i < MAPLE_PORTS; i++)
for (int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
@ -375,25 +386,50 @@ void mcfg_SerializeDevices(void **data, unsigned int *total_size)
maple_device* device = MapleDevices[i][j]; maple_device* device = MapleDevices[i][j];
if (device != nullptr) if (device != nullptr)
deviceType = device->get_device_type(); deviceType = device->get_device_type();
REICAST_S(deviceType); ser << deviceType;
if (device != nullptr) if (device != nullptr)
device->serialize(data, total_size); device->serialize(ser);
} }
} }
void mcfg_UnserializeDevices(void **data, unsigned int *total_size, serialize_version_enum version) void mcfg_DeserializeDevices(Deserializer& deser)
{ {
mcfg_DestroyDevices(); mcfg_DestroyDevices();
u8 eeprom[sizeof(maple_naomi_jamma::eeprom)];
if (deser.version() < Deserializer::V23)
{
deser >> eeprom;
deser.skip(128); // Unused eeprom space
deser.skip<bool>(); // EEPROM_loaded
}
deser >> maple_ddt_pending_reset;
mapleDmaOut.clear();
if (deser.version() >= Deserializer::V23)
{
u32 size;
deser >> size;
for (u32 i = 0; i < size; i++)
{
u32 address;
deser >> address;
u32 dataSize;
deser >> dataSize;
mapleDmaOut.emplace_back(address, std::vector<u32>(dataSize));
deser.deserialize(mapleDmaOut.back().second.data(), dataSize);
}
}
for (int i = 0; i < MAPLE_PORTS; i++) for (int i = 0; i < MAPLE_PORTS; i++)
for (int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
u8 deviceType; u8 deviceType;
REICAST_US(deviceType); deser >> deviceType;
if (deviceType != MDT_None) if (deviceType != MDT_None)
{ {
mcfg_Create((MapleDeviceType)deviceType, i, j); mcfg_Create((MapleDeviceType)deviceType, i, j);
MapleDevices[i][j]->unserialize(data, total_size, version); MapleDevices[i][j]->deserialize(deser);
} }
} }
if (deser.version() < Deserializer::V23 && EEPROM != nullptr)
memcpy(EEPROM, eeprom, sizeof(eeprom));
} }

View File

@ -102,8 +102,8 @@ extern MapleInputState mapleInputState[4];
void mcfg_CreateDevices(); void mcfg_CreateDevices();
void mcfg_DestroyDevices(); void mcfg_DestroyDevices();
void mcfg_SerializeDevices(void **data, unsigned int *total_size); void mcfg_SerializeDevices(Serializer& ser);
void mcfg_UnserializeDevices(void **data, unsigned int *total_size, serialize_version_enum version); void mcfg_DeserializeDevices(Deserializer& deser);
bool maple_atomiswave_coin_chute(int slot); bool maple_atomiswave_coin_chute(int slot);
void push_vmu_screen(int bus_id, int bus_port, u8* buffer); void push_vmu_screen(int bus_id, int bus_port, u8* buffer);

View File

@ -323,27 +323,25 @@ struct maple_sega_vmu: maple_base
return MDT_SegaVMU; return MDT_SegaVMU;
} }
bool serialize(void **data, unsigned int *total_size) override void serialize(Serializer& ser) const override
{ {
maple_base::serialize(data, total_size); maple_base::serialize(ser);
REICAST_S(flash_data); ser << flash_data;
REICAST_S(lcd_data); ser << lcd_data;
REICAST_S(lcd_data_decoded); ser << lcd_data_decoded;
return true ;
} }
bool unserialize(void **data, unsigned int *total_size, serialize_version_enum version) override void deserialize(Deserializer& deser) override
{ {
maple_base::unserialize(data, total_size, version); maple_base::deserialize(deser);
REICAST_US(flash_data); deser >> flash_data;
REICAST_US(lcd_data); deser >> lcd_data;
REICAST_US(lcd_data_decoded); deser >> lcd_data_decoded;
for (u8 b : lcd_data) for (u8 b : lcd_data)
if (b != 0) if (b != 0)
{ {
config->SetImage(lcd_data_decoded); config->SetImage(lcd_data_decoded);
break; break;
} }
return true ;
} }
void initializeVmu() void initializeVmu()
@ -735,28 +733,26 @@ struct maple_microphone: maple_base
return MDT_Microphone; return MDT_Microphone;
} }
bool serialize(void **data, unsigned int *total_size) override void serialize(Serializer& ser) const override
{ {
maple_base::serialize(data, total_size); maple_base::serialize(ser);
REICAST_S(gain); ser << gain;
REICAST_S(sampling); ser << sampling;
REICAST_S(eight_khz); ser << eight_khz;
REICAST_SKIP(480 - sizeof(u32) - sizeof(bool) * 2);
return true;
} }
bool unserialize(void **data, unsigned int *total_size, serialize_version_enum version) override void deserialize(Deserializer& deser) override
{ {
if (sampling) if (sampling)
StopAudioRecording(); StopAudioRecording();
maple_base::unserialize(data, total_size, version); maple_base::deserialize(deser);
REICAST_US(gain); deser >> gain;
REICAST_US(sampling); deser >> sampling;
REICAST_US(eight_khz); deser >> eight_khz;
REICAST_SKIP(480 - sizeof(u32) - sizeof(bool) * 2); deser.skip(480 - sizeof(u32) - sizeof(bool) * 2, Deserializer::V23);
if (sampling) if (sampling)
StartAudioRecording(eight_khz); StartAudioRecording(eight_khz);
return true;
} }
void OnSetup() override void OnSetup() override
{ {
gain = 0xf; gain = 0xf;
@ -909,22 +905,21 @@ struct maple_sega_purupuru : maple_base
return MDT_PurupuruPack; return MDT_PurupuruPack;
} }
bool serialize(void **data, unsigned int *total_size) override void serialize(Serializer& ser) const override
{ {
maple_base::serialize(data, total_size); maple_base::serialize(ser);
REICAST_S(AST); ser << AST;
REICAST_S(AST_ms); ser << AST_ms;
REICAST_S(VIBSET); ser << VIBSET;
return true ; }
} void deserialize(Deserializer& deser) override
bool unserialize(void **data, unsigned int *total_size, serialize_version_enum version) override {
{ maple_base::deserialize(deser);
maple_base::unserialize(data, total_size, version); deser >> AST;
REICAST_US(AST); deser >> AST_ms;
REICAST_US(AST_ms); deser >> VIBSET;
REICAST_US(VIBSET); }
return true ;
}
u32 dma(u32 cmd) override u32 dma(u32 cmd) override
{ {
switch (cmd) switch (cmd)
@ -1166,10 +1161,10 @@ struct maple_mouse : maple_base
wstr(maple_sega_brand, 60); wstr(maple_sega_brand, 60);
// Low-consumption standby current (2) // Low-consumption standby current (2)
w16(0x0069); // 10.5 mA w16(0x0190); // 40 mA
// Maximum current consumption (2) // Maximum current consumption (2)
w16(0x0120); // 28.8 mA w16(0x01f4); // 50 mA
return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll; return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll;

View File

@ -5,6 +5,7 @@
#include "maple_helper.h" #include "maple_helper.h"
#include <cmath> #include <cmath>
#include "input/gamepad.h" #include "input/gamepad.h"
#include "serialize.h"
enum MapleFunctionID enum MapleFunctionID
{ {
@ -133,15 +134,15 @@ struct maple_device
virtual ~maple_device(); virtual ~maple_device();
virtual u32 RawDma(u32* buffer_in, u32 buffer_in_len, u32* buffer_out) = 0; virtual u32 RawDma(u32* buffer_in, u32 buffer_in_len, u32* buffer_out) = 0;
virtual bool serialize(void **data, unsigned int *total_size) {
REICAST_S(player_num); virtual void serialize(Serializer& ser) const {
return true; ser << player_num;
} }
virtual bool unserialize(void **data, unsigned int *total_size, serialize_version_enum version) { virtual void deserialize(Deserializer& deser) {
if (version >= V14) if (deser.version() >= Deserializer::V14)
REICAST_US(player_num); deser >> player_num;
return true;
} }
virtual MapleDeviceType get_device_type() = 0; virtual MapleDeviceType get_device_type() = 0;
virtual bool get_lightgun_pos() { return false; } virtual bool get_lightgun_pos() { return false; }
virtual const void *getData(size_t& size) const { size = 0; return nullptr; } virtual const void *getData(size_t& size) const { size = 0; return nullptr; }
@ -163,8 +164,7 @@ void limit_joystick_magnitude(s8& joyx, s8& joyy)
} }
} }
extern u8 EEPROM[0x100]; extern u8 *EEPROM;
void load_naomi_eeprom();
#define SWAP32(a) ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff)) #define SWAP32(a) ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff))
@ -257,7 +257,7 @@ class jvs_io_board;
struct maple_naomi_jamma : maple_base struct maple_naomi_jamma : maple_base
{ {
const u8 ALL_NODES = 0xff; static constexpr u8 ALL_NODES = 0xff;
std::vector<std::unique_ptr<jvs_io_board>> io_boards; std::vector<std::unique_ptr<jvs_io_board>> io_boards;
bool crazy_mode = false; bool crazy_mode = false;
@ -265,9 +265,10 @@ struct maple_naomi_jamma : maple_base
u8 jvs_repeat_request[32][256]; u8 jvs_repeat_request[32][256];
u8 jvs_receive_buffer[32][258]; u8 jvs_receive_buffer[32][258];
u32 jvs_receive_length[32] = { 0 }; u32 jvs_receive_length[32] = { 0 };
u8 eeprom[128];
maple_naomi_jamma(); maple_naomi_jamma();
~maple_naomi_jamma() override; ~maple_naomi_jamma();
MapleDeviceType get_device_type() override MapleDeviceType get_device_type() override
{ {
@ -289,6 +290,6 @@ struct maple_naomi_jamma : maple_base
u32 RawDma(u32* buffer_in, u32 buffer_in_len, u32* buffer_out) override; u32 RawDma(u32* buffer_in, u32 buffer_in_len, u32* buffer_out) override;
u32 dma(u32 cmd) override { return 0; } u32 dma(u32 cmd) override { return 0; }
bool serialize(void **data, unsigned int *total_size) override; void serialize(Serializer& ser) const override;
bool unserialize(void **data, unsigned int *total_size, serialize_version_enum version) override; void deserialize(Deserializer& deser) override;
}; };

View File

@ -38,6 +38,8 @@ static void maple_handle_reconnect();
//ddt/etc are just hacked for wince to work //ddt/etc are just hacked for wince to work
//now with proper maple delayed DMA maybe its time to look into it ? //now with proper maple delayed DMA maybe its time to look into it ?
bool maple_ddt_pending_reset; bool maple_ddt_pending_reset;
// pending DMA xfers
std::vector<std::pair<u32, std::vector<u32>>> mapleDmaOut;
void maple_vblank() void maple_vblank()
{ {
@ -175,6 +177,7 @@ static void maple_DoDma()
{ {
asic_RaiseInterrupt(holly_MAPLE_OVERRUN); asic_RaiseInterrupt(holly_MAPLE_OVERRUN);
SB_MDST = 0; SB_MDST = 0;
mapleDmaOut.clear();
return; return;
} }
#else #else
@ -185,13 +188,12 @@ static void maple_DoDma()
header_2|=(3<<26); header_2|=(3<<26);
} }
#endif #endif
u32* p_out=(u32*)GetMemPtr(header_2,4); u32* p_data = (u32 *)GetMemPtr(addr + 8, plen * sizeof(u32));
if (p_data == nullptr)
u32* p_data =(u32*) GetMemPtr(addr + 8,(plen)*sizeof(u32));
if (p_data == NULL)
{ {
INFO_LOG(MAPLE, "MAPLE ERROR : INVALID SB_MDSTAR value 0x%X", addr); INFO_LOG(MAPLE, "MAPLE ERROR : INVALID SB_MDSTAR value 0x%X", addr);
SB_MDST=0; SB_MDST = 0;
mapleDmaOut.clear();
return; return;
} }
const u32 frame_header = swap_msb ? SWAP32(p_data[0]) : p_data[0]; const u32 frame_header = swap_msb ? SWAP32(p_data[0]) : p_data[0];
@ -213,37 +215,33 @@ static void maple_DoDma()
if (swap_msb) if (swap_msb)
{ {
static u32 maple_in_buf[1024 / 4]; static u32 maple_in_buf[1024 / 4];
static u32 maple_out_buf[1024 / 4];
maple_in_buf[0] = frame_header; maple_in_buf[0] = frame_header;
for (u32 i = 1; i < inlen; i++) for (u32 i = 1; i < inlen; i++)
maple_in_buf[i] = SWAP32(p_data[i]); maple_in_buf[i] = SWAP32(p_data[i]);
p_data = maple_in_buf; p_data = maple_in_buf;
p_out = maple_out_buf;
} }
u32 outlen = MapleDevices[bus][port]->RawDma(&p_data[0], inlen * 4 + 4, &p_out[0]); u32 outbuf[1024 / 4];
u32 outlen = MapleDevices[bus][port]->RawDma(&p_data[0], inlen * 4 + 4, outbuf);
xfer_count += outlen; xfer_count += outlen;
#ifdef STRICT_MODE #ifdef STRICT_MODE
if (!check_mdapro(header_2 + outlen - 1)) if (!check_mdapro(header_2 + outlen - 1))
{ {
// TODO: This isn't correct (with SB_MMSEL=1) since the interrupt
// should be raised before the memory is written to
asic_RaiseInterrupt(holly_MAPLE_OVERRUN); asic_RaiseInterrupt(holly_MAPLE_OVERRUN);
SB_MDST = 0; SB_MDST = 0;
mapleDmaOut.clear();
return; return;
} }
#endif #endif
if (swap_msb) if (swap_msb)
{
u32 *final_out = (u32 *)GetMemPtr(header_2, outlen);
for (u32 i = 0; i < outlen / 4; i++) for (u32 i = 0; i < outlen / 4; i++)
final_out[i] = SWAP32(p_out[i]); outbuf[i] = SWAP32(outbuf[i]);
} mapleDmaOut.emplace_back(header_2, std::vector<u32>(outbuf, outbuf + outlen / 4));
} }
else else
{ {
if (port != 5 && command != 1) if (port != 5 && command != 1)
INFO_LOG(MAPLE, "MAPLE: Unknown device bus %d port %d cmd %d reci %d", bus, port, command, reci); INFO_LOG(MAPLE, "MAPLE: Unknown device bus %d port %d cmd %d reci %d", bus, port, command, reci);
p_out[0]=0xFFFFFFFF; mapleDmaOut.emplace_back(header_2, std::vector<u32>(1, 0xFFFFFFFF));
} }
//goto next command //goto next command
@ -278,23 +276,30 @@ static void maple_DoDma()
} }
} }
//printf("Maple XFER size %d bytes - %.2f ms\n",xfer_count,xfer_count*100.0f/(2*1024*1024/8)); //printf("Maple XFER size %d bytes - %.2f ms\n", xfer_count, xfer_count * 1000.0f / (2 * 1024 * 1024 / 8));
if (!occupy) if (!occupy)
sh4_sched_request(maple_schid, std::min((u64)xfer_count * (SH4_MAIN_CLOCK / (2 * 1024 * 1024 / 8)), (u64)SH4_MAIN_CLOCK)); sh4_sched_request(maple_schid, std::min((u64)xfer_count * (SH4_MAIN_CLOCK / (2 * 1024 * 1024 / 8)), (u64)SH4_MAIN_CLOCK));
} }
static int maple_schd(int tag, int c, int j) static int maple_schd(int tag, int c, int j)
{ {
if (SB_MDEN&1) if (SB_MDEN & 1)
{ {
SB_MDST=0; for (const auto& pair : mapleDmaOut)
{
size_t size = pair.second.size() * sizeof(u32);
u32 *p = (u32 *)GetMemPtr(pair.first, size);
memcpy(p, pair.second.data(), size);
}
SB_MDST = 0;
asic_RaiseInterrupt(holly_MAPLE_DMA); asic_RaiseInterrupt(holly_MAPLE_DMA);
} }
else else
{ {
INFO_LOG(MAPLE, "WARNING: MAPLE DMA ABORT"); INFO_LOG(MAPLE, "WARNING: MAPLE DMA ABORT");
SB_MDST=0; //I really wonder what this means, can the DMA be continued ? SB_MDST = 0; //I really wonder what this means, can the DMA be continued ?
} }
mapleDmaOut.clear();
return 0; return 0;
} }

View File

@ -27,36 +27,7 @@
#define LOGJVS(...) DEBUG_LOG(JVS, __VA_ARGS__) #define LOGJVS(...) DEBUG_LOG(JVS, __VA_ARGS__)
u8 EEPROM[0x100]; u8 *EEPROM;
bool EEPROM_loaded = false;
void load_naomi_eeprom()
{
if (!EEPROM_loaded)
{
EEPROM_loaded = true;
std::string eeprom_file = hostfs::getArcadeFlashPath() + ".eeprom";
FILE* f = nowide::fopen(eeprom_file.c_str(), "rb");
if (f)
{
if (std::fread(EEPROM, 1, 0x80, f) != 0x80)
WARN_LOG(MAPLE, "Failed or truncated read of EEPROM '%s'", eeprom_file.c_str());
std::fclose(f);
DEBUG_LOG(MAPLE, "Loaded EEPROM from %s", eeprom_file.c_str());
}
else if (naomi_default_eeprom != NULL)
{
DEBUG_LOG(MAPLE, "Using default EEPROM file");
memcpy(EEPROM, naomi_default_eeprom, 0x80);
}
else
DEBUG_LOG(MAPLE, "EEPROM file not found at %s and no default found", eeprom_file.c_str());
if (config::GGPOEnable)
MD5Sum().add(EEPROM, sizeof(EEPROM))
.getDigest(settings.network.md5.eeprom);
}
}
const u32 naomi_button_mapping[32] = { const u32 naomi_button_mapping[32] = {
NAOMI_BTN2_KEY, // DC_BTN_C NAOMI_BTN2_KEY, // DC_BTN_C
@ -175,8 +146,8 @@ public:
virtual ~jvs_io_board() = default; virtual ~jvs_io_board() = default;
u32 handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_out); u32 handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_out);
bool serialize(void **data, unsigned int *total_size); void serialize(Serializer& ser) const;
bool unserialize(void **data, unsigned int *total_size, serialize_version_enum version); void deserialize(Deserializer& deser);
bool lightgun_as_analog = false; bool lightgun_as_analog = false;
@ -706,11 +677,32 @@ maple_naomi_jamma::maple_naomi_jamma()
io_boards.push_back(std::unique_ptr<jvs_837_13844_wrungp>(new jvs_837_13844_wrungp(1, this))); io_boards.push_back(std::unique_ptr<jvs_837_13844_wrungp>(new jvs_837_13844_wrungp(1, this)));
break; break;
} }
std::string eeprom_file = hostfs::getArcadeFlashPath() + ".eeprom";
FILE* f = nowide::fopen(eeprom_file.c_str(), "rb");
if (f)
{
if (std::fread(eeprom, 1, 0x80, f) != 0x80)
WARN_LOG(MAPLE, "Failed or truncated read of EEPROM '%s'", eeprom_file.c_str());
std::fclose(f);
DEBUG_LOG(MAPLE, "Loaded EEPROM from %s", eeprom_file.c_str());
}
else if (naomi_default_eeprom != NULL)
{
DEBUG_LOG(MAPLE, "Using default EEPROM file");
memcpy(eeprom, naomi_default_eeprom, 0x80);
}
else
DEBUG_LOG(MAPLE, "EEPROM file not found at %s and no default found", eeprom_file.c_str());
if (config::GGPOEnable)
MD5Sum().add(eeprom, sizeof(eeprom))
.getDigest(settings.network.md5.eeprom);
EEPROM = eeprom;
} }
maple_naomi_jamma::~maple_naomi_jamma() maple_naomi_jamma::~maple_naomi_jamma()
{ {
EEPROM_loaded = false; EEPROM = nullptr;
} }
void maple_naomi_jamma::send_jvs_message(u32 node_id, u32 channel, u32 length, u8 *data) void maple_naomi_jamma::send_jvs_message(u32 node_id, u32 channel, u32 length, u8 *data)
@ -976,18 +968,19 @@ void maple_naomi_jamma::handle_86_subcommand()
case 0x0B: //EEPROM write case 0x0B: //EEPROM write
{ {
load_naomi_eeprom();
int address = dma_buffer_in[1]; int address = dma_buffer_in[1];
int size = dma_buffer_in[2]; int size = dma_buffer_in[2];
DEBUG_LOG(MAPLE, "EEprom write %08X %08X\n", address, size); DEBUG_LOG(MAPLE, "EEprom write %08X %08X\n", address, size);
//printState(Command,buffer_in,buffer_in_len); //printState(Command,buffer_in,buffer_in_len);
memcpy(EEPROM + address, dma_buffer_in + 4, size); address = address % sizeof(eeprom);
size = std::min((int)sizeof(eeprom) - address, size);
memcpy(eeprom + address, dma_buffer_in + 4, size);
std::string eeprom_file = hostfs::getArcadeFlashPath() + ".eeprom"; std::string eeprom_file = hostfs::getArcadeFlashPath() + ".eeprom";
FILE* f = nowide::fopen(eeprom_file.c_str(), "wb"); FILE* f = nowide::fopen(eeprom_file.c_str(), "wb");
if (f) if (f)
{ {
std::fwrite(EEPROM, 1, 0x80, f); std::fwrite(eeprom, 1, sizeof(eeprom), f);
std::fclose(f); std::fclose(f);
INFO_LOG(MAPLE, "Saved EEPROM to %s", eeprom_file.c_str()); INFO_LOG(MAPLE, "Saved EEPROM to %s", eeprom_file.c_str());
} }
@ -998,7 +991,7 @@ void maple_naomi_jamma::handle_86_subcommand()
w8(0x00); w8(0x00);
w8(0x20); w8(0x20);
w8(0x01); w8(0x01);
memcpy(dma_buffer_out, EEPROM, 4); memcpy(dma_buffer_out, eeprom, 4);
dma_buffer_out += 4; dma_buffer_out += 4;
*dma_count_out += 4; *dma_count_out += 4;
} }
@ -1006,17 +999,17 @@ void maple_naomi_jamma::handle_86_subcommand()
case 0x3: //EEPROM read case 0x3: //EEPROM read
{ {
load_naomi_eeprom();
//printf("EEprom READ\n"); //printf("EEprom READ\n");
int address = dma_buffer_in[1]; int address = dma_buffer_in[1] % sizeof(eeprom);
//printState(Command,buffer_in,buffer_in_len); //printState(Command,buffer_in,buffer_in_len);
w8(MDRS_JVSReply); w8(MDRS_JVSReply);
w8(0x00); w8(0x00);
w8(0x20); w8(0x20);
w8(0x20); w8(0x20);
memcpy(dma_buffer_out, EEPROM + address, 0x80); int size = sizeof(eeprom) - address;
dma_buffer_out += 0x80; memcpy(dma_buffer_out, eeprom + address, size);
*dma_count_out += 0x80; dma_buffer_out += size;
*dma_count_out += size;
} }
break; break;
@ -1237,34 +1230,33 @@ u32 maple_naomi_jamma::RawDma(u32* buffer_in, u32 buffer_in_len, u32* buffer_out
return out_len; return out_len;
} }
bool maple_naomi_jamma::serialize(void **data, unsigned int *total_size) void maple_naomi_jamma::serialize(Serializer& ser) const
{ {
maple_base::serialize(data, total_size); maple_base::serialize(ser);
REICAST_S(crazy_mode); ser << crazy_mode;
REICAST_S(jvs_repeat_request); ser << jvs_repeat_request;
REICAST_S(jvs_receive_length); ser << jvs_receive_length;
REICAST_S(jvs_receive_buffer); ser << jvs_receive_buffer;
size_t board_count = io_boards.size(); ser << eeprom;
REICAST_S(board_count); u32 board_count = io_boards.size();
ser << board_count;
for (u32 i = 0; i < io_boards.size(); i++) for (u32 i = 0; i < io_boards.size(); i++)
io_boards[i]->serialize(data, total_size); io_boards[i]->serialize(ser);
return true ;
} }
void maple_naomi_jamma::deserialize(Deserializer& deser)
bool maple_naomi_jamma::unserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
maple_base::unserialize(data, total_size, version); maple_base::deserialize(deser);
REICAST_US(crazy_mode); deser >> crazy_mode;
REICAST_US(jvs_repeat_request); deser >> jvs_repeat_request;
REICAST_US(jvs_receive_length); deser >> jvs_receive_length;
REICAST_US(jvs_receive_buffer); deser >> jvs_receive_buffer;
size_t board_count; if (deser.version() >= Deserializer::V23)
REICAST_US(board_count); deser >> eeprom;
u32 board_count;
deser >> board_count;
deser.skip(sizeof(size_t) - sizeof(u32), Deserializer::V23);
for (u32 i = 0; i < board_count; i++) for (u32 i = 0; i < board_count; i++)
io_boards[i]->unserialize(data, total_size, version); io_boards[i]->deserialize(deser);
return true ;
} }
u16 jvs_io_board::read_analog_axis(int player_num, int player_axis, bool inverted) u16 jvs_io_board::read_analog_axis(int player_num, int player_axis, bool inverted)
@ -1675,18 +1667,13 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
return length; return length;
} }
bool jvs_io_board::serialize(void **data, unsigned int *total_size) void jvs_io_board::serialize(Serializer& ser) const
{ {
REICAST_S(node_id); ser << node_id;
REICAST_S(lightgun_as_analog); ser << lightgun_as_analog;
return true ;
} }
void jvs_io_board::deserialize(Deserializer& deser)
bool jvs_io_board::unserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
REICAST_US(node_id); deser >> node_id;
REICAST_US(lightgun_as_analog); deser >> lightgun_as_analog;
return true ;
} }

View File

@ -27,6 +27,7 @@
#include "hw/sh4/sh4_sched.h" #include "hw/sh4/sh4_sched.h"
#include "oslib/oslib.h" #include "oslib/oslib.h"
#include "network/picoppp.h" #include "network/picoppp.h"
#include "serialize.h"
#define MODEM_COUNTRY_RES 0 #define MODEM_COUNTRY_RES 0
#define MODEM_COUNTRY_JAP 1 #define MODEM_COUNTRY_JAP 1
@ -748,25 +749,24 @@ void ModemWriteMem_A0_006(u32 addr, u32 data, u32 size)
LOG("modem reg %03X write %X -- wtf is it?",reg,data); LOG("modem reg %03X write %X -- wtf is it?",reg,data);
} }
void ModemSerialize(void **data, unsigned int *total_size) void ModemSerialize(Serializer& ser)
{ {
REICAST_S(modem_regs); ser << modem_regs;
REICAST_S(dspram); ser << dspram;
REICAST_S(state); ser << state;
REICAST_S(connect_state); ser << connect_state;
REICAST_S(last_dial_time); ser << last_dial_time;
REICAST_S(data_sent); ser << data_sent;
} }
void ModemDeserialize(Deserializer& deser)
void ModemDeserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
if (version >= V20) if (deser.version() >= Deserializer::V20)
{ {
REICAST_US(modem_regs); deser >> modem_regs;
REICAST_US(dspram); deser >> dspram;
REICAST_US(state); deser >> state;
REICAST_US(connect_state); deser >> connect_state;
REICAST_US(last_dial_time); deser >> last_dial_time;
REICAST_US(data_sent); deser >> data_sent;
} }
} }

View File

@ -29,5 +29,5 @@ void ModemReset();
void ModemTerm(); void ModemTerm();
u32 ModemReadMem_A0_006(u32 addr,u32 size); u32 ModemReadMem_A0_006(u32 addr,u32 size);
void ModemWriteMem_A0_006(u32 addr,u32 data,u32 size); void ModemWriteMem_A0_006(u32 addr,u32 data,u32 size);
void ModemSerialize(void **data, unsigned int *total_size); void ModemSerialize(Serializer& ser);
void ModemDeserialize(void **data, unsigned int *total_size, serialize_version_enum version); void ModemDeserialize(Deserializer& deser);

View File

@ -162,6 +162,7 @@ ROM board internal layouts:
*/ */
#include "awcartridge.h" #include "awcartridge.h"
#include "awave_regs.h" #include "awave_regs.h"
#include "serialize.h"
u32 AWCartridge::ReadMem(u32 address, u32 size) { u32 AWCartridge::ReadMem(u32 address, u32 size) {
verify(size != 1); verify(size != 1);
@ -423,28 +424,28 @@ std::string AWCartridge::GetGameId()
return game_id; return game_id;
} }
void AWCartridge::Serialize(void **data, unsigned int *total_size) void AWCartridge::Serialize(Serializer& ser) const
{ {
REICAST_S(mpr_offset); ser << mpr_offset;
REICAST_S(mpr_bank); ser << mpr_bank;
REICAST_S(epr_offset); ser << epr_offset;
REICAST_S(mpr_file_offset); ser << mpr_file_offset;
REICAST_S(mpr_record_index); ser << mpr_record_index;
REICAST_S(mpr_first_file_index); ser << mpr_first_file_index;
REICAST_S(dma_offset); ser << dma_offset;
REICAST_S(dma_limit); ser << dma_limit;
Cartridge::Serialize(data, total_size); Cartridge::Serialize(ser);
} }
void AWCartridge::Unserialize(void **data, unsigned int *total_size) void AWCartridge::Deserialize(Deserializer& deser)
{ {
REICAST_US(mpr_offset); deser >> mpr_offset;
REICAST_US(mpr_bank); deser >> mpr_bank;
REICAST_US(epr_offset); deser >> epr_offset;
REICAST_US(mpr_file_offset); deser >> mpr_file_offset;
REICAST_US(mpr_record_index); deser >> mpr_record_index;
REICAST_US(mpr_first_file_index); deser >> mpr_first_file_index;
REICAST_US(dma_offset); deser >> dma_offset;
REICAST_US(dma_limit); deser >> dma_limit;
Cartridge::Unserialize(data, total_size); Cartridge::Deserialize(deser);
} }

View File

@ -28,8 +28,8 @@ public:
std::string GetGameId() override; std::string GetGameId() override;
void SetKey(u32 key) override; void SetKey(u32 key) override;
void Serialize(void **data, unsigned int *total_size) override; void Serialize(Serializer& ser) const override;
void Unserialize(void **data, unsigned int *total_size) override; void Deserialize(Deserializer& deser) override;
private: private:
void device_reset(); void device_reset();

View File

@ -8,6 +8,7 @@
* // copyright-holders:Olivier Galibert * // copyright-holders:Olivier Galibert
*/ */
#include "m1cartridge.h" #include "m1cartridge.h"
#include "serialize.h"
M1Cartridge::M1Cartridge(u32 size) : NaomiCartridge(size) M1Cartridge::M1Cartridge(u32 size) : NaomiCartridge(size)
{ {
@ -127,32 +128,34 @@ u32 M1Cartridge::get_decrypted_32b()
return res; return res;
} }
void M1Cartridge::Serialize(void** data, unsigned int* total_size) { void M1Cartridge::Serialize(Serializer& ser) const
REICAST_S(buffer); {
REICAST_S(dict); ser << buffer;
REICAST_S(hist); ser << dict;
REICAST_S(avail_val); ser << hist;
REICAST_S(rom_cur_address); ser << avail_val;
REICAST_S(buffer_actual_size); ser << rom_cur_address;
REICAST_S(avail_bits); ser << buffer_actual_size;
REICAST_S(stream_ended); ser << avail_bits;
REICAST_S(has_history); ser << stream_ended;
REICAST_S(encryption); ser << has_history;
ser << encryption;
NaomiCartridge::Serialize(data, total_size); NaomiCartridge::Serialize(ser);
} }
void M1Cartridge::Unserialize(void** data, unsigned int* total_size) { void M1Cartridge::Deserialize(Deserializer& deser)
REICAST_US(buffer); {
REICAST_US(dict); deser >> buffer;
REICAST_US(hist); deser >> dict;
REICAST_US(avail_val); deser >> hist;
REICAST_US(rom_cur_address); deser >> avail_val;
REICAST_US(buffer_actual_size); deser >> rom_cur_address;
REICAST_US(avail_bits); deser >> buffer_actual_size;
REICAST_US(stream_ended); deser >> avail_bits;
REICAST_US(has_history); deser >> stream_ended;
REICAST_US(encryption); deser >> has_history;
deser >> encryption;
NaomiCartridge::Unserialize(data, total_size); NaomiCartridge::Deserialize(deser);
} }

View File

@ -34,8 +34,8 @@ public:
} }
void AdvancePtr(u32 size) override; void AdvancePtr(u32 size) override;
void Serialize(void** data, unsigned int* total_size) override; void Serialize(Serializer& ser) const override;
void Unserialize(void** data, unsigned int* total_size) override; void Deserialize(Deserializer& deser) override;
void setActelId(u32 actel_id) { this->actel_id = actel_id; } void setActelId(u32 actel_id) { this->actel_id = actel_id; }

View File

@ -9,6 +9,7 @@
*/ */
#include "m4cartridge.h" #include "m4cartridge.h"
#include "serialize.h"
// Decoder for M4-type NAOMI cart encryption // Decoder for M4-type NAOMI cart encryption
@ -294,31 +295,30 @@ std::string M4Cartridge::GetGameId()
return game_id; return game_id;
} }
void M4Cartridge::Serialize(void** data, unsigned int* total_size) void M4Cartridge::Serialize(Serializer& ser) const
{ {
REICAST_S(buffer); ser << buffer;
REICAST_S(rom_cur_address); ser << rom_cur_address;
REICAST_S(buffer_actual_size); ser << buffer_actual_size;
REICAST_S(iv); ser << iv;
REICAST_S(counter); ser << counter;
REICAST_S(encryption); ser << encryption;
REICAST_S(cfi_mode); ser << cfi_mode;
REICAST_S(xfer_ready); ser << xfer_ready;
NaomiCartridge::Serialize(data, total_size); NaomiCartridge::Serialize(ser);
} }
void M4Cartridge::Unserialize(void** data, unsigned int* total_size) void M4Cartridge::Deserialize(Deserializer& deser)
{ {
REICAST_US(buffer); deser >> buffer;
REICAST_US(rom_cur_address); deser >> rom_cur_address;
REICAST_US(buffer_actual_size); deser >> buffer_actual_size;
REICAST_US(iv); deser >> iv;
REICAST_US(counter); deser >> counter;
REICAST_US(encryption); deser >> encryption;
REICAST_US(cfi_mode); deser >> cfi_mode;
REICAST_US(xfer_ready); deser >> xfer_ready;
NaomiCartridge::Unserialize(data, total_size); NaomiCartridge::Deserialize(deser);
} }

View File

@ -45,8 +45,8 @@ public:
void* GetDmaPtr(u32 &size) override; void* GetDmaPtr(u32 &size) override;
void AdvancePtr(u32 size) override; void AdvancePtr(u32 size) override;
std::string GetGameId() override; std::string GetGameId() override;
void Serialize(void** data, unsigned int* total_size) override; void Serialize(Serializer& ser) const override;
void Unserialize(void** data, unsigned int* total_size) override; void Deserialize(Deserializer& deser) override;
void SetKey(u32 key) override { this->m4id = key; } void SetKey(u32 key) override { this->m4id = key; }
void SetKeyData(u8 *key_data) override { this->m_key_data = key_data; } void SetKeyData(u8 *key_data) override { this->m_key_data = key_data; }

View File

@ -15,6 +15,7 @@
#include "naomi_regs.h" #include "naomi_regs.h"
#include "naomi_m3comm.h" #include "naomi_m3comm.h"
#include "network/naomi_network.h" #include "network/naomi_network.h"
#include "serialize.h"
//#define NAOMI_COMM //#define NAOMI_COMM
@ -652,69 +653,73 @@ void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) {
INFO_LOG(NAOMI, "Unhandled write @ %x (%d): %x", addr, size, data); INFO_LOG(NAOMI, "Unhandled write @ %x (%d): %x", addr, size, data);
} }
void naomi_Serialize(void **data, unsigned int *total_size) void naomi_Serialize(Serializer& ser)
{ {
REICAST_S(GSerialBuffer); ser << GSerialBuffer;
REICAST_S(BSerialBuffer); ser << BSerialBuffer;
REICAST_S(GBufPos); ser << GBufPos;
REICAST_S(BBufPos); ser << BBufPos;
REICAST_S(GState); ser << GState;
REICAST_S(BState); ser << BState;
REICAST_S(GOldClk); ser << GOldClk;
REICAST_S(BOldClk); ser << BOldClk;
REICAST_S(BControl); ser << BControl;
REICAST_S(BCmd); ser << BCmd;
REICAST_S(BLastCmd); ser << BLastCmd;
REICAST_S(GControl); ser << GControl;
REICAST_S(GCmd); ser << GCmd;
REICAST_S(GLastCmd); ser << GLastCmd;
REICAST_S(SerStep); ser << SerStep;
REICAST_S(SerStep2); ser << SerStep2;
REICAST_SA(BSerial,69); ser.serialize(BSerial, 69);
REICAST_SA(GSerial,69); ser.serialize(GSerial, 69);
REICAST_S(reg_dimm_command); ser << reg_dimm_command;
REICAST_S(reg_dimm_offsetl); ser << reg_dimm_offsetl;
REICAST_S(reg_dimm_parameterl); ser << reg_dimm_parameterl;
REICAST_S(reg_dimm_parameterh); ser << reg_dimm_parameterh;
REICAST_S(reg_dimm_status); ser << reg_dimm_status;
REICAST_S(aw_maple_devs); ser << aw_maple_devs;
REICAST_S(coin_chute_time); ser << coin_chute_time;
REICAST_S(aw_ram_test_skipped); ser << aw_ram_test_skipped;
// TODO serialize m3comm? // TODO serialize m3comm?
} }
void naomi_Deserialize(Deserializer& deser)
void naomi_Unserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
REICAST_US(GSerialBuffer); if (deser.version() < Deserializer::V9_LIBRETRO)
REICAST_US(BSerialBuffer);
REICAST_US(GBufPos);
REICAST_US(BBufPos);
REICAST_US(GState);
REICAST_US(BState);
REICAST_US(GOldClk);
REICAST_US(BOldClk);
REICAST_US(BControl);
REICAST_US(BCmd);
REICAST_US(BLastCmd);
REICAST_US(GControl);
REICAST_US(GCmd);
REICAST_US(GLastCmd);
REICAST_US(SerStep);
REICAST_US(SerStep2);
REICAST_USA(BSerial,69);
REICAST_USA(GSerial,69);
REICAST_US(reg_dimm_command);
REICAST_US(reg_dimm_offsetl);
REICAST_US(reg_dimm_parameterl);
REICAST_US(reg_dimm_parameterh);
REICAST_US(reg_dimm_status);
if (version < V11)
REICAST_SKIP(1); // NaomiDataRead
else if (version >= V14)
REICAST_US(aw_maple_devs);
if (version >= V20)
{ {
REICAST_US(coin_chute_time); deser.skip<u32>(); // naomi_updates
REICAST_US(aw_ram_test_skipped); deser.skip<u32>(); // BoardID
}
deser >> GSerialBuffer;
deser >> BSerialBuffer;
deser >> GBufPos;
deser >> BBufPos;
deser >> GState;
deser >> BState;
deser >> GOldClk;
deser >> BOldClk;
deser >> BControl;
deser >> BCmd;
deser >> BLastCmd;
deser >> GControl;
deser >> GCmd;
deser >> GLastCmd;
deser >> SerStep;
deser >> SerStep2;
deser.deserialize(BSerial, 69);
deser.deserialize(GSerial, 69);
deser >> reg_dimm_command;
deser >> reg_dimm_offsetl;
deser >> reg_dimm_parameterl;
deser >> reg_dimm_parameterh;
deser >> reg_dimm_status;
if (deser.version() < Deserializer::V11)
deser.skip<u8>();
else if (deser.version() >= Deserializer::V14)
deser >> aw_maple_devs;
if (deser.version() >= Deserializer::V20)
{
deser >> coin_chute_time;
deser >> aw_ram_test_skipped;
} }
} }

View File

@ -1,14 +1,14 @@
/* /*
** naomi.h ** naomi.h
*/ */
#pragma once #pragma once
#include "types.h"
void naomi_reg_Init(); void naomi_reg_Init();
void naomi_reg_Term(); void naomi_reg_Term();
void naomi_reg_Reset(bool hard); void naomi_reg_Reset(bool hard);
void naomi_Serialize(void **data, unsigned int *total_size); void naomi_Serialize(Serializer& ser);
void naomi_Unserialize(void **data, unsigned int *total_size, serialize_version_enum version); void naomi_Deserialize(Deserializer& deser);
u32 ReadMem_naomi(u32 Addr, u32 size); u32 ReadMem_naomi(u32 Addr, u32 size);
void WriteMem_naomi(u32 Addr, u32 data, u32 size); void WriteMem_naomi(u32 Addr, u32 data, u32 size);

View File

@ -36,6 +36,7 @@
#include "emulator.h" #include "emulator.h"
#include "cfg/option.h" #include "cfg/option.h"
#include "oslib/oslib.h" #include "oslib/oslib.h"
#include "serialize.h"
Cartridge *CurrentCartridge; Cartridge *CurrentCartridge;
bool bios_loaded = false; bool bios_loaded = false;
@ -857,22 +858,22 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
DEBUG_LOG(NAOMI, "naomi?WTF? WriteMem: %X <= %X, %d", address, data, size); DEBUG_LOG(NAOMI, "naomi?WTF? WriteMem: %X <= %X, %d", address, data, size);
} }
void NaomiCartridge::Serialize(void** data, unsigned int* total_size) void NaomiCartridge::Serialize(Serializer& ser) const
{ {
REICAST_S(RomPioOffset); ser << RomPioOffset;
REICAST_S(RomPioAutoIncrement); ser << RomPioAutoIncrement;
REICAST_S(DmaOffset); ser << DmaOffset;
REICAST_S(DmaCount); ser << DmaCount;
Cartridge::Serialize(data, total_size); Cartridge::Serialize(ser);
} }
void NaomiCartridge::Unserialize(void** data, unsigned int* total_size) void NaomiCartridge::Deserialize(Deserializer& deser)
{ {
REICAST_US(RomPioOffset); deser >> RomPioOffset;
REICAST_US(RomPioAutoIncrement); deser >> RomPioAutoIncrement;
REICAST_US(DmaOffset); deser >> DmaOffset;
REICAST_US(DmaCount); deser >> DmaCount;
Cartridge::Unserialize(data, total_size); Cartridge::Deserialize(deser);
} }
bool M2Cartridge::Read(u32 offset, u32 size, void* dst) bool M2Cartridge::Read(u32 offset, u32 size, void* dst)
@ -962,12 +963,12 @@ std::string M2Cartridge::GetGameId()
return game_id; return game_id;
} }
void M2Cartridge::Serialize(void** data, unsigned int* total_size) { void M2Cartridge::Serialize(Serializer& ser) const {
REICAST_S(naomi_cart_ram); ser << naomi_cart_ram;
NaomiCartridge::Serialize(data, total_size); NaomiCartridge::Serialize(ser);
} }
void M2Cartridge::Unserialize(void** data, unsigned int* total_size) { void M2Cartridge::Deserialize(Deserializer& deser) {
REICAST_US(naomi_cart_ram); deser >> naomi_cart_ram;
NaomiCartridge::Unserialize(data, total_size); NaomiCartridge::Deserialize(deser);
} }

View File

@ -24,8 +24,8 @@ public:
virtual void* GetDmaPtr(u32 &size) = 0; virtual void* GetDmaPtr(u32 &size) = 0;
virtual void AdvancePtr(u32 size) = 0; virtual void AdvancePtr(u32 size) = 0;
virtual std::string GetGameId(); virtual std::string GetGameId();
virtual void Serialize(void **data, unsigned int *total_size) {} virtual void Serialize(Serializer& ser) const {}
virtual void Unserialize(void **data, unsigned int *total_size) {} virtual void Deserialize(Deserializer& deser) {}
virtual void SetKey(u32 key) { } virtual void SetKey(u32 key) { }
virtual void SetKeyData(u8 *key_data) { } virtual void SetKeyData(u8 *key_data) { }
@ -43,8 +43,8 @@ public:
void WriteMem(u32 address, u32 data, u32 size) override; void WriteMem(u32 address, u32 data, u32 size) override;
void* GetDmaPtr(u32 &size) override; void* GetDmaPtr(u32 &size) override;
void AdvancePtr(u32 size) override {} void AdvancePtr(u32 size) override {}
void Serialize(void** data, unsigned int* total_size) override; void Serialize(Serializer& ser) const override;
void Unserialize(void** data, unsigned int* total_size) override; void Deserialize(Deserializer& deser) override;
void SetKey(u32 key) override { this->key = key; } void SetKey(u32 key) override { this->key = key; }
@ -72,8 +72,8 @@ public:
bool Read(u32 offset, u32 size, void* dst) override; bool Read(u32 offset, u32 size, void* dst) override;
bool Write(u32 offset, u32 size, u32 data) override; bool Write(u32 offset, u32 size, u32 data) override;
u16 ReadCipheredData(u32 offset); u16 ReadCipheredData(u32 offset);
void Serialize(void** data, unsigned int* total_size) override; void Serialize(Serializer& ser) const override;
void Unserialize(void** data, unsigned int* total_size) override; void Deserialize(Deserializer& deser) override;
void* GetDmaPtr(u32& size) override; void* GetDmaPtr(u32& size) override;
std::string GetGameId() override; std::string GetGameId() override;

View File

@ -101,7 +101,6 @@ void write_naomi_flash(u32 addr, u8 value)
// //
void write_naomi_eeprom(u32 offset, u8 value) void write_naomi_eeprom(u32 offset, u8 value)
{ {
load_naomi_eeprom();
if (offset >= 3 && offset < 20) if (offset >= 3 && offset < 20)
{ {
EEPROM[offset] = value; EEPROM[offset] = value;

View File

@ -7,6 +7,7 @@
#include "cfg/option.h" #include "cfg/option.h"
#include "network/ggpo.h" #include "network/ggpo.h"
#include "emulator.h" #include "emulator.h"
#include "serialize.h"
#include <mutex> #include <mutex>
#include <zlib.h> #include <zlib.h>
@ -37,7 +38,7 @@ u32 fb_watch_addr_start;
u32 fb_watch_addr_end; u32 fb_watch_addr_end;
bool fb_dirty; bool fb_dirty;
bool pend_rend = false; static bool pend_rend;
TA_context* _pvrrc; TA_context* _pvrrc;
@ -470,28 +471,28 @@ void rend_start_rollback()
vramRollback.Wait(); vramRollback.Wait();
} }
void rend_serialize(void **data, unsigned int *total_size) void rend_serialize(Serializer& ser)
{ {
REICAST_S(fb_w_cur); ser << fb_w_cur;
REICAST_S(render_called); ser << render_called;
REICAST_S(fb_dirty); ser << fb_dirty;
REICAST_S(fb_watch_addr_start); ser << fb_watch_addr_start;
REICAST_S(fb_watch_addr_end); ser << fb_watch_addr_end;
} }
void rend_deserialize(Deserializer& deser)
void rend_deserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
if ((version >= V12_LIBRETRO && version < V5) || version >= V12) if ((deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5) || deser.version() >= Deserializer::V12)
REICAST_US(fb_w_cur); deser >> fb_w_cur;
else else
fb_w_cur = 1; fb_w_cur = 1;
if (version >= V20) if (deser.version() >= Deserializer::V20)
{ {
REICAST_US(render_called); deser >> render_called;
REICAST_US(fb_dirty); deser >> fb_dirty;
REICAST_US(fb_watch_addr_start); deser >> fb_watch_addr_start;
REICAST_US(fb_watch_addr_end); deser >> fb_watch_addr_end;
} }
pend_rend = false;
} }
void rend_resize_renderer() void rend_resize_renderer()

View File

@ -18,8 +18,8 @@ void rend_reset();
void rend_disable_rollback(); void rend_disable_rollback();
void rend_start_rollback(); void rend_start_rollback();
void rend_allow_rollback(); void rend_allow_rollback();
void rend_serialize(void **data, unsigned int *total_size); void rend_serialize(Serializer& ser);
void rend_deserialize(void **data, unsigned int *total_size, serialize_version_enum version); void rend_deserialize(Deserializer& deser);
void rend_resize_renderer(); void rend_resize_renderer();
/////// ///////

View File

@ -1,44 +0,0 @@
// drkPvr.cpp : Defines the entry point for the DLL application.
//
/*
Plugin structure
Interface
SPG
TA
Renderer
*/
#include "spg.h"
#include "pvr_regs.h"
#include "Renderer_if.h"
#include "ta_ctx.h"
#include "rend/TexCache.h"
void libPvr_Reset(bool hard)
{
KillTex = true;
Regs_Reset(hard);
spg_Reset(hard);
if (hard)
rend_reset();
tactx_Term();
}
s32 libPvr_Init()
{
if (!spg_Init())
{
//failed
return -1;
}
return 0;
}
//called when exiting from sh4 thread , from the new thread context (for any thread specific de init) :P
void libPvr_Term()
{
tactx_Term();
spg_Term();
}

141
core/hw/pvr/pvr.cpp Normal file
View File

@ -0,0 +1,141 @@
/*
Copyright 2021 flyinghead
This file is part of Flycast.
Flycast 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, either version 2 of the License, or
(at your option) any later version.
Flycast 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 for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pvr.h"
#include "spg.h"
#include "pvr_regs.h"
#include "Renderer_if.h"
#include "ta_ctx.h"
#include "rend/TexCache.h"
#include "serialize.h"
#include "pvr_mem.h"
// ta.cpp
extern u8 ta_fsm[2049]; //[2048] stores the current state
extern u32 ta_fsm_cl;
// pvr_regs.cpp
extern bool fog_needs_update;
extern bool pal_needs_update;
namespace pvr
{
void reset(bool hard)
{
KillTex = true;
Regs_Reset(hard);
spg_Reset(hard);
if (hard)
rend_reset();
tactx_Term();
}
void init()
{
spg_Init();
}
void term()
{
tactx_Term();
spg_Term();
}
void serialize(Serializer& ser)
{
YUV_serialize(ser);
ser << pvr_regs;
spg_Serialize(ser);
rend_serialize(ser);
ser << ta_fsm[2048];
ser << ta_fsm_cl;
SerializeTAContext(ser);
if (!ser.rollback())
ser.serialize(vram.data, vram.size);
}
void deserialize(Deserializer& deser)
{
if (deser.version() < Deserializer::V9_LIBRETRO)
{
deser.skip<u32>(); // FrameCount
deser.skip<bool>(); // pend_rend
}
YUV_deserialize(deser);
if (deser.version() >= Deserializer::V5_LIBRETRO && deser.version() < Deserializer::V9_LIBRETRO)
deser.skip<bool>(); // fog_needs_update
deser >> pvr_regs;
fog_needs_update = true;
spg_Deserialize(deser);
if (deser.version() < Deserializer::V9_LIBRETRO)
{
deser.skip(4 * 256); // ta_type_lut
deser.skip(2048); // ta_fsm
}
rend_deserialize(deser);
deser >> ta_fsm[2048];
deser >> ta_fsm_cl;
if (deser.version() >= Deserializer::V5_LIBRETRO && deser.version() < Deserializer::V9_LIBRETRO)
{
deser.skip<bool>(); // pal_needs_update
deser.skip(4 * 4); // _pal_rev_256
deser.skip(4 * 64); // _pal_rev_16
deser.skip(4 * 4); // pal_rev_256
deser.skip(4 * 64); // pal_rev_16
deser.skip(4 * 65536 * 3); // decoded_colors
deser.skip(4); // tileclip_val
deser.skip(65536); // f32_su8_tbl
deser.skip(4); // FaceBaseColor
deser.skip(4); // FaceOffsColor
deser.skip(4); // SFaceBaseColor
deser.skip(4); // SFaceOffsColor
deser.skip(4); // palette_index
deser.skip<bool>(); // KillTex
deser.skip(4 * 1024); // palette16_ram
deser.skip(4 * 1024); // palette32_ram
deser.skip(4 * 1024 * 8 * 2); // detwiddle
}
else if (deser.version() <= Deserializer::V4)
{
deser.skip(4);
deser.skip(65536);
deser.skip(4);
deser.skip(4);
deser.skip(4);
deser.skip(4);
}
if (deser.version() >= Deserializer::V11 || (deser.version() >= Deserializer::V10_LIBRETRO && deser.version() <= Deserializer::VLAST_LIBRETRO))
DeserializeTAContext(deser);
if (!deser.rollback())
deser.deserialize(vram.data, vram.size);
pal_needs_update = true;
}
}

32
core/hw/pvr/pvr.h Normal file
View File

@ -0,0 +1,32 @@
/*
Copyright 2021 flyinghead
This file is part of Flycast.
Flycast 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, either version 2 of the License, or
(at your option) any later version.
Flycast 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 for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
namespace pvr
{
void init();
void term();
void reset(bool hard);
void serialize(Serializer& ser);
void deserialize(Deserializer& deser);
}

View File

@ -9,6 +9,7 @@
#include "ta.h" #include "ta.h"
#include "hw/holly/sb.h" #include "hw/holly/sb.h"
#include "hw/holly/holly_intc.h" #include "hw/holly/holly_intc.h"
#include "serialize.h"
static u32 pvr_map32(u32 offset32); static u32 pvr_map32(u32 offset32);
@ -172,29 +173,28 @@ static void YUV_data(const SQBuffer *data, u32 count)
verify(count==0); verify(count==0);
} }
void YUV_serialize(void **data, unsigned int *total_size) void YUV_serialize(Serializer& ser)
{ {
REICAST_S(YUV_tempdata); ser << YUV_tempdata;
REICAST_S(YUV_dest); ser << YUV_dest;
REICAST_S(YUV_blockcount); ser << YUV_blockcount;
REICAST_S(YUV_x_curr); ser << YUV_x_curr;
REICAST_S(YUV_y_curr); ser << YUV_y_curr;
REICAST_S(YUV_x_size); ser << YUV_x_size;
REICAST_S(YUV_y_size); ser << YUV_y_size;
REICAST_S(YUV_index); ser << YUV_index;
} }
void YUV_deserialize(Deserializer& deser)
void YUV_unserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
REICAST_US(YUV_tempdata); deser >> YUV_tempdata;
REICAST_US(YUV_dest); deser >> YUV_dest;
REICAST_US(YUV_blockcount); deser >> YUV_blockcount;
REICAST_US(YUV_x_curr); deser >> YUV_x_curr;
REICAST_US(YUV_y_curr); deser >> YUV_y_curr;
REICAST_US(YUV_x_size); deser >> YUV_x_size;
REICAST_US(YUV_y_size); deser >> YUV_y_size;
if (version >= V16) if (deser.version() >= Deserializer::V16)
REICAST_US(YUV_index); deser >> YUV_index;
else else
YUV_index = 0; YUV_index = 0;
} }

View File

@ -14,8 +14,8 @@ void DYNACALL TAWrite(u32 address, const SQBuffer *data, u32 count);
void DYNACALL TAWriteSQ(u32 address, const SQBuffer *sqb); void DYNACALL TAWriteSQ(u32 address, const SQBuffer *sqb);
void YUV_init(); void YUV_init();
void YUV_serialize(void **data, unsigned int *total_size); void YUV_serialize(Serializer& ser);
void YUV_unserialize(void **data, unsigned int *total_size, serialize_version_enum version); void YUV_deserialize(Deserializer& deser);
// 32-bit vram path handlers // 32-bit vram path handlers
template<typename T> T DYNACALL pvr_read32p(u32 addr); template<typename T> T DYNACALL pvr_read32p(u32 addr);

View File

@ -6,6 +6,8 @@
#include "input/gamepad_device.h" #include "input/gamepad_device.h"
#include "oslib/oslib.h" #include "oslib/oslib.h"
#include "rend/TexCache.h" #include "rend/TexCache.h"
#include "hw/maple/maple_if.h"
#include "serialize.h"
//SPG emulation; Scanline/Raster beam registers & interrupts //SPG emulation; Scanline/Raster beam registers & interrupts
@ -104,7 +106,10 @@ int spg_line_sched(int tag, int cycl, int jit)
} }
if (SPG_VBLANK_INT.vblank_out_interrupt_line_number == prv_cur_scanline) if (SPG_VBLANK_INT.vblank_out_interrupt_line_number == prv_cur_scanline)
{
maple_vblank();
asic_RaiseInterrupt(holly_SCANINT2); asic_RaiseInterrupt(holly_SCANINT2);
}
if (SPG_VBLANK.vstart == prv_cur_scanline) if (SPG_VBLANK.vstart == prv_cur_scanline)
in_vblank=1; in_vblank=1;
@ -318,51 +323,49 @@ void SetREP(TA_context* cntx)
sh4_sched_request(render_end_schid, 4096); sh4_sched_request(render_end_schid, 4096);
} }
void spg_Serialize(void **data, unsigned int *total_size) void spg_Serialize(Serializer& ser)
{ {
REICAST_S(in_vblank); ser << in_vblank;
REICAST_S(clc_pvr_scanline); ser << clc_pvr_scanline;
REICAST_S(maple_int_pending); ser << maple_int_pending;
REICAST_S(pvr_numscanlines); ser << pvr_numscanlines;
REICAST_S(prv_cur_scanline); ser << prv_cur_scanline;
REICAST_S(Line_Cycles); ser << Line_Cycles;
REICAST_S(Frame_Cycles); ser << Frame_Cycles;
REICAST_S(lightgun_line); ser << lightgun_line;
REICAST_S(lightgun_hpos); ser << lightgun_hpos;
} }
void spg_Deserialize(Deserializer& deser)
void spg_Unserialize(void **data, unsigned int *total_size, serialize_version_enum version)
{ {
REICAST_US(in_vblank); deser >> in_vblank;
REICAST_US(clc_pvr_scanline); deser >> clc_pvr_scanline;
if (version < V9_LIBRETRO) if (deser.version() < Deserializer::V9_LIBRETRO)
{ {
u32 i; deser >> pvr_numscanlines;
REICAST_US(pvr_numscanlines); deser >> prv_cur_scanline;
REICAST_US(prv_cur_scanline); deser >> vblk_cnt;
REICAST_US(vblk_cnt); deser >> Line_Cycles;
REICAST_US(Line_Cycles); deser >> Frame_Cycles;
REICAST_US(Frame_Cycles); deser.skip<double>(); // speed_load_mspdf
REICAST_SKIP(8); // speed_load_mspdf deser.skip<u32>(); // mips_counter
REICAST_US(i); // mips_counter deser.skip<double>(); // full_rps
REICAST_SKIP(8); // full_rps if (deser.version() <= Deserializer::V4)
if (version <= V4) deser.skip<u32>(); // fskip
REICAST_US(i); // fskip
} }
else if (version >= V12) else if (deser.version() >= Deserializer::V12)
{ {
REICAST_US(maple_int_pending); deser >> maple_int_pending;
if (version >= V14) if (deser.version() >= Deserializer::V14)
{ {
REICAST_US(pvr_numscanlines); deser >> pvr_numscanlines;
REICAST_US(prv_cur_scanline); deser >> prv_cur_scanline;
REICAST_US(Line_Cycles); deser >> Line_Cycles;
REICAST_US(Frame_Cycles); deser >> Frame_Cycles;
REICAST_US(lightgun_line); deser >> lightgun_line;
REICAST_US(lightgun_hpos); deser >> lightgun_hpos;
} }
} }
if (version < V14) if (deser.version() < Deserializer::V14)
CalculateSync(); CalculateSync();
else else
setFramebufferScaling(); setFramebufferScaling();

View File

@ -6,8 +6,8 @@ extern bool SH4FastEnough;
bool spg_Init(); bool spg_Init();
void spg_Term(); void spg_Term();
void spg_Reset(bool Manual); void spg_Reset(bool Manual);
void spg_Serialize(void **data, unsigned int *total_size); void spg_Serialize(Serializer& ser);
void spg_Unserialize(void **data, unsigned int *total_size, serialize_version_enum version); void spg_Deserialize(Deserializer& deser);
void CalculateSync(); void CalculateSync();
void read_lightgun_position(int x, int y); void read_lightgun_position(int x, int y);

View File

@ -2,6 +2,7 @@
#include "spg.h" #include "spg.h"
#include "cfg/option.h" #include "cfg/option.h"
#include "Renderer_if.h" #include "Renderer_if.h"
#include "serialize.h"
extern u32 fskip; extern u32 fskip;
extern u32 FrameCount; extern u32 FrameCount;
@ -207,36 +208,36 @@ void tactx_Term()
const u32 NULL_CONTEXT = ~0u; const u32 NULL_CONTEXT = ~0u;
static void serializeContext(void **data, unsigned int *total_size, const TA_context *ctx) static void serializeContext(Serializer& ser, const TA_context *ctx)
{ {
if (ser.dryrun())
{
// Maximum size: address, size, data, render pass count, render passes
ser.skip(4 + 4 + TA_DATA_SIZE + 4 + ARRAY_SIZE(tad_context::render_passes) * 4);
return;
}
if (ctx == nullptr) if (ctx == nullptr)
{ {
REICAST_S(NULL_CONTEXT); ser << NULL_CONTEXT;
return; return;
} }
REICAST_S(ctx->Address); ser << ctx->Address;
const tad_context& tad = ctx == ::ta_ctx ? ta_tad : ctx->tad; const tad_context& tad = ctx == ::ta_ctx ? ta_tad : ctx->tad;
const u32 taSize = tad.thd_data - tad.thd_root; const u32 taSize = tad.thd_data - tad.thd_root;
REICAST_S(taSize); ser << taSize;
if (*data == nullptr) ser.serialize(tad.thd_root, taSize);
{ ser << tad.render_pass_count;
// Maximum size
REICAST_SKIP(TA_DATA_SIZE + 4 + ARRAY_SIZE(tad.render_passes) * 4);
return;
}
REICAST_SA(tad.thd_root, taSize);
REICAST_S(tad.render_pass_count);
for (u32 i = 0; i < tad.render_pass_count; i++) for (u32 i = 0; i < tad.render_pass_count; i++)
{ {
u32 offset = (u32)(tad.render_passes[i] - tad.thd_root); u32 offset = (u32)(tad.render_passes[i] - tad.thd_root);
REICAST_S(offset); ser << offset;
} }
} }
static void deserializeContext(void **data, unsigned int *total_size, serialize_version_enum version, TA_context **pctx) static void deserializeContext(Deserializer& deser, TA_context **pctx)
{ {
u32 address; u32 address;
REICAST_US(address); deser >> address;
if (address == NULL_CONTEXT) if (address == NULL_CONTEXT)
{ {
*pctx = nullptr; *pctx = nullptr;
@ -244,17 +245,17 @@ static void deserializeContext(void **data, unsigned int *total_size, serialize_
} }
*pctx = tactx_Find(address, true); *pctx = tactx_Find(address, true);
u32 size; u32 size;
REICAST_US(size); deser >> size;
tad_context& tad = (*pctx)->tad; tad_context& tad = (*pctx)->tad;
REICAST_USA(tad.thd_root, size); deser.deserialize(tad.thd_root, size);
tad.thd_data = tad.thd_root + size; tad.thd_data = tad.thd_root + size;
if (version >= V12 || (version >= V12_LIBRETRO && version < V5)) if (deser.version() >= Deserializer::V12 || (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5))
{ {
REICAST_US(tad.render_pass_count); deser >> tad.render_pass_count;
for (u32 i = 0; i < tad.render_pass_count; i++) for (u32 i = 0; i < tad.render_pass_count; i++)
{ {
u32 offset; u32 offset;
REICAST_US(offset); deser >> offset;
tad.render_passes[i] = tad.thd_root + offset; tad.render_passes[i] = tad.thd_root + offset;
} }
} }
@ -264,23 +265,23 @@ static void deserializeContext(void **data, unsigned int *total_size, serialize_
} }
} }
void SerializeTAContext(void **data, unsigned int *total_size) void SerializeTAContext(Serializer& ser)
{ {
serializeContext(data, total_size, ta_ctx); serializeContext(ser, ta_ctx);
if (TA_CURRENT_CTX != CORE_CURRENT_CTX) if (TA_CURRENT_CTX != CORE_CURRENT_CTX)
serializeContext(data, total_size, tactx_Find(TA_CURRENT_CTX, false)); serializeContext(ser, tactx_Find(TA_CURRENT_CTX, false));
else else
serializeContext(data, total_size, nullptr); serializeContext(ser, nullptr);
}
void UnserializeTAContext(void **data, unsigned int *total_size, serialize_version_enum version) }
void DeserializeTAContext(Deserializer& deser)
{ {
if (::ta_ctx != nullptr) if (::ta_ctx != nullptr)
SetCurrentTARC(TACTX_NONE); SetCurrentTARC(TACTX_NONE);
TA_context *ta_cur_ctx; TA_context *ta_cur_ctx;
deserializeContext(data, total_size, version, &ta_cur_ctx); deserializeContext(deser, &ta_cur_ctx);
if (ta_cur_ctx != nullptr) if (ta_cur_ctx != nullptr)
SetCurrentTARC(ta_cur_ctx->Address); SetCurrentTARC(ta_cur_ctx->Address);
if (version >= V20) if (deser.version() >= Deserializer::V20)
deserializeContext(data, total_size, version, &ta_cur_ctx); deserializeContext(deser, &ta_cur_ctx);
} }

View File

@ -276,5 +276,5 @@ void FinishRender(TA_context* ctx);
void FillBGP(TA_context* ctx); void FillBGP(TA_context* ctx);
bool UsingAutoSort(int pass_number); bool UsingAutoSort(int pass_number);
bool rend_framePending(); bool rend_framePending();
void SerializeTAContext(void **data, unsigned int *total_size); void SerializeTAContext(Serializer& ser);
void UnserializeTAContext(void **data, unsigned int *total_size, serialize_version_enum version); void DeserializeTAContext(Deserializer& deser);

View File

@ -6,7 +6,7 @@
TLB_Entry UTLB[64]; TLB_Entry UTLB[64];
TLB_Entry ITLB[4]; TLB_Entry ITLB[4];
u32 ITLB_LRU_USE[64]; static u32 ITLB_LRU_USE[64];
//SQ fast remap , mainly hackish , assumes 1MB pages //SQ fast remap , mainly hackish , assumes 1MB pages
//max 64MB can be remapped on SQ //max 64MB can be remapped on SQ

View File

@ -22,6 +22,7 @@
#include "sh4_mem.h" #include "sh4_mem.h"
#include "modules/mmu.h" #include "modules/mmu.h"
#include "hw/sh4/sh4_core.h" #include "hw/sh4/sh4_core.h"
#include "serialize.h"
static bool cachedArea(u32 area) static bool cachedArea(u32 area)
{ {
@ -101,18 +102,11 @@ public:
memset(&lines[0], 0, sizeof(lines)); memset(&lines[0], 0, sizeof(lines));
} }
bool Serialize(void **data, unsigned int *total_size) void Serialize(Serializer& ser) {
{ ser << lines;
REICAST_S(lines);
return true;
} }
void Deserialize(Deserializer& deser) {
bool Unserialize(void **data, unsigned int *total_size) deser >> lines;
{
REICAST_US(lines);
return true;
} }
u32 ReadAddressArray(u32 addr) u32 ReadAddressArray(u32 addr)
@ -373,18 +367,11 @@ public:
memset(&lines[0], 0, sizeof(lines)); memset(&lines[0], 0, sizeof(lines));
} }
bool Serialize(void **data, unsigned int *total_size) void Serialize(Serializer& ser) {
{ ser << lines;
REICAST_S(lines);
return true;
} }
void Deserialize(Deserializer& deser) {
bool Unserialize(void **data, unsigned int *total_size) deser >> lines;
{
REICAST_US(lines);
return true;
} }
u32 ReadAddressArray(u32 addr) u32 ReadAddressArray(u32 addr)

View File

@ -272,15 +272,14 @@ static bool load_game_state(unsigned char *buffer, int len)
INFO_LOG(NETWORK, "load_game_state"); INFO_LOG(NETWORK, "load_game_state");
rend_start_rollback(); rend_start_rollback();
// FIXME will invalidate too much stuff: palette/fog textures, maple stuff
// FIXME dynarecs // FIXME dynarecs
int frame = *(u32 *)buffer; Deserializer deser(buffer, len, true);
unsigned usedLen = sizeof(u32); int frame;
buffer += usedLen; deser >> frame;
dc_unserialize((void **)&buffer, &usedLen, true); dc_deserialize(deser);
if (len != (int)usedLen) if (deser.size() != (u32)len)
{ {
ERROR_LOG(NETWORK, "load_game_state len %d used %d", len, usedLen); ERROR_LOG(NETWORK, "load_game_state len %d used %d", len, (int)deser.size());
die("fatal"); die("fatal");
} }
for (int f = lastSavedFrame - 1; f >= frame; f--) for (int f = lastSavedFrame - 1; f >= frame; f--)
@ -319,13 +318,11 @@ static bool save_game_state(unsigned char **buffer, int *len, int *checksum, int
*len = 0; *len = 0;
return false; return false;
} }
u8 *data = *buffer; Serializer ser(*buffer, allocSize, true);
*(u32 *)data = frame; ser << frame;
unsigned usedSize = sizeof(frame); dc_serialize(ser);
data += usedSize; verify(ser.size() < allocSize);
dc_serialize((void **)&data, &usedSize, true); *len = ser.size();
verify(usedSize < allocSize);
*len = usedSize;
#ifdef SYNC_TEST #ifdef SYNC_TEST
*checksum = XXH32(*buffer, usedSize, 7); *checksum = XXH32(*buffer, usedSize, 7);
#endif #endif

View File

@ -13,6 +13,7 @@
#include "input/gamepad_device.h" #include "input/gamepad_device.h"
#include "lua/lua.h" #include "lua/lua.h"
#include "stdclass.h" #include "stdclass.h"
#include "serialize.h"
int flycast_init(int argc, char* argv[]) int flycast_init(int argc, char* argv[])
{ {
@ -79,33 +80,19 @@ void flycast_term()
void dc_savestate(int index) void dc_savestate(int index)
{ {
unsigned int total_size = 0; Serializer ser;
void *data = nullptr; dc_serialize(ser);
if (!dc_serialize(&data, &total_size)) void *data = malloc(ser.size());
{
WARN_LOG(SAVESTATE, "Failed to save state - could not initialize total size") ;
gui_display_notification("Save state failed", 2000);
return;
}
data = malloc(total_size);
if (data == nullptr) if (data == nullptr)
{ {
WARN_LOG(SAVESTATE, "Failed to save state - could not malloc %d bytes", total_size); WARN_LOG(SAVESTATE, "Failed to save state - could not malloc %d bytes", (int)ser.size());
gui_display_notification("Save state failed - memory full", 2000); gui_display_notification("Save state failed - memory full", 2000);
return; return;
} }
void *data_ptr = data; ser = Serializer(data, ser.size());
total_size = 0; dc_serialize(ser);
if (!dc_serialize(&data_ptr, &total_size))
{
WARN_LOG(SAVESTATE, "Failed to save state - could not serialize data") ;
gui_display_notification("Save state failed", 2000);
free(data);
return;
}
std::string filename = hostfs::getSavestatePath(index, true); std::string filename = hostfs::getSavestatePath(index, true);
#if 0 #if 0
@ -119,7 +106,7 @@ void dc_savestate(int index)
return; return;
} }
std::fwrite(data, 1, total_size, f) ; std::fwrite(data, 1, ser.size(), f) ;
std::fclose(f); std::fclose(f);
#else #else
RZipFile zipFile; RZipFile zipFile;
@ -130,7 +117,7 @@ void dc_savestate(int index)
free(data); free(data);
return; return;
} }
if (zipFile.Write(data, total_size) != total_size) if (zipFile.Write(data, ser.size()) != ser.size())
{ {
WARN_LOG(SAVESTATE, "Failed to save state - error writing %s", filename.c_str()); WARN_LOG(SAVESTATE, "Failed to save state - error writing %s", filename.c_str());
gui_display_notification("Error saving state", 2000); gui_display_notification("Error saving state", 2000);
@ -142,7 +129,7 @@ void dc_savestate(int index)
#endif #endif
free(data); free(data);
INFO_LOG(SAVESTATE, "Saved state to %s size %d", filename.c_str(), total_size) ; INFO_LOG(SAVESTATE, "Saved state to %s size %d", filename.c_str(), (int)ser.size()) ;
gui_display_notification("State saved", 1000); gui_display_notification("State saved", 1000);
} }
@ -216,8 +203,14 @@ void dc_loadstate(int index)
return; return;
} }
const void *data_ptr = data; try {
dc_loadstate(&data_ptr, total_size); Deserializer deser(data, total_size);
dc_loadstate(deser);
if (deser.size() != total_size)
WARN_LOG(SAVESTATE, "Savestate size %d but only %d bytes used", total_size, (int)deser.size());
} catch (const Deserializer::Exception& e) {
ERROR_LOG(SAVESTATE, "%s", e.what());
}
free(data); free(data);
EventManager::event(Event::LoadState); EventManager::event(Event::LoadState);

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "serialize.h"
#define SYSCALL_GDROM 0x00 #define SYSCALL_GDROM 0x00
@ -44,6 +45,8 @@
#define MISC_INIT 0x00 #define MISC_INIT 0x00
#define MISC_SETVECTOR 0x01 #define MISC_SETVECTOR 0x01
void gdrom_hle_init();
void gdrom_hle_term();
void gdrom_hle_op(); void gdrom_hle_op();
typedef enum { BIOS_ERROR = -1, BIOS_INACTIVE, BIOS_ACTIVE, BIOS_COMPLETED, BIOS_DATA_AVAIL } gd_bios_status; typedef enum { BIOS_ERROR = -1, BIOS_INACTIVE, BIOS_ACTIVE, BIOS_COMPLETED, BIOS_DATA_AVAIL } gd_bios_status;
@ -67,45 +70,42 @@ struct gdrom_hle_state_t
bool dma_trans_ended = false; bool dma_trans_ended = false;
u64 xfer_end_time = 0; u64 xfer_end_time = 0;
bool Serialize(void **data, unsigned int *total_size) void Serialize(Serializer& ser)
{ {
REICAST_S(last_request_id); ser << last_request_id;
REICAST_S(next_request_id); ser << next_request_id;
REICAST_S(status); ser << status;
REICAST_S(command); ser << command;
REICAST_S(params); ser << params;
REICAST_S(result); ser << result;
REICAST_S(cur_sector); ser << cur_sector;
REICAST_S(multi_read_sector); ser << multi_read_sector;
REICAST_S(multi_read_offset); ser << multi_read_offset;
REICAST_S(multi_read_count); ser << multi_read_count;
REICAST_S(multi_read_total); ser << multi_read_total;
REICAST_S(multi_callback); ser << multi_callback;
REICAST_S(multi_callback_arg); ser << multi_callback_arg;
REICAST_S(dma_trans_ended); ser << dma_trans_ended;
REICAST_S(xfer_end_time); ser << xfer_end_time;
return true;
} }
bool Unserialize(void **data, unsigned int *total_size) void Deserialize(Deserializer& deser)
{ {
REICAST_US(last_request_id); deser >> last_request_id;
REICAST_US(next_request_id); deser >> next_request_id;
REICAST_US(status); deser >> status;
REICAST_US(command); deser >> command;
REICAST_US(params); deser >> params;
REICAST_US(result); deser >> result;
REICAST_US(cur_sector); deser >> cur_sector;
REICAST_US(multi_read_sector); deser >> multi_read_sector;
REICAST_US(multi_read_offset); deser >> multi_read_offset;
REICAST_US(multi_read_count); deser >> multi_read_count;
REICAST_US(multi_read_total); deser >> multi_read_total;
REICAST_US(multi_callback); deser >> multi_callback;
REICAST_US(multi_callback_arg); deser >> multi_callback_arg;
REICAST_US(dma_trans_ended); deser >> dma_trans_ended;
REICAST_US(xfer_end_time); deser >> xfer_end_time;
return true;
} }
}; };
extern gdrom_hle_state_t gd_hle_state; extern gdrom_hle_state_t gd_hle_state;

File diff suppressed because it is too large Load Diff

212
core/serialize.h Normal file
View File

@ -0,0 +1,212 @@
/*
Copyright 2021 flyinghead
This file is part of Flycast.
Flycast 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, either version 2 of the License, or
(at your option) any later version.
Flycast 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 for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
#include <limits>
class SerializeBase
{
public:
enum Version : int32_t {
V1,
V2,
V3,
V4,
V5_LIBRETRO,
V6_LIBRETRO,
V7_LIBRETRO,
V8_LIBRETRO,
V9_LIBRETRO,
V10_LIBRETRO,
V11_LIBRETRO,
V12_LIBRETRO,
V13_LIBRETRO,
VLAST_LIBRETRO = V13_LIBRETRO,
V5 = 800,
V6 = 801,
V7 = 802,
V8 = 803,
V9 = 804,
V10 = 805,
V11 = 806,
V12 = 807,
V13 = 808,
V14 = 809,
V15 = 810,
V16 = 811,
V17 = 812,
V18 = 813,
V19 = 814,
V20 = 815,
V21 = 816,
V22 = 817,
V23 = 818,
Current = V23,
Next = Current + 1,
};
size_t size() const { return _size; }
bool rollback() const { return _rollback; }
protected:
SerializeBase(size_t limit, bool rollback)
: _size(0), limit(limit), _rollback(rollback) {}
size_t _size;
size_t limit;
bool _rollback;
};
class Deserializer : public SerializeBase
{
public:
class Exception : public std::runtime_error
{
public:
Exception(const char *msg) : std::runtime_error(msg) {}
};
Deserializer(const void *data, size_t limit, bool rollback = false)
: SerializeBase(limit, rollback), data((const u8 *)data)
{
deserialize(_version);
if (_version > V13_LIBRETRO && _version < V5)
throw Exception("Unsupported version");
if (_version > Current)
throw Exception("Version too recent");
}
template<typename T>
void deserialize(T& obj)
{
doDeserialize(&obj, sizeof(T));
}
template<typename T>
void deserialize(T *obj, size_t count)
{
doDeserialize(obj, sizeof(T) * count);
}
template<typename T>
void skip(Version minVersion = Next)
{
skip(sizeof(T), minVersion);
}
void skip(size_t size, Version minVersion = Next)
{
if (_version >= minVersion)
return;
if (this->_size + size > limit)
{
WARN_LOG(SAVESTATE, "Savestate overflow: current %d limit %d sz %d", (int)this->_size, (int)limit, (int)size);
throw Exception("Invalid savestate");
}
data += size;
this->_size += size;
}
Version version() const { return _version; }
private:
void doDeserialize(void *dest, size_t size)
{
if (this->_size + size > limit) // FIXME one more test vs. current
{
WARN_LOG(SAVESTATE, "Savestate overflow: current %d limit %d sz %d", (int)this->_size, (int)limit, (int)size);
throw Exception("Invalid savestate");
}
memcpy(dest, data, size);
data += size;
this->_size += size;
}
Version _version;
const u8 *data;
};
class Serializer : public SerializeBase
{
public:
Serializer()
: SerializeBase(std::numeric_limits<size_t>::max(), false), data(nullptr) { }
Serializer(void *data, size_t limit, bool rollback = false)
: SerializeBase(limit, rollback), data((u8 *)data)
{
Version v = Current;
serialize(v);
}
template<typename T>
void serialize(const T& obj)
{
doSerialize(&obj, sizeof(T));
}
template<typename T>
void serialize(const T *obj, size_t count)
{
doSerialize(obj, sizeof(T) * count);
}
template<typename T>
void skip()
{
skip(sizeof(T));
}
void skip(size_t size)
{
verify(this->_size + size <= limit);
if (data != nullptr)
data += size;
this->_size += size;
}
bool dryrun() const { return data == nullptr; }
private:
void doSerialize(const void *src, size_t size)
{
verify(this->_size + size <= limit);
if (data != nullptr)
{
memcpy(data, src, size);
data += size;
}
this->_size += size;
}
u8 *data;
};
template<typename T>
Serializer& operator<<(Serializer& ctx, const T& obj) {
ctx.serialize(obj);
return ctx;
}
template<typename T>
Deserializer& operator>>(Deserializer& ctx, T& obj) {
ctx.deserialize(obj);
return ctx;
}
void dc_serialize(Serializer& ctx);
void dc_deserialize(Deserializer& ctx);

View File

@ -186,19 +186,6 @@ inline static void JITWriteProtect(bool enabled) {
void os_DebugBreak(); void os_DebugBreak();
#define dbgbreak os_DebugBreak() #define dbgbreak os_DebugBreak()
bool rc_serialize(const void *src, unsigned int src_size, void **dest, unsigned int *total_size) ;
bool rc_unserialize(void *src, unsigned int src_size, void **dest, unsigned int *total_size);
bool dc_serialize(void **data, unsigned int *total_size, bool rollback = false);
bool dc_unserialize(void **data, unsigned int *total_size, bool rollback = false);
#define REICAST_S(v) rc_serialize(&(v), sizeof(v), data, total_size)
#define REICAST_US(v) rc_unserialize(&(v), sizeof(v), data, total_size)
#define REICAST_SA(v_arr,num) rc_serialize((v_arr), sizeof((v_arr)[0])*(num), data, total_size)
#define REICAST_USA(v_arr,num) rc_unserialize((v_arr), sizeof((v_arr)[0])*(num), data, total_size)
#define REICAST_SKIP(size) do { if (*data) *(u8**)data += (size); *total_size += (size); } while (false)
#ifndef _MSC_VER #ifndef _MSC_VER
#define stricmp strcasecmp #define stricmp strcasecmp
#endif #endif
@ -400,11 +387,6 @@ inline bool is_u8(u32 v) { return (u8)v==(s32)v; }
inline bool is_s16(u32 v) { return (s16)v==(s32)v; } inline bool is_s16(u32 v) { return (s16)v==(s32)v; }
inline bool is_u16(u32 v) { return (u16)v==(u32)v; } inline bool is_u16(u32 v) { return (u16)v==(u32)v; }
//PVR
s32 libPvr_Init();
void libPvr_Reset(bool hard);
void libPvr_Term();
// 0x00600000 - 0x006007FF [NAOMI] (modem area for dreamcast) // 0x00600000 - 0x006007FF [NAOMI] (modem area for dreamcast)
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size); u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size);
void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size); void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size);
@ -481,38 +463,5 @@ public:
LoadCancelledException() : FlycastException("") {} LoadCancelledException() : FlycastException("") {}
}; };
enum serialize_version_enum { class Serializer;
V1, class Deserializer;
V2,
V3,
V4,
V5_LIBRETRO,
V6_LIBRETRO,
V7_LIBRETRO,
V8_LIBRETRO,
V9_LIBRETRO,
V10_LIBRETRO,
V11_LIBRETRO,
V12_LIBRETRO,
V13_LIBRETRO,
V5 = 800,
V6 = 801,
V7 = 802,
V8 = 803,
V9 = 804,
V10 = 805,
V11 = 806,
V12 = 807,
V13 = 808,
V14 = 809,
V15 = 810,
V16 = 811,
V17 = 812,
V18 = 813,
V19 = 814,
V20 = 815,
V21 = 816,
V22 = 817,
VCUR_FLYCAST = V22,
};

View File

@ -1739,14 +1739,11 @@ size_t retro_serialize_size()
emu.stop(); emu.stop();
unsigned int total_size = 0; Serializer ser;
void *data = nullptr; dc_serialize(ser);
dc_serialize(&data, &total_size);
emu.start(); emu.start();
return total_size; return ser.size();
} }
bool retro_serialize(void *data, size_t size) bool retro_serialize(void *data, size_t size)
@ -1756,12 +1753,11 @@ bool retro_serialize(void *data, size_t size)
emu.stop(); emu.stop();
unsigned int total_size = 0; Serializer ser(data, size);
bool result = dc_serialize(&data, &total_size); dc_serialize(ser);
emu.start(); emu.start();
return result; return true;
} }
bool retro_unserialize(const void * data, size_t size) bool retro_unserialize(const void * data, size_t size)
@ -1771,11 +1767,16 @@ bool retro_unserialize(const void * data, size_t size)
emu.stop(); emu.stop();
bool result = dc_loadstate(&data, size); try {
Deserializer deser(data, size);
dc_loadstate(deser);
emu.start();
emu.start(); return true;
} catch (const Deserializer::Exception& e) {
return result; ERROR_LOG(SAVESTATE, "Loading state failed: %s", e.what());
return false;
}
} }
// Cheats // Cheats

View File

@ -28,10 +28,10 @@ TEST_F(SerializeTest, SizeTest)
MapleExpansionDevices[1][1] = MDT_SegaVMU; MapleExpansionDevices[1][1] = MDT_SegaVMU;
mcfg_CreateDevices(); mcfg_CreateDevices();
unsigned int total_size = 0; std::vector<char> data(30000000);
void *data = nullptr; Serializer ser(data.data(), data.size());
ASSERT_TRUE(dc_serialize(&data, &total_size)); dc_serialize(ser);
ASSERT_EQ(28192092u, total_size); ASSERT_EQ(28191583u, ser.size());
} }