cff531af |
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 |
b4db550e |
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 |
16 | extern int *sn76496_regs;\r |
17 | \r |
18 | typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);\r |
19 | typedef size_t (areaeof)(void *file);\r |
20 | typedef int (areaseek)(void *file, long offset, int whence);\r |
21 | typedef int (areaclose)(void *file);\r |
22 | \r |
23 | static arearw *areaRead;\r |
24 | static arearw *areaWrite;\r |
25 | static areaeof *areaEof;\r |
26 | static areaseek *areaSeek;\r |
27 | static areaclose *areaClose;\r |
28 | \r |
29 | carthw_state_chunk *carthw_chunks;\r |
30 | void (*PicoStateProgressCB)(const char *str);\r |
31 | void (*PicoLoadStateHook)(void);\r |
32 | \r |
33 | \r |
34 | /* I/O functions */\r |
35 | static 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 |
40 | static 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 |
45 | static 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 |
62 | static 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 |
88 | static 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 |
135 | typedef 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 | //\r |
178 | CHUNK_DEFAULT_COUNT,\r |
179 | CHUNK_CARTHW_ = CHUNK_CARTHW, // defined in PicoInt\r |
180 | } chunk_name_e;\r |
181 | \r |
182 | static const char * const chunk_names[] = {\r |
183 | "INVALID!",\r |
184 | "M68K state",\r |
185 | "RAM",\r |
186 | "VRAM",\r |
187 | "ZRAM",\r |
188 | "CRAM", // 5\r |
189 | "VSRAM",\r |
190 | "emu state",\r |
191 | "VIDEO",\r |
192 | "Z80 state",\r |
193 | "PSG", // 10\r |
194 | "FM",\r |
195 | // CD stuff\r |
196 | "S68K state",\r |
197 | "PRG_RAM",\r |
198 | "WORD_RAM",\r |
199 | "PCM_RAM", // 15\r |
200 | "BRAM",\r |
201 | "GATE ARRAY regs",\r |
202 | "PCM state",\r |
203 | "CDC",\r |
204 | "CDD", // 20\r |
205 | "SCD",\r |
206 | "GFX chip",\r |
207 | "MCD state",\r |
208 | //\r |
209 | "IO",\r |
210 | "SMS state", // 25\r |
211 | // 32x\r |
212 | "MSH2",\r |
213 | "MSH2 data",\r |
214 | "MSH2 peri",\r |
215 | "SSH2",\r |
216 | "SSH2 data", // 30\r |
217 | "SSH2 peri",\r |
218 | "32X system regs",\r |
219 | "M68K BIOS",\r |
220 | "MSH2 BIOS",\r |
221 | "SSH2 BIOS", // 35\r |
222 | "SDRAM",\r |
223 | "DRAM",\r |
224 | "PAL",\r |
225 | };\r |
226 | \r |
227 | static int write_chunk(chunk_name_e name, int len, void *data, void *file)\r |
228 | {\r |
229 | size_t bwritten = 0;\r |
230 | bwritten += areaWrite(&name, 1, 1, file);\r |
231 | bwritten += areaWrite(&len, 1, 4, file);\r |
232 | bwritten += areaWrite(data, 1, len, file);\r |
233 | \r |
234 | return (bwritten == len + 4 + 1);\r |
235 | }\r |
236 | \r |
237 | #define CHECKED_WRITE(name,len,data) { \\r |
238 | if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \\r |
239 | strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r |
240 | PicoStateProgressCB(sbuff); \\r |
241 | } \\r |
242 | if (!write_chunk(name, len, data, file)) return 1; \\r |
243 | }\r |
244 | \r |
245 | #define CHECKED_WRITE_BUFF(name,buff) { \\r |
246 | if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT) { \\r |
247 | strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff) - 9); \\r |
248 | PicoStateProgressCB(sbuff); \\r |
249 | } \\r |
250 | if (!write_chunk(name, sizeof(buff), &buff, file)) return 1; \\r |
251 | }\r |
252 | \r |
253 | static int state_save(void *file)\r |
254 | {\r |
255 | char sbuff[32] = "Saving.. ";\r |
256 | unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r |
257 | void *ym2612_regs = YM2612GetRegs();\r |
258 | int ver = 0x0170; // not really used..\r |
259 | \r |
260 | areaWrite("PicoSEXT", 1, 8, file);\r |
261 | areaWrite(&ver, 1, 4, file);\r |
262 | \r |
263 | if (!(PicoAHW & PAHW_SMS)) {\r |
264 | memset(buff, 0, sizeof(buff));\r |
265 | SekPackCpu(buff, 0);\r |
266 | CHECKED_WRITE_BUFF(CHUNK_M68K, buff);\r |
267 | CHECKED_WRITE_BUFF(CHUNK_RAM, Pico.ram);\r |
268 | CHECKED_WRITE_BUFF(CHUNK_VSRAM, Pico.vsram);\r |
269 | CHECKED_WRITE_BUFF(CHUNK_IOPORTS, Pico.ioports);\r |
270 | ym2612_pack_state();\r |
271 | CHECKED_WRITE(CHUNK_FM, 0x200+4, ym2612_regs);\r |
272 | }\r |
273 | else {\r |
274 | CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r |
275 | }\r |
276 | \r |
277 | CHECKED_WRITE_BUFF(CHUNK_VRAM, Pico.vram);\r |
278 | CHECKED_WRITE_BUFF(CHUNK_ZRAM, Pico.zram);\r |
279 | CHECKED_WRITE_BUFF(CHUNK_CRAM, Pico.cram);\r |
280 | CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);\r |
281 | CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r |
282 | \r |
283 | z80_pack(buff_z80);\r |
284 | CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);\r |
285 | CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);\r |
286 | \r |
287 | if (PicoAHW & PAHW_MCD)\r |
288 | {\r |
289 | memset(buff, 0, sizeof(buff));\r |
290 | SekPackCpu(buff, 1);\r |
291 | if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r |
292 | wram_1M_to_2M(Pico_mcd->word_ram2M);\r |
293 | Pico_mcd->m.hint_vector = *(unsigned short *)(Pico_mcd->bios + 0x72);\r |
294 | \r |
295 | CHECKED_WRITE_BUFF(CHUNK_S68K, buff);\r |
296 | CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);\r |
297 | CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format\r |
298 | CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);\r |
299 | CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);\r |
300 | CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs\r |
301 | CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);\r |
302 | CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);\r |
303 | CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);\r |
304 | CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);\r |
305 | CHECKED_WRITE_BUFF(CHUNK_RC, Pico_mcd->rot_comp);\r |
306 | CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);\r |
307 | \r |
308 | if (Pico_mcd->s68k_regs[3] & 4) // convert back\r |
309 | wram_2M_to_1M(Pico_mcd->word_ram2M);\r |
310 | }\r |
311 | \r |
f3a57b2d |
312 | #ifndef NO_32X\r |
b4db550e |
313 | if (PicoAHW & PAHW_32X)\r |
314 | {\r |
315 | unsigned char cpubuff[SH2_STATE_SIZE];\r |
316 | \r |
317 | memset(cpubuff, 0, sizeof(cpubuff));\r |
318 | \r |
319 | sh2_pack(&sh2s[0], cpubuff);\r |
320 | CHECKED_WRITE_BUFF(CHUNK_MSH2, cpubuff);\r |
321 | CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, Pico32xMem->data_array[0]);\r |
322 | CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, Pico32xMem->sh2_peri_regs[0]);\r |
323 | \r |
324 | sh2_pack(&sh2s[1], cpubuff);\r |
325 | CHECKED_WRITE_BUFF(CHUNK_SSH2, cpubuff);\r |
326 | CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, Pico32xMem->data_array[1]);\r |
327 | CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, Pico32xMem->sh2_peri_regs[1]);\r |
328 | \r |
329 | CHECKED_WRITE_BUFF(CHUNK_32XSYS, Pico32x);\r |
330 | CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);\r |
331 | CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);\r |
332 | CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);\r |
333 | CHECKED_WRITE_BUFF(CHUNK_SDRAM, Pico32xMem->sdram);\r |
334 | CHECKED_WRITE_BUFF(CHUNK_DRAM, Pico32xMem->dram);\r |
335 | CHECKED_WRITE_BUFF(CHUNK_32XPAL, Pico32xMem->pal);\r |
336 | }\r |
f3a57b2d |
337 | #endif\r |
b4db550e |
338 | \r |
339 | if (carthw_chunks != NULL)\r |
340 | {\r |
341 | carthw_state_chunk *chwc;\r |
342 | if (PicoStateProgressCB)\r |
343 | PicoStateProgressCB("Saving.. cart hw state");\r |
344 | for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)\r |
345 | CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r |
346 | }\r |
347 | \r |
348 | return 0;\r |
349 | }\r |
350 | \r |
351 | static int g_read_offs = 0;\r |
352 | \r |
353 | #define R_ERROR_RETURN(error) \\r |
354 | { \\r |
355 | elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r |
356 | return 1; \\r |
357 | }\r |
358 | \r |
359 | // when is eof really set?\r |
360 | #define CHECKED_READ(len,data) { \\r |
361 | if (areaRead(data, 1, len, file) != len) { \\r |
362 | if (len == 1 && areaEof(file)) goto readend; \\r |
363 | R_ERROR_RETURN("areaRead: premature EOF\n"); \\r |
364 | return 1; \\r |
365 | } \\r |
366 | g_read_offs += len; \\r |
367 | }\r |
368 | \r |
369 | #define CHECKED_READ2(len2,data) { \\r |
370 | if (len2 != len) { \\r |
371 | elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \\r |
372 | if (len > len2) R_ERROR_RETURN("failed."); \\r |
373 | /* else read anyway and hope for the best.. */ \\r |
374 | } \\r |
375 | CHECKED_READ(len, data); \\r |
376 | }\r |
377 | \r |
378 | #define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r |
379 | \r |
380 | static int state_load(void *file)\r |
381 | {\r |
382 | unsigned char buff_m68k[0x60], buff_s68k[0x60];\r |
383 | unsigned char buff_z80[Z80_STATE_SIZE];\r |
384 | unsigned char buff_sh2[SH2_STATE_SIZE];\r |
385 | unsigned char chunk;\r |
386 | void *ym2612_regs;\r |
387 | char header[8];\r |
388 | int ver, len;\r |
389 | \r |
03065bb6 |
390 | memset(buff_m68k, 0, sizeof(buff_m68k));\r |
391 | memset(buff_s68k, 0, sizeof(buff_s68k));\r |
392 | memset(buff_z80, 0, sizeof(buff_z80));\r |
393 | \r |
b4db550e |
394 | g_read_offs = 0;\r |
395 | CHECKED_READ(8, header);\r |
396 | if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r |
397 | R_ERROR_RETURN("bad header");\r |
398 | CHECKED_READ(4, &ver);\r |
399 | \r |
400 | while (!areaEof(file))\r |
401 | {\r |
402 | CHECKED_READ(1, &chunk);\r |
403 | CHECKED_READ(4, &len);\r |
404 | if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r |
405 | if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))\r |
406 | R_ERROR_RETURN("cd chunk in non CD state?");\r |
407 | if (CHUNK_MSH2 <= chunk && chunk <= CHUNK_32XPAL && !(PicoAHW & PAHW_32X))\r |
408 | R_ERROR_RETURN("32x chunk in non 32x state?");\r |
409 | \r |
410 | switch (chunk)\r |
411 | {\r |
412 | case CHUNK_M68K:\r |
413 | CHECKED_READ_BUFF(buff_m68k);\r |
414 | break;\r |
415 | \r |
416 | case CHUNK_Z80:\r |
417 | CHECKED_READ_BUFF(buff_z80);\r |
b4db550e |
418 | break;\r |
419 | \r |
420 | case CHUNK_RAM: CHECKED_READ_BUFF(Pico.ram); break;\r |
421 | case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); break;\r |
422 | case CHUNK_ZRAM: CHECKED_READ_BUFF(Pico.zram); break;\r |
423 | case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); break;\r |
424 | case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); break;\r |
425 | case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;\r |
426 | case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;\r |
427 | case CHUNK_IOPORTS: CHECKED_READ_BUFF(Pico.ioports); break;\r |
428 | case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;\r |
429 | case CHUNK_FM:\r |
430 | ym2612_regs = YM2612GetRegs();\r |
431 | CHECKED_READ2(0x200+4, ym2612_regs);\r |
432 | ym2612_unpack_state();\r |
433 | break;\r |
434 | \r |
435 | case CHUNK_SMS:\r |
436 | CHECKED_READ_BUFF(Pico.ms);\r |
437 | break;\r |
438 | \r |
439 | // cd stuff\r |
440 | case CHUNK_S68K:\r |
441 | CHECKED_READ_BUFF(buff_s68k);\r |
442 | break;\r |
443 | \r |
444 | case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;\r |
445 | case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;\r |
446 | case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;\r |
447 | case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;\r |
448 | case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r |
449 | case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r |
450 | case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;\r |
451 | case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;\r |
452 | case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;\r |
453 | case CHUNK_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;\r |
454 | case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;\r |
455 | \r |
456 | // 32x stuff\r |
f3a57b2d |
457 | #ifndef NO_32X\r |
b4db550e |
458 | case CHUNK_MSH2:\r |
459 | CHECKED_READ_BUFF(buff_sh2);\r |
460 | sh2_unpack(&sh2s[0], buff_sh2);\r |
461 | break;\r |
462 | \r |
463 | case CHUNK_SSH2:\r |
464 | CHECKED_READ_BUFF(buff_sh2);\r |
465 | sh2_unpack(&sh2s[1], buff_sh2);\r |
466 | break;\r |
467 | \r |
468 | case CHUNK_MSH2_DATA: CHECKED_READ_BUFF(Pico32xMem->data_array[0]); break;\r |
469 | case CHUNK_MSH2_PERI: CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[0]); break;\r |
470 | case CHUNK_SSH2_DATA: CHECKED_READ_BUFF(Pico32xMem->data_array[1]); break;\r |
471 | case CHUNK_SSH2_PERI: CHECKED_READ_BUFF(Pico32xMem->sh2_peri_regs[1]); break;\r |
472 | case CHUNK_32XSYS: CHECKED_READ_BUFF(Pico32x); break;\r |
473 | case CHUNK_M68K_BIOS: CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;\r |
474 | case CHUNK_MSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;\r |
475 | case CHUNK_SSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;\r |
476 | case CHUNK_SDRAM: CHECKED_READ_BUFF(Pico32xMem->sdram); break;\r |
477 | case CHUNK_DRAM: CHECKED_READ_BUFF(Pico32xMem->dram); break;\r |
478 | case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break;\r |
f3a57b2d |
479 | #endif\r |
b4db550e |
480 | default:\r |
481 | if (carthw_chunks != NULL)\r |
482 | {\r |
483 | carthw_state_chunk *chwc;\r |
484 | for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {\r |
485 | if (chwc->chunk == chunk) {\r |
486 | CHECKED_READ2(chwc->size, chwc->ptr);\r |
487 | goto breakswitch;\r |
488 | }\r |
489 | }\r |
490 | }\r |
491 | elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);\r |
492 | areaSeek(file, len, SEEK_CUR);\r |
493 | break;\r |
494 | }\r |
495 | breakswitch:;\r |
496 | }\r |
497 | \r |
498 | readend:\r |
499 | if (PicoAHW & PAHW_SMS)\r |
500 | PicoStateLoadedMS();\r |
501 | \r |
502 | if (PicoAHW & PAHW_MCD)\r |
503 | {\r |
504 | PicoMemStateLoaded();\r |
505 | \r |
506 | if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1))\r |
507 | cdda_start_play();\r |
508 | \r |
b4db550e |
509 | SekUnpackCpu(buff_s68k, 1);\r |
510 | }\r |
511 | \r |
03065bb6 |
512 | // must unpack 68k and z80 after banks are set up\r |
b4db550e |
513 | if (!(PicoAHW & PAHW_SMS))\r |
514 | SekUnpackCpu(buff_m68k, 0);\r |
515 | \r |
03065bb6 |
516 | z80_unpack(buff_z80);\r |
517 | \r |
b4db550e |
518 | if (PicoAHW & PAHW_32X)\r |
519 | Pico32xStateLoaded();\r |
520 | \r |
521 | return 0;\r |
522 | }\r |
523 | \r |
524 | static int state_load_gfx(void *file)\r |
525 | {\r |
526 | int ver, len, found = 0, to_find = 4;\r |
527 | char buff[8];\r |
528 | \r |
529 | if (PicoAHW & PAHW_32X)\r |
530 | to_find += 2;\r |
531 | \r |
532 | g_read_offs = 0;\r |
533 | CHECKED_READ(8, buff);\r |
534 | if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))\r |
535 | R_ERROR_RETURN("bad header");\r |
536 | CHECKED_READ(4, &ver);\r |
537 | \r |
538 | while (!areaEof(file) && found < to_find)\r |
539 | {\r |
540 | CHECKED_READ(1, buff);\r |
541 | CHECKED_READ(4, &len);\r |
542 | if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r |
543 | if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoAHW & PAHW_MCD))\r |
544 | R_ERROR_RETURN("cd chunk in non CD state?");\r |
545 | \r |
546 | switch (buff[0])\r |
547 | {\r |
548 | case CHUNK_VRAM: CHECKED_READ_BUFF(Pico.vram); found++; break;\r |
549 | case CHUNK_CRAM: CHECKED_READ_BUFF(Pico.cram); found++; break;\r |
550 | case CHUNK_VSRAM: CHECKED_READ_BUFF(Pico.vsram); found++; break;\r |
551 | case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r |
552 | \r |
f3a57b2d |
553 | #ifndef NO_32X\r |
b4db550e |
554 | case CHUNK_DRAM:\r |
555 | if (Pico32xMem != NULL)\r |
556 | CHECKED_READ_BUFF(Pico32xMem->dram);\r |
557 | break;\r |
558 | \r |
559 | case CHUNK_32XPAL:\r |
560 | if (Pico32xMem != NULL)\r |
561 | CHECKED_READ_BUFF(Pico32xMem->pal);\r |
562 | Pico32x.dirty_pal = 1;\r |
563 | break;\r |
564 | \r |
565 | case CHUNK_32XSYS:\r |
566 | CHECKED_READ_BUFF(Pico32x);\r |
567 | break;\r |
f3a57b2d |
568 | #endif\r |
b4db550e |
569 | default:\r |
570 | areaSeek(file, len, SEEK_CUR);\r |
571 | break;\r |
572 | }\r |
573 | }\r |
574 | \r |
575 | readend:\r |
576 | return 0;\r |
577 | }\r |
578 | \r |
579 | int PicoState(const char *fname, int is_save)\r |
580 | {\r |
581 | void *afile = NULL;\r |
582 | int ret;\r |
583 | \r |
584 | afile = open_save_file(fname, is_save);\r |
585 | if (afile == NULL)\r |
586 | return -1;\r |
587 | \r |
588 | if (is_save)\r |
589 | ret = state_save(afile);\r |
590 | else {\r |
591 | ret = state_load(afile);\r |
592 | if (ret != 0) {\r |
593 | areaSeek(afile, 0, SEEK_SET);\r |
594 | ret = state_load_legacy(afile);\r |
595 | }\r |
596 | \r |
597 | if (PicoLoadStateHook != NULL)\r |
598 | PicoLoadStateHook();\r |
599 | Pico.m.dirtyPal = 1;\r |
600 | }\r |
601 | \r |
602 | areaClose(afile);\r |
603 | return ret;\r |
604 | }\r |
605 | \r |
606 | int PicoStateLoadGfx(const char *fname)\r |
607 | {\r |
608 | void *afile;\r |
609 | int ret;\r |
610 | \r |
611 | afile = open_save_file(fname, 0);\r |
612 | if (afile == NULL)\r |
613 | return -1;\r |
614 | \r |
615 | ret = state_load_gfx(afile);\r |
616 | if (ret != 0) {\r |
617 | // assume legacy\r |
618 | areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM\r |
619 | areaRead(Pico.vram, 1, sizeof(Pico.vram), afile);\r |
620 | areaSeek(afile, 0x2000, SEEK_CUR);\r |
621 | areaRead(Pico.cram, 1, sizeof(Pico.cram), afile);\r |
622 | areaRead(Pico.vsram, 1, sizeof(Pico.vsram), afile);\r |
623 | areaSeek(afile, 0x221a0, SEEK_SET);\r |
624 | areaRead(&Pico.video, 1, sizeof(Pico.video), afile);\r |
625 | }\r |
626 | areaClose(afile);\r |
627 | return 0;\r |
628 | }\r |
629 | \r |
630 | // tmp state\r |
631 | struct PicoTmp\r |
632 | {\r |
633 | unsigned short vram[0x8000];\r |
634 | unsigned short cram[0x40];\r |
635 | unsigned short vsram[0x40];\r |
636 | \r |
637 | //struct PicoMisc m;\r |
638 | struct PicoVideo video;\r |
639 | \r |
640 | struct {\r |
641 | struct Pico32x p32x;\r |
642 | unsigned short dram[2][0x20000/2];\r |
643 | unsigned short pal[0x100];\r |
644 | } t32x;\r |
645 | };\r |
646 | \r |
647 | // returns data ptr to free() or PicoTmpStateRestore()\r |
648 | void *PicoTmpStateSave(void)\r |
649 | {\r |
650 | // gfx only for now\r |
651 | struct PicoTmp *t = malloc(sizeof(*t));\r |
652 | if (t == NULL)\r |
653 | return NULL;\r |
654 | \r |
655 | memcpy(t->vram, Pico.vram, sizeof(Pico.vram));\r |
656 | memcpy(t->cram, Pico.cram, sizeof(Pico.cram));\r |
657 | memcpy(t->vsram, Pico.vsram, sizeof(Pico.vsram));\r |
658 | memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r |
659 | \r |
f3a57b2d |
660 | #ifndef NO_32X\r |
b4db550e |
661 | if (PicoAHW & PAHW_32X) {\r |
662 | memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));\r |
663 | memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));\r |
664 | memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));\r |
665 | }\r |
f3a57b2d |
666 | #endif\r |
b4db550e |
667 | \r |
668 | return t;\r |
669 | }\r |
670 | \r |
671 | void PicoTmpStateRestore(void *data)\r |
672 | {\r |
673 | struct PicoTmp *t = data;\r |
674 | if (t == NULL)\r |
675 | return;\r |
676 | \r |
677 | memcpy(Pico.vram, t->vram, sizeof(Pico.vram));\r |
678 | memcpy(Pico.cram, t->cram, sizeof(Pico.cram));\r |
679 | memcpy(Pico.vsram, t->vsram, sizeof(Pico.vsram));\r |
680 | memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r |
681 | Pico.m.dirtyPal = 1;\r |
682 | \r |
f3a57b2d |
683 | #ifndef NO_32X\r |
b4db550e |
684 | if (PicoAHW & PAHW_32X) {\r |
685 | memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));\r |
686 | memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));\r |
687 | memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));\r |
688 | Pico32x.dirty_pal = 1;\r |
689 | }\r |
f3a57b2d |
690 | #endif\r |
b4db550e |
691 | }\r |
692 | \r |
693 | // vim:shiftwidth=2:expandtab\r |