32x and sms savestates. Core-independent z80 state. SS bugfixing/refactoring.
[picodrive.git] / pico / state.c
1 // (c) Copyright 2004 Dave, All rights reserved.\r
2 // (c) Copyright 2006-2010 notaz, All rights reserved.\r
3 // Free for non-commercial use.\r
4 \r
5 // For commercial use, separate licencing terms must be obtained.\r
6 \r
7 \r
8 #include "pico_int.h"\r
9 #include <zlib/zlib.h>\r
10 \r
11 #include "../cpu/sh2/sh2.h"\r
12 #include "sound/ym2612.h"\r
13 \r
14 // sn76496\r
15 extern int *sn76496_regs;\r
16 \r
17 typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);\r
18 typedef size_t (areaeof)(void *file);\r
19 typedef int    (areaseek)(void *file, long offset, int whence);\r
20 typedef int    (areaclose)(void *file);\r
21 \r
22 static arearw    *areaRead;\r
23 static arearw    *areaWrite;\r
24 static areaeof   *areaEof;\r
25 static areaseek  *areaSeek;\r
26 static areaclose *areaClose;\r
27 \r
28 carthw_state_chunk *carthw_chunks;\r
29 void (*PicoStateProgressCB)(const char *str);\r
30 void (*PicoLoadStateHook)(void);\r
31 \r
32 \r
33 /* I/O functions */\r
34 static size_t gzRead2(void *p, size_t _size, size_t _n, void *file)\r
35 {\r
36   return gzread(file, p, _size * _n);\r
37 }\r
38 \r
39 static size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)\r
40 {\r
41   return gzwrite(file, p, _size * _n);\r
42 }\r
43 \r
44 static void set_cbs(int gz)\r
45 {\r
46   if (gz) {\r
47     areaRead  = gzRead2;\r
48     areaWrite = gzWrite2;\r
49     areaEof   = (areaeof *) gzeof;\r
50     areaSeek  = (areaseek *) gzseek;\r
51     areaClose = (areaclose *) gzclose;\r
52   } else {\r
53     areaRead  = (arearw *) fread;\r
54     areaWrite = (arearw *) fwrite;\r
55     areaEof   = (areaeof *) feof;\r
56     areaSeek  = (areaseek *) fseek;\r
57     areaClose = (areaclose *) fclose;\r
58   }\r
59 }\r
60 \r
61 static void *open_save_file(const char *fname, int is_save)\r
62 {\r
63   int len = strlen(fname);\r
64   void *afile = NULL;\r
65 \r
66   if (len > 3 && strcmp(fname + len - 3, ".gz") == 0)\r
67   {\r
68     if ( (afile = gzopen(fname, is_save ? "wb" : "rb")) ) {\r
69       set_cbs(1);\r
70       if (is_save)\r
71         gzsetparams(afile, 9, Z_DEFAULT_STRATEGY);\r
72     }\r
73   }\r
74   else\r
75   {\r
76     if ( (afile = fopen(fname, is_save ? "wb" : "rb")) ) {\r
77       set_cbs(0);\r
78     }\r
79   }\r
80 \r
81   return afile;\r
82 }\r
83 \r
84 // legacy savestate loading\r
85 #define SCANP(f, x) areaRead(&Pico.x, sizeof(Pico.x), 1, f)\r
86 \r
87 static int state_load_legacy(void *file)\r
88 {\r
89   unsigned char head[32];\r
90   unsigned char cpu[0x60];\r
91   unsigned char cpu_z80[Z80_STATE_SIZE];\r
92   void *ym2612_regs;\r
93   int ok;\r
94 \r
95   memset(&cpu,0,sizeof(cpu));\r
96   memset(&cpu_z80,0,sizeof(cpu_z80));\r
97 \r
98   memset(head, 0, sizeof(head));\r
99   areaRead(head, sizeof(head), 1, file);\r
100   if (strcmp((char *)head, "Pico") != 0)\r
101     return -1;\r
102 \r
103   elprintf(EL_STATUS, "legacy savestate");\r
104 \r
105   // Scan all the memory areas:\r
106   SCANP(file, ram);\r
107   SCANP(file, vram);\r
108   SCANP(file, zram);\r
109   SCANP(file, cram);\r
110   SCANP(file, vsram);\r
111 \r
112   // Pack, scan and unpack the cpu data:\r
113   areaRead(cpu, sizeof(cpu), 1, file);\r
114   SekUnpackCpu(cpu, 0);\r
115 \r
116   SCANP(file, m);\r
117   SCANP(file, video);\r
118 \r
119   ok = areaRead(cpu_z80, sizeof(cpu_z80), 1, file) == sizeof(cpu_z80);\r
120   // do not unpack if we fail to load z80 state\r
121   if (!ok) z80_reset();\r
122   else     z80_unpack(cpu_z80);\r
123 \r
124   ym2612_regs = YM2612GetRegs();\r
125   areaRead(sn76496_regs, 28*4, 1, file);\r
126   areaRead(ym2612_regs, 0x200+4, 1, file);\r
127   ym2612_unpack_state();\r
128 \r
129   return 0;\r
130 }\r
131 \r
132 // ---------------------------------------------------------------------------\r
133 \r
134 typedef enum {\r
135   CHUNK_M68K = 1,\r
136   CHUNK_RAM,\r
137   CHUNK_VRAM,\r
138   CHUNK_ZRAM,\r
139   CHUNK_CRAM,    // 5\r
140   CHUNK_VSRAM,\r
141   CHUNK_MISC,\r
142   CHUNK_VIDEO,\r
143   CHUNK_Z80,\r
144   CHUNK_PSG,     // 10\r
145   CHUNK_FM,\r
146   // CD stuff\r
147   CHUNK_S68K,\r
148   CHUNK_PRG_RAM,\r
149   CHUNK_WORD_RAM,\r
150   CHUNK_PCM_RAM, // 15\r
151   CHUNK_BRAM,\r
152   CHUNK_GA_REGS,\r
153   CHUNK_PCM,\r
154   CHUNK_CDC,\r
155   CHUNK_CDD,     // 20\r
156   CHUNK_SCD,\r
157   CHUNK_RC,\r
158   CHUNK_MISC_CD,\r
159   //\r
160   CHUNK_IOPORTS, // versions < 1.70 did not save that..\r
161   CHUNK_SMS,     // 25\r
162   // 32x\r
163   CHUNK_MSH2,\r
164   CHUNK_MSH2_DATA,\r
165   CHUNK_MSH2_PERI,\r
166   CHUNK_SSH2,\r
167   CHUNK_SSH2_DATA, // 30\r
168   CHUNK_SSH2_PERI,\r
169   CHUNK_32XSYS,\r
170   CHUNK_M68K_BIOS,\r
171   CHUNK_MSH2_BIOS,\r
172   CHUNK_SSH2_BIOS, // 35\r
173   CHUNK_SDRAM,\r
174   CHUNK_DRAM,\r
175   CHUNK_32XPAL,\r
176   //\r
177   CHUNK_DEFAULT_COUNT,\r
178   CHUNK_CARTHW_ = CHUNK_CARTHW,  // defined in PicoInt\r
179 } chunk_name_e;\r
180 \r
181 static const char * const chunk_names[] = {\r
182   "INVALID!",\r
183   "M68K state",\r
184   "RAM",\r
185   "VRAM",\r
186   "ZRAM",\r
187   "CRAM",      // 5\r
188   "VSRAM",\r
189   "emu state",\r
190   "VIDEO",\r
191   "Z80 state",\r
192   "PSG",       // 10\r
193   "FM",\r
194   // CD stuff\r
195   "S68K state",\r
196   "PRG_RAM",\r
197   "WORD_RAM",\r
198   "PCM_RAM",   // 15\r
199   "BRAM",\r
200   "GATE ARRAY regs",\r
201   "PCM state",\r
202   "CDC",\r
203   "CDD",       // 20\r
204   "SCD",\r
205   "GFX chip",\r
206   "MCD state",\r
207   //\r
208   "IO",\r
209   "SMS state", // 25\r
210   // 32x\r
211   "MSH2",\r
212   "MSH2 data",\r
213   "MSH2 peri",\r
214   "SSH2",\r
215   "SSH2 data", // 30\r
216   "SSH2 peri",\r
217   "32X system regs",\r
218   "M68K BIOS",\r
219   "MSH2 BIOS",\r
220   "SSH2 BIOS", // 35\r
221   "SDRAM",\r
222   "DRAM",\r
223   "PAL",\r
224 };\r
225 \r
226 static int write_chunk(chunk_name_e name, int len, void *data, void *file)\r
227 {\r
228   size_t bwritten = 0;\r
229   bwritten += areaWrite(&name, 1, 1, file);\r
230   bwritten += areaWrite(&len, 1, 4, file);\r
231   bwritten += areaWrite(data, 1, len, file);\r
232 \r
233   return (bwritten == len + 4 + 1);\r
234 }\r
235 \r
236 #define CHECKED_WRITE(name,len,data) { \\r
237   if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \\r
238     strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
239     PicoStateProgressCB(sbuff); \\r
240   } \\r
241   if (!write_chunk(name, len, data, file)) return 1; \\r
242 }\r
243 \r
244 #define CHECKED_WRITE_BUFF(name,buff) { \\r
245   if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \\r
246     strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r
247     PicoStateProgressCB(sbuff); \\r
248   } \\r
249   if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \\r
250 }\r
251 \r
252 static int state_save(void *file)\r
253 {\r
254   char sbuff[32] = "Saving.. ";\r
255   unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r
256   void *ym2612_regs = YM2612GetRegs();\r
257   int ver = 0x0170; // not really used..\r
258 \r
259   areaWrite("PicoSEXT", 1, 8, file);\r
260   areaWrite(&ver, 1, 4, file);\r
261 \r
262   if (!(PicoAHW & PAHW_SMS)) {\r
263     memset(buff, 0, sizeof(buff));\r
264     SekPackCpu(buff, 0);\r
265     CHECKED_WRITE_BUFF(CHUNK_M68K,  buff);\r
266     CHECKED_WRITE_BUFF(CHUNK_RAM,   Pico.ram);\r
267     CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);\r
268     CHECKED_WRITE_BUFF(CHUNK_IOPORTS, Pico.ioports);\r
269     ym2612_pack_state();\r
270     CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);\r
271   }\r
272   else {\r
273     CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r
274   }\r
275 \r
276   CHECKED_WRITE_BUFF(CHUNK_VRAM,  Pico.vram);\r
277   CHECKED_WRITE_BUFF(CHUNK_ZRAM,  Pico.zram);\r
278   CHECKED_WRITE_BUFF(CHUNK_CRAM,  Pico.cram);\r
279   CHECKED_WRITE_BUFF(CHUNK_MISC,  Pico.m);\r
280   CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r
281 \r
282   z80_pack(buff_z80);\r
283   CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);\r
284   CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);\r
285 \r
286   if (PicoAHW & PAHW_MCD)\r
287   {\r
288     memset(buff, 0, sizeof(buff));\r
289     SekPackCpu(buff, 1);\r
290     if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r
291       wram_1M_to_2M(Pico_mcd->word_ram2M);\r
292     Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);\r
293 \r
294     CHECKED_WRITE_BUFF(CHUNK_S68K,     buff);\r
295     CHECKED_WRITE_BUFF(CHUNK_PRG_RAM,  Pico_mcd->prg_ram);\r
296     CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format\r
297     CHECKED_WRITE_BUFF(CHUNK_PCM_RAM,  Pico_mcd->pcm_ram);\r
298     CHECKED_WRITE_BUFF(CHUNK_BRAM,     Pico_mcd->bram);\r
299     CHECKED_WRITE_BUFF(CHUNK_GA_REGS,  Pico_mcd->s68k_regs); // GA regs, not CPU regs\r
300     CHECKED_WRITE_BUFF(CHUNK_PCM,      Pico_mcd->pcm);\r
301     CHECKED_WRITE_BUFF(CHUNK_CDD,      Pico_mcd->cdd);\r
302     CHECKED_WRITE_BUFF(CHUNK_CDC,      Pico_mcd->cdc);\r
303     CHECKED_WRITE_BUFF(CHUNK_SCD,      Pico_mcd->scd);\r
304     CHECKED_WRITE_BUFF(CHUNK_RC,       Pico_mcd->rot_comp);\r
305     CHECKED_WRITE_BUFF(CHUNK_MISC_CD,  Pico_mcd->m);\r
306 \r
307     if (Pico_mcd->s68k_regs[3] & 4) // convert back\r
308       wram_2M_to_1M(Pico_mcd->word_ram2M);\r
309   }\r
310 \r
311   if (PicoAHW & PAHW_32X)\r
312   {\r
313     unsigned char cpubuff[SH2_STATE_SIZE];\r
314 \r
315     memset(cpubuff, 0, sizeof(cpubuff));\r
316 \r
317     sh2_pack(&sh2s[0], cpubuff);\r
318     CHECKED_WRITE_BUFF(CHUNK_MSH2,      cpubuff);\r
319     CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, Pico32xMem->data_array[0]);\r
320     CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, Pico32xMem->sh2_peri_regs[0]);\r
321 \r
322     sh2_pack(&sh2s[1], cpubuff);\r
323     CHECKED_WRITE_BUFF(CHUNK_SSH2,      cpubuff);\r
324     CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, Pico32xMem->data_array[1]);\r
325     CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, Pico32xMem->sh2_peri_regs[1]);\r
326 \r
327     CHECKED_WRITE_BUFF(CHUNK_32XSYS,    Pico32x);\r
328     CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);\r
329     CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);\r
330     CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);\r
331     CHECKED_WRITE_BUFF(CHUNK_SDRAM,     Pico32xMem->sdram);\r
332     CHECKED_WRITE_BUFF(CHUNK_DRAM,      Pico32xMem->dram);\r
333     CHECKED_WRITE_BUFF(CHUNK_32XPAL,    Pico32xMem->pal);\r
334   }\r
335 \r
336   if (carthw_chunks != NULL)\r
337   {\r
338     carthw_state_chunk *chwc;\r
339     if (PicoStateProgressCB)\r
340       PicoStateProgressCB("Saving.. cart hw state");\r
341     for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)\r
342       CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r
343   }\r
344 \r
345   return 0;\r
346 }\r
347 \r
348 static int g_read_offs = 0;\r
349 \r
350 #define R_ERROR_RETURN(error) \\r
351 { \\r
352   elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r
353   return 1; \\r
354 }\r
355 \r
356 // when is eof really set?\r
357 #define CHECKED_READ(len,data) { \\r
358   if (areaRead(data, 1, len, file) != len) { \\r
359     if (len == 1 && areaEof(file)) goto readend; \\r
360     R_ERROR_RETURN("areaRead: premature EOF\n"); \\r
361     return 1; \\r
362   } \\r
363   g_read_offs += len; \\r
364 }\r
365 \r
366 #define CHECKED_READ2(len2,data) { \\r
367   if (len2 != len) { \\r
368     elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \\r
369     if (len > len2) R_ERROR_RETURN("failed."); \\r
370     /* else read anyway and hope for the best.. */ \\r
371   } \\r
372   CHECKED_READ(len, data); \\r
373 }\r
374 \r
375 #define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r
376 \r
377 static int state_load(void *file)\r
378 {\r
379   unsigned char buff_m68k[0x60], buff_s68k[0x60];\r
380   unsigned char buff_z80[Z80_STATE_SIZE];\r
381   unsigned char buff_sh2[SH2_STATE_SIZE];\r
382   unsigned char chunk;\r
383   void *ym2612_regs;\r
384   char header[8];\r
385   int ver, len;\r
386 \r
387   g_read_offs = 0;\r
388   CHECKED_READ(8, header);\r
389   if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r
390     R_ERROR_RETURN("bad header");\r
391   CHECKED_READ(4, &ver);\r
392 \r
393   while (!areaEof(file))\r
394   {\r
395     CHECKED_READ(1, &chunk);\r
396     CHECKED_READ(4, &len);\r
397     if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
398     if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))\r
399       R_ERROR_RETURN("cd chunk in non CD state?");\r
400     if (CHUNK_MSH2 <= chunk && chunk <= CHUNK_32XPAL && !(PicoAHW & PAHW_32X))\r
401       R_ERROR_RETURN("32x chunk in non 32x state?");\r
402 \r
403     switch (chunk)\r
404     {\r
405       case CHUNK_M68K:\r
406         CHECKED_READ_BUFF(buff_m68k);\r
407         break;\r
408 \r
409       case CHUNK_Z80:\r
410         CHECKED_READ_BUFF(buff_z80);\r
411         z80_unpack(buff_z80);\r
412         break;\r
413 \r
414       case CHUNK_RAM:     CHECKED_READ_BUFF(Pico.ram); break;\r
415       case CHUNK_VRAM:    CHECKED_READ_BUFF(Pico.vram); break;\r
416       case CHUNK_ZRAM:    CHECKED_READ_BUFF(Pico.zram); break;\r
417       case CHUNK_CRAM:    CHECKED_READ_BUFF(Pico.cram); break;\r
418       case CHUNK_VSRAM:   CHECKED_READ_BUFF(Pico.vsram); break;\r
419       case CHUNK_MISC:    CHECKED_READ_BUFF(Pico.m); break;\r
420       case CHUNK_VIDEO:   CHECKED_READ_BUFF(Pico.video); break;\r
421       case CHUNK_IOPORTS: CHECKED_READ_BUFF(Pico.ioports); break;\r
422       case CHUNK_PSG:     CHECKED_READ2(28*4, sn76496_regs); break;\r
423       case CHUNK_FM:\r
424         ym2612_regs = YM2612GetRegs();\r
425         CHECKED_READ2(0x200+4, ym2612_regs);\r
426         ym2612_unpack_state();\r
427         break;\r
428 \r
429       case CHUNK_SMS:\r
430         CHECKED_READ_BUFF(Pico.ms);\r
431         break;\r
432 \r
433       // cd stuff\r
434       case CHUNK_S68K:\r
435         CHECKED_READ_BUFF(buff_s68k);\r
436         break;\r
437 \r
438       case CHUNK_PRG_RAM:  CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;\r
439       case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;\r
440       case CHUNK_PCM_RAM:  CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;\r
441       case CHUNK_BRAM:     CHECKED_READ_BUFF(Pico_mcd->bram); break;\r
442       case CHUNK_GA_REGS:  CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r
443       case CHUNK_PCM:      CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r
444       case CHUNK_CDD:      CHECKED_READ_BUFF(Pico_mcd->cdd); break;\r
445       case CHUNK_CDC:      CHECKED_READ_BUFF(Pico_mcd->cdc); break;\r
446       case CHUNK_SCD:      CHECKED_READ_BUFF(Pico_mcd->scd); break;\r
447       case CHUNK_RC:       CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;\r
448       case CHUNK_MISC_CD:  CHECKED_READ_BUFF(Pico_mcd->m); break;\r
449 \r
450       // 32x stuff\r
451       case CHUNK_MSH2:\r
452         CHECKED_READ_BUFF(buff_sh2);\r
453         sh2_unpack(&sh2s[0], buff_sh2);\r
454         break;\r
455 \r
456       case CHUNK_SSH2:\r
457         CHECKED_READ_BUFF(buff_sh2);\r
458         sh2_unpack(&sh2s[1], buff_sh2);\r
459         break;\r
460 \r
461       case CHUNK_MSH2_DATA:   CHECKED_READ_BUFF(Pico32xMem->data_array[0]); break;\r
462       case CHUNK_MSH2_PERI:   CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[0]); break;\r
463       case CHUNK_SSH2_DATA:   CHECKED_READ_BUFF(Pico32xMem->data_array[1]); break;\r
464       case CHUNK_SSH2_PERI:   CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[1]); break;\r
465       case CHUNK_32XSYS:      CHECKED_READ_BUFF(Pico32x); break;\r
466       case CHUNK_M68K_BIOS:   CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;\r
467       case CHUNK_MSH2_BIOS:   CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;\r
468       case CHUNK_SSH2_BIOS:   CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;\r
469       case CHUNK_SDRAM:       CHECKED_READ_BUFF(Pico32xMem->sdram); break;\r
470       case CHUNK_DRAM:        CHECKED_READ_BUFF(Pico32xMem->dram); break;\r
471       case CHUNK_32XPAL:      CHECKED_READ_BUFF(Pico32xMem->pal); break;\r
472 \r
473       default:\r
474         if (carthw_chunks != NULL)\r
475         {\r
476           carthw_state_chunk *chwc;\r
477           for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {\r
478             if (chwc->chunk == chunk) {\r
479               CHECKED_READ2(chwc->size, chwc->ptr);\r
480               goto breakswitch;\r
481             }\r
482           }\r
483         }\r
484         elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);\r
485         areaSeek(file, len, SEEK_CUR);\r
486         break;\r
487     }\r
488 breakswitch:;\r
489   }\r
490 \r
491 readend:\r
492   if (PicoAHW & PAHW_SMS)\r
493     PicoStateLoadedMS();\r
494 \r
495   if (PicoAHW & PAHW_MCD)\r
496   {\r
497     PicoMemStateLoaded();\r
498 \r
499     if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r
500       cdda_start_play();\r
501 \r
502     // must unpack after mem is set up\r
503     SekUnpackCpu(buff_s68k, 1);\r
504   }\r
505 \r
506   if (!(PicoAHW & PAHW_SMS))\r
507     SekUnpackCpu(buff_m68k, 0);\r
508 \r
509   if (PicoAHW & PAHW_32X)\r
510     Pico32xStateLoaded();\r
511 \r
512   return 0;\r
513 }\r
514 \r
515 static int state_load_gfx(void *file)\r
516 {\r
517   int ver, len, found = 0, to_find = 4;\r
518   char buff[8];\r
519 \r
520   if (PicoAHW & PAHW_32X)\r
521     to_find += 2;\r
522 \r
523   g_read_offs = 0;\r
524   CHECKED_READ(8, buff);\r
525   if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))\r
526     R_ERROR_RETURN("bad header");\r
527   CHECKED_READ(4, &ver);\r
528 \r
529   while (!areaEof(file) && found < to_find)\r
530   {\r
531     CHECKED_READ(1, buff);\r
532     CHECKED_READ(4, &len);\r
533     if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r
534     if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))\r
535       R_ERROR_RETURN("cd chunk in non CD state?");\r
536 \r
537     switch (buff[0])\r
538     {\r
539       case CHUNK_VRAM:  CHECKED_READ_BUFF(Pico.vram);  found++; break;\r
540       case CHUNK_CRAM:  CHECKED_READ_BUFF(Pico.cram);  found++; break;\r
541       case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;\r
542       case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r
543 \r
544       case CHUNK_DRAM:\r
545         if (Pico32xMem != NULL)\r
546           CHECKED_READ_BUFF(Pico32xMem->dram);\r
547         break;\r
548 \r
549       case CHUNK_32XPAL:\r
550         if (Pico32xMem != NULL)\r
551           CHECKED_READ_BUFF(Pico32xMem->pal);\r
552         Pico32x.dirty_pal = 1;\r
553         break;\r
554 \r
555       case CHUNK_32XSYS:\r
556         CHECKED_READ_BUFF(Pico32x);\r
557         break;\r
558 \r
559       default:\r
560         areaSeek(file, len, SEEK_CUR);\r
561         break;\r
562     }\r
563   }\r
564 \r
565 readend:\r
566   return 0;\r
567 }\r
568 \r
569 int PicoState(const char *fname, int is_save)\r
570 {\r
571   void *afile = NULL;\r
572   int ret;\r
573 \r
574   afile = open_save_file(fname, is_save);\r
575   if (afile == NULL)\r
576     return -1;\r
577 \r
578   if (is_save)\r
579     ret = state_save(afile);\r
580   else {\r
581     ret = state_load(afile);\r
582     if (ret != 0) {\r
583       areaSeek(afile, 0, SEEK_SET);\r
584       ret = state_load_legacy(afile);\r
585     }\r
586 \r
587     if (PicoLoadStateHook != NULL)\r
588       PicoLoadStateHook();\r
589     Pico.m.dirtyPal = 1;\r
590   }\r
591 \r
592   areaClose(afile);\r
593   return ret;\r
594 }\r
595 \r
596 int PicoStateLoadGfx(const char *fname)\r
597 {\r
598   void *afile;\r
599   int ret;\r
600 \r
601   afile = open_save_file(fname, 0);\r
602   if (afile == NULL)\r
603     return -1;\r
604 \r
605   ret = state_load_gfx(afile);\r
606   if (ret != 0) {\r
607     // assume legacy\r
608     areaSeek(afile, 0x10020, SEEK_SET);  // skip header and RAM\r
609     areaRead(Pico.vram, 1, sizeof(Pico.vram), afile);\r
610     areaSeek(afile, 0x2000, SEEK_CUR);\r
611     areaRead(Pico.cram, 1, sizeof(Pico.cram), afile);\r
612     areaRead(Pico.vsram, 1, sizeof(Pico.vsram), afile);\r
613     areaSeek(afile, 0x221a0, SEEK_SET);\r
614     areaRead(&Pico.video, 1, sizeof(Pico.video), afile);\r
615   }\r
616   areaClose(afile);\r
617   return 0;\r
618 }\r
619 \r
620 // tmp state\r
621 struct PicoTmp\r
622 {\r
623   unsigned short vram[0x8000];\r
624   unsigned short cram[0x40];\r
625   unsigned short vsram[0x40];\r
626 \r
627   //struct PicoMisc m;\r
628   struct PicoVideo video;\r
629 \r
630   struct {\r
631     struct Pico32x p32x;\r
632     unsigned short dram[2][0x20000/2];\r
633     unsigned short pal[0x100];\r
634   } t32x;\r
635 };\r
636 \r
637 // returns data ptr to free() or PicoTmpStateRestore()\r
638 void *PicoTmpStateSave(void)\r
639 {\r
640   // gfx only for now\r
641   struct PicoTmp *t = malloc(sizeof(*t));\r
642   if (t == NULL)\r
643     return NULL;\r
644 \r
645   memcpy(t->vram, Pico.vram, sizeof(Pico.vram));\r
646   memcpy(t->cram, Pico.cram, sizeof(Pico.cram));\r
647   memcpy(t->vsram, Pico.vsram, sizeof(Pico.vsram));\r
648   memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r
649 \r
650   if (PicoAHW & PAHW_32X) {\r
651     memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));\r
652     memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));\r
653     memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));\r
654   }\r
655 \r
656   return t;\r
657 }\r
658 \r
659 void PicoTmpStateRestore(void *data)\r
660 {\r
661   struct PicoTmp *t = data;\r
662   if (t == NULL)\r
663     return;\r
664 \r
665   memcpy(Pico.vram, t->vram, sizeof(Pico.vram));\r
666   memcpy(Pico.cram, t->cram, sizeof(Pico.cram));\r
667   memcpy(Pico.vsram, t->vsram, sizeof(Pico.vsram));\r
668   memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r
669   Pico.m.dirtyPal = 1;\r
670 \r
671   if (PicoAHW & PAHW_32X) {\r
672     memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));\r
673     memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));\r
674     memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));\r
675     Pico32x.dirty_pal = 1;\r
676   }\r
677 }\r
678 \r
679 // vim:shiftwidth=2:expandtab\r