Files
parallel-dc/core/serialize.cpp
T
LibretroAdmin ad3ee3c7b1 naomi 2: the machine
A flat NAOMI image whose header says "Naomi2" is run as a NAOMI 2, with
the BIOS from naomi2.zip (or .7z). Until now every such image was taken
for a NAOMI 1, and the BIOS answered "this game is not acceptable by
main board" - which is what upstream flycast does with one as well.

What a NAOMI 2 has that a NAOMI does not:

  - The geometry processor of the last patch, in area 2: its registers
    at 08800000, its command port at 09000000, its 32 MB at 0a000000,
    and at 085f6800 and 085f8000 the holly's and the PowerVR's registers
    written to both PowerVRs at once (core/hw/pvr/elan_host.cpp). What
    it sends goes into the tile accelerator the way a store queue write
    does.

  - A second PowerVR. The two are one here, as in upstream: one set of
    registers, one video memory. What the second has of its own is its
    normal interrupt status, at 025f6900: the end of a list and the end
    of a render are raised in both, and the game clears each.

  - The second PowerVR's video memory is the mirror 32 MB above the
    first's, and games write every texture there too. The texture
    cache did not watch the mirror ("the mirrors don't seem to be
    used"), so a texture changed through it kept its old picture. On a
    NAOMI 2 it is watched.

  - Frames several times the size of anything a NAOMI sends: the tile
    accelerator's buffer and the lists a frame is parsed into are four
    times as big on a NAOMI 2, and a buffer kept from another machine
    is not reused.

Save states: version V20 adds, on a NAOMI 2 only, the second interrupt
status, the chip's state and memory, and the time its texture transfer
ends. Older states load as before.

"Is this a NAOMI" is asked in a dozen places: SYSTEM_IS_NAOMI() answers
for both.

Tested with a flat image of Virtua Fighter 4 and naomi2.7z, in the
RetroArch nightly of 7 October under Xvfb (Mesa llvmpipe):

  - The BIOS starts the game; the attract mode's temple scene and the
    demonstration fight are drawn - letterbox, coin text, the stage, the
    fighters and their shadows - by the OpenGL and the Vulkan renderer,
    per triangle and per pixel, and look alike in all four.
  - Against upstream flycast (which lights in vertex shaders), made to
    run the same image as a NAOMI 2 by a change of three lines: the same
    scenes, the same picture to the eye. The two do not reach a scene on
    the same frame, so they were not compared pixel by pixel.
  - What the chip sends the tile accelerator over 1500 frames is the
    same, byte for byte, from run to run.
  - Threaded rendering on and off: 138 pixels of a 1440x1080 frame
    differ, where two runs with the same setting differ in 54. Those
    are Mesa's: a texture with mirrored repeat comes out differently
    from run to run on llvmpipe, and identically with plain repeat.
  - A state saved, the game run 50 frames on, the state loaded and the
    game run on: 100 frames later its state differs from a straight
    run's in no more bytes than two straight runs differ from each
    other (about 900 of 92 MB).
  - tools/threads/headless.sh, the Dreamcast test disc: passes.

Not done here: the chip's memory is not in the recompiler's direct
mapping, so its accesses go by the handlers; NAOMI 2 games in MAME's
zip form are not in the game table; starting without a BIOS.
2026-10-08 03:50:06 +02:00

1299 lines
33 KiB
C++

// serialize.cpp : save states
#include "types.h"
#include "hw/aica/dsp.h"
#include "hw/aica/aica.h"
#include "hw/aica/sgc_if.h"
#include "hw/arm7/arm7.h"
#include "hw/holly/sb_mem.h"
#include "hw/flashrom/flashrom.h"
#include "hw/mem/_vmem.h"
#include "hw/gdrom/gdromv3.h"
#include "hw/maple/maple_devs.h"
#include "hw/maple/maple_cfg.h"
#include "hw/pvr/Renderer_if.h"
#include "hw/pvr/ta_structs.h"
#include "hw/sh4/sh4_interrupts.h"
#include "hw/sh4/sh4_sched.h"
#include "hw/sh4/sh4_mmr.h"
#include "hw/sh4/modules/mmu.h"
#include "imgread/common.h"
#include "reios/reios.h"
#include "reios/gdrom_hle.h"
#include <map>
#include <set>
#include "rend/gles/gles.h"
#include "hw/sh4/dyna/blockmanager.h"
#include "hw/sh4/dyna/ngen.h"
#include "hw/naomi/naomi.h"
#include "hw/naomi/naomi_cart.h"
#include "hw/sh4/sh4_cache.h"
#include "hw/bba/bba.h"
#define LIBRETRO_SKIP(size) do { if (*data) *(u8**)data += (size); *total_size += (size); } while (false)
/*
* search for "maybe" to find items that were left out that may be needed
*/
//./core/hw/arm7/arm_mem.cpp
extern bool aica_interr;
extern u32 aica_reg_L;
extern bool e68k_out;
extern u32 e68k_reg_L;
extern u32 e68k_reg_M;
//./core/hw/arm7/arm7.cpp
extern DECL_ALIGN(8) reg_pair arm_Reg[RN_ARM_REG_SLOTS];
extern bool armIrqEnable;
extern bool armFiqEnable;
extern int armMode;
extern bool Arm7Enabled;
//./core/hw/aica/dsp.o
extern DECL_ALIGN(4096) dsp_t dsp;
//./core/hw/aica/aica.o
extern AicaTimer timers[3];
//./core/hw/aica/aica_if.o
extern VArray2 aica_ram;
extern u32 VREG;//video reg =P
extern u32 ARMRST;//arm reset reg
extern u32 rtc_EN;
extern u32 RealTimeClock;
extern int dma_sched_id;
//./core/hw/aica/aica_mem.o
extern u8 aica_reg[0x8000];
//./core/hw/aica/sgc_if.o
struct ChannelEx;
#define AicaChannel ChannelEx
//special handling
//extern AicaChannel AicaChannel::Chans[64];
#define Chans AicaChannel::Chans
#define CDDA_SIZE (2352/2)
extern s16 cdda_sector[CDDA_SIZE];
extern u32 cdda_index;
//./core/hw/holly/sb.o
extern Array<RegisterStruct> sb_regs;
extern u32 SB_ISTNRM;
extern u32 SB_FFST_rc;
extern u32 SB_FFST;
//./core/hw/holly/sb_mem.o
extern SRamChip sys_nvmem_sram;
extern DCFlashChip sys_nvmem_flash;
//./core/hw/pvr/elan_host.o
#include "hw/pvr/elan.h"
#include "hw/pvr/elan_host.h"
#include "hw/holly/holly_intc.h"
//./core/hw/gdrom/gdromv3.o
extern int gdrom_sched;
extern int gd_swap_schid;
extern signed int sns_asc;
extern signed int sns_ascq;
extern signed int sns_key;
extern packet_cmd_t packet_cmd;
extern u32 set_mode_offset;
extern read_params_t read_params ;
extern packet_cmd_t packet_cmd;
//Buffer for sector reads [dma]
extern read_buff_t read_buff ;
//pio buffer
extern pio_buff_t pio_buff ;
extern u32 set_mode_offset;
extern ata_cmd_t ata_cmd ;
extern cdda_t cdda ;
extern gd_states gd_state;
extern DiscType gd_disk_type;
extern u32 data_write_mode;
//Registers
extern u32 DriveSel;
extern GD_ErrRegT Error;
extern GD_InterruptReasonT IntReason;
extern GD_FeaturesT Features;
extern GD_SecCountT SecCount;
extern GD_SecNumbT SecNumber;
extern GD_StatusT GDStatus;
extern ByteCount_t ByteCount ;
extern int GDROM_TICK;
//./core/hw/maple/maple_devs.o
extern char EEPROM[0x100];
extern bool EEPROM_loaded;
//./core/hw/maple/maple_if.o
//needs special handler
extern maple_device* MapleDevices[4][6];
extern int maple_sched;
#include "hw/maple/maple_if.h"
extern bool maple_ddt_pending_reset;
#ifdef ENABLE_MODEM
//./core/hw/modem/modem.cpp
extern int modem_sched;
#endif
//./core/hw/pvr/Renderer_if.o
extern bool pend_rend;
extern u32 fb_w_cur;
//./core/hw/pvr/pvr_mem.o
extern u32 YUV_tempdata[512/4];//512 bytes
extern u32 YUV_dest;
extern u32 YUV_blockcount;
extern u32 YUV_x_curr;
extern u32 YUV_y_curr;
extern u32 YUV_x_size;
extern u32 YUV_y_size;
//./core/hw/pvr/pvr_regs.o
extern u8 pvr_regs[pvr_RegSize];
//./core/hw/pvr/spg.o
extern u32 in_vblank;
extern u32 clc_pvr_scanline;
extern u32 pvr_cur_scanline;
extern int render_end_schid;
extern int vblank_schid;
//./core/hw/pvr/ta.o
extern u8 ta_fsm[2049]; //[2048] stores the current state
extern u32 ta_fsm_cl;
//./core/hw/pvr/ta_vtx.o
//./core/rend/TexCache.o
extern VArray2 vram;
//./core/hw/sh4/sh4_mmr.o
extern Array<u8> OnChipRAM;
extern Array<RegisterStruct> CCN; //CCN : 14 registers
extern Array<RegisterStruct> UBC; //UBC : 9 registers
extern Array<RegisterStruct> BSC; //BSC : 18 registers
extern Array<RegisterStruct> DMAC; //DMAC : 17 registers
extern Array<RegisterStruct> CPG; //CPG : 5 registers
extern Array<RegisterStruct> RTC; //RTC : 16 registers
extern Array<RegisterStruct> INTC; //INTC : 4 registers
extern Array<RegisterStruct> TMU; //TMU : 12 registers
extern Array<RegisterStruct> SCI; //SCI : 8 registers
extern Array<RegisterStruct> SCIF; //SCIF : 10 registers
//./core/hw/sh4/sh4_mem.o
extern VArray2 mem_b;
//./core/hw/sh4/sh4_interrupts.o
extern DECL_ALIGN(64) u16 InterruptEnvId[32];
extern DECL_ALIGN(64) u32 InterruptBit[32];
extern DECL_ALIGN(64) u32 InterruptLevelBit[16];
extern u32 interrupt_vpend; // Vector of pending interrupts
extern u32 interrupt_vmask; // Vector of masked interrupts (-1 inhibits all interrupts)
extern u32 decoded_srimask; // Vector of interrupts allowed by SR.IMSK (-1 inhibits all interrupts)
//./core/hw/sh4/sh4_core_regs.o
extern Sh4RCB* p_sh4rcb;
//./core/hw/sh4/sh4_sched.o
extern u64 sh4_sched_ffb;
extern std::vector<sched_list> sch_list;
//./core/hw/sh4/interpr/sh4_interpreter.o
extern int aica_schid;
extern int rtc_schid;
//./core/hw/sh4/modules/serial.o
extern SCIF_SCFSR2_type SCIF_SCFSR2;
extern SCIF_SCSCR2_type SCIF_SCSCR2;
//./core/hw/sh4/modules/bsc.o
extern BSC_PDTRA_type BSC_PDTRA;
//./core/hw/sh4/modules/tmu.o
extern u32 tmu_shift[3];
extern u32 tmu_mask[3];
extern u64 tmu_mask64[3];
extern u32 old_mode[3];
extern int tmu_sched[3];
extern u32 tmu_ch_base[3];
extern u64 tmu_ch_base64[3];
//./core/hw/sh4/modules/ccn.o
extern u32 CCN_QACR_TR[2];
//./core/hw/sh4/modules/mmu.o
extern u32 ITLB_LRU_USE[64];
//./core/imgread/common.o
extern u32 NullDriveDiscType;
extern u8 q_subchannel[96];
//./core/nullDC.o
extern unsigned FLASH_SIZE;
extern unsigned BBSRAM_SIZE;
extern unsigned BIOS_SIZE;
extern unsigned RAM_SIZE;
extern unsigned ARAM_SIZE;
extern unsigned VRAM_SIZE;
extern unsigned RAM_MASK;
extern unsigned ARAM_MASK;
extern unsigned VRAM_MASK;
//./core/hw/naomi/naomi.o
extern u32 GSerialBuffer;
extern u32 BSerialBuffer;
extern int GBufPos;
extern int BBufPos;
extern int GState;
extern int BState;
extern int GOldClk;
extern int BOldClk;
extern int BControl;
extern int BCmd;
extern int BLastCmd;
extern int GControl;
extern int GCmd;
extern int GLastCmd;
extern int SerStep;
extern int SerStep2;
extern unsigned char BSerial[];
extern unsigned char GSerial[];
/*
* Deserialization input-buffer bounds tracking.
*
* The libretro frontend hands retro_unserialize() a buffer and its length.
* Historically that length was only used to disambiguate two legacy save-state
* versions and never to bound the reads, so a truncated or malformed state
* (netplay peer, runahead, on-disk corruption) walked memcpy() straight off the
* end of the input buffer. dc_unserialize() now publishes the input base and
* length here; ra_unserialize() refuses to read past the end and latches a
* failure that propagates to the retro_unserialize() return value.
*/
static const u8 *unserialize_base = NULL;
static size_t unserialize_limit = 0;
static bool unserialize_failed = false;
void ra_unserialize_init(const void *base, size_t limit)
{
unserialize_base = (const u8 *)base;
unserialize_limit = limit;
unserialize_failed = false;
}
bool ra_unserialize_failed(void)
{
return unserialize_failed;
}
bool ra_serialize(const void *src, unsigned int src_size, void **dest, unsigned int *total_size)
{
if ( *dest != NULL )
{
memcpy(*dest, src, src_size) ;
*dest = ((unsigned char*)*dest) + src_size ;
}
*total_size += src_size ;
return true ;
}
bool ra_unserialize(void *src, unsigned int src_size, void **dest, unsigned int *total_size)
{
if ( *dest != NULL )
{
/* Reject any read that would run past the end of the frontend-supplied
* input buffer. base==NULL means the limit is unknown (legacy callers);
* fall back to the original unchecked behavior in that case only. */
if (unserialize_base != NULL)
{
size_t offset = (size_t)((const u8 *)*dest - unserialize_base);
if (offset > unserialize_limit || src_size > unserialize_limit - offset)
{
unserialize_failed = true;
/* Leave the destination zero-initialized rather than reading
* out of bounds, and stop consuming input. */
memset(src, 0, src_size);
*total_size += src_size ;
return false ;
}
}
memcpy(src, *dest, src_size) ;
*dest = ((unsigned char*)*dest) + src_size ;
}
*total_size += src_size ;
return true ;
}
bool register_serialize(Array<RegisterStruct>& regs,void **data, unsigned int *total_size )
{
int i = 0 ;
for ( i = 0 ; i < regs.Size ; i++ )
{
/* A register that is read through a function keeps the function's
* address where the others keep their value. That is not state:
* register_unserialize() reads it into a dummy. Writing its low
* half out all the same put a host address, different in every
* process, into the state for each such register; write zero. */
u32 value = (regs.data[i].flags & REG_RF) ? 0 : regs.data[i].data32 ;
LIBRETRO_S(regs.data[i].flags) ;
LIBRETRO_S(value) ;
}
return true ;
}
bool register_unserialize(Array<RegisterStruct>& regs,void **data, unsigned int *total_size, u32 force_size = 0)
{
int i = 0 ;
u32 dummy = 0 ;
if (force_size == 0)
force_size = regs.Size;
for ( i = 0 ; i < force_size ; i++ )
{
LIBRETRO_US(regs.data[i].flags) ;
if ( ! (regs.data[i].flags & REG_RF) )
LIBRETRO_US(regs.data[i].data32) ;
else
LIBRETRO_US(dummy) ;
}
return true ;
}
bool dc_serialize(void **data, unsigned int *total_size)
{
int i = 0;
int j = 0;
serialize_version_enum version = VCUR_LIBRETRO;
*total_size = 0 ;
//dc not initialized yet
if ( p_sh4rcb == NULL )
return false ;
LIBRETRO_S(version) ;
LIBRETRO_S(aica_interr) ;
LIBRETRO_S(aica_reg_L) ;
LIBRETRO_S(e68k_out) ;
LIBRETRO_S(e68k_reg_L) ;
LIBRETRO_S(e68k_reg_M) ;
LIBRETRO_SA(arm_Reg,RN_ARM_REG_COUNT);
LIBRETRO_S(armIrqEnable);
LIBRETRO_S(armFiqEnable);
LIBRETRO_S(armMode);
LIBRETRO_S(Arm7Enabled);
LIBRETRO_S(dsp);
for ( i = 0 ; i < 3 ; i++)
{
LIBRETRO_S(timers[i].c_step);
LIBRETRO_S(timers[i].m_step);
}
LIBRETRO_SA(aica_ram.data,aica_ram.size) ;
LIBRETRO_S(VREG);
LIBRETRO_S(ARMRST);
LIBRETRO_S(rtc_EN);
LIBRETRO_SA(aica_reg,0x8000);
channel_serialize(data, total_size) ;
libCore_CDDA_Detach();
LIBRETRO_SA(cdda_sector,CDDA_SIZE);
LIBRETRO_S(cdda_index);
register_serialize(sb_regs, data, total_size) ;
LIBRETRO_S(SB_ISTNRM);
LIBRETRO_S(SB_FFST_rc);
LIBRETRO_S(SB_FFST);
LIBRETRO_S(sys_nvmem_sram.size);
LIBRETRO_S(sys_nvmem_sram.mask);
LIBRETRO_SA(sys_nvmem_sram.data,sys_nvmem_sram.size);
LIBRETRO_S(sys_nvmem_flash.size);
LIBRETRO_S(sys_nvmem_flash.mask);
LIBRETRO_S(sys_nvmem_flash.state);
LIBRETRO_SA(sys_nvmem_flash.data,sys_nvmem_flash.size);
LIBRETRO_S(GD_HardwareInfo) ;
LIBRETRO_S(sns_asc);
LIBRETRO_S(sns_ascq);
LIBRETRO_S(sns_key);
LIBRETRO_S(packet_cmd);
LIBRETRO_S(set_mode_offset);
LIBRETRO_S(read_params);
LIBRETRO_S(packet_cmd);
LIBRETRO_S(pio_buff);
LIBRETRO_S(set_mode_offset);
LIBRETRO_S(ata_cmd);
LIBRETRO_S(cdda);
LIBRETRO_S(gd_state);
LIBRETRO_S(gd_disk_type);
LIBRETRO_S(data_write_mode);
LIBRETRO_S(DriveSel);
LIBRETRO_S(Error);
LIBRETRO_S(IntReason);
LIBRETRO_S(Features);
LIBRETRO_S(SecCount);
LIBRETRO_S(SecNumber);
LIBRETRO_S(GDStatus);
LIBRETRO_S(ByteCount);
LIBRETRO_S(GDROM_TICK);
LIBRETRO_SA(EEPROM,0x100);
LIBRETRO_S(EEPROM_loaded);
LIBRETRO_S(maple_ddt_pending_reset);
mcfg_SerializeDevices(data, total_size);
LIBRETRO_SA(YUV_tempdata,512/4);
LIBRETRO_S(YUV_dest);
LIBRETRO_S(YUV_blockcount);
LIBRETRO_S(YUV_x_curr);
LIBRETRO_S(YUV_y_curr);
LIBRETRO_S(YUV_x_size);
LIBRETRO_S(YUV_y_size);
LIBRETRO_SA(pvr_regs,pvr_RegSize);
LIBRETRO_S(in_vblank);
LIBRETRO_S(clc_pvr_scanline);
LIBRETRO_S(pvr_cur_scanline);
LIBRETRO_S(fb_w_cur);
LIBRETRO_S(ta_fsm[2048]);
LIBRETRO_S(ta_fsm_cl);
SerializeTAContext(data, total_size);
LIBRETRO_SA(vram.data, vram.size);
LIBRETRO_SA(OnChipRAM.data,OnChipRAM_SIZE);
register_serialize(CCN, data, total_size) ;
register_serialize(UBC, data, total_size) ;
register_serialize(BSC, data, total_size) ;
register_serialize(DMAC, data, total_size) ;
register_serialize(CPG, data, total_size) ;
register_serialize(RTC, data, total_size) ;
register_serialize(INTC, data, total_size) ;
register_serialize(TMU, data, total_size) ;
register_serialize(SCI, data, total_size) ;
register_serialize(SCIF, data, total_size) ;
icache.Serialize(data, total_size);
ocache.Serialize(data, total_size);
LIBRETRO_SA(mem_b.data, mem_b.size);
LIBRETRO_SA(InterruptEnvId,32);
LIBRETRO_SA(InterruptBit,32);
LIBRETRO_SA(InterruptLevelBit,16);
LIBRETRO_S(interrupt_vpend);
LIBRETRO_S(interrupt_vmask);
LIBRETRO_S(decoded_srimask);
//default to nommu_full
i = 3 ;
if ( do_sqw_nommu == &do_sqw_nommu_area_3)
i = 0 ;
else if (do_sqw_nommu == &do_sqw_nommu_area_3_nonvmem)
i = 1 ;
else if (do_sqw_nommu==(sqw_fp*)&TAWriteSQ)
i = 2 ;
else if (do_sqw_nommu==&do_sqw_nommu_full)
i = 3 ;
LIBRETRO_S(i) ;
LIBRETRO_SA((*p_sh4rcb).sq_buffer,64/8);
//store these before unserializing and then restore after
//void *getptr = &((*p_sh4rcb).cntx.sr.GetFull) ;
//void *setptr = &((*p_sh4rcb).cntx.sr.SetFull) ;
LIBRETRO_S((*p_sh4rcb).cntx);
LIBRETRO_S(sh4_sched_ffb);
LIBRETRO_S(sch_list[aica_schid].tag) ;
LIBRETRO_S(sch_list[aica_schid].start) ;
LIBRETRO_S(sch_list[aica_schid].end) ;
LIBRETRO_S(sch_list[rtc_schid].tag) ;
LIBRETRO_S(sch_list[rtc_schid].start) ;
LIBRETRO_S(sch_list[rtc_schid].end) ;
LIBRETRO_S(sch_list[gdrom_sched].tag) ;
LIBRETRO_S(sch_list[gdrom_sched].start) ;
LIBRETRO_S(sch_list[gdrom_sched].end) ;
LIBRETRO_S(sch_list[maple_sched].tag) ;
LIBRETRO_S(sch_list[maple_sched].start) ;
LIBRETRO_S(sch_list[maple_sched].end) ;
LIBRETRO_S(sch_list[dma_sched_id].tag) ;
LIBRETRO_S(sch_list[dma_sched_id].start) ;
LIBRETRO_S(sch_list[dma_sched_id].end) ;
for (int i = 0; i < 3; i++)
{
LIBRETRO_S(sch_list[tmu_sched[i]].tag) ;
LIBRETRO_S(sch_list[tmu_sched[i]].start) ;
LIBRETRO_S(sch_list[tmu_sched[i]].end) ;
}
LIBRETRO_S(sch_list[render_end_schid].tag) ;
LIBRETRO_S(sch_list[render_end_schid].start) ;
LIBRETRO_S(sch_list[render_end_schid].end) ;
LIBRETRO_S(sch_list[vblank_schid].tag) ;
LIBRETRO_S(sch_list[vblank_schid].start) ;
LIBRETRO_S(sch_list[vblank_schid].end) ;
LIBRETRO_S(settings.network.EmulateBBA);
#ifdef ENABLE_MODEM
if (settings.network.EmulateBBA)
{
bba_Serialize(data, total_size);
}
else
{
LIBRETRO_S(sch_list[modem_sched].tag) ;
LIBRETRO_S(sch_list[modem_sched].start) ;
LIBRETRO_S(sch_list[modem_sched].end) ;
}
#else
LIBRETRO_S(i);
LIBRETRO_S(i);
LIBRETRO_S(i);
#endif
LIBRETRO_S(SCIF_SCFSR2);
LIBRETRO_S(SCIF_SCSCR2);
LIBRETRO_S(BSC_PDTRA);
LIBRETRO_SA(tmu_shift,3);
LIBRETRO_SA(tmu_mask,3);
LIBRETRO_SA(tmu_mask64,3);
LIBRETRO_SA(old_mode,3);
LIBRETRO_SA(tmu_ch_base,3);
LIBRETRO_SA(tmu_ch_base64,3);
LIBRETRO_SA(CCN_QACR_TR,2);
LIBRETRO_S(UTLB);
LIBRETRO_S(ITLB);
LIBRETRO_S(sq_remap);
LIBRETRO_S(ITLB_LRU_USE);
LIBRETRO_S(NullDriveDiscType);
LIBRETRO_SA(q_subchannel,96);
LIBRETRO_S(FLASH_SIZE);
LIBRETRO_S(BBSRAM_SIZE);
LIBRETRO_S(BIOS_SIZE);
LIBRETRO_S(RAM_SIZE);
LIBRETRO_S(ARAM_SIZE);
LIBRETRO_S(VRAM_SIZE);
LIBRETRO_S(RAM_MASK);
LIBRETRO_S(ARAM_MASK);
LIBRETRO_S(VRAM_MASK);
LIBRETRO_S(GSerialBuffer);
LIBRETRO_S(BSerialBuffer);
LIBRETRO_S(GBufPos);
LIBRETRO_S(BBufPos);
LIBRETRO_S(GState);
LIBRETRO_S(BState);
LIBRETRO_S(GOldClk);
LIBRETRO_S(BOldClk);
LIBRETRO_S(BControl);
LIBRETRO_S(BCmd);
LIBRETRO_S(BLastCmd);
LIBRETRO_S(GControl);
LIBRETRO_S(GCmd);
LIBRETRO_S(GLastCmd);
LIBRETRO_S(SerStep);
LIBRETRO_S(SerStep2);
LIBRETRO_SA(BSerial,69);
LIBRETRO_SA(GSerial,69);
LIBRETRO_S(reg_dimm_command);
LIBRETRO_S(reg_dimm_offsetl);
LIBRETRO_S(reg_dimm_parameterl);
LIBRETRO_S(reg_dimm_parameterh);
LIBRETRO_S(reg_dimm_status);
LIBRETRO_SKIP(1); // NaomiDataRead
LIBRETRO_S(settings.dreamcast.broadcast);
LIBRETRO_S(settings.dreamcast.cable);
LIBRETRO_S(settings.dreamcast.region);
if (CurrentCartridge != NULL)
CurrentCartridge->Serialize(data, total_size);
gd_hle_state.Serialize(data, total_size);
settings.network.EmulateBBA = false;
/* V14: the AICA RTC. Its per-second increment is already deterministic
* (driven by the SH4 scheduler), but the initial value is seeded from the
* host clock and was never serialized, so netplay peers and runahead
* rollbacks diverged whenever a game read the clock. Carry it in the state
* so it is synced along with everything else. */
LIBRETRO_S(RealTimeClock);
/* V18: the answers of a Maple transfer that is under way, which are not
* in the game's memory until it is over. */
LIBRETRO_S(maple_out_used);
LIBRETRO_SA(maple_out, MAPLE_OUT_WORDS);
/* V19: the drive still looking at a disc that has just been put in */
LIBRETRO_S(sch_list[gd_swap_schid].start);
LIBRETRO_S(sch_list[gd_swap_schid].end);
/* V20: what a NAOMI 2 has that a NAOMI does not - the second PowerVR's
* interrupts, and the geometry processor with its memory. */
if (settings.System == DC_PLATFORM_NAOMI2 && elan_ram)
{
elan_state_t elan;
elan_get_state(&elan);
LIBRETRO_S(SB_ISTNRM1);
LIBRETRO_S(elan);
LIBRETRO_SA(elan_ram, ELAN_RAM_SIZE);
LIBRETRO_S(sch_list[elan_schid].start);
LIBRETRO_S(sch_list[elan_schid].end);
}
return true ;
}
bool dc_unserialize(void **data, unsigned int *total_size, size_t actual_data_size)
{
int i = 0;
int j = 0;
u8 dummy ;
int dummy_int ;
serialize_version_enum version = V1 ;
*total_size = 0 ;
/* Publish the input buffer bounds so ra_unserialize() can reject reads
* past the end of a truncated or malformed state. *data points at the
* start of the frontend-supplied buffer on entry. */
ra_unserialize_init(*data, actual_data_size);
LIBRETRO_US(version) ;
//This normally isn't necessary - but we need some way to differentiate between save states
//that were created after the format change and before the new format had a new version saved in it
if (version == V1 && actual_data_size != 48324799 && actual_data_size != 48855967)
version = V2 ;
LIBRETRO_US(aica_interr) ;
LIBRETRO_US(aica_reg_L) ;
LIBRETRO_US(e68k_out) ;
LIBRETRO_US(e68k_reg_L) ;
LIBRETRO_US(e68k_reg_M) ;
LIBRETRO_USA(arm_Reg,RN_ARM_REG_COUNT);
LIBRETRO_US(armIrqEnable);
LIBRETRO_US(armFiqEnable);
LIBRETRO_US(armMode);
LIBRETRO_US(Arm7Enabled);
if (version < V9)
{
LIBRETRO_SKIP(256); // cpuBitsSet
LIBRETRO_SKIP(1); // intState
LIBRETRO_SKIP(1); // stopState
LIBRETRO_SKIP(1); // holdState
}
LIBRETRO_US(dsp);
for ( i = 0 ; i < 3 ; i++)
{
LIBRETRO_US(timers[i].c_step);
LIBRETRO_US(timers[i].m_step);
}
LIBRETRO_USA(aica_ram.data,aica_ram.size) ;
LIBRETRO_US(VREG);
LIBRETRO_US(ARMRST);
LIBRETRO_US(rtc_EN);
if (version < V3)
LIBRETRO_US(dummy_int); //dma_sched_id
LIBRETRO_USA(aica_reg,0x8000);
if (version < V7)
{
LIBRETRO_SKIP(4 * 16); // volume_lut
LIBRETRO_SKIP(4 * 256 + 768); // tl_lut. Due to a previous bug this is not 4 * (256 + 768)
LIBRETRO_SKIP(4 * 64); // AEG_ATT_SPS
LIBRETRO_SKIP(4 * 64); // AEG_DSR_SPS
LIBRETRO_SKIP(2); // pl
LIBRETRO_SKIP(2); // pr
}
channel_unserialize(data, total_size, version);
libCore_CDDA_Detach();
LIBRETRO_USA(cdda_sector,CDDA_SIZE);
LIBRETRO_US(cdda_index);
if (version < V9)
{
LIBRETRO_SKIP(4 * 64); // mxlr
LIBRETRO_SKIP(4); // samples_gen
}
register_unserialize(sb_regs, data, total_size) ;
LIBRETRO_US(SB_ISTNRM);
LIBRETRO_US(SB_FFST_rc);
LIBRETRO_US(SB_FFST);
/* size/mask describe the live, already-allocated nvmem buffers. Read the
* stored values into temporaries and only copy up to the real allocation,
* so a corrupt state whose size exceeds the buffer can't overflow data[]
* (and can't clobber the live size/mask either). */
{
u32 stored_size, stored_mask;
LIBRETRO_US(stored_size);
LIBRETRO_US(stored_mask);
u32 copy = stored_size < sys_nvmem_sram.size ? stored_size : sys_nvmem_sram.size;
LIBRETRO_USA(sys_nvmem_sram.data, copy);
if (stored_size > copy)
LIBRETRO_SKIP(stored_size - copy);
}
{
u32 stored_size, stored_mask;
LIBRETRO_US(stored_size);
LIBRETRO_US(stored_mask);
LIBRETRO_US(sys_nvmem_flash.state);
u32 copy = stored_size < sys_nvmem_flash.size ? stored_size : sys_nvmem_flash.size;
LIBRETRO_USA(sys_nvmem_flash.data, copy);
if (stored_size > copy)
LIBRETRO_SKIP(stored_size - copy);
}
LIBRETRO_US(GD_HardwareInfo) ;
if (version < V3)
LIBRETRO_US(dummy_int); //gdrom_sched
LIBRETRO_US(sns_asc);
LIBRETRO_US(sns_ascq);
LIBRETRO_US(sns_key);
LIBRETRO_US(packet_cmd);
LIBRETRO_US(set_mode_offset);
LIBRETRO_US(read_params);
LIBRETRO_US(packet_cmd);
// read_buff
read_buff.cache_size = 0;
if (version < V9)
LIBRETRO_SKIP(4 + 4 + 2352 * 8192);
LIBRETRO_US(pio_buff);
LIBRETRO_US(set_mode_offset);
LIBRETRO_US(ata_cmd);
LIBRETRO_US(cdda);
/* The status used to be a flag, playing or not, with whatever followed
* it in its word: a state from then has something here that is none of
* the four states, and is read as the flag. This was done to every
* state, and made a drive that was paused, or had played to the end,
* play. */
if ((u32)cdda.status > (u32)cdda_t::Terminated)
cdda.status = ((u32)cdda.status & 0xFF) ? cdda_t::Playing : cdda_t::NoInfo;
LIBRETRO_US(gd_state);
LIBRETRO_US(gd_disk_type);
LIBRETRO_US(data_write_mode);
LIBRETRO_US(DriveSel);
LIBRETRO_US(Error);
LIBRETRO_US(IntReason);
LIBRETRO_US(Features);
LIBRETRO_US(SecCount);
LIBRETRO_US(SecNumber);
LIBRETRO_US(GDStatus);
LIBRETRO_US(ByteCount);
LIBRETRO_US(GDROM_TICK);
LIBRETRO_USA(EEPROM,0x100);
LIBRETRO_US(EEPROM_loaded);
if ( version == V1 )
{
//V1 saved NaomiState which was a struct of 3 u8 variables
LIBRETRO_US(dummy);
LIBRETRO_US(dummy);
LIBRETRO_US(dummy);
}
LIBRETRO_US(maple_ddt_pending_reset);
if ( version == V1 )
{
for (i = 0 ; i < 4 ; i++)
for (j = 0 ; j < 6 ; j++)
if ( MapleDevices[i][j] != 0 )
{
MapleDeviceType devtype = MapleDevices[i][j]->get_device_type() ;
mcfg_DestroyDevice(i,j) ;
mcfg_Create(devtype, i, j);
MapleDevices[i][j]->maple_unserialize(data, total_size) ;
}
}
else
mcfg_UnserializeDevices(data, total_size);
if (version < V9)
{
LIBRETRO_SKIP(4); // FrameCOunt
LIBRETRO_SKIP(1); // pend_rend
}
pend_rend = false;
LIBRETRO_USA(YUV_tempdata,512/4);
LIBRETRO_US(YUV_dest);
LIBRETRO_US(YUV_blockcount);
LIBRETRO_US(YUV_x_curr);
LIBRETRO_US(YUV_y_curr);
LIBRETRO_US(YUV_x_size);
LIBRETRO_US(YUV_y_size);
if (version < V9)
LIBRETRO_SKIP(1); // fog_needs_update
LIBRETRO_USA(pvr_regs,pvr_RegSize);
LIBRETRO_US(in_vblank);
LIBRETRO_US(clc_pvr_scanline);
/* pvr_cur_scanline: current raster line. Not saved before V15, where the
* post-load CalculateSync() reset it to 0; keep that behaviour for old
* states so their (approximate) load path is unchanged. */
if (version >= V15)
LIBRETRO_US(pvr_cur_scanline);
else
pvr_cur_scanline = 0;
fb_w_cur = 1;
if (version < V9)
{
LIBRETRO_US(i); // pvr_numscanlines
LIBRETRO_US(i); // prv_cur_scanline
LIBRETRO_US(i); // vblk_cnt
LIBRETRO_US(i); // Line_Cycles
LIBRETRO_US(i); // Frame_Cycles
if (version < V3)
{
LIBRETRO_US(dummy_int); //render_end_schid
LIBRETRO_US(dummy_int); //vblank_schid
LIBRETRO_US(dummy_int); //time_sync
}
LIBRETRO_SKIP(8); // speed_load_mspdf
LIBRETRO_US(dummy_int); // mips_counter
LIBRETRO_SKIP(8); // full_rps
LIBRETRO_SKIP(4 * 256); // ta_type_lut
LIBRETRO_SKIP(2048); // ta_fsm
}
if (version >= V12)
LIBRETRO_US(fb_w_cur);
else
fb_w_cur = 1;
LIBRETRO_US(ta_fsm[2048]);
LIBRETRO_US(ta_fsm_cl);
if (version < V9)
{
LIBRETRO_SKIP(1); // pal_needs_update
LIBRETRO_SKIP(4 * 4); // _pal_rev_256
LIBRETRO_SKIP(4 * 64); // _pal_rev_16
LIBRETRO_SKIP(4 * 4); // pal_rev_256
LIBRETRO_SKIP(4 * 64); // pal_rev_16
LIBRETRO_SKIP(4 * 65536 * 3); // decoded_colors
LIBRETRO_US(i); // tileclip_val
LIBRETRO_SKIP(65536); // f32_su8_tbl
LIBRETRO_US(i); // FaceBaseColor
LIBRETRO_US(i); // FaceOffsColor
LIBRETRO_US(i); // SFaceBaseColor
LIBRETRO_US(i); // SFaceOffsColor
LIBRETRO_US(i); // palette_index
LIBRETRO_US(dummy); // KillTex
LIBRETRO_SKIP(4 * 1024); // palette16_ram
LIBRETRO_SKIP(4 * 1024); // palette32_ram
LIBRETRO_SKIP(4 * 1024 * 8 * 2); // detwiddle
}
KillTex = true;
if (version >= V10)
UnserializeTAContext(data, total_size, VCUR_LIBRETRO);
LIBRETRO_USA(vram.data, vram.size);
LIBRETRO_USA(OnChipRAM.data,OnChipRAM_SIZE);
register_unserialize(CCN, data, total_size, version < V4 ? 16 : 0) ;
register_unserialize(UBC, data, total_size) ;
register_unserialize(BSC, data, total_size) ;
register_unserialize(DMAC, data, total_size) ;
register_unserialize(CPG, data, total_size) ;
register_unserialize(RTC, data, total_size) ;
register_unserialize(INTC, data, total_size, version < V4 ? 4 : 0) ;
register_unserialize(TMU, data, total_size) ;
register_unserialize(SCI, data, total_size) ;
register_unserialize(SCIF, data, total_size) ;
if (version >= V9)
icache.Unserialize(data, total_size);
else
icache.Reset(true);
if (version >= V10)
ocache.Unserialize(data, total_size);
else
ocache.Reset(true);
LIBRETRO_USA(mem_b.data, mem_b.size);
if (version < V9)
{
u16 dum16;
LIBRETRO_US(dum16); // IRLPriority
}
LIBRETRO_USA(InterruptEnvId,32);
LIBRETRO_USA(InterruptBit,32);
LIBRETRO_USA(InterruptLevelBit,16);
LIBRETRO_US(interrupt_vpend);
LIBRETRO_US(interrupt_vmask);
LIBRETRO_US(decoded_srimask);
LIBRETRO_US(i) ;
if ( i == 0 )
do_sqw_nommu = &do_sqw_nommu_area_3 ;
else if ( i == 1 )
do_sqw_nommu = &do_sqw_nommu_area_3_nonvmem ;
else if ( i == 2 )
do_sqw_nommu = (sqw_fp*)&TAWriteSQ ;
else if ( i == 3 )
do_sqw_nommu = &do_sqw_nommu_full ;
LIBRETRO_USA((*p_sh4rcb).sq_buffer,64/8);
LIBRETRO_US((*p_sh4rcb).cntx);
if (version < V9)
{
LIBRETRO_US(dummy_int); // old_rm
LIBRETRO_US(dummy_int); // old_dn
}
LIBRETRO_US(sh4_sched_ffb);
if (version < V9)
{
LIBRETRO_SKIP(4); // sh4_sched_intr
if (version < V3)
LIBRETRO_US(dummy_int); // sh4_sched_next_id
}
LIBRETRO_US(sch_list[aica_schid].tag) ;
LIBRETRO_US(sch_list[aica_schid].start) ;
LIBRETRO_US(sch_list[aica_schid].end) ;
LIBRETRO_US(sch_list[rtc_schid].tag) ;
LIBRETRO_US(sch_list[rtc_schid].start) ;
LIBRETRO_US(sch_list[rtc_schid].end) ;
LIBRETRO_US(sch_list[gdrom_sched].tag) ;
LIBRETRO_US(sch_list[gdrom_sched].start) ;
LIBRETRO_US(sch_list[gdrom_sched].end) ;
LIBRETRO_US(sch_list[maple_sched].tag) ;
LIBRETRO_US(sch_list[maple_sched].start) ;
LIBRETRO_US(sch_list[maple_sched].end) ;
LIBRETRO_US(sch_list[dma_sched_id].tag) ;
LIBRETRO_US(sch_list[dma_sched_id].start) ;
LIBRETRO_US(sch_list[dma_sched_id].end) ;
for (int i = 0; i < 3; i++)
{
LIBRETRO_US(sch_list[tmu_sched[i]].tag) ;
LIBRETRO_US(sch_list[tmu_sched[i]].start) ;
LIBRETRO_US(sch_list[tmu_sched[i]].end) ;
}
LIBRETRO_US(sch_list[render_end_schid].tag) ;
LIBRETRO_US(sch_list[render_end_schid].start) ;
LIBRETRO_US(sch_list[render_end_schid].end) ;
LIBRETRO_US(sch_list[vblank_schid].tag) ;
LIBRETRO_US(sch_list[vblank_schid].start) ;
LIBRETRO_US(sch_list[vblank_schid].end) ;
if (version < V9)
{
LIBRETRO_US(dummy_int); // sch_list[time_sync].tag
LIBRETRO_US(dummy_int); // sch_list[time_sync].start
LIBRETRO_US(dummy_int); // sch_list[time_sync].end
}
if (version >= V13)
LIBRETRO_US(settings.network.EmulateBBA);
else
settings.network.EmulateBBA = false;
if ( version >= V2 )
{
#ifdef ENABLE_MODEM
if (settings.network.EmulateBBA)
{
bba_Unserialize(data, total_size);
}
else
{
LIBRETRO_US(sch_list[modem_sched].tag) ;
LIBRETRO_US(sch_list[modem_sched].start) ;
LIBRETRO_US(sch_list[modem_sched].end) ;
}
#else
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
#endif
}
if (version < V3)
{
LIBRETRO_US(dummy_int); //aica_sched
LIBRETRO_US(dummy_int); //rtc_sched
}
LIBRETRO_US(SCIF_SCFSR2);
if (version < V9)
{
LIBRETRO_SKIP(1); // SCIF_SCFRDR2
LIBRETRO_US(dummy_int); // SCIF_SCFDR2
}
else if (version >= V11)
LIBRETRO_US(SCIF_SCSCR2);
LIBRETRO_US(BSC_PDTRA);
LIBRETRO_USA(tmu_shift,3);
LIBRETRO_USA(tmu_mask,3);
LIBRETRO_USA(tmu_mask64,3);
LIBRETRO_USA(old_mode,3);
if (version < V3)
{
//tmu_sched*3
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
}
LIBRETRO_USA(tmu_ch_base,3);
LIBRETRO_USA(tmu_ch_base64,3);
LIBRETRO_USA(CCN_QACR_TR,2);
// not the routine the state names, which may be from before each queue went by its own register
CCN_QACR_select();
if (version < V6)
{
for (int i = 0; i < 64; i++)
{
LIBRETRO_US(UTLB[i].Address);
LIBRETRO_US(UTLB[i].Data);
}
for (int i = 0; i < 4; i++)
{
LIBRETRO_US(ITLB[i].Address);
LIBRETRO_US(ITLB[i].Data);
}
}
else
{
LIBRETRO_US(UTLB);
LIBRETRO_US(ITLB);
}
if (version >= V11)
LIBRETRO_US(sq_remap);
LIBRETRO_US(ITLB_LRU_USE);
LIBRETRO_US(NullDriveDiscType);
LIBRETRO_USA(q_subchannel,96);
LIBRETRO_US(FLASH_SIZE);
LIBRETRO_US(BBSRAM_SIZE);
LIBRETRO_US(BIOS_SIZE);
LIBRETRO_US(RAM_SIZE);
LIBRETRO_US(ARAM_SIZE);
LIBRETRO_US(VRAM_SIZE);
LIBRETRO_US(RAM_MASK);
LIBRETRO_US(ARAM_MASK);
LIBRETRO_US(VRAM_MASK);
if (version < V9)
{
LIBRETRO_US(dummy_int); // naomi_updates
if (version < V4)
{
LIBRETRO_US(dummy_int); // RomPioOffset
LIBRETRO_US(dummy_int); // DmaOffset
LIBRETRO_US(dummy_int); // DmaCount
}
LIBRETRO_US(dummy_int); // BoardID
}
LIBRETRO_US(GSerialBuffer);
LIBRETRO_US(BSerialBuffer);
LIBRETRO_US(GBufPos);
LIBRETRO_US(BBufPos);
LIBRETRO_US(GState);
LIBRETRO_US(BState);
LIBRETRO_US(GOldClk);
LIBRETRO_US(BOldClk);
LIBRETRO_US(BControl);
LIBRETRO_US(BCmd);
LIBRETRO_US(BLastCmd);
LIBRETRO_US(GControl);
LIBRETRO_US(GCmd);
LIBRETRO_US(GLastCmd);
LIBRETRO_US(SerStep);
LIBRETRO_US(SerStep2);
LIBRETRO_USA(BSerial,69);
LIBRETRO_USA(GSerial,69);
LIBRETRO_US(reg_dimm_command);
LIBRETRO_US(reg_dimm_offsetl);
LIBRETRO_US(reg_dimm_parameterl);
LIBRETRO_US(reg_dimm_parameterh);
LIBRETRO_US(reg_dimm_status);
LIBRETRO_SKIP(1); // NaomiDataRead
if (version < V4)
{
LIBRETRO_US(dummy_int); // NAOMI_ROM_OFFSETH
LIBRETRO_US(dummy_int); // NAOMI_ROM_OFFSETL
LIBRETRO_US(dummy_int); // NAOMI_ROM_DATA
LIBRETRO_US(dummy_int); // NAOMI_DMA_OFFSETH
LIBRETRO_US(dummy_int); // NAOMI_DMA_OFFSETL
LIBRETRO_US(dummy_int); // NAOMI_DMA_COUNT
LIBRETRO_US(dummy_int); // NAOMI_BOARDID_WRITE
LIBRETRO_US(dummy_int); // NAOMI_BOARDID_READ
LIBRETRO_US(dummy_int); // NAOMI_COMM_OFFSET
LIBRETRO_US(dummy_int); // NAOMI_COMM_DATA
}
if (version < V9)
{
LIBRETRO_US(dummy_int); // cycle_counter
LIBRETRO_US(dummy_int); // idxnxx
#if FEAT_SHREC != DYNAREC_NONE
LIBRETRO_SKIP(sizeof(state_t)); // state
LIBRETRO_US(dummy_int); // div_som_reg1
LIBRETRO_US(dummy_int); // div_som_reg2
LIBRETRO_US(dummy_int); // div_som_reg3
LIBRETRO_US(dummy_int); // LastAddr
LIBRETRO_US(dummy_int); // LastAddr_min
LIBRETRO_SKIP(1024); // block_hash
#endif
// RegisterRead, RegisterWrite
for (int i = 0; i < sh4_reg_count; i++)
{
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
}
LIBRETRO_US(dummy_int); // fallback_blocks
LIBRETRO_US(dummy_int); // total_blocks
LIBRETRO_US(dummy_int); // REMOVED_OPS
if (version < V5)
{
LIBRETRO_US(dummy_int); // u16 kcode[4]
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int); // u8 rt[4]
LIBRETRO_US(dummy_int); // u8 lt[4]
LIBRETRO_US(dummy_int); // u32 vks[4]
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int);
LIBRETRO_US(dummy_int); // s8 joyx[4]
LIBRETRO_US(dummy_int); // s8 joyy[4]
}
}
if (version >= V3)
{
LIBRETRO_US(settings.dreamcast.broadcast);
LIBRETRO_US(settings.dreamcast.cable);
LIBRETRO_US(settings.dreamcast.region);
}
if (version >= V4 && CurrentCartridge != NULL)
{
CurrentCartridge->Unserialize(data, total_size);
}
if (version >= V7)
gd_hle_state.Unserialize(data, total_size);
if (version >= V14)
LIBRETRO_US(RealTimeClock);
/* Before V18 a transfer's answers were in memory from its start, and
* so they are in such a state: there is nothing waiting. */
maple_out_used = 0;
if (version >= V18)
{
LIBRETRO_US(maple_out_used);
LIBRETRO_USA(maple_out, MAPLE_OUT_WORDS);
if (maple_out_used > MAPLE_OUT_WORDS)
maple_out_used = 0;
}
// Before V19 a disc put in was ready at once: there is never a look under way
sch_list[gd_swap_schid].end = -1;
if (version >= V19)
{
LIBRETRO_US(sch_list[gd_swap_schid].start);
LIBRETRO_US(sch_list[gd_swap_schid].end);
}
if (version >= V20 && settings.System == DC_PLATFORM_NAOMI2 && elan_ram)
{
elan_state_t elan;
LIBRETRO_US(SB_ISTNRM1);
LIBRETRO_US(elan);
LIBRETRO_USA(elan_ram, ELAN_RAM_SIZE);
LIBRETRO_US(sch_list[elan_schid].start);
LIBRETRO_US(sch_list[elan_schid].end);
elan_set_state(&elan);
}
/* Fail the whole load if any read was rejected for running past the end
* of the input buffer. Callers (retro_unserialize) then bail cleanly
* instead of continuing on partially-garbage state. */
return !ra_unserialize_failed() ;
}