stop IdleDet from affecting save states
[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
12#include "../cpu/sh2/sh2.h"\r
13#include "sound/ym2612.h"\r
86b38dc4 14#include "state.h"\r
b4db550e 15\r
16// sn76496\r
17extern int *sn76496_regs;\r
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
63 if (len > 3 && strcmp(fname + len - 3, ".gz") == 0)\r
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
109 CHUNK_IOPORTS, // versions < 1.70 did not save that..\r
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
27e26273 126 CHUNK_32X_FIRST = CHUNK_MSH2,\r
127 CHUNK_32X_LAST = CHUNK_32X_EVT,\r
ae214f1c 128 // add new stuff here\r
129 CHUNK_CD_EVT = 50,\r
a93a80de 130 CHUNK_CD_GFX,\r
3f23709e 131 CHUNK_CD_CDC,\r
274fcc35 132 CHUNK_CD_CDD,\r
b4db550e 133 //\r
134 CHUNK_DEFAULT_COUNT,\r
ae214f1c 135 CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt)\r
b4db550e 136} chunk_name_e;\r
137\r
cfae1ae1 138static const char * const chunk_names[CHUNK_DEFAULT_COUNT] = {\r
b4db550e 139 "INVALID!",\r
140 "M68K state",\r
141 "RAM",\r
142 "VRAM",\r
143 "ZRAM",\r
144 "CRAM", // 5\r
145 "VSRAM",\r
146 "emu state",\r
147 "VIDEO",\r
148 "Z80 state",\r
149 "PSG", // 10\r
150 "FM",\r
151 // CD stuff\r
152 "S68K state",\r
153 "PRG_RAM",\r
154 "WORD_RAM",\r
155 "PCM_RAM", // 15\r
156 "BRAM",\r
157 "GATE ARRAY regs",\r
158 "PCM state",\r
159 "CDC",\r
160 "CDD", // 20\r
161 "SCD",\r
162 "GFX chip",\r
163 "MCD state",\r
164 //\r
165 "IO",\r
166 "SMS state", // 25\r
167 // 32x\r
168 "MSH2",\r
169 "MSH2 data",\r
170 "MSH2 peri",\r
171 "SSH2",\r
172 "SSH2 data", // 30\r
173 "SSH2 peri",\r
174 "32X system regs",\r
175 "M68K BIOS",\r
176 "MSH2 BIOS",\r
177 "SSH2 BIOS", // 35\r
178 "SDRAM",\r
179 "DRAM",\r
180 "PAL",\r
6a98f03e 181 "events",\r
b4db550e 182};\r
183\r
184static int write_chunk(chunk_name_e name, int len, void *data, void *file)\r
185{\r
186 size_t bwritten = 0;\r
187 bwritten += areaWrite(&name, 1, 1, file);\r
188 bwritten += areaWrite(&len, 1, 4, file);\r
189 bwritten += areaWrite(data, 1, len, file);\r
190\r
191 return (bwritten == len + 4 + 1);\r
192}\r
193\r
3f23709e 194#define CHUNK_LIMIT_W 18772 // sizeof(cdc)\r
195\r
b4db550e 196#define CHECKED_WRITE(name,len,data) { \\r
cfae1ae1 197 if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
b4db550e 198 strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
199 PicoStateProgressCB(sbuff); \\r
200 } \\r
3f23709e 201 if (data == buf2 && len > CHUNK_LIMIT_W) \\r
202 goto out; \\r
203 if (!write_chunk(name, len, data, file)) \\r
204 goto out; \\r
b4db550e 205}\r
206\r
207#define CHECKED_WRITE_BUFF(name,buff) { \\r
cfae1ae1 208 if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
b4db550e 209 strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
210 PicoStateProgressCB(sbuff); \\r
211 } \\r
3f23709e 212 if (!write_chunk(name, sizeof(buff), &buff, file)) \\r
213 goto out; \\r
b4db550e 214}\r
215\r
216static int state_save(void *file)\r
217{\r
218 char sbuff[32] = "Saving.. ";\r
219 unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r
220 void *ym2612_regs = YM2612GetRegs();\r
3f23709e 221 void *buf2 = NULL;\r
222 int ver = 0x0191; // not really used..\r
223 int retval = -1;\r
a93a80de 224 int len;\r
b4db550e 225\r
226 areaWrite("PicoSEXT", 1, 8, file);\r
227 areaWrite(&ver, 1, 4, file);\r
228\r
93f9619e 229 if (!(PicoIn.AHW & PAHW_SMS)) {\r
7e056c85 230 // the patches can cause incompatible saves with no-idle\r
231 SekFinishIdleDet();\r
232\r
b4db550e 233 memset(buff, 0, sizeof(buff));\r
234 SekPackCpu(buff, 0);\r
235 CHECKED_WRITE_BUFF(CHUNK_M68K, buff);\r
88fd63ad 236 CHECKED_WRITE_BUFF(CHUNK_RAM, PicoMem.ram);\r
237 CHECKED_WRITE_BUFF(CHUNK_VSRAM, PicoMem.vsram);\r
238 CHECKED_WRITE_BUFF(CHUNK_IOPORTS, PicoMem.ioports);\r
b4db550e 239 ym2612_pack_state();\r
240 CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);\r
7e056c85 241\r
242 if (!(PicoIn.opt & POPT_DIS_IDLE_DET))\r
243 SekInitIdleDet();\r
b4db550e 244 }\r
245 else {\r
246 CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r
247 }\r
248\r
88fd63ad 249 CHECKED_WRITE_BUFF(CHUNK_VRAM, PicoMem.vram);\r
250 CHECKED_WRITE_BUFF(CHUNK_ZRAM, PicoMem.zram);\r
251 CHECKED_WRITE_BUFF(CHUNK_CRAM, PicoMem.cram);\r
b4db550e 252 CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);\r
253 CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r
254\r
255 z80_pack(buff_z80);\r
256 CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);\r
257 CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);\r
258\r
93f9619e 259 if (PicoIn.AHW & PAHW_MCD)\r
b4db550e 260 {\r
3f23709e 261 buf2 = malloc(CHUNK_LIMIT_W);\r
262 if (buf2 == NULL)\r
263 return -1;\r
264\r
b4db550e 265 memset(buff, 0, sizeof(buff));\r
266 SekPackCpu(buff, 1);\r
267 if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r
268 wram_1M_to_2M(Pico_mcd->word_ram2M);\r
895d1512 269 memcpy(&Pico_mcd->m.hint_vector, Pico_mcd->bios + 0x72,\r
270 sizeof(Pico_mcd->m.hint_vector));\r
b4db550e 271\r
272 CHECKED_WRITE_BUFF(CHUNK_S68K, buff);\r
273 CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);\r
274 CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format\r
275 CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);\r
276 CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);\r
277 CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
278 CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);\r
b4db550e 279 CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);\r
ae214f1c 280 memset(buff, 0, 0x40);\r
281 memcpy(buff, pcd_event_times, sizeof(pcd_event_times));\r
282 CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff);\r
3f23709e 283\r
284 len = gfx_context_save(buf2);\r
285 CHECKED_WRITE(CHUNK_CD_GFX, len, buf2);\r
286 len = cdc_context_save(buf2);\r
287 CHECKED_WRITE(CHUNK_CD_CDC, len, buf2);\r
274fcc35 288 len = cdd_context_save(buf2);\r
289 CHECKED_WRITE(CHUNK_CD_CDD, len, buf2);\r
b4db550e 290\r
291 if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
292 wram_2M_to_1M(Pico_mcd->word_ram2M);\r
293 }\r
294\r
f3a57b2d 295#ifndef NO_32X\r
93f9619e 296 if (PicoIn.AHW & PAHW_32X)\r
b4db550e 297 {\r
298 unsigned char cpubuff[SH2_STATE_SIZE];\r
299\r
300 memset(cpubuff, 0, sizeof(cpubuff));\r
301\r
302 sh2_pack(&sh2s[0], cpubuff);\r
303 CHECKED_WRITE_BUFF(CHUNK_MSH2, cpubuff);\r
f81107f5 304 CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, sh2s[0].data_array);\r
305 CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, sh2s[0].peri_regs);\r
b4db550e 306\r
307 sh2_pack(&sh2s[1], cpubuff);\r
308 CHECKED_WRITE_BUFF(CHUNK_SSH2, cpubuff);\r
f81107f5 309 CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, sh2s[1].data_array);\r
310 CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, sh2s[1].peri_regs);\r
b4db550e 311\r
312 CHECKED_WRITE_BUFF(CHUNK_32XSYS, Pico32x);\r
313 CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);\r
314 CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);\r
315 CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);\r
316 CHECKED_WRITE_BUFF(CHUNK_SDRAM, Pico32xMem->sdram);\r
317 CHECKED_WRITE_BUFF(CHUNK_DRAM, Pico32xMem->dram);\r
318 CHECKED_WRITE_BUFF(CHUNK_32XPAL, Pico32xMem->pal);\r
ed4402a7 319\r
6a98f03e 320 memset(buff, 0, 0x40);\r
ae214f1c 321 memcpy(buff, p32x_event_times, sizeof(p32x_event_times));\r
6a98f03e 322 CHECKED_WRITE(CHUNK_32X_EVT, 0x40, buff);\r
b4db550e 323 }\r
f3a57b2d 324#endif\r
b4db550e 325\r
326 if (carthw_chunks != NULL)\r
327 {\r
328 carthw_state_chunk *chwc;\r
329 if (PicoStateProgressCB)\r
330 PicoStateProgressCB("Saving.. cart hw state");\r
331 for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)\r
332 CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r
333 }\r
334\r
3f23709e 335 retval = 0;\r
336\r
337out:\r
338 if (buf2 != NULL)\r
339 free(buf2);\r
340 return retval;\r
b4db550e 341}\r
342\r
343static int g_read_offs = 0;\r
344\r
345#define R_ERROR_RETURN(error) \\r
346{ \\r
347 elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r
3f23709e 348 goto out; \\r
b4db550e 349}\r
350\r
351// when is eof really set?\r
352#define CHECKED_READ(len,data) { \\r
353 if (areaRead(data, 1, len, file) != len) { \\r
354 if (len == 1 && areaEof(file)) goto readend; \\r
355 R_ERROR_RETURN("areaRead: premature EOF\n"); \\r
b4db550e 356 } \\r
357 g_read_offs += len; \\r
358}\r
359\r
360#define CHECKED_READ2(len2,data) { \\r
361 if (len2 != len) { \\r
362 elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \\r
363 if (len > len2) R_ERROR_RETURN("failed."); \\r
364 /* else read anyway and hope for the best.. */ \\r
365 } \\r
366 CHECKED_READ(len, data); \\r
367}\r
368\r
369#define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r
370\r
3f23709e 371#define CHUNK_LIMIT_R 0x10960 // sizeof(old_cdc)\r
372\r
373#define CHECKED_READ_LIM(data) { \\r
374 if (len > CHUNK_LIMIT_R) \\r
375 R_ERROR_RETURN("chunk size over limit."); \\r
376 CHECKED_READ(len, data); \\r
377}\r
378\r
b4db550e 379static int state_load(void *file)\r
380{\r
381 unsigned char buff_m68k[0x60], buff_s68k[0x60];\r
382 unsigned char buff_z80[Z80_STATE_SIZE];\r
383 unsigned char buff_sh2[SH2_STATE_SIZE];\r
3f23709e 384 unsigned char *buf = NULL;\r
b4db550e 385 unsigned char chunk;\r
386 void *ym2612_regs;\r
3f23709e 387 int len_check;\r
388 int retval = -1;\r
b4db550e 389 char header[8];\r
390 int ver, len;\r
391\r
03065bb6 392 memset(buff_m68k, 0, sizeof(buff_m68k));\r
393 memset(buff_s68k, 0, sizeof(buff_s68k));\r
394 memset(buff_z80, 0, sizeof(buff_z80));\r
395\r
3f23709e 396 buf = malloc(CHUNK_LIMIT_R);\r
397 if (buf == NULL)\r
398 return -1;\r
399\r
b4db550e 400 g_read_offs = 0;\r
401 CHECKED_READ(8, header);\r
402 if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r
403 R_ERROR_RETURN("bad header");\r
404 CHECKED_READ(4, &ver);\r
405\r
ae214f1c 406 memset(pcd_event_times, 0, sizeof(pcd_event_times));\r
407 memset(p32x_event_times, 0, sizeof(p32x_event_times));\r
408\r
b4db550e 409 while (!areaEof(file))\r
410 {\r
3f23709e 411 len_check = 0;\r
b4db550e 412 CHECKED_READ(1, &chunk);\r
413 CHECKED_READ(4, &len);\r
414 if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
93f9619e 415 if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r
b4db550e 416 R_ERROR_RETURN("cd chunk in non CD state?");\r
93f9619e 417 if (CHUNK_32X_FIRST <= chunk && chunk <= CHUNK_32X_LAST && !(PicoIn.AHW & PAHW_32X))\r
27e26273 418 Pico32xStartup();\r
b4db550e 419\r
420 switch (chunk)\r
421 {\r
422 case CHUNK_M68K:\r
423 CHECKED_READ_BUFF(buff_m68k);\r
424 break;\r
425\r
426 case CHUNK_Z80:\r
427 CHECKED_READ_BUFF(buff_z80);\r
b4db550e 428 break;\r
429\r
88fd63ad 430 case CHUNK_RAM: CHECKED_READ_BUFF(PicoMem.ram); break;\r
431 case CHUNK_VRAM: CHECKED_READ_BUFF(PicoMem.vram); break;\r
432 case CHUNK_ZRAM: CHECKED_READ_BUFF(PicoMem.zram); break;\r
433 case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); break;\r
434 case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); break;\r
b4db550e 435 case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;\r
436 case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;\r
88fd63ad 437 case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break;\r
b4db550e 438 case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;\r
439 case CHUNK_FM:\r
440 ym2612_regs = YM2612GetRegs();\r
441 CHECKED_READ2(0x200+4, ym2612_regs);\r
442 ym2612_unpack_state();\r
443 break;\r
444\r
445 case CHUNK_SMS:\r
446 CHECKED_READ_BUFF(Pico.ms);\r
447 break;\r
448\r
449 // cd stuff\r
450 case CHUNK_S68K:\r
451 CHECKED_READ_BUFF(buff_s68k);\r
452 break;\r
453\r
454 case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;\r
455 case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;\r
456 case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;\r
457 case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;\r
458 case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
459 case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
b4db550e 460 case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;\r
461\r
ae214f1c 462 case CHUNK_CD_EVT:\r
3f23709e 463 CHECKED_READ2(0x40, buf);\r
464 memcpy(pcd_event_times, buf, sizeof(pcd_event_times));\r
ae214f1c 465 break;\r
466\r
a93a80de 467 case CHUNK_CD_GFX:\r
3f23709e 468 CHECKED_READ_LIM(buf);\r
469 len_check = gfx_context_load(buf);\r
470 break;\r
471\r
472 case CHUNK_CD_CDC:\r
473 CHECKED_READ_LIM(buf);\r
474 len_check = cdc_context_load(buf);\r
475 break;\r
476\r
274fcc35 477 case CHUNK_CD_CDD:\r
478 CHECKED_READ_LIM(buf);\r
479 len_check = cdd_context_load(buf);\r
480 break;\r
481\r
3f23709e 482 // old, to be removed:\r
483 case CHUNK_CDC:\r
484 CHECKED_READ_LIM(buf);\r
485 cdc_context_load_old(buf);\r
a93a80de 486 break;\r
487\r
274fcc35 488 case CHUNK_SCD:\r
489 CHECKED_READ_LIM(buf);\r
490 cdd_context_load_old(buf);\r
491 break;\r
492\r
b4db550e 493 // 32x stuff\r
f3a57b2d 494#ifndef NO_32X\r
b4db550e 495 case CHUNK_MSH2:\r
496 CHECKED_READ_BUFF(buff_sh2);\r
497 sh2_unpack(&sh2s[0], buff_sh2);\r
498 break;\r
499\r
500 case CHUNK_SSH2:\r
501 CHECKED_READ_BUFF(buff_sh2);\r
502 sh2_unpack(&sh2s[1], buff_sh2);\r
503 break;\r
504\r
f81107f5 505 case CHUNK_MSH2_DATA: CHECKED_READ_BUFF(sh2s[0].data_array); break;\r
506 case CHUNK_MSH2_PERI: CHECKED_READ_BUFF(sh2s[0].peri_regs); break;\r
507 case CHUNK_SSH2_DATA: CHECKED_READ_BUFF(sh2s[1].data_array); break;\r
508 case CHUNK_SSH2_PERI: CHECKED_READ_BUFF(sh2s[1].peri_regs); break;\r
b4db550e 509 case CHUNK_32XSYS: CHECKED_READ_BUFF(Pico32x); break;\r
510 case CHUNK_M68K_BIOS: CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;\r
511 case CHUNK_MSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;\r
512 case CHUNK_SSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;\r
513 case CHUNK_SDRAM: CHECKED_READ_BUFF(Pico32xMem->sdram); break;\r
514 case CHUNK_DRAM: CHECKED_READ_BUFF(Pico32xMem->dram); break;\r
515 case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break;\r
6a98f03e 516\r
517 case CHUNK_32X_EVT:\r
3f23709e 518 CHECKED_READ2(0x40, buf);\r
519 memcpy(p32x_event_times, buf, sizeof(p32x_event_times));\r
6a98f03e 520 break;\r
f3a57b2d 521#endif\r
b4db550e 522 default:\r
523 if (carthw_chunks != NULL)\r
524 {\r
525 carthw_state_chunk *chwc;\r
526 for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {\r
527 if (chwc->chunk == chunk) {\r
528 CHECKED_READ2(chwc->size, chwc->ptr);\r
529 goto breakswitch;\r
530 }\r
531 }\r
532 }\r
533 elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);\r
534 areaSeek(file, len, SEEK_CUR);\r
535 break;\r
536 }\r
3f23709e 537breakswitch:\r
538 if (len_check != 0 && len_check != len)\r
539 elprintf(EL_STATUS, "load_state: chunk %d has bad len %d/%d",\r
540 len, len_check);\r
b4db550e 541 }\r
542\r
543readend:\r
93f9619e 544 if (PicoIn.AHW & PAHW_SMS)\r
b4db550e 545 PicoStateLoadedMS();\r
546\r
93f9619e 547 if (PicoIn.AHW & PAHW_32X)\r
27e26273 548 Pico32xStateLoaded(1);\r
549\r
e23f4494 550 if (PicoLoadStateHook != NULL)\r
551 PicoLoadStateHook();\r
552\r
03065bb6 553 // must unpack 68k and z80 after banks are set up\r
93f9619e 554 if (!(PicoIn.AHW & PAHW_SMS))\r
b4db550e 555 SekUnpackCpu(buff_m68k, 0);\r
93f9619e 556 if (PicoIn.AHW & PAHW_MCD)\r
27e26273 557 SekUnpackCpu(buff_s68k, 1);\r
b4db550e 558\r
03065bb6 559 z80_unpack(buff_z80);\r
560\r
27e26273 561 // due to dep from 68k cycles..\r
88fd63ad 562 Pico.t.m68c_aim = Pico.t.m68c_cnt;\r
93f9619e 563 if (PicoIn.AHW & PAHW_32X)\r
27e26273 564 Pico32xStateLoaded(0);\r
93f9619e 565 if (PicoIn.AHW & PAHW_MCD)\r
ae214f1c 566 {\r
567 SekCycleAimS68k = SekCycleCntS68k;\r
568 pcd_state_loaded();\r
ae214f1c 569 }\r
b4db550e 570\r
e6488636 571 Pico.m.dirtyPal = 1;\r
572 Pico.video.status &= ~(SR_VB | SR_F);\r
0e4bde9b 573 Pico.video.status |= ((Pico.video.reg[1] >> 3) ^ SR_VB) & SR_VB;\r
574 Pico.video.status |= (Pico.video.pending_ints << 2) & SR_F;\r
e6488636 575\r
3f23709e 576 retval = 0;\r
577\r
578out:\r
579 free(buf);\r
580 return retval;\r
b4db550e 581}\r
582\r
583static int state_load_gfx(void *file)\r
584{\r
585 int ver, len, found = 0, to_find = 4;\r
586 char buff[8];\r
587\r
93f9619e 588 if (PicoIn.AHW & PAHW_32X)\r
b4db550e 589 to_find += 2;\r
590\r
591 g_read_offs = 0;\r
592 CHECKED_READ(8, buff);\r
593 if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))\r
594 R_ERROR_RETURN("bad header");\r
595 CHECKED_READ(4, &ver);\r
596\r
597 while (!areaEof(file) && found < to_find)\r
598 {\r
599 CHECKED_READ(1, buff);\r
600 CHECKED_READ(4, &len);\r
601 if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
93f9619e 602 if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r
b4db550e 603 R_ERROR_RETURN("cd chunk in non CD state?");\r
604\r
605 switch (buff[0])\r
606 {\r
88fd63ad 607 case CHUNK_VRAM: CHECKED_READ_BUFF(PicoMem.vram); found++; break;\r
608 case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); found++; break;\r
609 case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); found++; break;\r
b4db550e 610 case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r
611\r
f3a57b2d 612#ifndef NO_32X\r
b4db550e 613 case CHUNK_DRAM:\r
614 if (Pico32xMem != NULL)\r
615 CHECKED_READ_BUFF(Pico32xMem->dram);\r
616 break;\r
617\r
618 case CHUNK_32XPAL:\r
619 if (Pico32xMem != NULL)\r
620 CHECKED_READ_BUFF(Pico32xMem->pal);\r
621 Pico32x.dirty_pal = 1;\r
622 break;\r
623\r
624 case CHUNK_32XSYS:\r
625 CHECKED_READ_BUFF(Pico32x);\r
626 break;\r
f3a57b2d 627#endif\r
b4db550e 628 default:\r
629 areaSeek(file, len, SEEK_CUR);\r
630 break;\r
631 }\r
632 }\r
633\r
3f23709e 634out:\r
b4db550e 635readend:\r
636 return 0;\r
637}\r
638\r
86b38dc4 639static int pico_state_internal(void *afile, int is_save)\r
b4db550e 640{\r
b4db550e 641 int ret;\r
642\r
b4db550e 643 if (is_save)\r
644 ret = state_save(afile);\r
e6488636 645 else\r
b4db550e 646 ret = state_load(afile);\r
b4db550e 647\r
86b38dc4 648 return ret;\r
649}\r
650\r
651int PicoState(const char *fname, int is_save)\r
652{\r
653 void *afile = NULL;\r
654 int ret;\r
655\r
656 afile = open_save_file(fname, is_save);\r
657 if (afile == NULL)\r
658 return -1;\r
659\r
660 ret = pico_state_internal(afile, is_save);\r
b4db550e 661 areaClose(afile);\r
662 return ret;\r
663}\r
664\r
86b38dc4 665int PicoStateFP(void *afile, int is_save,\r
666 arearw *read, arearw *write, areaeof *eof, areaseek *seek)\r
667{\r
668 areaRead = read;\r
669 areaWrite = write;\r
670 areaEof = eof;\r
671 areaSeek = seek;\r
672 areaClose = NULL;\r
673\r
674 return pico_state_internal(afile, is_save);\r
675}\r
676\r
b4db550e 677int PicoStateLoadGfx(const char *fname)\r
678{\r
679 void *afile;\r
680 int ret;\r
681\r
682 afile = open_save_file(fname, 0);\r
683 if (afile == NULL)\r
684 return -1;\r
685\r
686 ret = state_load_gfx(afile);\r
687 if (ret != 0) {\r
688 // assume legacy\r
689 areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM\r
88fd63ad 690 areaRead(PicoMem.vram, 1, sizeof(PicoMem.vram), afile);\r
b4db550e 691 areaSeek(afile, 0x2000, SEEK_CUR);\r
88fd63ad 692 areaRead(PicoMem.cram, 1, sizeof(PicoMem.cram), afile);\r
693 areaRead(PicoMem.vsram, 1, sizeof(PicoMem.vsram), afile);\r
b4db550e 694 areaSeek(afile, 0x221a0, SEEK_SET);\r
695 areaRead(&Pico.video, 1, sizeof(Pico.video), afile);\r
696 }\r
697 areaClose(afile);\r
698 return 0;\r
699}\r
700\r
701// tmp state\r
702struct PicoTmp\r
703{\r
704 unsigned short vram[0x8000];\r
705 unsigned short cram[0x40];\r
706 unsigned short vsram[0x40];\r
707\r
708 //struct PicoMisc m;\r
709 struct PicoVideo video;\r
710\r
711 struct {\r
712 struct Pico32x p32x;\r
713 unsigned short dram[2][0x20000/2];\r
714 unsigned short pal[0x100];\r
715 } t32x;\r
716};\r
717\r
718// returns data ptr to free() or PicoTmpStateRestore()\r
719void *PicoTmpStateSave(void)\r
720{\r
721 // gfx only for now\r
722 struct PicoTmp *t = malloc(sizeof(*t));\r
723 if (t == NULL)\r
724 return NULL;\r
725\r
88fd63ad 726 memcpy(t->vram, PicoMem.vram, sizeof(PicoMem.vram));\r
727 memcpy(t->cram, PicoMem.cram, sizeof(PicoMem.cram));\r
728 memcpy(t->vsram, PicoMem.vsram, sizeof(PicoMem.vsram));\r
b4db550e 729 memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r
730\r
f3a57b2d 731#ifndef NO_32X\r
93f9619e 732 if (PicoIn.AHW & PAHW_32X) {\r
b4db550e 733 memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));\r
734 memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));\r
735 memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));\r
736 }\r
f3a57b2d 737#endif\r
b4db550e 738\r
739 return t;\r
740}\r
741\r
742void PicoTmpStateRestore(void *data)\r
743{\r
744 struct PicoTmp *t = data;\r
745 if (t == NULL)\r
746 return;\r
747\r
88fd63ad 748 memcpy(PicoMem.vram, t->vram, sizeof(PicoMem.vram));\r
749 memcpy(PicoMem.cram, t->cram, sizeof(PicoMem.cram));\r
750 memcpy(PicoMem.vsram, t->vsram, sizeof(PicoMem.vsram));\r
b4db550e 751 memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r
752 Pico.m.dirtyPal = 1;\r
753\r
f3a57b2d 754#ifndef NO_32X\r
93f9619e 755 if (PicoIn.AHW & PAHW_32X) {\r
b4db550e 756 memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));\r
757 memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));\r
758 memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));\r
759 Pico32x.dirty_pal = 1;\r
760 }\r
f3a57b2d 761#endif\r
b4db550e 762}\r
763\r
ed4402a7 764// vim:shiftwidth=2:ts=2:expandtab\r