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