stop IdleDet from affecting save states
[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.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 // ---------------------------------------------------------------------------\r
82 \r
83 typedef 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
103   CHUNK_CDC,     // old\r
104   CHUNK_CDD,     // 20 old\r
105   CHUNK_SCD,     // old\r
106   CHUNK_RC,      // old\r
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
125   CHUNK_32X_EVT,\r
126   CHUNK_32X_FIRST = CHUNK_MSH2,\r
127   CHUNK_32X_LAST = CHUNK_32X_EVT,\r
128   // add new stuff here\r
129   CHUNK_CD_EVT = 50,\r
130   CHUNK_CD_GFX,\r
131   CHUNK_CD_CDC,\r
132   CHUNK_CD_CDD,\r
133   //\r
134   CHUNK_DEFAULT_COUNT,\r
135   CHUNK_CARTHW_ = CHUNK_CARTHW,  // 64 (defined in PicoInt)\r
136 } chunk_name_e;\r
137 \r
138 static const char * const chunk_names[CHUNK_DEFAULT_COUNT] = {\r
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
181   "events",\r
182 };\r
183 \r
184 static 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
194 #define CHUNK_LIMIT_W 18772 // sizeof(cdc)\r
195 \r
196 #define CHECKED_WRITE(name,len,data) { \\r
197   if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
198     strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
199     PicoStateProgressCB(sbuff); \\r
200   } \\r
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
205 }\r
206 \r
207 #define CHECKED_WRITE_BUFF(name,buff) { \\r
208   if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r
209     strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
210     PicoStateProgressCB(sbuff); \\r
211   } \\r
212   if (!write_chunk(name, sizeof(buff), &buff, file)) \\r
213     goto out; \\r
214 }\r
215 \r
216 static 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
221   void *buf2 = NULL;\r
222   int ver = 0x0191; // not really used..\r
223   int retval = -1;\r
224   int len;\r
225 \r
226   areaWrite("PicoSEXT", 1, 8, file);\r
227   areaWrite(&ver, 1, 4, file);\r
228 \r
229   if (!(PicoIn.AHW & PAHW_SMS)) {\r
230     // the patches can cause incompatible saves with no-idle\r
231     SekFinishIdleDet();\r
232 \r
233     memset(buff, 0, sizeof(buff));\r
234     SekPackCpu(buff, 0);\r
235     CHECKED_WRITE_BUFF(CHUNK_M68K,  buff);\r
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
239     ym2612_pack_state();\r
240     CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);\r
241 \r
242     if (!(PicoIn.opt & POPT_DIS_IDLE_DET))\r
243       SekInitIdleDet();\r
244   }\r
245   else {\r
246     CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r
247   }\r
248 \r
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
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
259   if (PicoIn.AHW & PAHW_MCD)\r
260   {\r
261     buf2 = malloc(CHUNK_LIMIT_W);\r
262     if (buf2 == NULL)\r
263       return -1;\r
264 \r
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
269     memcpy(&Pico_mcd->m.hint_vector, Pico_mcd->bios + 0x72,\r
270       sizeof(Pico_mcd->m.hint_vector));\r
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
279     CHECKED_WRITE_BUFF(CHUNK_MISC_CD,  Pico_mcd->m);\r
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
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
288     len = cdd_context_save(buf2);\r
289     CHECKED_WRITE(CHUNK_CD_CDD, len, buf2);\r
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
295 #ifndef NO_32X\r
296   if (PicoIn.AHW & PAHW_32X)\r
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
304     CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, sh2s[0].data_array);\r
305     CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, sh2s[0].peri_regs);\r
306 \r
307     sh2_pack(&sh2s[1], cpubuff);\r
308     CHECKED_WRITE_BUFF(CHUNK_SSH2,      cpubuff);\r
309     CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, sh2s[1].data_array);\r
310     CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, sh2s[1].peri_regs);\r
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
319 \r
320     memset(buff, 0, 0x40);\r
321     memcpy(buff, p32x_event_times, sizeof(p32x_event_times));\r
322     CHECKED_WRITE(CHUNK_32X_EVT, 0x40, buff);\r
323   }\r
324 #endif\r
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
335   retval = 0;\r
336 \r
337 out:\r
338   if (buf2 != NULL)\r
339     free(buf2);\r
340   return retval;\r
341 }\r
342 \r
343 static 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
348   goto out; \\r
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
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
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
379 static 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
384   unsigned char *buf = NULL;\r
385   unsigned char chunk;\r
386   void *ym2612_regs;\r
387   int len_check;\r
388   int retval = -1;\r
389   char header[8];\r
390   int ver, len;\r
391 \r
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
396   buf = malloc(CHUNK_LIMIT_R);\r
397   if (buf == NULL)\r
398     return -1;\r
399 \r
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
406   memset(pcd_event_times, 0, sizeof(pcd_event_times));\r
407   memset(p32x_event_times, 0, sizeof(p32x_event_times));\r
408 \r
409   while (!areaEof(file))\r
410   {\r
411     len_check = 0;\r
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
415     if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r
416       R_ERROR_RETURN("cd chunk in non CD state?");\r
417     if (CHUNK_32X_FIRST <= chunk && chunk <= CHUNK_32X_LAST && !(PicoIn.AHW & PAHW_32X))\r
418       Pico32xStartup();\r
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
428         break;\r
429 \r
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
435       case CHUNK_MISC:    CHECKED_READ_BUFF(Pico.m); break;\r
436       case CHUNK_VIDEO:   CHECKED_READ_BUFF(Pico.video); break;\r
437       case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break;\r
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
460       case CHUNK_MISC_CD:  CHECKED_READ_BUFF(Pico_mcd->m); break;\r
461 \r
462       case CHUNK_CD_EVT:\r
463         CHECKED_READ2(0x40, buf);\r
464         memcpy(pcd_event_times, buf, sizeof(pcd_event_times));\r
465         break;\r
466 \r
467       case CHUNK_CD_GFX:\r
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
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
482       // old, to be removed:\r
483       case CHUNK_CDC:\r
484         CHECKED_READ_LIM(buf);\r
485         cdc_context_load_old(buf);\r
486         break;\r
487 \r
488       case CHUNK_SCD:\r
489         CHECKED_READ_LIM(buf);\r
490         cdd_context_load_old(buf);\r
491         break;\r
492 \r
493       // 32x stuff\r
494 #ifndef NO_32X\r
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
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
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
516 \r
517       case CHUNK_32X_EVT:\r
518         CHECKED_READ2(0x40, buf);\r
519         memcpy(p32x_event_times, buf, sizeof(p32x_event_times));\r
520         break;\r
521 #endif\r
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
537 breakswitch:\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
541   }\r
542 \r
543 readend:\r
544   if (PicoIn.AHW & PAHW_SMS)\r
545     PicoStateLoadedMS();\r
546 \r
547   if (PicoIn.AHW & PAHW_32X)\r
548     Pico32xStateLoaded(1);\r
549 \r
550   if (PicoLoadStateHook != NULL)\r
551     PicoLoadStateHook();\r
552 \r
553   // must unpack 68k and z80 after banks are set up\r
554   if (!(PicoIn.AHW & PAHW_SMS))\r
555     SekUnpackCpu(buff_m68k, 0);\r
556   if (PicoIn.AHW & PAHW_MCD)\r
557     SekUnpackCpu(buff_s68k, 1);\r
558 \r
559   z80_unpack(buff_z80);\r
560 \r
561   // due to dep from 68k cycles..\r
562   Pico.t.m68c_aim = Pico.t.m68c_cnt;\r
563   if (PicoIn.AHW & PAHW_32X)\r
564     Pico32xStateLoaded(0);\r
565   if (PicoIn.AHW & PAHW_MCD)\r
566   {\r
567     SekCycleAimS68k = SekCycleCntS68k;\r
568     pcd_state_loaded();\r
569   }\r
570 \r
571   Pico.m.dirtyPal = 1;\r
572   Pico.video.status &= ~(SR_VB | SR_F);\r
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
575 \r
576   retval = 0;\r
577 \r
578 out:\r
579   free(buf);\r
580   return retval;\r
581 }\r
582 \r
583 static 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
588   if (PicoIn.AHW & PAHW_32X)\r
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
602     if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r
603       R_ERROR_RETURN("cd chunk in non CD state?");\r
604 \r
605     switch (buff[0])\r
606     {\r
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
610       case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r
611 \r
612 #ifndef NO_32X\r
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
627 #endif\r
628       default:\r
629         areaSeek(file, len, SEEK_CUR);\r
630         break;\r
631     }\r
632   }\r
633 \r
634 out:\r
635 readend:\r
636   return 0;\r
637 }\r
638 \r
639 static int pico_state_internal(void *afile, int is_save)\r
640 {\r
641   int ret;\r
642 \r
643   if (is_save)\r
644     ret = state_save(afile);\r
645   else\r
646     ret = state_load(afile);\r
647 \r
648   return ret;\r
649 }\r
650 \r
651 int 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
661   areaClose(afile);\r
662   return ret;\r
663 }\r
664 \r
665 int 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
677 int 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
690     areaRead(PicoMem.vram, 1, sizeof(PicoMem.vram), afile);\r
691     areaSeek(afile, 0x2000, SEEK_CUR);\r
692     areaRead(PicoMem.cram, 1, sizeof(PicoMem.cram), afile);\r
693     areaRead(PicoMem.vsram, 1, sizeof(PicoMem.vsram), afile);\r
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
702 struct 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
719 void *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
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
729   memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r
730 \r
731 #ifndef NO_32X\r
732   if (PicoIn.AHW & PAHW_32X) {\r
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
737 #endif\r
738 \r
739   return t;\r
740 }\r
741 \r
742 void PicoTmpStateRestore(void *data)\r
743 {\r
744   struct PicoTmp *t = data;\r
745   if (t == NULL)\r
746     return;\r
747 \r
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
751   memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r
752   Pico.m.dirtyPal = 1;\r
753 \r
754 #ifndef NO_32X\r
755   if (PicoIn.AHW & PAHW_32X) {\r
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
761 #endif\r
762 }\r
763 \r
764 // vim:shiftwidth=2:ts=2:expandtab\r