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 |
325ee167 |
10 | #include <zlib.h>\r |
b4db550e |
11 | \r |
f821bb70 |
12 | #include <cpu/sh2/sh2.h>\r |
b4db550e |
13 | #include "sound/ym2612.h"\r |
4d97b0a7 |
14 | #include "sound/ym2413.h"\r |
15 | #include "sound/sn76496.h"\r |
d600fee4 |
16 | #include "cd/megasd.h"\r |
86b38dc4 |
17 | #include "state.h"\r |
b4db550e |
18 | \r |
b4db550e |
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 |
c7e1c39b |
63 | if (len > 3 && strcasecmp(fname + len - 3, ".gz") == 0)\r |
b4db550e |
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 |
b4db550e |
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 |
3f23709e |
103 | CHUNK_CDC, // old\r |
274fcc35 |
104 | CHUNK_CDD, // 20 old\r |
105 | CHUNK_SCD, // old\r |
3f23709e |
106 | CHUNK_RC, // old\r |
b4db550e |
107 | CHUNK_MISC_CD,\r |
108 | //\r |
4a521146 |
109 | CHUNK_IOPORTS, // old\r |
b4db550e |
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 |
6a98f03e |
125 | CHUNK_32X_EVT,\r |
a2f24bfa |
126 | //rename\r |
27e26273 |
127 | CHUNK_32X_FIRST = CHUNK_MSH2,\r |
128 | CHUNK_32X_LAST = CHUNK_32X_EVT,\r |
ae214f1c |
129 | // add new stuff here\r |
130 | CHUNK_CD_EVT = 50,\r |
a93a80de |
131 | CHUNK_CD_GFX,\r |
3f23709e |
132 | CHUNK_CD_CDC,\r |
274fcc35 |
133 | CHUNK_CD_CDD,\r |
2ec448a8 |
134 | CHUNK_YM2413,\r |
fa4e0531 |
135 | CHUNK_PICO_PCM,\r |
136 | CHUNK_PICO,\r |
d600fee4 |
137 | CHUNK_CD_MSD,\r |
d4b5888a |
138 | CHUNK_VDP,\r |
ccce7ee7 |
139 | CHUNK_FM_TIMERS,\r |
4a521146 |
140 | CHUNK_FMv3 = 60,\r |
141 | CHUNK_IOPORTSv2,\r |
b4db550e |
142 | //\r |
143 | CHUNK_DEFAULT_COUNT,\r |
ae214f1c |
144 | CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt)\r |
a2f24bfa |
145 | \r |
b4db550e |
146 | } chunk_name_e;\r |
147 | \r |
cfae1ae1 |
148 | static const char * const chunk_names[CHUNK_DEFAULT_COUNT] = {\r |
b4db550e |
149 | "INVALID!",\r |
150 | "M68K state",\r |
151 | "RAM",\r |
152 | "VRAM",\r |
153 | "ZRAM",\r |
154 | "CRAM", // 5\r |
155 | "VSRAM",\r |
156 | "emu state",\r |
157 | "VIDEO",\r |
158 | "Z80 state",\r |
159 | "PSG", // 10\r |
160 | "FM",\r |
161 | // CD stuff\r |
162 | "S68K state",\r |
163 | "PRG_RAM",\r |
164 | "WORD_RAM",\r |
165 | "PCM_RAM", // 15\r |
166 | "BRAM",\r |
167 | "GATE ARRAY regs",\r |
168 | "PCM state",\r |
169 | "CDC",\r |
170 | "CDD", // 20\r |
171 | "SCD",\r |
172 | "GFX chip",\r |
173 | "MCD state",\r |
174 | //\r |
175 | "IO",\r |
176 | "SMS state", // 25\r |
177 | // 32x\r |
178 | "MSH2",\r |
179 | "MSH2 data",\r |
180 | "MSH2 peri",\r |
181 | "SSH2",\r |
182 | "SSH2 data", // 30\r |
183 | "SSH2 peri",\r |
184 | "32X system regs",\r |
185 | "M68K BIOS",\r |
186 | "MSH2 BIOS",\r |
187 | "SSH2 BIOS", // 35\r |
188 | "SDRAM",\r |
189 | "DRAM",\r |
fa4e0531 |
190 | "32X palette",\r |
191 | "32X events",\r |
b4db550e |
192 | };\r |
193 | \r |
64360d13 |
194 | static int write_chunk(unsigned char name, int len, void *data, void *file)\r |
b4db550e |
195 | {\r |
196 | size_t bwritten = 0;\r |
197 | bwritten += areaWrite(&name, 1, 1, file);\r |
198 | bwritten += areaWrite(&len, 1, 4, file);\r |
199 | bwritten += areaWrite(data, 1, len, file);\r |
200 | \r |
201 | return (bwritten == len + 4 + 1);\r |
202 | }\r |
203 | \r |
3f23709e |
204 | #define CHUNK_LIMIT_W 18772 // sizeof(cdc)\r |
205 | \r |
b4db550e |
206 | #define CHECKED_WRITE(name,len,data) { \\r |
cfae1ae1 |
207 | if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r |
21707975 |
208 | strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff)-1 - 9); \\r |
209 | sbuff[sizeof(sbuff)-1] = '\0'; \\r |
b4db550e |
210 | PicoStateProgressCB(sbuff); \\r |
211 | } \\r |
3f23709e |
212 | if (data == buf2 && len > CHUNK_LIMIT_W) \\r |
213 | goto out; \\r |
214 | if (!write_chunk(name, len, data, file)) \\r |
215 | goto out; \\r |
b4db550e |
216 | }\r |
217 | \r |
218 | #define CHECKED_WRITE_BUFF(name,buff) { \\r |
cfae1ae1 |
219 | if (PicoStateProgressCB && name < CHUNK_DEFAULT_COUNT && chunk_names[name]) { \\r |
21707975 |
220 | strncpy(sbuff + 9, chunk_names[name], sizeof(sbuff)-1 - 9); \\r |
221 | sbuff[sizeof(sbuff)-1] = '\0'; \\r |
b4db550e |
222 | PicoStateProgressCB(sbuff); \\r |
223 | } \\r |
3f23709e |
224 | if (!write_chunk(name, sizeof(buff), &buff, file)) \\r |
225 | goto out; \\r |
b4db550e |
226 | }\r |
227 | \r |
228 | static int state_save(void *file)\r |
229 | {\r |
230 | char sbuff[32] = "Saving.. ";\r |
231 | unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];\r |
3f23709e |
232 | void *buf2 = NULL;\r |
233 | int ver = 0x0191; // not really used..\r |
234 | int retval = -1;\r |
a93a80de |
235 | int len;\r |
b4db550e |
236 | \r |
fa4e0531 |
237 | buf2 = malloc(CHUNK_LIMIT_W);\r |
238 | if (buf2 == NULL)\r |
239 | return -1;\r |
240 | \r |
b4db550e |
241 | areaWrite("PicoSEXT", 1, 8, file);\r |
242 | areaWrite(&ver, 1, 4, file);\r |
243 | \r |
93f9619e |
244 | if (!(PicoIn.AHW & PAHW_SMS)) {\r |
7e056c85 |
245 | // the patches can cause incompatible saves with no-idle\r |
246 | SekFinishIdleDet();\r |
247 | \r |
b4db550e |
248 | memset(buff, 0, sizeof(buff));\r |
249 | SekPackCpu(buff, 0);\r |
250 | CHECKED_WRITE_BUFF(CHUNK_M68K, buff);\r |
88fd63ad |
251 | CHECKED_WRITE_BUFF(CHUNK_RAM, PicoMem.ram);\r |
252 | CHECKED_WRITE_BUFF(CHUNK_VSRAM, PicoMem.vsram);\r |
253 | CHECKED_WRITE_BUFF(CHUNK_IOPORTS, PicoMem.ioports);\r |
4a521146 |
254 | len = io_ports_pack(buf2, CHUNK_LIMIT_W);\r |
255 | CHECKED_WRITE(CHUNK_IOPORTSv2, len, buf2);\r |
fa4e0531 |
256 | if (PicoIn.AHW & PAHW_PICO) {\r |
257 | len = PicoPicoPCMSave(buf2, CHUNK_LIMIT_W);\r |
258 | CHECKED_WRITE(CHUNK_PICO_PCM, len, buf2);\r |
259 | CHECKED_WRITE(CHUNK_PICO, sizeof(PicoPicohw), &PicoPicohw);\r |
260 | } else {\r |
bcf8175e |
261 | #ifdef __GP2X__\r |
4d97b0a7 |
262 | void *ym_regs = YM2612GetRegs();\r |
bcf8175e |
263 | ym2612_pack_state_old();\r |
bcf8175e |
264 | CHECKED_WRITE(CHUNK_FM, 0x200+4, ym_regs);\r |
265 | #else\r |
ccce7ee7 |
266 | // write fm state first since timer load needs OPN.ST.mode\r |
267 | len = YM2612PicoStateSave3(buf2, CHUNK_LIMIT_W);\r |
268 | CHECKED_WRITE(CHUNK_FMv3, len, buf2);\r |
269 | len = ym2612_pack_timers(buf2, CHUNK_LIMIT_W);\r |
270 | CHECKED_WRITE(CHUNK_FM_TIMERS, len, buf2);\r |
bcf8175e |
271 | #endif\r |
fa4e0531 |
272 | }\r |
7e056c85 |
273 | \r |
274 | if (!(PicoIn.opt & POPT_DIS_IDLE_DET))\r |
275 | SekInitIdleDet();\r |
b4db550e |
276 | }\r |
277 | else {\r |
278 | CHECKED_WRITE_BUFF(CHUNK_SMS, Pico.ms);\r |
4d97b0a7 |
279 | // only store the FM unit state if it was really used\r |
280 | if (Pico.m.hardware & PMS_HW_FMUSED) {\r |
281 | len = ym2413_pack_state(buf2, CHUNK_LIMIT_W);\r |
282 | CHECKED_WRITE(CHUNK_YM2413, len, buf2);\r |
283 | }\r |
b4db550e |
284 | }\r |
fa4e0531 |
285 | CHECKED_WRITE(CHUNK_PSG, 28*4, sn76496_regs);\r |
286 | \r |
287 | if (!(PicoIn.AHW & PAHW_PICO)) {\r |
288 | z80_pack(buff_z80);\r |
289 | CHECKED_WRITE_BUFF(CHUNK_Z80, buff_z80);\r |
290 | CHECKED_WRITE_BUFF(CHUNK_ZRAM, PicoMem.zram);\r |
291 | }\r |
b4db550e |
292 | \r |
88fd63ad |
293 | CHECKED_WRITE_BUFF(CHUNK_VRAM, PicoMem.vram);\r |
88fd63ad |
294 | CHECKED_WRITE_BUFF(CHUNK_CRAM, PicoMem.cram);\r |
daf29df9 |
295 | \r |
fa4e0531 |
296 | CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);\r |
d4b5888a |
297 | len = PicoVideoSave(buf2);\r |
298 | CHECKED_WRITE(CHUNK_VDP, len, buf2);\r |
b4db550e |
299 | CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r |
300 | \r |
93f9619e |
301 | if (PicoIn.AHW & PAHW_MCD)\r |
b4db550e |
302 | {\r |
303 | memset(buff, 0, sizeof(buff));\r |
304 | SekPackCpu(buff, 1);\r |
305 | if (Pico_mcd->s68k_regs[3] & 4) // 1M mode?\r |
306 | wram_1M_to_2M(Pico_mcd->word_ram2M);\r |
a1fc78f3 |
307 | memcpy(&Pico_mcd->m.hint_vector, Pico_mcd->bios + 0x72,\r |
895d1512 |
308 | sizeof(Pico_mcd->m.hint_vector));\r |
b4db550e |
309 | \r |
310 | CHECKED_WRITE_BUFF(CHUNK_S68K, buff);\r |
311 | CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);\r |
312 | CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram2M); // in 2M format\r |
313 | CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);\r |
314 | CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);\r |
315 | CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs\r |
316 | CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);\r |
b4db550e |
317 | CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);\r |
ae214f1c |
318 | memset(buff, 0, 0x40);\r |
319 | memcpy(buff, pcd_event_times, sizeof(pcd_event_times));\r |
320 | CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff);\r |
3f23709e |
321 | \r |
322 | len = gfx_context_save(buf2);\r |
323 | CHECKED_WRITE(CHUNK_CD_GFX, len, buf2);\r |
324 | len = cdc_context_save(buf2);\r |
325 | CHECKED_WRITE(CHUNK_CD_CDC, len, buf2);\r |
274fcc35 |
326 | len = cdd_context_save(buf2);\r |
327 | CHECKED_WRITE(CHUNK_CD_CDD, len, buf2);\r |
b4db550e |
328 | \r |
d600fee4 |
329 | CHECKED_WRITE_BUFF(CHUNK_CD_MSD, Pico_msd);\r |
330 | \r |
b4db550e |
331 | if (Pico_mcd->s68k_regs[3] & 4) // convert back\r |
332 | wram_2M_to_1M(Pico_mcd->word_ram2M);\r |
333 | }\r |
334 | \r |
f3a57b2d |
335 | #ifndef NO_32X\r |
93f9619e |
336 | if (PicoIn.AHW & PAHW_32X)\r |
b4db550e |
337 | {\r |
338 | unsigned char cpubuff[SH2_STATE_SIZE];\r |
339 | \r |
340 | memset(cpubuff, 0, sizeof(cpubuff));\r |
341 | \r |
342 | sh2_pack(&sh2s[0], cpubuff);\r |
343 | CHECKED_WRITE_BUFF(CHUNK_MSH2, cpubuff);\r |
f81107f5 |
344 | CHECKED_WRITE_BUFF(CHUNK_MSH2_DATA, sh2s[0].data_array);\r |
345 | CHECKED_WRITE_BUFF(CHUNK_MSH2_PERI, sh2s[0].peri_regs);\r |
b4db550e |
346 | \r |
347 | sh2_pack(&sh2s[1], cpubuff);\r |
348 | CHECKED_WRITE_BUFF(CHUNK_SSH2, cpubuff);\r |
f81107f5 |
349 | CHECKED_WRITE_BUFF(CHUNK_SSH2_DATA, sh2s[1].data_array);\r |
350 | CHECKED_WRITE_BUFF(CHUNK_SSH2_PERI, sh2s[1].peri_regs);\r |
b4db550e |
351 | \r |
352 | CHECKED_WRITE_BUFF(CHUNK_32XSYS, Pico32x);\r |
353 | CHECKED_WRITE_BUFF(CHUNK_M68K_BIOS, Pico32xMem->m68k_rom);\r |
354 | CHECKED_WRITE_BUFF(CHUNK_MSH2_BIOS, Pico32xMem->sh2_rom_m);\r |
355 | CHECKED_WRITE_BUFF(CHUNK_SSH2_BIOS, Pico32xMem->sh2_rom_s);\r |
356 | CHECKED_WRITE_BUFF(CHUNK_SDRAM, Pico32xMem->sdram);\r |
357 | CHECKED_WRITE_BUFF(CHUNK_DRAM, Pico32xMem->dram);\r |
358 | CHECKED_WRITE_BUFF(CHUNK_32XPAL, Pico32xMem->pal);\r |
ed4402a7 |
359 | \r |
6a98f03e |
360 | memset(buff, 0, 0x40);\r |
ae214f1c |
361 | memcpy(buff, p32x_event_times, sizeof(p32x_event_times));\r |
6a98f03e |
362 | CHECKED_WRITE(CHUNK_32X_EVT, 0x40, buff);\r |
b4db550e |
363 | }\r |
f3a57b2d |
364 | #endif\r |
b4db550e |
365 | \r |
366 | if (carthw_chunks != NULL)\r |
367 | {\r |
368 | carthw_state_chunk *chwc;\r |
369 | if (PicoStateProgressCB)\r |
370 | PicoStateProgressCB("Saving.. cart hw state");\r |
371 | for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++)\r |
372 | CHECKED_WRITE(chwc->chunk, chwc->size, chwc->ptr);\r |
373 | }\r |
374 | \r |
92f7a430 |
375 | CHECKED_WRITE(0, 0, NULL);\r |
3f23709e |
376 | retval = 0;\r |
377 | \r |
378 | out:\r |
379 | if (buf2 != NULL)\r |
380 | free(buf2);\r |
381 | return retval;\r |
b4db550e |
382 | }\r |
383 | \r |
384 | static int g_read_offs = 0;\r |
385 | \r |
386 | #define R_ERROR_RETURN(error) \\r |
387 | { \\r |
388 | elprintf(EL_STATUS, "load_state @ %x: " error, g_read_offs); \\r |
3f23709e |
389 | goto out; \\r |
b4db550e |
390 | }\r |
391 | \r |
392 | // when is eof really set?\r |
393 | #define CHECKED_READ(len,data) { \\r |
394 | if (areaRead(data, 1, len, file) != len) { \\r |
395 | if (len == 1 && areaEof(file)) goto readend; \\r |
396 | R_ERROR_RETURN("areaRead: premature EOF\n"); \\r |
b4db550e |
397 | } \\r |
398 | g_read_offs += len; \\r |
399 | }\r |
400 | \r |
401 | #define CHECKED_READ2(len2,data) { \\r |
402 | if (len2 != len) { \\r |
403 | elprintf(EL_STATUS, "unexpected len %i, wanted %i (%s)", len, len2, #len2); \\r |
404 | if (len > len2) R_ERROR_RETURN("failed."); \\r |
405 | /* else read anyway and hope for the best.. */ \\r |
406 | } \\r |
407 | CHECKED_READ(len, data); \\r |
408 | }\r |
409 | \r |
410 | #define CHECKED_READ_BUFF(buff) CHECKED_READ2(sizeof(buff), &buff);\r |
411 | \r |
3f23709e |
412 | #define CHUNK_LIMIT_R 0x10960 // sizeof(old_cdc)\r |
413 | \r |
414 | #define CHECKED_READ_LIM(data) { \\r |
415 | if (len > CHUNK_LIMIT_R) \\r |
416 | R_ERROR_RETURN("chunk size over limit."); \\r |
417 | CHECKED_READ(len, data); \\r |
418 | }\r |
419 | \r |
b4db550e |
420 | static int state_load(void *file)\r |
421 | {\r |
422 | unsigned char buff_m68k[0x60], buff_s68k[0x60];\r |
423 | unsigned char buff_z80[Z80_STATE_SIZE];\r |
424 | unsigned char buff_sh2[SH2_STATE_SIZE];\r |
d4b5888a |
425 | unsigned char buff_vdp[0x200];\r |
3f23709e |
426 | unsigned char *buf = NULL;\r |
b4db550e |
427 | unsigned char chunk;\r |
2ec448a8 |
428 | void *ym_regs;\r |
3f23709e |
429 | int len_check;\r |
430 | int retval = -1;\r |
b4db550e |
431 | char header[8];\r |
fa23e7cc |
432 | int ver, has_32x = 0;\r |
433 | int len, len_vdp = 0;\r |
b4db550e |
434 | \r |
03065bb6 |
435 | memset(buff_m68k, 0, sizeof(buff_m68k));\r |
436 | memset(buff_s68k, 0, sizeof(buff_s68k));\r |
437 | memset(buff_z80, 0, sizeof(buff_z80));\r |
438 | \r |
3f23709e |
439 | buf = malloc(CHUNK_LIMIT_R);\r |
440 | if (buf == NULL)\r |
441 | return -1;\r |
442 | \r |
b4db550e |
443 | g_read_offs = 0;\r |
444 | CHECKED_READ(8, header);\r |
445 | if (strncmp(header, "PicoSMCD", 8) && strncmp(header, "PicoSEXT", 8))\r |
446 | R_ERROR_RETURN("bad header");\r |
447 | CHECKED_READ(4, &ver);\r |
448 | \r |
ae214f1c |
449 | memset(pcd_event_times, 0, sizeof(pcd_event_times));\r |
450 | memset(p32x_event_times, 0, sizeof(p32x_event_times));\r |
451 | \r |
b4db550e |
452 | while (!areaEof(file))\r |
453 | {\r |
3f23709e |
454 | len_check = 0;\r |
b4db550e |
455 | CHECKED_READ(1, &chunk);\r |
456 | CHECKED_READ(4, &len);\r |
457 | if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r |
93f9619e |
458 | if (CHUNK_S68K <= chunk && chunk <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r |
b4db550e |
459 | R_ERROR_RETURN("cd chunk in non CD state?");\r |
fa23e7cc |
460 | \r |
461 | // 32X only appears in PicoDrive after it has been enabled, so track this\r |
462 | has_32x |= CHUNK_32X_FIRST <= chunk && chunk <= CHUNK_32X_LAST;\r |
463 | if (has_32x && !(PicoIn.AHW & PAHW_32X))\r |
27e26273 |
464 | Pico32xStartup();\r |
b4db550e |
465 | \r |
466 | switch (chunk)\r |
467 | {\r |
468 | case CHUNK_M68K:\r |
469 | CHECKED_READ_BUFF(buff_m68k);\r |
470 | break;\r |
471 | \r |
472 | case CHUNK_Z80:\r |
473 | CHECKED_READ_BUFF(buff_z80);\r |
b4db550e |
474 | break;\r |
475 | \r |
88fd63ad |
476 | case CHUNK_RAM: CHECKED_READ_BUFF(PicoMem.ram); break;\r |
477 | case CHUNK_VRAM: CHECKED_READ_BUFF(PicoMem.vram); break;\r |
478 | case CHUNK_ZRAM: CHECKED_READ_BUFF(PicoMem.zram); break;\r |
479 | case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); break;\r |
480 | case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); break;\r |
b4db550e |
481 | case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;\r |
d4b5888a |
482 | case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break;\r |
483 | case CHUNK_VDP: CHECKED_READ2((len_vdp = len), buff_vdp); break;\r |
daf29df9 |
484 | \r |
88fd63ad |
485 | case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break;\r |
b4db550e |
486 | case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;\r |
2ec448a8 |
487 | case CHUNK_YM2413:\r |
4d97b0a7 |
488 | CHECKED_READ(len, buf);\r |
489 | ym2413_unpack_state(buf, len);\r |
490 | Pico.m.hardware |= PMS_HW_FMUSED;\r |
2ec448a8 |
491 | break;\r |
b4db550e |
492 | case CHUNK_FM:\r |
2ec448a8 |
493 | ym_regs = YM2612GetRegs();\r |
494 | CHECKED_READ2(0x200+4, ym_regs);\r |
ccce7ee7 |
495 | ym2612_unpack_state_old();\r |
496 | break;\r |
4a521146 |
497 | case CHUNK_FM_TIMERS: CHECKED_READ(len, buf); ym2612_unpack_timers(buf, len); break;\r |
498 | case CHUNK_FMv3: CHECKED_READ(len, buf); YM2612PicoStateLoad3(buf, len); break;\r |
499 | case CHUNK_IOPORTSv2: CHECKED_READ(len, buf); io_ports_unpack(buf, len); break;\r |
b4db550e |
500 | \r |
fa4e0531 |
501 | case CHUNK_PICO_PCM:\r |
502 | CHECKED_READ(len, buf);\r |
503 | PicoPicoPCMLoad(buf, len);\r |
504 | break;\r |
505 | case CHUNK_PICO:\r |
506 | CHECKED_READ_BUFF(PicoPicohw);\r |
507 | break;\r |
508 | \r |
b4db550e |
509 | case CHUNK_SMS:\r |
510 | CHECKED_READ_BUFF(Pico.ms);\r |
511 | break;\r |
512 | \r |
513 | // cd stuff\r |
514 | case CHUNK_S68K:\r |
515 | CHECKED_READ_BUFF(buff_s68k);\r |
516 | break;\r |
517 | \r |
518 | case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;\r |
519 | case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram2M); break;\r |
520 | case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;\r |
521 | case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;\r |
522 | case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;\r |
523 | case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;\r |
b4db550e |
524 | case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;\r |
d600fee4 |
525 | case CHUNK_CD_MSD: CHECKED_READ_BUFF(Pico_msd); break;\r |
b4db550e |
526 | \r |
ae214f1c |
527 | case CHUNK_CD_EVT:\r |
3f23709e |
528 | CHECKED_READ2(0x40, buf);\r |
529 | memcpy(pcd_event_times, buf, sizeof(pcd_event_times));\r |
ae214f1c |
530 | break;\r |
531 | \r |
a93a80de |
532 | case CHUNK_CD_GFX:\r |
3f23709e |
533 | CHECKED_READ_LIM(buf);\r |
534 | len_check = gfx_context_load(buf);\r |
535 | break;\r |
536 | \r |
537 | case CHUNK_CD_CDC:\r |
538 | CHECKED_READ_LIM(buf);\r |
539 | len_check = cdc_context_load(buf);\r |
540 | break;\r |
541 | \r |
274fcc35 |
542 | case CHUNK_CD_CDD:\r |
543 | CHECKED_READ_LIM(buf);\r |
544 | len_check = cdd_context_load(buf);\r |
545 | break;\r |
546 | \r |
3f23709e |
547 | // old, to be removed:\r |
548 | case CHUNK_CDC:\r |
549 | CHECKED_READ_LIM(buf);\r |
550 | cdc_context_load_old(buf);\r |
a93a80de |
551 | break;\r |
552 | \r |
274fcc35 |
553 | case CHUNK_SCD:\r |
554 | CHECKED_READ_LIM(buf);\r |
555 | cdd_context_load_old(buf);\r |
556 | break;\r |
557 | \r |
b4db550e |
558 | // 32x stuff\r |
f3a57b2d |
559 | #ifndef NO_32X\r |
b4db550e |
560 | case CHUNK_MSH2:\r |
561 | CHECKED_READ_BUFF(buff_sh2);\r |
562 | sh2_unpack(&sh2s[0], buff_sh2);\r |
563 | break;\r |
564 | \r |
565 | case CHUNK_SSH2:\r |
566 | CHECKED_READ_BUFF(buff_sh2);\r |
567 | sh2_unpack(&sh2s[1], buff_sh2);\r |
568 | break;\r |
569 | \r |
f81107f5 |
570 | case CHUNK_MSH2_DATA: CHECKED_READ_BUFF(sh2s[0].data_array); break;\r |
571 | case CHUNK_MSH2_PERI: CHECKED_READ_BUFF(sh2s[0].peri_regs); break;\r |
572 | case CHUNK_SSH2_DATA: CHECKED_READ_BUFF(sh2s[1].data_array); break;\r |
573 | case CHUNK_SSH2_PERI: CHECKED_READ_BUFF(sh2s[1].peri_regs); break;\r |
b4db550e |
574 | case CHUNK_32XSYS: CHECKED_READ_BUFF(Pico32x); break;\r |
575 | case CHUNK_M68K_BIOS: CHECKED_READ_BUFF(Pico32xMem->m68k_rom); break;\r |
576 | case CHUNK_MSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_m); break;\r |
577 | case CHUNK_SSH2_BIOS: CHECKED_READ_BUFF(Pico32xMem->sh2_rom_s); break;\r |
578 | case CHUNK_SDRAM: CHECKED_READ_BUFF(Pico32xMem->sdram); break;\r |
579 | case CHUNK_DRAM: CHECKED_READ_BUFF(Pico32xMem->dram); break;\r |
580 | case CHUNK_32XPAL: CHECKED_READ_BUFF(Pico32xMem->pal); break;\r |
6a98f03e |
581 | \r |
582 | case CHUNK_32X_EVT:\r |
3f23709e |
583 | CHECKED_READ2(0x40, buf);\r |
584 | memcpy(p32x_event_times, buf, sizeof(p32x_event_times));\r |
6a98f03e |
585 | break;\r |
f3a57b2d |
586 | #endif\r |
b4db550e |
587 | default:\r |
464b4c17 |
588 | if (!len && !chunk)\r |
92f7a430 |
589 | goto readend;\r |
b4db550e |
590 | if (carthw_chunks != NULL)\r |
591 | {\r |
592 | carthw_state_chunk *chwc;\r |
593 | for (chwc = carthw_chunks; chwc->ptr != NULL; chwc++) {\r |
594 | if (chwc->chunk == chunk) {\r |
595 | CHECKED_READ2(chwc->size, chwc->ptr);\r |
596 | goto breakswitch;\r |
597 | }\r |
598 | }\r |
599 | }\r |
600 | elprintf(EL_STATUS, "load_state: skipping unknown chunk %i of size %i", chunk, len);\r |
601 | areaSeek(file, len, SEEK_CUR);\r |
602 | break;\r |
603 | }\r |
3f23709e |
604 | breakswitch:\r |
605 | if (len_check != 0 && len_check != len)\r |
606 | elprintf(EL_STATUS, "load_state: chunk %d has bad len %d/%d",\r |
607 | len, len_check);\r |
b4db550e |
608 | }\r |
609 | \r |
610 | readend:\r |
d4b5888a |
611 | PicoVideoLoad(buff_vdp, len_vdp);\r |
612 | \r |
fa23e7cc |
613 | if (PicoIn.AHW & PAHW_32X)\r |
614 | if (!has_32x)\r |
615 | Pico32xShutdown(); // in case of loading a state with 32X disabled\r |
616 | \r |
93f9619e |
617 | if (PicoIn.AHW & PAHW_SMS)\r |
b4db550e |
618 | PicoStateLoadedMS();\r |
619 | \r |
93f9619e |
620 | if (PicoIn.AHW & PAHW_32X)\r |
27e26273 |
621 | Pico32xStateLoaded(1);\r |
622 | \r |
e23f4494 |
623 | if (PicoLoadStateHook != NULL)\r |
624 | PicoLoadStateHook();\r |
625 | \r |
03065bb6 |
626 | // must unpack 68k and z80 after banks are set up\r |
93f9619e |
627 | if (!(PicoIn.AHW & PAHW_SMS))\r |
b4db550e |
628 | SekUnpackCpu(buff_m68k, 0);\r |
93f9619e |
629 | if (PicoIn.AHW & PAHW_MCD)\r |
27e26273 |
630 | SekUnpackCpu(buff_s68k, 1);\r |
b4db550e |
631 | \r |
03065bb6 |
632 | z80_unpack(buff_z80);\r |
633 | \r |
93f9619e |
634 | if (PicoIn.AHW & PAHW_32X)\r |
27e26273 |
635 | Pico32xStateLoaded(0);\r |
93f9619e |
636 | if (PicoIn.AHW & PAHW_MCD)\r |
ae214f1c |
637 | pcd_state_loaded();\r |
da414888 |
638 | if (!(PicoIn.AHW & PAHW_SMS)) {\r |
639 | Pico.video.status &= ~(SR_VB | SR_F);\r |
640 | Pico.video.status |= ((Pico.video.reg[1] >> 3) ^ SR_VB) & SR_VB;\r |
641 | Pico.video.status |= (Pico.video.pending_ints << 2) & SR_F;\r |
642 | }\r |
b4db550e |
643 | \r |
e6488636 |
644 | Pico.m.dirtyPal = 1;\r |
3f23709e |
645 | retval = 0;\r |
646 | \r |
647 | out:\r |
648 | free(buf);\r |
649 | return retval;\r |
b4db550e |
650 | }\r |
651 | \r |
652 | static int state_load_gfx(void *file)\r |
653 | {\r |
654 | int ver, len, found = 0, to_find = 4;\r |
5d4a7fb9 |
655 | u8 buff_vdp[0x200];\r |
656 | int len_vdp = 0;\r |
b4db550e |
657 | char buff[8];\r |
658 | \r |
93f9619e |
659 | if (PicoIn.AHW & PAHW_32X)\r |
4496577e |
660 | to_find += 3;\r |
b4db550e |
661 | \r |
662 | g_read_offs = 0;\r |
663 | CHECKED_READ(8, buff);\r |
664 | if (strncmp((char *)buff, "PicoSMCD", 8) && strncmp((char *)buff, "PicoSEXT", 8))\r |
665 | R_ERROR_RETURN("bad header");\r |
666 | CHECKED_READ(4, &ver);\r |
667 | \r |
668 | while (!areaEof(file) && found < to_find)\r |
669 | {\r |
670 | CHECKED_READ(1, buff);\r |
671 | CHECKED_READ(4, &len);\r |
672 | if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");\r |
93f9619e |
673 | if (buff[0] > CHUNK_FM && buff[0] <= CHUNK_MISC_CD && !(PicoIn.AHW & PAHW_MCD))\r |
b4db550e |
674 | R_ERROR_RETURN("cd chunk in non CD state?");\r |
675 | \r |
676 | switch (buff[0])\r |
677 | {\r |
88fd63ad |
678 | case CHUNK_VRAM: CHECKED_READ_BUFF(PicoMem.vram); found++; break;\r |
679 | case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); found++; break;\r |
680 | case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); found++; break;\r |
b4db550e |
681 | case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); found++; break;\r |
5d4a7fb9 |
682 | case CHUNK_VDP: CHECKED_READ2((len_vdp = len), buff_vdp); break;\r |
b4db550e |
683 | \r |
f3a57b2d |
684 | #ifndef NO_32X\r |
b4db550e |
685 | case CHUNK_DRAM:\r |
686 | if (Pico32xMem != NULL)\r |
687 | CHECKED_READ_BUFF(Pico32xMem->dram);\r |
4496577e |
688 | found++;\r |
b4db550e |
689 | break;\r |
690 | \r |
691 | case CHUNK_32XPAL:\r |
692 | if (Pico32xMem != NULL)\r |
693 | CHECKED_READ_BUFF(Pico32xMem->pal);\r |
4496577e |
694 | found++;\r |
b4db550e |
695 | Pico32x.dirty_pal = 1;\r |
696 | break;\r |
697 | \r |
698 | case CHUNK_32XSYS:\r |
699 | CHECKED_READ_BUFF(Pico32x);\r |
4496577e |
700 | found++;\r |
b4db550e |
701 | break;\r |
f3a57b2d |
702 | #endif\r |
b4db550e |
703 | default:\r |
704 | areaSeek(file, len, SEEK_CUR);\r |
705 | break;\r |
706 | }\r |
707 | }\r |
5d4a7fb9 |
708 | PicoVideoLoad(buff_vdp, len_vdp);\r |
b4db550e |
709 | \r |
3f23709e |
710 | out:\r |
b4db550e |
711 | readend:\r |
712 | return 0;\r |
713 | }\r |
714 | \r |
86b38dc4 |
715 | static int pico_state_internal(void *afile, int is_save)\r |
b4db550e |
716 | {\r |
b4db550e |
717 | int ret;\r |
718 | \r |
b4db550e |
719 | if (is_save)\r |
720 | ret = state_save(afile);\r |
e6488636 |
721 | else\r |
b4db550e |
722 | ret = state_load(afile);\r |
b4db550e |
723 | \r |
86b38dc4 |
724 | return ret;\r |
725 | }\r |
726 | \r |
727 | int PicoState(const char *fname, int is_save)\r |
728 | {\r |
729 | void *afile = NULL;\r |
730 | int ret;\r |
731 | \r |
732 | afile = open_save_file(fname, is_save);\r |
733 | if (afile == NULL)\r |
734 | return -1;\r |
735 | \r |
736 | ret = pico_state_internal(afile, is_save);\r |
b4db550e |
737 | areaClose(afile);\r |
738 | return ret;\r |
739 | }\r |
740 | \r |
86b38dc4 |
741 | int PicoStateFP(void *afile, int is_save,\r |
742 | arearw *read, arearw *write, areaeof *eof, areaseek *seek)\r |
743 | {\r |
744 | areaRead = read;\r |
745 | areaWrite = write;\r |
746 | areaEof = eof;\r |
747 | areaSeek = seek;\r |
748 | areaClose = NULL;\r |
749 | \r |
750 | return pico_state_internal(afile, is_save);\r |
751 | }\r |
752 | \r |
b4db550e |
753 | int PicoStateLoadGfx(const char *fname)\r |
754 | {\r |
755 | void *afile;\r |
756 | int ret;\r |
757 | \r |
758 | afile = open_save_file(fname, 0);\r |
759 | if (afile == NULL)\r |
760 | return -1;\r |
761 | \r |
762 | ret = state_load_gfx(afile);\r |
763 | if (ret != 0) {\r |
764 | // assume legacy\r |
765 | areaSeek(afile, 0x10020, SEEK_SET); // skip header and RAM\r |
88fd63ad |
766 | areaRead(PicoMem.vram, 1, sizeof(PicoMem.vram), afile);\r |
b4db550e |
767 | areaSeek(afile, 0x2000, SEEK_CUR);\r |
88fd63ad |
768 | areaRead(PicoMem.cram, 1, sizeof(PicoMem.cram), afile);\r |
769 | areaRead(PicoMem.vsram, 1, sizeof(PicoMem.vsram), afile);\r |
b4db550e |
770 | areaSeek(afile, 0x221a0, SEEK_SET);\r |
771 | areaRead(&Pico.video, 1, sizeof(Pico.video), afile);\r |
5d4a7fb9 |
772 | PicoVideoCacheSAT(1);\r |
b4db550e |
773 | }\r |
774 | areaClose(afile);\r |
e721f801 |
775 | \r |
4496577e |
776 | Pico.est.rendstatus = -1;\r |
b4db550e |
777 | return 0;\r |
778 | }\r |
779 | \r |
780 | // tmp state\r |
781 | struct PicoTmp\r |
782 | {\r |
783 | unsigned short vram[0x8000];\r |
784 | unsigned short cram[0x40];\r |
785 | unsigned short vsram[0x40];\r |
c5ecd7a0 |
786 | unsigned int satcache[2*0x80];\r |
b4db550e |
787 | \r |
788 | //struct PicoMisc m;\r |
789 | struct PicoVideo video;\r |
5d4a7fb9 |
790 | u8 vdp[0x200];\r |
791 | int vdp_len;\r |
b4db550e |
792 | \r |
793 | struct {\r |
794 | struct Pico32x p32x;\r |
795 | unsigned short dram[2][0x20000/2];\r |
796 | unsigned short pal[0x100];\r |
797 | } t32x;\r |
798 | };\r |
799 | \r |
800 | // returns data ptr to free() or PicoTmpStateRestore()\r |
801 | void *PicoTmpStateSave(void)\r |
802 | {\r |
803 | // gfx only for now\r |
804 | struct PicoTmp *t = malloc(sizeof(*t));\r |
805 | if (t == NULL)\r |
806 | return NULL;\r |
807 | \r |
88fd63ad |
808 | memcpy(t->vram, PicoMem.vram, sizeof(PicoMem.vram));\r |
809 | memcpy(t->cram, PicoMem.cram, sizeof(PicoMem.cram));\r |
810 | memcpy(t->vsram, PicoMem.vsram, sizeof(PicoMem.vsram));\r |
e721f801 |
811 | memcpy(t->satcache, VdpSATCache, sizeof(VdpSATCache));\r |
b4db550e |
812 | memcpy(&t->video, &Pico.video, sizeof(Pico.video));\r |
5d4a7fb9 |
813 | t->vdp_len = PicoVideoSave(t->vdp);\r |
b4db550e |
814 | \r |
f3a57b2d |
815 | #ifndef NO_32X\r |
93f9619e |
816 | if (PicoIn.AHW & PAHW_32X) {\r |
b4db550e |
817 | memcpy(&t->t32x.p32x, &Pico32x, sizeof(Pico32x));\r |
818 | memcpy(t->t32x.dram, Pico32xMem->dram, sizeof(Pico32xMem->dram));\r |
819 | memcpy(t->t32x.pal, Pico32xMem->pal, sizeof(Pico32xMem->pal));\r |
820 | }\r |
f3a57b2d |
821 | #endif\r |
b4db550e |
822 | \r |
823 | return t;\r |
824 | }\r |
825 | \r |
826 | void PicoTmpStateRestore(void *data)\r |
827 | {\r |
828 | struct PicoTmp *t = data;\r |
829 | if (t == NULL)\r |
830 | return;\r |
831 | \r |
88fd63ad |
832 | memcpy(PicoMem.vram, t->vram, sizeof(PicoMem.vram));\r |
833 | memcpy(PicoMem.cram, t->cram, sizeof(PicoMem.cram));\r |
834 | memcpy(PicoMem.vsram, t->vsram, sizeof(PicoMem.vsram));\r |
e721f801 |
835 | memcpy(VdpSATCache, t->satcache, sizeof(VdpSATCache));\r |
b4db550e |
836 | memcpy(&Pico.video, &t->video, sizeof(Pico.video));\r |
837 | Pico.m.dirtyPal = 1;\r |
5d4a7fb9 |
838 | PicoVideoLoad(t->vdp, t->vdp_len);\r |
b4db550e |
839 | \r |
f3a57b2d |
840 | #ifndef NO_32X\r |
93f9619e |
841 | if (PicoIn.AHW & PAHW_32X) {\r |
b4db550e |
842 | memcpy(&Pico32x, &t->t32x.p32x, sizeof(Pico32x));\r |
843 | memcpy(Pico32xMem->dram, t->t32x.dram, sizeof(Pico32xMem->dram));\r |
844 | memcpy(Pico32xMem->pal, t->t32x.pal, sizeof(Pico32xMem->pal));\r |
845 | Pico32x.dirty_pal = 1;\r |
846 | }\r |
f3a57b2d |
847 | #endif\r |
a20300bf |
848 | free(t);\r |
b4db550e |
849 | }\r |
850 | \r |
ed4402a7 |
851 | // vim:shiftwidth=2:ts=2:expandtab\r |