sh2 overclock and logging stuff, menu refactoring
[picodrive.git] / pico / state.c
CommitLineData
b4db550e 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
15extern int *sn76496_regs;\r
16\r
17typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);\r
18typedef size_t (areaeof)(void *file);\r
19typedef int (areaseek)(void *file, long offset, int whence);\r
20typedef int (areaclose)(void *file);\r
21\r
22static arearw *areaRead;\r
23static arearw *areaWrite;\r
24static areaeof *areaEof;\r
25static areaseek *areaSeek;\r
26static areaclose *areaClose;\r
27\r
28carthw_state_chunk *carthw_chunks;\r
29void (*PicoStateProgressCB)(const char *str);\r
30void (*PicoLoadStateHook)(void);\r
31\r
32\r
33/* I/O functions */\r
34static 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
39static 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
44static 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
61static 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
87static 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
134typedef 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
181static 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
226static 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
252static 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
348static 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
377static 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
488breakswitch:;\r
489 }\r
490\r
491readend:\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
515static 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
565readend:\r
566 return 0;\r
567}\r
568\r
569int 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
596int 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
621struct 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
638void *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
659void 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