+// (c) Copyright 2004 Dave, All rights reserved.\r
+// (c) Copyright 2006-2010 notaz, All rights reserved.\r
+// Free for non-commercial use.\r
+\r
+// For commercial use, separate licencing terms must be obtained.\r
+\r
+\r
+#include "pico_int.h"\r
+#include <zlib/zlib.h>\r
+\r
+#include "../cpu/sh2/sh2.h"\r
+#include "sound/ym2612.h"\r
+\r
+// sn76496\r
+extern int *sn76496_regs;\r
+\r
+typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);\r
+typedef size_t (areaeof)(void *file);\r
+typedef int (areaseek)(void *file, long offset, int whence);\r
+typedef int (areaclose)(void *file);\r
+\r
+static arearw *areaRead;\r
+static arearw *areaWrite;\r
+static areaeof *areaEof;\r
+static areaseek *areaSeek;\r
+static areaclose *areaClose;\r
+\r
+carthw_state_chunk *carthw_chunks;\r
+void (*PicoStateProgressCB)(const char *str);\r
+void (*PicoLoadStateHook)(void);\r
+\r
+\r
+/* I/O functions */\r
+static size_t gzRead2(void *p, size_t _size, size_t _n, void *file)\r
+{\r
+ return gzread(file, p, _size * _n);\r
+}\r
+\r
+static size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)\r
+{\r
+ return gzwrite(file, p, _size * _n);\r
+}\r
+\r
+static void set_cbs(int gz)\r
+{\r
+ if (gz) {\r
+ areaRead = gzRead2;\r
+ areaWrite = gzWrite2;\r
+ areaEof = (areaeof *) gzeof;\r
+ areaSeek = (areaseek *) gzseek;\r
+ areaClose = (areaclose *) gzclose;\r
+ } else {\r
+ areaRead = (arearw *) fread;\r
+ areaWrite = (arearw *) fwrite;\r
+ areaEof = (areaeof *) feof;\r
+ areaSeek = (areaseek *) fseek;\r
+ areaClose = (areaclose *) fclose;\r
+ }\r
+}\r
+\r
+static void *open_save_file(const char *fname, int is_save)\r
+{\r
+ int len = strlen(fname);\r
+ void *afile = NULL;\r
+\r
+ if (len > 3 && strcmp(fname + len - 3, ".gz") == 0)\r
+ {\r
+ if ( (afile = gzopen(fname, is_save ? "wb" : "rb")) ) {\r
+ set_cbs(1);\r
+ if (is_save)\r
+ gzsetparams(afile, 9, Z_DEFAULT_STRATEGY);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if ( (afile = fopen(fname, is_save ? "wb" : "rb")) ) {\r
+ set_cbs(0);\r
+ }\r
+ }\r
+\r
+ return afile;\r
+}\r
+\r
+// legacy savestate loading\r
+#define SCANP(f, x) areaRead(&Pico.x, sizeof(Pico.x), 1, f)\r
+\r
+static int state_load_legacy(void *file)\r
+{\r
+ unsigned char head[32];\r
+ unsigned char cpu[0x60];\r
+ unsigned char cpu_z80[Z80_STATE_SIZE];\r
+ void *ym2612_regs;\r
+ int ok;\r
+\r
+ memset(&cpu,0,sizeof(cpu));\r
+ memset(&cpu_z80,0,sizeof(cpu_z80));\r
+\r
+ memset(head, 0, sizeof(head));\r
+ areaRead(head, sizeof(head), 1, file);\r
+ if (strcmp((char *)head, "Pico") != 0)\r
+ return -1;\r
+\r
+ elprintf(EL_STATUS, "legacy savestate");\r
+\r
+ // Scan all the memory areas:\r
+ SCANP(file, ram);\r
+ SCANP(file, vram);\r
+ SCANP(file, zram);\r
+ SCANP(file, cram);\r
+ SCANP(file, vsram);\r
+\r
+ // Pack, scan and unpack the cpu data:\r
+ areaRead(cpu, sizeof(cpu), 1, file);\r
+ SekUnpackCpu(cpu, 0);\r
+\r
+ SCANP(file, m);\r
+ SCANP(file, video);\r
+\r
+ ok = areaRead(cpu_z80, sizeof(cpu_z80), 1, file) == sizeof(cpu_z80);\r
+ // do not unpack if we fail to load z80 state\r
+ if (!ok) z80_reset();\r
+ else z80_unpack(cpu_z80);\r
+\r
+ ym2612_regs = YM2612GetRegs();\r
+ areaRead(sn76496_regs, 28*4, 1, file);\r
+ areaRead(ym2612_regs, 0x200+4, 1, file);\r
+ ym2612_unpack_state();\r
+\r
+ return 0;\r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+\r
+typedef enum {\r
+ CHUNK_M68K = 1,\r
+ CHUNK_RAM,\r
+ CHUNK_VRAM,\r
+ CHUNK_ZRAM,\r
+ CHUNK_CRAM, // 5\r
+ CHUNK_VSRAM,\r
+ CHUNK_MISC,\r
+ CHUNK_VIDEO,\r
+ CHUNK_Z80,\r
+ CHUNK_PSG, // 10\r
+ CHUNK_FM,\r
+ // CD stuff\r
+ CHUNK_S68K,\r
+ CHUNK_PRG_RAM,\r
+ CHUNK_WORD_RAM,\r
+ CHUNK_PCM_RAM, // 15\r
+ CHUNK_BRAM,\r
+ CHUNK_GA_REGS,\r
+ CHUNK_PCM,\r
+ CHUNK_CDC,\r
+ CHUNK_CDD, // 20\r
+ CHUNK_SCD,\r
+ CHUNK_RC,\r
+ CHUNK_MISC_CD,\r
+ //\r
+ CHUNK_IOPORTS, // versions < 1.70 did not save that..\r
+ CHUNK_SMS, // 25\r
+ // 32x\r
+ CHUNK_MSH2,\r
+ CHUNK_MSH2_DATA,\r
+ CHUNK_MSH2_PERI,\r
+ CHUNK_SSH2,\r
+ CHUNK_SSH2_DATA, // 30\r
+ CHUNK_SSH2_PERI,\r
+ CHUNK_32XSYS,\r
+ CHUNK_M68K_BIOS,\r
+ CHUNK_MSH2_BIOS,\r
+ CHUNK_SSH2_BIOS, // 35\r
+ CHUNK_SDRAM,\r
+ CHUNK_DRAM,\r
+ CHUNK_32XPAL,\r
+ //\r
+ CHUNK_DEFAULT_COUNT,\r
+ CHUNK_CARTHW_ = CHUNK_CARTHW, // defined in PicoInt\r
+} chunk_name_e;\r
+\r
+static const char * const chunk_names[] = {\r
+ "INVALID!",\r
+ "M68K state",\r
+ "RAM",\r
+ "VRAM",\r
+ "ZRAM",\r
+ "CRAM", // 5\r
+ "VSRAM",\r
+ "emu state",\r
+ "VIDEO",\r
+ "Z80 state",\r
+ "PSG", // 10\r
+ "FM",\r
+ // CD stuff\r
+ "S68K state",\r
+ "PRG_RAM",\r
+ "WORD_RAM",\r
+ "PCM_RAM", // 15\r
+ "BRAM",\r
+ "GATE ARRAY regs",\r
+ "PCM state",\r
+ "CDC",\r
+ "CDD", // 20\r
+ "SCD",\r
+ "GFX chip",\r
+ "MCD state",\r
+ //\r
+ "IO",\r
+ "SMS state", // 25\r
+ // 32x\r
+ "MSH2",\r
+ "MSH2 data",\r
+ "MSH2 peri",\r
+ "SSH2",\r
+ "SSH2 data", // 30\r
+ "SSH2 peri",\r
+ "32X system regs",\r
+ "M68K BIOS",\r
+ "MSH2 BIOS",\r
+ "SSH2 BIOS", // 35\r
+ "SDRAM",\r
+ "DRAM",\r
+ "PAL",\r
+};\r
+\r
+static int write_chunk(chunk_name_e name, int len, void *data, void *file)\r
+{\r
+ size_t bwritten = 0;\r
+ bwritten += areaWrite(&name, 1, 1, file);\r
+ bwritten += areaWrite(&len, 1, 4, file);\r
+ bwritten += areaWrite(data, 1, len, file);\r
+\r
+ return (bwritten == len + 4 + 1);\r
+}\r
+\r
+#define CHECKED_WRITE(name,len,data) { \\r
+ if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \\r
+ strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
+ PicoStateProgressCB(sbuff); \\r
+ } \\r
+ if (!write_chunk(name, len, data, file)) return 1; \\r
+}\r
+\r
+#define CHECKED_WRITE_BUFF(name,buff) { \\r
+ if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \\r
+ strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
+ PicoStateProgressCB(sbuff); \\r
+ } \\r
+ if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \\r
+}\r
+\r
+static int state_save(void *file)\r
+{\r
+ char sbuff[32] = "Saving.. ";\r
+ unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r
+ void *ym2612_regs = YM2612GetRegs();\r
+ int ver = 0x0170; // not really used..\r
+\r
+ areaWrite("PicoSEXT", 1, 8, file);\r
+ areaWrite(&ver, 1, 4, file);\r
+\r
+ if (!(PicoAHW & PAHW_SMS)) {\r
+ memset(buff, 0, sizeof(buff));\r
+ SekPackCpu(buff, 0);\r
+ CHECKED_WRITE_BUFF(CHUNK_M68K, buff);\r
+ CHECKED_WRITE_BUFF(CHUNK_RAM, Pico.ram);\r
+ CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);\r
+ CHECKED_WRITE_BUFF(CHUNK_IOPORTS, Pico.ioports);\r
+ ym2612_pack_state();\r
+ CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);\r
+ }\r
+ else {\r
+ CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r
+ }\r
+\r
+ CHECKED_WRITE_BUFF(CHUNK_VRAM, Pico.vram);\r
+ CHECKED_WRITE_BUFF(CHUNK_ZRAM, Pico.zram);\r
+ CHECKED_WRITE_BUFF(CHUNK_CRAM, Pico.cram);\r
+ CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);\r
+ CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r
+\r
+ z80_pack(buff_z80);\r
+ CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);\r
+ CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);\r
+\r
+ if (PicoAHW & PAHW_MCD)\r
+ {\r
+ memset(buff, 0, sizeof(buff));\r
+ SekPackCpu(buff, 1);\r
+ if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r
+ wram_1M_to_2M(Pico_mcd->word_ram2M);\r
+ Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);\r
+\r
+ CHECKED_WRITE_BUFF(CHUNK_S68K, buff);\r
+ CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);\r
+ CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format\r
+ CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);\r
+ CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);\r
+ CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
+ CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);\r
+ CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);\r
+ CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);\r
+ CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);\r
+ CHECKED_WRITE_BUFF(CHUNK_RC, Pico_mcd->rot_comp);\r
+ CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);\r
+\r
+ if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
+ wram_2M_to_1M(Pico_mcd->word_ram2M);\r
+ }\r
+\r
+ if (PicoAHW & PAHW_32X)\r
+ {\r
+ unsigned char cpubuff[SH2_STATE_SIZE];\r
+\r
+ memset(cpubuff, 0, sizeof(cpubuff));\r
+\r
+ sh2_pack(&sh2s[0], cpubuff);\r
+ CHECKED_WRITE_BUFF(CHUNK_MSH2, cpubuff);\r
+ CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, Pico32xMem->data_array[0]);\r
+ CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, Pico32xMem->sh2_peri_regs[0]);\r
+\r
+ sh2_pack(&sh2s[1], cpubuff);\r
+ CHECKED_WRITE_BUFF(CHUNK_SSH2, cpubuff);\r
+ CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, Pico32xMem->data_array[1]);\r
+ CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, Pico32xMem->sh2_peri_regs[1]);\r
+\r
+ CHECKED_WRITE_BUFF(CHUNK_32XSYS, Pico32x);\r
+ CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);\r
+ CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);\r
+ CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);\r
+ CHECKED_WRITE_BUFF(CHUNK_SDRAM, Pico32xMem->sdram);\r
+ CHECKED_WRITE_BUFF(CHUNK_DRAM, Pico32xMem->dram);\r
+ CHECKED_WRITE_BUFF(CHUNK_32XPAL, Pico32xMem->pal);\r
+ }\r
+\r
+ if (carthw_chunks != NULL)\r
+ {\r
+ carthw_state_chunk *chwc;\r
+ if (PicoStateProgressCB)\r
+ PicoStateProgressCB("Saving.. cart hw state");\r
+ for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)\r
+ CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int g_read_offs = 0;\r
+\r
+#define R_ERROR_RETURN(error) \\r
+{ \\r
+ elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r
+ return 1; \\r
+}\r
+\r
+// when is eof really set?\r
+#define CHECKED_READ(len,data) { \\r
+ if (areaRead(data, 1, len, file) != len) { \\r
+ if (len == 1 && areaEof(file)) goto readend; \\r
+ R_ERROR_RETURN("areaRead: premature EOF\n"); \\r
+ return 1; \\r
+ } \\r
+ g_read_offs += len; \\r
+}\r
+\r
+#define CHECKED_READ2(len2,data) { \\r
+ if (len2 != len) { \\r
+ elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \\r
+ if (len > len2) R_ERROR_RETURN("failed."); \\r
+ /* else read anyway and hope for the best.. */ \\r
+ } \\r
+ CHECKED_READ(len, data); \\r
+}\r
+\r
+#define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r
+\r
+static int state_load(void *file)\r
+{\r
+ unsigned char buff_m68k[0x60], buff_s68k[0x60];\r
+ unsigned char buff_z80[Z80_STATE_SIZE];\r
+ unsigned char buff_sh2[SH2_STATE_SIZE];\r
+ unsigned char chunk;\r
+ void *ym2612_regs;\r
+ char header[8];\r
+ int ver, len;\r
+\r
+ g_read_offs = 0;\r
+ CHECKED_READ(8, header);\r
+ if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r
+ R_ERROR_RETURN("bad header");\r
+ CHECKED_READ(4, &ver);\r
+\r
+ while (!areaEof(file))\r
+ {\r
+ CHECKED_READ(1, &chunk);\r
+ CHECKED_READ(4, &len);\r
+ if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
+ if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))\r
+ R_ERROR_RETURN("cd chunk in non CD state?");\r
+ if (CHUNK_MSH2 <= chunk && chunk <= CHUNK_32XPAL && !(PicoAHW & PAHW_32X))\r
+ R_ERROR_RETURN("32x chunk in non 32x state?");\r
+\r
+ switch (chunk)\r
+ {\r
+ case CHUNK_M68K:\r
+ CHECKED_READ_BUFF(buff_m68k);\r
+ break;\r
+\r
+ case CHUNK_Z80:\r
+ CHECKED_READ_BUFF(buff_z80);\r
+ z80_unpack(buff_z80);\r
+ break;\r
+\r
+ case CHUNK_RAM: CHECKED_READ_BUFF(Pico.ram); break;\r
+ case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); break;\r
+ case CHUNK_ZRAM: CHECKED_READ_BUFF(Pico.zram); break;\r
+ case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); break;\r
+ case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); break;\r
+ case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;\r
+ case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;\r
+ case CHUNK_IOPORTS: CHECKED_READ_BUFF(Pico.ioports); break;\r
+ case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;\r
+ case CHUNK_FM:\r
+ ym2612_regs = YM2612GetRegs();\r
+ CHECKED_READ2(0x200+4, ym2612_regs);\r
+ ym2612_unpack_state();\r
+ break;\r
+\r
+ case CHUNK_SMS:\r
+ CHECKED_READ_BUFF(Pico.ms);\r
+ break;\r
+\r
+ // cd stuff\r
+ case CHUNK_S68K:\r
+ CHECKED_READ_BUFF(buff_s68k);\r
+ break;\r
+\r
+ case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;\r
+ case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;\r
+ case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;\r
+ case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;\r
+ case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
+ case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
+ case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;\r
+ case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;\r
+ case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;\r
+ case CHUNK_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;\r
+ case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;\r
+\r
+ // 32x stuff\r
+ case CHUNK_MSH2:\r
+ CHECKED_READ_BUFF(buff_sh2);\r
+ sh2_unpack(&sh2s[0], buff_sh2);\r
+ break;\r
+\r
+ case CHUNK_SSH2:\r
+ CHECKED_READ_BUFF(buff_sh2);\r
+ sh2_unpack(&sh2s[1], buff_sh2);\r
+ break;\r
+\r
+ case CHUNK_MSH2_DATA: CHECKED_READ_BUFF(Pico32xMem->data_array[0]); break;\r
+ case CHUNK_MSH2_PERI: CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[0]); break;\r
+ case CHUNK_SSH2_DATA: CHECKED_READ_BUFF(Pico32xMem->data_array[1]); break;\r
+ case CHUNK_SSH2_PERI: CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[1]); break;\r
+ case CHUNK_32XSYS: CHECKED_READ_BUFF(Pico32x); break;\r
+ case CHUNK_M68K_BIOS: CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;\r
+ case CHUNK_MSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;\r
+ case CHUNK_SSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;\r
+ case CHUNK_SDRAM: CHECKED_READ_BUFF(Pico32xMem->sdram); break;\r
+ case CHUNK_DRAM: CHECKED_READ_BUFF(Pico32xMem->dram); break;\r
+ case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break;\r
+\r
+ default:\r
+ if (carthw_chunks != NULL)\r
+ {\r
+ carthw_state_chunk *chwc;\r
+ for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {\r
+ if (chwc->chunk == chunk) {\r
+ CHECKED_READ2(chwc->size, chwc->ptr);\r
+ goto breakswitch;\r
+ }\r
+ }\r
+ }\r
+ elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);\r
+ areaSeek(file, len, SEEK_CUR);\r
+ break;\r
+ }\r
+breakswitch:;\r
+ }\r
+\r
+readend:\r
+ if (PicoAHW & PAHW_SMS)\r
+ PicoStateLoadedMS();\r
+\r
+ if (PicoAHW & PAHW_MCD)\r
+ {\r
+ PicoMemStateLoaded();\r
+\r
+ if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
+ cdda_start_play();\r
+\r
+ // must unpack after mem is set up\r
+ SekUnpackCpu(buff_s68k, 1);\r
+ }\r
+\r
+ if (!(PicoAHW & PAHW_SMS))\r
+ SekUnpackCpu(buff_m68k, 0);\r
+\r
+ if (PicoAHW & PAHW_32X)\r
+ Pico32xStateLoaded();\r
+\r
+ return 0;\r
+}\r
+\r
+static int state_load_gfx(void *file)\r
+{\r
+ int ver, len, found = 0, to_find = 4;\r
+ char buff[8];\r
+\r
+ if (PicoAHW & PAHW_32X)\r
+ to_find += 2;\r
+\r
+ g_read_offs = 0;\r
+ CHECKED_READ(8, buff);\r
+ if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))\r
+ R_ERROR_RETURN("bad header");\r
+ CHECKED_READ(4, &ver);\r
+\r
+ while (!areaEof(file) && found < to_find)\r
+ {\r
+ CHECKED_READ(1, buff);\r
+ CHECKED_READ(4, &len);\r
+ if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
+ if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))\r
+ R_ERROR_RETURN("cd chunk in non CD state?");\r
+\r
+ switch (buff[0])\r
+ {\r
+ case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); found++; break;\r
+ case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); found++; break;\r
+ case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;\r
+ case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r
+\r
+ case CHUNK_DRAM:\r
+ if (Pico32xMem != NULL)\r
+ CHECKED_READ_BUFF(Pico32xMem->dram);\r
+ break;\r
+\r
+ case CHUNK_32XPAL:\r
+ if (Pico32xMem != NULL)\r
+ CHECKED_READ_BUFF(Pico32xMem->pal);\r
+ Pico32x.dirty_pal = 1;\r
+ break;\r
+\r
+ case CHUNK_32XSYS:\r
+ CHECKED_READ_BUFF(Pico32x);\r
+ break;\r
+\r
+ default:\r
+ areaSeek(file, len, SEEK_CUR);\r
+ break;\r
+ }\r
+ }\r
+\r
+readend:\r
+ return 0;\r
+}\r
+\r
+int PicoState(const char *fname, int is_save)\r
+{\r
+ void *afile = NULL;\r
+ int ret;\r
+\r
+ afile = open_save_file(fname, is_save);\r
+ if (afile == NULL)\r
+ return -1;\r
+\r
+ if (is_save)\r
+ ret = state_save(afile);\r
+ else {\r
+ ret = state_load(afile);\r
+ if (ret != 0) {\r
+ areaSeek(afile, 0, SEEK_SET);\r
+ ret = state_load_legacy(afile);\r
+ }\r
+\r
+ if (PicoLoadStateHook != NULL)\r
+ PicoLoadStateHook();\r
+ Pico.m.dirtyPal = 1;\r
+ }\r
+\r
+ areaClose(afile);\r
+ return ret;\r
+}\r
+\r
+int PicoStateLoadGfx(const char *fname)\r
+{\r
+ void *afile;\r
+ int ret;\r
+\r
+ afile = open_save_file(fname, 0);\r
+ if (afile == NULL)\r
+ return -1;\r
+\r
+ ret = state_load_gfx(afile);\r
+ if (ret != 0) {\r
+ // assume legacy\r
+ areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM\r
+ areaRead(Pico.vram, 1, sizeof(Pico.vram), afile);\r
+ areaSeek(afile, 0x2000, SEEK_CUR);\r
+ areaRead(Pico.cram, 1, sizeof(Pico.cram), afile);\r
+ areaRead(Pico.vsram, 1, sizeof(Pico.vsram), afile);\r
+ areaSeek(afile, 0x221a0, SEEK_SET);\r
+ areaRead(&Pico.video, 1, sizeof(Pico.video), afile);\r
+ }\r
+ areaClose(afile);\r
+ return 0;\r
+}\r
+\r
+// tmp state\r
+struct PicoTmp\r
+{\r
+ unsigned short vram[0x8000];\r
+ unsigned short cram[0x40];\r
+ unsigned short vsram[0x40];\r
+\r
+ //struct PicoMisc m;\r
+ struct PicoVideo video;\r
+\r
+ struct {\r
+ struct Pico32x p32x;\r
+ unsigned short dram[2][0x20000/2];\r
+ unsigned short pal[0x100];\r
+ } t32x;\r
+};\r
+\r
+// returns data ptr to free() or PicoTmpStateRestore()\r
+void *PicoTmpStateSave(void)\r
+{\r
+ // gfx only for now\r
+ struct PicoTmp *t = malloc(sizeof(*t));\r
+ if (t == NULL)\r
+ return NULL;\r
+\r
+ memcpy(t->vram, Pico.vram, sizeof(Pico.vram));\r
+ memcpy(t->cram, Pico.cram, sizeof(Pico.cram));\r
+ memcpy(t->vsram, Pico.vsram, sizeof(Pico.vsram));\r
+ memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r
+\r
+ if (PicoAHW & PAHW_32X) {\r
+ memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));\r
+ memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));\r
+ memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));\r
+ }\r
+\r
+ return t;\r
+}\r
+\r
+void PicoTmpStateRestore(void *data)\r
+{\r
+ struct PicoTmp *t = data;\r
+ if (t == NULL)\r
+ return;\r
+\r
+ memcpy(Pico.vram, t->vram, sizeof(Pico.vram));\r
+ memcpy(Pico.cram, t->cram, sizeof(Pico.cram));\r
+ memcpy(Pico.vsram, t->vsram, sizeof(Pico.vsram));\r
+ memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r
+ Pico.m.dirtyPal = 1;\r
+\r
+ if (PicoAHW & PAHW_32X) {\r
+ memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));\r
+ memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));\r
+ memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));\r
+ Pico32x.dirty_pal = 1;\r
+ }\r
+}\r
+\r
+// vim:shiftwidth=2:expandtab\r