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