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