pandora: fix readme and pxml version
[picodrive.git] / pico / state.c
CommitLineData
cff531af 1/*\r
2 * PicoDrive\r
3 * (C) notaz, 2010\r
4 *\r
5 * This work is licensed under the terms of MAME license.\r
6 * See COPYING file in the top-level directory.\r
7 */\r
b4db550e 8\r
9#include "pico_int.h"\r
325ee167 10#include <zlib.h>\r
b4db550e 11\r
f821bb70 12#include <cpu/sh2/sh2.h>\r
b4db550e 13#include "sound/ym2612.h"\r
4d97b0a7 14#include "sound/ym2413.h"\r
15#include "sound/sn76496.h"\r
d600fee4 16#include "cd/megasd.h"\r
86b38dc4 17#include "state.h"\r
b4db550e 18\r
b4db550e 19static arearw *areaRead;\r
20static arearw *areaWrite;\r
21static areaeof *areaEof;\r
22static areaseek *areaSeek;\r
23static areaclose *areaClose;\r
24\r
25carthw_state_chunk *carthw_chunks;\r
26void (*PicoStateProgressCB)(const char *str);\r
27void (*PicoLoadStateHook)(void);\r
28\r
29\r
30/* I/O functions */\r
31static size_t gzRead2(void *p, size_t _size, size_t _n, void *file)\r
32{\r
33 return gzread(file, p, _size * _n);\r
34}\r
35\r
36static size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)\r
37{\r
38 return gzwrite(file, p, _size * _n);\r
39}\r
40\r
41static void set_cbs(int gz)\r
42{\r
43 if (gz) {\r
44 areaRead = gzRead2;\r
45 areaWrite = gzWrite2;\r
46 areaEof = (areaeof *) gzeof;\r
47 areaSeek = (areaseek *) gzseek;\r
48 areaClose = (areaclose *) gzclose;\r
49 } else {\r
50 areaRead = (arearw *) fread;\r
51 areaWrite = (arearw *) fwrite;\r
52 areaEof = (areaeof *) feof;\r
53 areaSeek = (areaseek *) fseek;\r
54 areaClose = (areaclose *) fclose;\r
55 }\r
56}\r
57\r
58static void *open_save_file(const char *fname, int is_save)\r
59{\r
60 int len = strlen(fname);\r
61 void *afile = NULL;\r
62\r
c7e1c39b 63 if (len > 3 && strcasecmp(fname + len - 3, ".gz") == 0)\r
b4db550e 64 {\r
65 if ( (afile = gzopen(fname, is_save ? "wb" : "rb")) ) {\r
66 set_cbs(1);\r
67 if (is_save)\r
68 gzsetparams(afile, 9, Z_DEFAULT_STRATEGY);\r
69 }\r
70 }\r
71 else\r
72 {\r
73 if ( (afile = fopen(fname, is_save ? "wb" : "rb")) ) {\r
74 set_cbs(0);\r
75 }\r
76 }\r
77\r
78 return afile;\r
79}\r
80\r
b4db550e 81// ---------------------------------------------------------------------------\r
82\r
83typedef enum {\r
84 CHUNK_M68K = 1,\r
85 CHUNK_RAM,\r
86 CHUNK_VRAM,\r
87 CHUNK_ZRAM,\r
88 CHUNK_CRAM, // 5\r
89 CHUNK_VSRAM,\r
90 CHUNK_MISC,\r
91 CHUNK_VIDEO,\r
92 CHUNK_Z80,\r
93 CHUNK_PSG, // 10\r
94 CHUNK_FM,\r
95 // CD stuff\r
96 CHUNK_S68K,\r
97 CHUNK_PRG_RAM,\r
98 CHUNK_WORD_RAM,\r
99 CHUNK_PCM_RAM, // 15\r
100 CHUNK_BRAM,\r
101 CHUNK_GA_REGS,\r
102 CHUNK_PCM,\r
3f23709e 103 CHUNK_CDC, // old\r
274fcc35 104 CHUNK_CDD, // 20 old\r
105 CHUNK_SCD, // old\r
3f23709e 106 CHUNK_RC, // old\r
b4db550e 107 CHUNK_MISC_CD,\r
108 //\r
4a521146 109 CHUNK_IOPORTS, // old\r
b4db550e 110 CHUNK_SMS, // 25\r
111 // 32x\r
112 CHUNK_MSH2,\r
113 CHUNK_MSH2_DATA,\r
114 CHUNK_MSH2_PERI,\r
115 CHUNK_SSH2,\r
116 CHUNK_SSH2_DATA, // 30\r
117 CHUNK_SSH2_PERI,\r
118 CHUNK_32XSYS,\r
119 CHUNK_M68K_BIOS,\r
120 CHUNK_MSH2_BIOS,\r
121 CHUNK_SSH2_BIOS, // 35\r
122 CHUNK_SDRAM,\r
123 CHUNK_DRAM,\r
124 CHUNK_32XPAL,\r
6a98f03e 125 CHUNK_32X_EVT,\r
a2f24bfa 126 //rename\r
27e26273 127 CHUNK_32X_FIRST = CHUNK_MSH2,\r
128 CHUNK_32X_LAST = CHUNK_32X_EVT,\r
ae214f1c 129 // add new stuff here\r
130 CHUNK_CD_EVT = 50,\r
a93a80de 131 CHUNK_CD_GFX,\r
3f23709e 132 CHUNK_CD_CDC,\r
274fcc35 133 CHUNK_CD_CDD,\r
2ec448a8 134 CHUNK_YM2413,\r
fa4e0531 135 CHUNK_PICO_PCM,\r
136 CHUNK_PICO,\r
d600fee4 137 CHUNK_CD_MSD,\r
d4b5888a 138 CHUNK_VDP,\r
ccce7ee7 139 CHUNK_FM_TIMERS,\r
4a521146 140 CHUNK_FMv3 = 60,\r
141 CHUNK_IOPORTSv2,\r
b4db550e 142 //\r
143 CHUNK_DEFAULT_COUNT,\r
ae214f1c 144 CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt)\r
a2f24bfa 145\r
b4db550e 146} chunk_name_e;\r
147\r
cfae1ae1 148static const char * const chunk_names[CHUNK_DEFAULT_COUNT] = {\r
b4db550e 149 "INVALID!",\r
150 "M68K state",\r
151 "RAM",\r
152 "VRAM",\r
153 "ZRAM",\r
154 "CRAM", // 5\r
155 "VSRAM",\r
156 "emu state",\r
157 "VIDEO",\r
158 "Z80 state",\r
159 "PSG", // 10\r
160 "FM",\r
161 // CD stuff\r
162 "S68K state",\r
163 "PRG_RAM",\r
164 "WORD_RAM",\r
165 "PCM_RAM", // 15\r
166 "BRAM",\r
167 "GATE ARRAY regs",\r
168 "PCM state",\r
169 "CDC",\r
170 "CDD", // 20\r
171 "SCD",\r
172 "GFX chip",\r
173 "MCD state",\r
174 //\r
175 "IO",\r
176 "SMS state", // 25\r
177 // 32x\r
178 "MSH2",\r
179 "MSH2 data",\r
180 "MSH2 peri",\r
181 "SSH2",\r
182 "SSH2 data", // 30\r
183 "SSH2 peri",\r
184 "32X system regs",\r
185 "M68K BIOS",\r
186 "MSH2 BIOS",\r
187 "SSH2 BIOS", // 35\r
188 "SDRAM",\r
189 "DRAM",\r
fa4e0531 190 "32X palette",\r
191 "32X events",\r
b4db550e 192};\r
193\r
64360d13 194static int write_chunk(unsigned char name, int len, void *data, void *file)\r
b4db550e 195{\r
196 size_t bwritten = 0;\r
197 bwritten += areaWrite(&name, 1, 1, file);\r
198 bwritten += areaWrite(&len, 1, 4, file);\r
199 bwritten += areaWrite(data, 1, len, file);\r
200\r
201 return (bwritten == len + 4 + 1);\r
202}\r
203\r
3f23709e 204#define CHUNK_LIMIT_W 18772 // sizeof(cdc)\r
205\r
b4db550e 206#define CHECKED_WRITE(name,len,data) { \\r
cfae1ae1 207 if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
21707975 208 strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff)-1 - 9); \\r
209 sbuff[sizeof(sbuff)-1] = '\0'; \\r
b4db550e 210 PicoStateProgressCB(sbuff); \\r
211 } \\r
3f23709e 212 if (data == buf2 && len > CHUNK_LIMIT_W) \\r
213 goto out; \\r
214 if (!write_chunk(name, len, data, file)) \\r
215 goto out; \\r
b4db550e 216}\r
217\r
218#define CHECKED_WRITE_BUFF(name,buff) { \\r
cfae1ae1 219 if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
21707975 220 strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff)-1 - 9); \\r
221 sbuff[sizeof(sbuff)-1] = '\0'; \\r
b4db550e 222 PicoStateProgressCB(sbuff); \\r
223 } \\r
3f23709e 224 if (!write_chunk(name, sizeof(buff), &buff, file)) \\r
225 goto out; \\r
b4db550e 226}\r
227\r
228static int state_save(void *file)\r
229{\r
230 char sbuff[32] = "Saving.. ";\r
231 unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r
3f23709e 232 void *buf2 = NULL;\r
233 int ver = 0x0191; // not really used..\r
234 int retval = -1;\r
a93a80de 235 int len;\r
b4db550e 236\r
fa4e0531 237 buf2 = malloc(CHUNK_LIMIT_W);\r
238 if (buf2 == NULL)\r
239 return -1;\r
240\r
b4db550e 241 areaWrite("PicoSEXT", 1, 8, file);\r
242 areaWrite(&ver, 1, 4, file);\r
243\r
93f9619e 244 if (!(PicoIn.AHW & PAHW_SMS)) {\r
7e056c85 245 // the patches can cause incompatible saves with no-idle\r
246 SekFinishIdleDet();\r
247\r
b4db550e 248 memset(buff, 0, sizeof(buff));\r
249 SekPackCpu(buff, 0);\r
250 CHECKED_WRITE_BUFF(CHUNK_M68K, buff);\r
88fd63ad 251 CHECKED_WRITE_BUFF(CHUNK_RAM, PicoMem.ram);\r
252 CHECKED_WRITE_BUFF(CHUNK_VSRAM, PicoMem.vsram);\r
253 CHECKED_WRITE_BUFF(CHUNK_IOPORTS, PicoMem.ioports);\r
4a521146 254 len = io_ports_pack(buf2, CHUNK_LIMIT_W);\r
255 CHECKED_WRITE(CHUNK_IOPORTSv2, len, buf2);\r
fa4e0531 256 if (PicoIn.AHW & PAHW_PICO) {\r
257 len = PicoPicoPCMSave(buf2, CHUNK_LIMIT_W);\r
258 CHECKED_WRITE(CHUNK_PICO_PCM, len, buf2);\r
259 CHECKED_WRITE(CHUNK_PICO, sizeof(PicoPicohw), &PicoPicohw);\r
260 } else {\r
bcf8175e 261#ifdef __GP2X__\r
4d97b0a7 262 void *ym_regs = YM2612GetRegs();\r
bcf8175e 263 ym2612_pack_state_old();\r
bcf8175e 264 CHECKED_WRITE(CHUNK_FM, 0x200+4, ym_regs);\r
265#else\r
ccce7ee7 266 // write fm state first since timer load needs OPN.ST.mode\r
267 len = YM2612PicoStateSave3(buf2, CHUNK_LIMIT_W);\r
268 CHECKED_WRITE(CHUNK_FMv3, len, buf2);\r
269 len = ym2612_pack_timers(buf2, CHUNK_LIMIT_W);\r
270 CHECKED_WRITE(CHUNK_FM_TIMERS, len, buf2);\r
bcf8175e 271#endif\r
fa4e0531 272 }\r
7e056c85 273\r
274 if (!(PicoIn.opt & POPT_DIS_IDLE_DET))\r
275 SekInitIdleDet();\r
b4db550e 276 }\r
277 else {\r
278 CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r
4d97b0a7 279 // only store the FM unit state if it was really used\r
280 if (Pico.m.hardware & PMS_HW_FMUSED) {\r
281 len = ym2413_pack_state(buf2, CHUNK_LIMIT_W);\r
282 CHECKED_WRITE(CHUNK_YM2413, len, buf2);\r
283 }\r
b4db550e 284 }\r
fa4e0531 285 CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);\r
286\r
287 if (!(PicoIn.AHW & PAHW_PICO)) {\r
288 z80_pack(buff_z80);\r
289 CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);\r
290 CHECKED_WRITE_BUFF(CHUNK_ZRAM, PicoMem.zram);\r
291 }\r
b4db550e 292\r
88fd63ad 293 CHECKED_WRITE_BUFF(CHUNK_VRAM, PicoMem.vram);\r
88fd63ad 294 CHECKED_WRITE_BUFF(CHUNK_CRAM, PicoMem.cram);\r
daf29df9 295\r
fa4e0531 296 CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);\r
d4b5888a 297 len = PicoVideoSave(buf2);\r
298 CHECKED_WRITE(CHUNK_VDP, len, buf2);\r
b4db550e 299 CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r
300\r
93f9619e 301 if (PicoIn.AHW & PAHW_MCD)\r
b4db550e 302 {\r
303 memset(buff, 0, sizeof(buff));\r
304 SekPackCpu(buff, 1);\r
305 if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r
306 wram_1M_to_2M(Pico_mcd->word_ram2M);\r
a1fc78f3 307 memcpy(&Pico_mcd->m.hint_vector, Pico_mcd->bios + 0x72,\r
895d1512 308 sizeof(Pico_mcd->m.hint_vector));\r
b4db550e 309\r
310 CHECKED_WRITE_BUFF(CHUNK_S68K, buff);\r
311 CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);\r
312 CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format\r
313 CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);\r
314 CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);\r
315 CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
316 CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);\r
b4db550e 317 CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);\r
ae214f1c 318 memset(buff, 0, 0x40);\r
319 memcpy(buff, pcd_event_times, sizeof(pcd_event_times));\r
320 CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff);\r
3f23709e 321\r
322 len = gfx_context_save(buf2);\r
323 CHECKED_WRITE(CHUNK_CD_GFX, len, buf2);\r
324 len = cdc_context_save(buf2);\r
325 CHECKED_WRITE(CHUNK_CD_CDC, len, buf2);\r
274fcc35 326 len = cdd_context_save(buf2);\r
327 CHECKED_WRITE(CHUNK_CD_CDD, len, buf2);\r
b4db550e 328\r
d600fee4 329 CHECKED_WRITE_BUFF(CHUNK_CD_MSD, Pico_msd);\r
330\r
b4db550e 331 if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
332 wram_2M_to_1M(Pico_mcd->word_ram2M);\r
333 }\r
334\r
f3a57b2d 335#ifndef NO_32X\r
93f9619e 336 if (PicoIn.AHW & PAHW_32X)\r
b4db550e 337 {\r
338 unsigned char cpubuff[SH2_STATE_SIZE];\r
339\r
340 memset(cpubuff, 0, sizeof(cpubuff));\r
341\r
342 sh2_pack(&sh2s[0], cpubuff);\r
343 CHECKED_WRITE_BUFF(CHUNK_MSH2, cpubuff);\r
f81107f5 344 CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, sh2s[0].data_array);\r
345 CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, sh2s[0].peri_regs);\r
b4db550e 346\r
347 sh2_pack(&sh2s[1], cpubuff);\r
348 CHECKED_WRITE_BUFF(CHUNK_SSH2, cpubuff);\r
f81107f5 349 CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, sh2s[1].data_array);\r
350 CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, sh2s[1].peri_regs);\r
b4db550e 351\r
352 CHECKED_WRITE_BUFF(CHUNK_32XSYS, Pico32x);\r
353 CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);\r
354 CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);\r
355 CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);\r
356 CHECKED_WRITE_BUFF(CHUNK_SDRAM, Pico32xMem->sdram);\r
357 CHECKED_WRITE_BUFF(CHUNK_DRAM, Pico32xMem->dram);\r
358 CHECKED_WRITE_BUFF(CHUNK_32XPAL, Pico32xMem->pal);\r
ed4402a7 359\r
6a98f03e 360 memset(buff, 0, 0x40);\r
ae214f1c 361 memcpy(buff, p32x_event_times, sizeof(p32x_event_times));\r
6a98f03e 362 CHECKED_WRITE(CHUNK_32X_EVT, 0x40, buff);\r
b4db550e 363 }\r
f3a57b2d 364#endif\r
b4db550e 365\r
366 if (carthw_chunks != NULL)\r
367 {\r
368 carthw_state_chunk *chwc;\r
369 if (PicoStateProgressCB)\r
370 PicoStateProgressCB("Saving.. cart hw state");\r
371 for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)\r
372 CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r
373 }\r
374\r
92f7a430 375 CHECKED_WRITE(0, 0, NULL);\r
3f23709e 376 retval = 0;\r
377\r
378out:\r
379 if (buf2 != NULL)\r
380 free(buf2);\r
381 return retval;\r
b4db550e 382}\r
383\r
384static int g_read_offs = 0;\r
385\r
386#define R_ERROR_RETURN(error) \\r
387{ \\r
388 elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r
3f23709e 389 goto out; \\r
b4db550e 390}\r
391\r
392// when is eof really set?\r
393#define CHECKED_READ(len,data) { \\r
394 if (areaRead(data, 1, len, file) != len) { \\r
395 if (len == 1 && areaEof(file)) goto readend; \\r
396 R_ERROR_RETURN("areaRead: premature EOF\n"); \\r
b4db550e 397 } \\r
398 g_read_offs += len; \\r
399}\r
400\r
401#define CHECKED_READ2(len2,data) { \\r
402 if (len2 != len) { \\r
403 elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \\r
404 if (len > len2) R_ERROR_RETURN("failed."); \\r
405 /* else read anyway and hope for the best.. */ \\r
406 } \\r
407 CHECKED_READ(len, data); \\r
408}\r
409\r
410#define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r
411\r
3f23709e 412#define CHUNK_LIMIT_R 0x10960 // sizeof(old_cdc)\r
413\r
414#define CHECKED_READ_LIM(data) { \\r
415 if (len > CHUNK_LIMIT_R) \\r
416 R_ERROR_RETURN("chunk size over limit."); \\r
417 CHECKED_READ(len, data); \\r
418}\r
419\r
b4db550e 420static int state_load(void *file)\r
421{\r
422 unsigned char buff_m68k[0x60], buff_s68k[0x60];\r
423 unsigned char buff_z80[Z80_STATE_SIZE];\r
424 unsigned char buff_sh2[SH2_STATE_SIZE];\r
d4b5888a 425 unsigned char buff_vdp[0x200];\r
3f23709e 426 unsigned char *buf = NULL;\r
b4db550e 427 unsigned char chunk;\r
2ec448a8 428 void *ym_regs;\r
3f23709e 429 int len_check;\r
430 int retval = -1;\r
b4db550e 431 char header[8];\r
fa23e7cc 432 int ver, has_32x = 0;\r
433 int len, len_vdp = 0;\r
b4db550e 434\r
03065bb6 435 memset(buff_m68k, 0, sizeof(buff_m68k));\r
436 memset(buff_s68k, 0, sizeof(buff_s68k));\r
437 memset(buff_z80, 0, sizeof(buff_z80));\r
438\r
3f23709e 439 buf = malloc(CHUNK_LIMIT_R);\r
440 if (buf == NULL)\r
441 return -1;\r
442\r
b4db550e 443 g_read_offs = 0;\r
444 CHECKED_READ(8, header);\r
445 if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r
446 R_ERROR_RETURN("bad header");\r
447 CHECKED_READ(4, &ver);\r
448\r
ae214f1c 449 memset(pcd_event_times, 0, sizeof(pcd_event_times));\r
450 memset(p32x_event_times, 0, sizeof(p32x_event_times));\r
451\r
b4db550e 452 while (!areaEof(file))\r
453 {\r
3f23709e 454 len_check = 0;\r
b4db550e 455 CHECKED_READ(1, &chunk);\r
456 CHECKED_READ(4, &len);\r
457 if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
93f9619e 458 if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r
b4db550e 459 R_ERROR_RETURN("cd chunk in non CD state?");\r
fa23e7cc 460\r
461 // 32X only appears in PicoDrive after it has been enabled, so track this\r
462 has_32x |= CHUNK_32X_FIRST <= chunk && chunk <= CHUNK_32X_LAST;\r
463 if (has_32x && !(PicoIn.AHW & PAHW_32X))\r
27e26273 464 Pico32xStartup();\r
b4db550e 465\r
466 switch (chunk)\r
467 {\r
468 case CHUNK_M68K:\r
469 CHECKED_READ_BUFF(buff_m68k);\r
470 break;\r
471\r
472 case CHUNK_Z80:\r
473 CHECKED_READ_BUFF(buff_z80);\r
b4db550e 474 break;\r
475\r
88fd63ad 476 case CHUNK_RAM: CHECKED_READ_BUFF(PicoMem.ram); break;\r
477 case CHUNK_VRAM: CHECKED_READ_BUFF(PicoMem.vram); break;\r
478 case CHUNK_ZRAM: CHECKED_READ_BUFF(PicoMem.zram); break;\r
479 case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); break;\r
480 case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); break;\r
b4db550e 481 case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;\r
d4b5888a 482 case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;\r
483 case CHUNK_VDP: CHECKED_READ2((len_vdp = len), buff_vdp); break;\r
daf29df9 484\r
88fd63ad 485 case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break;\r
b4db550e 486 case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;\r
2ec448a8 487 case CHUNK_YM2413:\r
4d97b0a7 488 CHECKED_READ(len, buf);\r
489 ym2413_unpack_state(buf, len);\r
490 Pico.m.hardware |= PMS_HW_FMUSED;\r
2ec448a8 491 break;\r
b4db550e 492 case CHUNK_FM:\r
2ec448a8 493 ym_regs = YM2612GetRegs();\r
494 CHECKED_READ2(0x200+4, ym_regs);\r
ccce7ee7 495 ym2612_unpack_state_old();\r
496 break;\r
4a521146 497 case CHUNK_FM_TIMERS: CHECKED_READ(len, buf); ym2612_unpack_timers(buf, len); break;\r
498 case CHUNK_FMv3: CHECKED_READ(len, buf); YM2612PicoStateLoad3(buf, len); break;\r
499 case CHUNK_IOPORTSv2: CHECKED_READ(len, buf); io_ports_unpack(buf, len); break;\r
b4db550e 500\r
fa4e0531 501 case CHUNK_PICO_PCM:\r
502 CHECKED_READ(len, buf);\r
503 PicoPicoPCMLoad(buf, len);\r
504 break;\r
505 case CHUNK_PICO:\r
506 CHECKED_READ_BUFF(PicoPicohw);\r
507 break;\r
508\r
b4db550e 509 case CHUNK_SMS:\r
510 CHECKED_READ_BUFF(Pico.ms);\r
511 break;\r
512\r
513 // cd stuff\r
514 case CHUNK_S68K:\r
515 CHECKED_READ_BUFF(buff_s68k);\r
516 break;\r
517\r
518 case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;\r
519 case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;\r
520 case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;\r
521 case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;\r
522 case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
523 case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
b4db550e 524 case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;\r
d600fee4 525 case CHUNK_CD_MSD: CHECKED_READ_BUFF(Pico_msd); break;\r
b4db550e 526\r
ae214f1c 527 case CHUNK_CD_EVT:\r
3f23709e 528 CHECKED_READ2(0x40, buf);\r
529 memcpy(pcd_event_times, buf, sizeof(pcd_event_times));\r
ae214f1c 530 break;\r
531\r
a93a80de 532 case CHUNK_CD_GFX:\r
3f23709e 533 CHECKED_READ_LIM(buf);\r
534 len_check = gfx_context_load(buf);\r
535 break;\r
536\r
537 case CHUNK_CD_CDC:\r
538 CHECKED_READ_LIM(buf);\r
539 len_check = cdc_context_load(buf);\r
540 break;\r
541\r
274fcc35 542 case CHUNK_CD_CDD:\r
543 CHECKED_READ_LIM(buf);\r
544 len_check = cdd_context_load(buf);\r
545 break;\r
546\r
3f23709e 547 // old, to be removed:\r
548 case CHUNK_CDC:\r
549 CHECKED_READ_LIM(buf);\r
550 cdc_context_load_old(buf);\r
a93a80de 551 break;\r
552\r
274fcc35 553 case CHUNK_SCD:\r
554 CHECKED_READ_LIM(buf);\r
555 cdd_context_load_old(buf);\r
556 break;\r
557\r
b4db550e 558 // 32x stuff\r
f3a57b2d 559#ifndef NO_32X\r
b4db550e 560 case CHUNK_MSH2:\r
561 CHECKED_READ_BUFF(buff_sh2);\r
562 sh2_unpack(&sh2s[0], buff_sh2);\r
563 break;\r
564\r
565 case CHUNK_SSH2:\r
566 CHECKED_READ_BUFF(buff_sh2);\r
567 sh2_unpack(&sh2s[1], buff_sh2);\r
568 break;\r
569\r
f81107f5 570 case CHUNK_MSH2_DATA: CHECKED_READ_BUFF(sh2s[0].data_array); break;\r
571 case CHUNK_MSH2_PERI: CHECKED_READ_BUFF(sh2s[0].peri_regs); break;\r
572 case CHUNK_SSH2_DATA: CHECKED_READ_BUFF(sh2s[1].data_array); break;\r
573 case CHUNK_SSH2_PERI: CHECKED_READ_BUFF(sh2s[1].peri_regs); break;\r
b4db550e 574 case CHUNK_32XSYS: CHECKED_READ_BUFF(Pico32x); break;\r
575 case CHUNK_M68K_BIOS: CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;\r
576 case CHUNK_MSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;\r
577 case CHUNK_SSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;\r
578 case CHUNK_SDRAM: CHECKED_READ_BUFF(Pico32xMem->sdram); break;\r
579 case CHUNK_DRAM: CHECKED_READ_BUFF(Pico32xMem->dram); break;\r
580 case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break;\r
6a98f03e 581\r
582 case CHUNK_32X_EVT:\r
3f23709e 583 CHECKED_READ2(0x40, buf);\r
584 memcpy(p32x_event_times, buf, sizeof(p32x_event_times));\r
6a98f03e 585 break;\r
f3a57b2d 586#endif\r
b4db550e 587 default:\r
464b4c17 588 if (!len && !chunk)\r
92f7a430 589 goto readend;\r
b4db550e 590 if (carthw_chunks != NULL)\r
591 {\r
592 carthw_state_chunk *chwc;\r
593 for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {\r
594 if (chwc->chunk == chunk) {\r
595 CHECKED_READ2(chwc->size, chwc->ptr);\r
596 goto breakswitch;\r
597 }\r
598 }\r
599 }\r
600 elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);\r
601 areaSeek(file, len, SEEK_CUR);\r
602 break;\r
603 }\r
3f23709e 604breakswitch:\r
605 if (len_check != 0 && len_check != len)\r
606 elprintf(EL_STATUS, "load_state: chunk %d has bad len %d/%d",\r
607 len, len_check);\r
b4db550e 608 }\r
609\r
610readend:\r
d4b5888a 611 PicoVideoLoad(buff_vdp, len_vdp);\r
612\r
fa23e7cc 613 if (PicoIn.AHW & PAHW_32X)\r
614 if (!has_32x)\r
615 Pico32xShutdown(); // in case of loading a state with 32X disabled\r
616\r
93f9619e 617 if (PicoIn.AHW & PAHW_SMS)\r
b4db550e 618 PicoStateLoadedMS();\r
619\r
93f9619e 620 if (PicoIn.AHW & PAHW_32X)\r
27e26273 621 Pico32xStateLoaded(1);\r
622\r
e23f4494 623 if (PicoLoadStateHook != NULL)\r
624 PicoLoadStateHook();\r
625\r
03065bb6 626 // must unpack 68k and z80 after banks are set up\r
93f9619e 627 if (!(PicoIn.AHW & PAHW_SMS))\r
b4db550e 628 SekUnpackCpu(buff_m68k, 0);\r
93f9619e 629 if (PicoIn.AHW & PAHW_MCD)\r
27e26273 630 SekUnpackCpu(buff_s68k, 1);\r
b4db550e 631\r
03065bb6 632 z80_unpack(buff_z80);\r
633\r
93f9619e 634 if (PicoIn.AHW & PAHW_32X)\r
27e26273 635 Pico32xStateLoaded(0);\r
93f9619e 636 if (PicoIn.AHW & PAHW_MCD)\r
ae214f1c 637 pcd_state_loaded();\r
da414888 638 if (!(PicoIn.AHW & PAHW_SMS)) {\r
639 Pico.video.status &= ~(SR_VB | SR_F);\r
640 Pico.video.status |= ((Pico.video.reg[1] >> 3) ^ SR_VB) & SR_VB;\r
641 Pico.video.status |= (Pico.video.pending_ints << 2) & SR_F;\r
642 }\r
b4db550e 643\r
e6488636 644 Pico.m.dirtyPal = 1;\r
3f23709e 645 retval = 0;\r
646\r
647out:\r
648 free(buf);\r
649 return retval;\r
b4db550e 650}\r
651\r
652static int state_load_gfx(void *file)\r
653{\r
654 int ver, len, found = 0, to_find = 4;\r
5d4a7fb9 655 u8 buff_vdp[0x200];\r
656 int len_vdp = 0;\r
b4db550e 657 char buff[8];\r
658\r
93f9619e 659 if (PicoIn.AHW & PAHW_32X)\r
4496577e 660 to_find += 3;\r
b4db550e 661\r
662 g_read_offs = 0;\r
663 CHECKED_READ(8, buff);\r
664 if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))\r
665 R_ERROR_RETURN("bad header");\r
666 CHECKED_READ(4, &ver);\r
667\r
668 while (!areaEof(file) && found < to_find)\r
669 {\r
670 CHECKED_READ(1, buff);\r
671 CHECKED_READ(4, &len);\r
672 if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
93f9619e 673 if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r
b4db550e 674 R_ERROR_RETURN("cd chunk in non CD state?");\r
675\r
676 switch (buff[0])\r
677 {\r
88fd63ad 678 case CHUNK_VRAM: CHECKED_READ_BUFF(PicoMem.vram); found++; break;\r
679 case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); found++; break;\r
680 case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); found++; break;\r
b4db550e 681 case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r
5d4a7fb9 682 case CHUNK_VDP: CHECKED_READ2((len_vdp = len), buff_vdp); break;\r
b4db550e 683\r
f3a57b2d 684#ifndef NO_32X\r
b4db550e 685 case CHUNK_DRAM:\r
686 if (Pico32xMem != NULL)\r
687 CHECKED_READ_BUFF(Pico32xMem->dram);\r
4496577e 688 found++;\r
b4db550e 689 break;\r
690\r
691 case CHUNK_32XPAL:\r
692 if (Pico32xMem != NULL)\r
693 CHECKED_READ_BUFF(Pico32xMem->pal);\r
4496577e 694 found++;\r
b4db550e 695 Pico32x.dirty_pal = 1;\r
696 break;\r
697\r
698 case CHUNK_32XSYS:\r
699 CHECKED_READ_BUFF(Pico32x);\r
4496577e 700 found++;\r
b4db550e 701 break;\r
f3a57b2d 702#endif\r
b4db550e 703 default:\r
704 areaSeek(file, len, SEEK_CUR);\r
705 break;\r
706 }\r
707 }\r
5d4a7fb9 708 PicoVideoLoad(buff_vdp, len_vdp);\r
b4db550e 709\r
3f23709e 710out:\r
b4db550e 711readend:\r
712 return 0;\r
713}\r
714\r
86b38dc4 715static int pico_state_internal(void *afile, int is_save)\r
b4db550e 716{\r
b4db550e 717 int ret;\r
718\r
b4db550e 719 if (is_save)\r
720 ret = state_save(afile);\r
e6488636 721 else\r
b4db550e 722 ret = state_load(afile);\r
b4db550e 723\r
86b38dc4 724 return ret;\r
725}\r
726\r
727int PicoState(const char *fname, int is_save)\r
728{\r
729 void *afile = NULL;\r
730 int ret;\r
731\r
732 afile = open_save_file(fname, is_save);\r
733 if (afile == NULL)\r
734 return -1;\r
735\r
736 ret = pico_state_internal(afile, is_save);\r
b4db550e 737 areaClose(afile);\r
738 return ret;\r
739}\r
740\r
86b38dc4 741int PicoStateFP(void *afile, int is_save,\r
742 arearw *read, arearw *write, areaeof *eof, areaseek *seek)\r
743{\r
744 areaRead = read;\r
745 areaWrite = write;\r
746 areaEof = eof;\r
747 areaSeek = seek;\r
748 areaClose = NULL;\r
749\r
750 return pico_state_internal(afile, is_save);\r
751}\r
752\r
b4db550e 753int PicoStateLoadGfx(const char *fname)\r
754{\r
755 void *afile;\r
756 int ret;\r
757\r
758 afile = open_save_file(fname, 0);\r
759 if (afile == NULL)\r
760 return -1;\r
761\r
762 ret = state_load_gfx(afile);\r
763 if (ret != 0) {\r
764 // assume legacy\r
765 areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM\r
88fd63ad 766 areaRead(PicoMem.vram, 1, sizeof(PicoMem.vram), afile);\r
b4db550e 767 areaSeek(afile, 0x2000, SEEK_CUR);\r
88fd63ad 768 areaRead(PicoMem.cram, 1, sizeof(PicoMem.cram), afile);\r
769 areaRead(PicoMem.vsram, 1, sizeof(PicoMem.vsram), afile);\r
b4db550e 770 areaSeek(afile, 0x221a0, SEEK_SET);\r
771 areaRead(&Pico.video, 1, sizeof(Pico.video), afile);\r
5d4a7fb9 772 PicoVideoCacheSAT(1);\r
b4db550e 773 }\r
774 areaClose(afile);\r
e721f801 775\r
4496577e 776 Pico.est.rendstatus = -1;\r
b4db550e 777 return 0;\r
778}\r
779\r
780// tmp state\r
781struct PicoTmp\r
782{\r
783 unsigned short vram[0x8000];\r
784 unsigned short cram[0x40];\r
785 unsigned short vsram[0x40];\r
c5ecd7a0 786 unsigned int satcache[2*0x80];\r
b4db550e 787\r
788 //struct PicoMisc m;\r
789 struct PicoVideo video;\r
5d4a7fb9 790 u8 vdp[0x200];\r
791 int vdp_len;\r
b4db550e 792\r
793 struct {\r
794 struct Pico32x p32x;\r
795 unsigned short dram[2][0x20000/2];\r
796 unsigned short pal[0x100];\r
797 } t32x;\r
798};\r
799\r
800// returns data ptr to free() or PicoTmpStateRestore()\r
801void *PicoTmpStateSave(void)\r
802{\r
803 // gfx only for now\r
804 struct PicoTmp *t = malloc(sizeof(*t));\r
805 if (t == NULL)\r
806 return NULL;\r
807\r
88fd63ad 808 memcpy(t->vram, PicoMem.vram, sizeof(PicoMem.vram));\r
809 memcpy(t->cram, PicoMem.cram, sizeof(PicoMem.cram));\r
810 memcpy(t->vsram, PicoMem.vsram, sizeof(PicoMem.vsram));\r
e721f801 811 memcpy(t->satcache, VdpSATCache, sizeof(VdpSATCache));\r
b4db550e 812 memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r
5d4a7fb9 813 t->vdp_len = PicoVideoSave(t->vdp);\r
b4db550e 814\r
f3a57b2d 815#ifndef NO_32X\r
93f9619e 816 if (PicoIn.AHW & PAHW_32X) {\r
b4db550e 817 memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));\r
818 memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));\r
819 memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));\r
820 }\r
f3a57b2d 821#endif\r
b4db550e 822\r
823 return t;\r
824}\r
825\r
826void PicoTmpStateRestore(void *data)\r
827{\r
828 struct PicoTmp *t = data;\r
829 if (t == NULL)\r
830 return;\r
831\r
88fd63ad 832 memcpy(PicoMem.vram, t->vram, sizeof(PicoMem.vram));\r
833 memcpy(PicoMem.cram, t->cram, sizeof(PicoMem.cram));\r
834 memcpy(PicoMem.vsram, t->vsram, sizeof(PicoMem.vsram));\r
e721f801 835 memcpy(VdpSATCache, t->satcache, sizeof(VdpSATCache));\r
b4db550e 836 memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r
837 Pico.m.dirtyPal = 1;\r
5d4a7fb9 838 PicoVideoLoad(t->vdp, t->vdp_len);\r
b4db550e 839\r
f3a57b2d 840#ifndef NO_32X\r
93f9619e 841 if (PicoIn.AHW & PAHW_32X) {\r
b4db550e 842 memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));\r
843 memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));\r
844 memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));\r
845 Pico32x.dirty_pal = 1;\r
846 }\r
f3a57b2d 847#endif\r
a20300bf 848 free(t);\r
b4db550e 849}\r
850\r
ed4402a7 851// vim:shiftwidth=2:ts=2:expandtab\r