comparison gst.c @ 451:b7c3b2d22858

Added support for saving savestates. Added gst savestate format test harness
author Mike Pavone <pavone@retrodev.com>
date Fri, 26 Jul 2013 19:55:04 -0700
parents
children 140af5509ce7
comparison
equal deleted inserted replaced
448:e85a107e6ec0 451:b7c3b2d22858
1 #include "gst.h"
2 #include <string.h>
3
4 #define GST_68K_REGS 0x80
5 #define GST_68K_REG_SIZE (0xDA-GST_68K_REGS)
6 #define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS)
7 #define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS)
8 #define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS)
9 #define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS)
10 #define GST_68K_RAM 0x2478
11 #define GST_Z80_REGS 0x404
12 #define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS)
13 #define GST_Z80_RAM 0x474
14 #define GST_VDP_REGS 0xFA
15 #define GST_VDP_MEM 0x12478
16 #define GST_YM_OFFSET 0x1E4
17 #define GST_YM_SIZE (0x3E4-GST_YM_OFFSET)
18
19 uint32_t read_le_32(uint8_t * data)
20 {
21 return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
22 }
23
24 uint16_t read_le_16(uint8_t * data)
25 {
26 return data[1] << 8 | data[0];
27 }
28
29 uint16_t read_be_16(uint8_t * data)
30 {
31 return data[0] << 8 | data[1];
32 }
33
34 void write_le_32(uint8_t * dst, uint32_t val)
35 {
36 dst[0] = val;
37 dst[1] = val >> 8;
38 dst[2] = val >> 16;
39 dst[3] = val >> 24;
40 }
41
42 void write_le_16(uint8_t * dst, uint16_t val)
43 {
44 dst[0] = val;
45 dst[1] = val >> 8;
46 }
47
48 void write_be_32(uint8_t * dst, uint32_t val)
49 {
50 dst[0] = val >> 24;
51 dst[1] = val >> 16;
52 dst[2] = val >> 8;
53 dst[3] = val;
54 }
55
56 void write_be_16(uint8_t * dst, uint16_t val)
57 {
58 dst[0] = val >> 8;
59 dst[1] = val;
60 }
61
62 uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile)
63 {
64 uint8_t buffer[4096];
65 fseek(gstfile, GST_68K_REGS, SEEK_SET);
66 if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
67 fputs("Failed to read 68K registers from savestate\n", stderr);
68 return 0;
69 }
70 uint8_t * curpos = buffer;
71 for (int i = 0; i < 8; i++) {
72 context->dregs[i] = read_le_32(curpos);
73 curpos += sizeof(uint32_t);
74 }
75 for (int i = 0; i < 8; i++) {
76 context->aregs[i] = read_le_32(curpos);
77 curpos += sizeof(uint32_t);
78 }
79 uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET);
80 uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET);
81 context->status = sr >> 8;
82 for (int flag = 4; flag >= 0; flag--) {
83 context->flags[flag] = sr & 1;
84 sr >>= 1;
85 }
86 if (context->status & (1 << 5)) {
87 context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET);
88 } else {
89 context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET);
90 }
91 fseek(gstfile, GST_68K_RAM, SEEK_SET);
92 for (int i = 0; i < (32*1024);) {
93 if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
94 fputs("Failed to read 68K RAM from savestate\n", stderr);
95 return 0;
96 }
97 for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
98 context->mem_pointers[1][i++] = read_be_16(curpos);
99 }
100 }
101 return pc;
102 }
103
104 uint8_t m68k_save_gst(m68k_context * context, uint32_t pc, FILE * gstfile)
105 {
106 uint8_t buffer[4096];
107 uint8_t * curpos = buffer;
108 for (int i = 0; i < 8; i++) {
109 write_le_32(curpos, context->dregs[i]);
110 curpos += sizeof(uint32_t);
111 }
112 for (int i = 0; i < 8; i++) {
113 write_le_32(curpos, context->aregs[i]);
114 curpos += sizeof(uint32_t);
115 }
116 write_le_32(buffer + GST_68K_PC_OFFSET, pc);
117 uint16_t sr = context->status << 3;
118 for (int flag = 4; flag >= 0; flag--) {
119 sr <<= 1;
120 sr |= context->flags[flag];
121 }
122 write_le_16(buffer + GST_68K_SR_OFFSET, sr);
123 if (context->status & (1 << 5)) {
124 write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[8]);
125 write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[7]);
126 } else {
127 write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[7]);
128 write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[8]);
129 }
130 fseek(gstfile, GST_68K_REGS, SEEK_SET);
131 if (fwrite(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
132 fputs("Failed to write 68K registers to savestate\n", stderr);
133 return 0;
134 }
135
136 fseek(gstfile, GST_68K_RAM, SEEK_SET);
137 for (int i = 0; i < (32*1024);) {
138 for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
139 write_be_16(curpos, context->mem_pointers[1][i++]);
140 }
141 if (fwrite(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
142 fputs("Failed to write 68K RAM to savestate\n", stderr);
143 return 0;
144 }
145 }
146 return 1;
147 }
148
149 uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
150 {
151 uint8_t regdata[GST_Z80_REG_SIZE];
152 fseek(gstfile, GST_Z80_REGS, SEEK_SET);
153 if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
154 fputs("Failed to read Z80 registers from savestate\n", stderr);
155 return 0;
156 }
157 uint8_t * curpos = regdata;
158 uint8_t f = *(curpos++);
159 context->flags[ZF_C] = f & 1;
160 f >>= 1;
161 context->flags[ZF_N] = f & 1;
162 f >>= 1;
163 context->flags[ZF_PV] = f & 1;
164 f >>= 2;
165 context->flags[ZF_H] = f & 1;
166 f >>= 2;
167 context->flags[ZF_Z] = f & 1;
168 f >>= 1;
169 context->flags[ZF_S] = f;
170
171 context->regs[Z80_A] = *curpos;
172 curpos += 3;
173 for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
174 context->regs[reg++] = *(curpos++);
175 context->regs[reg] = *curpos;
176 curpos += 3;
177 }
178 context->pc = read_le_16(curpos);
179 curpos += 4;
180 context->sp = read_le_16(curpos);
181 curpos += 4;
182 f = *(curpos++);
183 context->alt_flags[ZF_C] = f & 1;
184 f >>= 1;
185 context->alt_flags[ZF_N] = f & 1;
186 f >>= 1;
187 context->alt_flags[ZF_PV] = f & 1;
188 f >>= 2;
189 context->alt_flags[ZF_H] = f & 1;
190 f >>= 2;
191 context->alt_flags[ZF_Z] = f & 1;
192 f >>= 1;
193 context->alt_flags[ZF_S] = f;
194 context->alt_regs[Z80_A] = *curpos;
195 curpos += 3;
196 for (int reg = Z80_C; reg <= Z80_H; reg++) {
197 context->alt_regs[reg++] = *(curpos++);
198 context->alt_regs[reg] = *curpos;
199 curpos += 3;
200 }
201 context->regs[Z80_I] = *curpos;
202 curpos += 2;
203 context->iff1 = context->iff2 = *curpos;
204 curpos += 2;
205 reset = !*(curpos++);
206 busreq = *curpos;
207 curpos += 3;
208 uint32_t bank = read_le_32(curpos);
209 if (bank < 0x400000) {
210 context->mem_pointers[1] = context->mem_pointers[2] + bank;
211 } else {
212 context->mem_pointers[1] = NULL;
213 }
214 context->bank_reg = bank >> 15;
215 fseek(gstfile, GST_Z80_RAM, SEEK_SET);
216 if(fread(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) {
217 fputs("Failed to read Z80 RAM from savestate\n", stderr);
218 return 0;
219 }
220 return 1;
221 }
222
223 uint8_t vdp_load_gst(vdp_context * context, FILE * state_file)
224 {
225 uint8_t tmp_buf[CRAM_SIZE*2];
226 fseek(state_file, GST_VDP_REGS, SEEK_SET);
227 if (fread(context->regs, 1, VDP_REGS, state_file) != VDP_REGS) {
228 fputs("Failed to read VDP registers from savestate\n", stderr);
229 return 0;
230 }
231 context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
232 if (!context->double_res) {
233 context->framebuf = context->oddbuf;
234 }
235 latch_mode(context);
236 if (fread(tmp_buf, 1, sizeof(tmp_buf), state_file) != sizeof(tmp_buf)) {
237 fputs("Failed to read CRAM from savestate\n", stderr);
238 return 0;
239 }
240 for (int i = 0; i < CRAM_SIZE; i++) {
241 uint16_t value;
242 context->cram[i] = value = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
243 context->colors[i] = color_map[value & 0xEEE];
244 context->colors[i + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW];
245 context->colors[i + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT];
246 }
247 if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) {
248 fputs("Failed to read VSRAM from savestate\n", stderr);
249 return 0;
250 }
251 for (int i = 0; i < VSRAM_SIZE; i++) {
252 context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
253 }
254 fseek(state_file, GST_VDP_MEM, SEEK_SET);
255 if (fread(context->vdpmem, 1, VRAM_SIZE, state_file) != VRAM_SIZE) {
256 fputs("Failed to read VRAM from savestate\n", stderr);
257 return 0;
258 }
259 return 1;
260 }
261
262 uint8_t vdp_save_gst(vdp_context * context, FILE * outfile)
263 {
264 uint8_t tmp_buf[CRAM_SIZE*2];
265 fseek(outfile, GST_VDP_REGS, SEEK_SET);
266 if(fwrite(context->regs, 1, VDP_REGS, outfile) != VDP_REGS) {
267 fputs("Error writing VDP regs to savestate\n", stderr);
268 return 0;
269 }
270 for (int i = 0; i < CRAM_SIZE; i++)
271 {
272 tmp_buf[i*2] = context->cram[i];
273 tmp_buf[i*2+1] = context->cram[i] >> 8;
274 }
275 if (fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile) != sizeof(tmp_buf)) {
276 fputs("Error writing CRAM to savestate\n", stderr);
277 return 0;
278 }
279 for (int i = 0; i < VSRAM_SIZE; i++)
280 {
281 tmp_buf[i*2] = context->vsram[i];
282 tmp_buf[i*2+1] = context->vsram[i] >> 8;
283 }
284 if (fwrite(tmp_buf, 2, VSRAM_SIZE, outfile) != VSRAM_SIZE) {
285 fputs("Error writing VSRAM to savestate\n", stderr);
286 return 0;
287 }
288 fseek(outfile, GST_VDP_MEM, SEEK_SET);
289 if (fwrite(context->vdpmem, 1, VRAM_SIZE, outfile) != VRAM_SIZE) {
290 fputs("Error writing VRAM to savestate\n", stderr);
291 return 0;
292 }
293 return 1;
294 }
295
296 uint8_t z80_save_gst(z80_context * context, FILE * gstfile)
297 {
298 uint8_t regdata[GST_Z80_REG_SIZE];
299 uint8_t * curpos = regdata;
300 memset(regdata, 0, sizeof(regdata));
301 uint8_t f = context->flags[ZF_S];
302 f <<= 1;
303 f |= context->flags[ZF_Z] ;
304 f <<= 2;
305 f |= context->flags[ZF_H];
306 f <<= 2;
307 f |= context->flags[ZF_PV];
308 f <<= 1;
309 f |= context->flags[ZF_N];
310 f <<= 1;
311 f |= context->flags[ZF_C];
312 *(curpos++) = f;
313 *curpos = context->regs[Z80_A];
314
315 curpos += 3;
316 for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
317 *(curpos++) = context->regs[reg++];
318 *curpos = context->regs[reg];
319 curpos += 3;
320 }
321 write_le_16(curpos, context->pc);
322 curpos += 4;
323 write_le_16(curpos, context->sp);
324 curpos += 4;
325 f = context->alt_flags[ZF_S];
326 f <<= 1;
327 f |= context->alt_flags[ZF_Z] ;
328 f <<= 2;
329 f |= context->alt_flags[ZF_H];
330 f <<= 2;
331 f |= context->alt_flags[ZF_PV];
332 f <<= 1;
333 f |= context->alt_flags[ZF_N];
334 f <<= 1;
335 f |= context->alt_flags[ZF_C];
336 *(curpos++) = f;
337 *curpos = context->alt_regs[Z80_A];
338 curpos += 3;
339 for (int reg = Z80_C; reg <= Z80_H; reg++) {
340 *(curpos++) = context->alt_regs[reg++];
341 *curpos = context->alt_regs[reg];
342 curpos += 3;
343 }
344 *curpos = context->regs[Z80_I];
345 curpos += 2;
346 *curpos = context->iff1;
347 curpos += 2;
348 *(curpos++) = !reset;
349 *curpos = busreq;
350 curpos += 3;
351 uint32_t bank = context->bank_reg << 15;
352 write_le_32(curpos, bank);
353 fseek(gstfile, GST_Z80_REGS, SEEK_SET);
354 if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
355 return 0;
356 }
357 fseek(gstfile, GST_Z80_RAM, SEEK_SET);
358 if(fwrite(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) {
359 fputs("Failed to write Z80 RAM to savestate\n", stderr);
360 return 0;
361 }
362 return 1;
363 }
364
365 uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile)
366 {
367 uint8_t regdata[GST_YM_SIZE];
368 fseek(gstfile, GST_YM_OFFSET, SEEK_SET);
369 if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
370 return 0;
371 }
372 for (int i = 0; i < sizeof(regdata); i++) {
373 if (i & 0x100) {
374 ym_address_write_part2(context, i & 0xFF);
375 } else {
376 ym_address_write_part1(context, i);
377 }
378 ym_data_write(context, regdata[i]);
379 }
380 return 1;
381 }
382
383 uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile)
384 {
385 uint8_t regdata[GST_YM_SIZE];
386 for (int i = 0; i < sizeof(regdata); i++) {
387 if (i & 0x100) {
388 int reg = (i & 0xFF);
389 if (reg >= YM_PART2_START && reg < YM_REG_END) {
390 regdata[i] = context->part2_regs[reg-YM_PART2_START];
391 } else {
392 regdata[i] = 0xFF;
393 }
394 } else {
395 if (i >= YM_PART1_START && i < YM_REG_END) {
396 regdata[i] = context->part1_regs[i-YM_PART1_START];
397 } else {
398 regdata[i] = 0xFF;
399 }
400 }
401 }
402 fseek(gstfile, GST_YM_OFFSET, SEEK_SET);
403 if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
404 return 0;
405 }
406 return 1;
407 }
408
409 uint32_t load_gst(genesis_context * gen, char * fname)
410 {
411 FILE * gstfile = fopen(fname, "rb");
412 if (!gstfile) {
413 fprintf(stderr, "Could not open file %s for reading\n", fname);
414 goto error;
415 }
416 char ident[5];
417 if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) {
418 fprintf(stderr, "Could not read ident code from %s\n", fname);
419 goto error_close;
420 }
421 if (memcmp(ident, "GST\x40\xE0", 5) != 0) {
422 fprintf(stderr, "%s doesn't appear to be a GST savestate. The ident code is %c%c%c\\x%X\\x%X instead of GST\\x40\\xE0.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]);
423 goto error_close;
424 }
425 uint32_t pc = m68k_load_gst(gen->m68k, gstfile);
426 if (!pc) {
427 goto error_close;
428 }
429 if (!vdp_load_gst(gen->vdp, gstfile)) {
430 goto error_close;
431 }
432 if (!ym_load_gst(gen->ym, gstfile)) {
433 goto error_close;
434 }
435 if (!z80_load_gst(gen->z80, gstfile)) {
436 goto error_close;
437 }
438 gen->ports[0].control = 0x40;
439 gen->ports[1].control = 0x40;
440 fclose(gstfile);
441 return pc;
442
443 error_close:
444 fclose(gstfile);
445 error:
446 return 0;
447 }
448
449 uint8_t save_gst(genesis_context * gen, char *fname, uint32_t m68k_pc)
450 {
451 FILE * gstfile = fopen(fname, "wb");
452 if (!gstfile) {
453 fprintf(stderr, "Could not open %s for writing\n", fname);
454 goto error;
455 }
456 if (fwrite("GST\x40\xE0", 1, 5, gstfile) != 5) {
457 fputs("Error writing signature to savestate\n", stderr);
458 goto error_close;
459 }
460 if (!m68k_save_gst(gen->m68k, m68k_pc, gstfile)) {
461 goto error_close;
462 }
463 if (!z80_save_gst(gen->z80, gstfile)) {
464 goto error_close;
465 }
466 if (!vdp_save_gst(gen->vdp, gstfile)) {
467 goto error_close;
468 }
469 if (!ym_save_gst(gen->ym, gstfile)) {
470 goto error_close;
471 }
472 return 1;
473
474 error_close:
475 fclose(gstfile);
476 error:
477 return 0;
478 }