|
|
1.1 root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
2:
3: #include <sys/stat.h>
4: #include <unistd.h>
5: #include <stdio.h>
6: #include <stdlib.h>
7: #include <errno.h>
8: #include <time.h>
9: #include <string.h>
10: #include <errno.h>
11:
12: #include "generator.h"
13: #include "snprintf.h"
14:
15: #include "state.h"
16: #include "ui.h"
17: #include "cpu68k.h"
18: #include "cpuz80.h"
19: #include "vdp.h"
20: #include "gensound.h"
21: #include "fm.h"
22:
1.1.1.3 root 23: typedef struct _t_statelist {
24: struct _t_statelist *next;
25: char *mod;
26: char *name;
27: uint8 instance;
28: uint32 bytes;
29: uint32 size;
30: uint8 *data;
31: } t_statelist;
32:
33: FILE *state_outputfile; /* the file handle to place data blocks */
34: uint8 state_transfermode; /* 0 = save, 1 = load */
35: uint8 state_major; /* major version */
36: uint8 state_minor; /* minor version */
37: t_statelist *state_statelist; /* loaded state */
38:
1.1 root 39: /*
40: * NB:
41: * states are only loaded/saved at the end of the frame
42: */
43:
44: /*** state_date - return the modification date or 0 for non-existant ***/
45:
46: time_t state_date(const int slot)
47: {
48: char filename[256];
49: struct stat statbuf;
50:
51: snprintf(filename, sizeof(filename), "%s.gt%d", gen_leafname, slot);
52:
53: if (stat(filename, &statbuf) != 0)
54: return 0;
55: return statbuf.st_mtime;
56: }
57:
58: /*** state_load - load the given slot ***/
59:
60: int state_load(const int slot)
61: {
62: char filename[256];
63:
64: snprintf(filename, sizeof(filename), "%s.gt%d", gen_leafname, slot);
1.1.1.3 root 65: return state_loadfile(filename);
66: }
1.1 root 67:
1.1.1.3 root 68: /*** state_save - save to the given slot ***/
69:
70: int state_save(const int slot)
71: {
72: char filename[256];
73:
74: snprintf(filename, sizeof(filename), "%s.gt%d", gen_leafname, slot);
75: return state_savefile(filename);
76: }
77:
78: void state_transfer8(const char *mod, const char *name, uint8 instance,
79: uint8 *data, uint32 size)
80: {
81: t_statelist *l;
82: uint8 buf[4];
83: uint32 i;
84:
85: if (state_transfermode == 0) {
86: /* save */
87: fwrite(mod, strlen(mod)+1, 1, state_outputfile);
88: fwrite(name, strlen(name)+1, 1, state_outputfile);
89: buf[0] = instance;
90: buf[1] = 1; /* bytes per object */
91: fwrite(buf, 2, 1, state_outputfile);
92: buf[0] = (size >> 24) & 0xff;
93: buf[1] = (size >> 16) & 0xff;
94: buf[2] = (size >> 8) & 0xff;
95: buf[3] = size & 0xff;
96: fwrite(buf, 4, 1, state_outputfile);
97: fwrite(data, size, 1, state_outputfile);
98: } else {
99: /* load */
100: for (l = state_statelist; l; l = l->next) {
101: if (!strcasecmp(l->mod, mod) && !strcasecmp(l->name, name) &&
102: l->instance == instance && l->size == size && l->bytes == 1) {
103: for (i = 0; i < size; i++)
104: data[i] = l->data[i];
105: LOG_VERBOSE(("Loaded %s %s (%d)", mod, name, instance));
106: break;
107: }
108: }
109: if (l == NULL) {
110: LOG_CRITICAL(("bad %s/%s\n", mod, name));
111: memset(data, 0, size);
112: }
1.1 root 113: }
1.1.1.3 root 114: }
115:
116: void state_transfer16(const char *mod, const char *name, uint8 instance,
117: uint16 *data, uint32 size)
118: {
119: t_statelist *l;
120: uint8 buf[4];
121: uint32 i;
122:
123: if (state_transfermode == 0) {
124: /* save */
125: fwrite(mod, strlen(mod)+1, 1, state_outputfile);
126: fwrite(name, strlen(name)+1, 1, state_outputfile);
127: buf[0] = instance;
128: buf[1] = 2; /* bytes per object */
129: fwrite(buf, 2, 1, state_outputfile);
130: buf[0] = (size >> 24) & 0xff;
131: buf[1] = (size >> 16) & 0xff;
132: buf[2] = (size >> 8) & 0xff;
133: buf[3] = size & 0xff;
134: fwrite(buf, 4, 1, state_outputfile);
135: for (i = 0; i < size; i++) {
136: buf[0] = (data[i] >> 8) & 0xff;
137: buf[1] = data[i] & 0xff;
138: fwrite(buf, 2, 1, state_outputfile);
139: }
140: } else {
141: /* load */
142: for (l = state_statelist; l; l = l->next) {
143: if (!strcasecmp(l->mod, mod) && !strcasecmp(l->name, name) &&
144: l->instance == instance && l->size == size && l->bytes == 2) {
145: for (i = 0; i < size; i++)
146: data[i] = ((((uint8 *)l->data)[(i << 1)] << 8) |
147: (((uint8 *)l->data)[(i << 1) + 1]));
148: LOG_VERBOSE(("Loaded %s %s (%d)", mod, name, instance));
149: break;
150: }
151: }
152: if (l == NULL) {
153: LOG_CRITICAL(("bad %s/%s\n", mod, name));
154: memset(data, 0, size * 2);
155: }
1.1 root 156: }
1.1.1.3 root 157: }
158:
159: void state_transfer32(const char *mod, const char *name, uint8 instance,
160: uint32 *data, uint32 size)
161: {
162: t_statelist *l;
163: uint8 buf[4];
164: uint32 i;
165:
166: if (state_transfermode == 0) {
167: /* save */
168: fwrite(mod, strlen(mod)+1, 1, state_outputfile);
169: fwrite(name, strlen(name)+1, 1, state_outputfile);
170: buf[0] = instance;
171: buf[1] = 4; /* bytes per object */
172: fwrite(buf, 2, 1, state_outputfile);
173: buf[0] = (size >> 24) & 0xff;
174: buf[1] = (size >> 16) & 0xff;
175: buf[2] = (size >> 8) & 0xff;
176: buf[3] = size & 0xff;
177: fwrite(buf, 4, 1, state_outputfile);
178: for (i = 0; i < size; i++) {
179: buf[0] = (data[i] >> 24) & 0xff;
180: buf[1] = (data[i] >> 16) & 0xff;
181: buf[2] = (data[i] >> 8) & 0xff;
182: buf[3] = data[i] & 0xff;
183: fwrite(buf, 4, 1, state_outputfile);
184: }
185: } else {
186: /* load */
187: for (l = state_statelist; l; l = l->next) {
188: if (!strcasecmp(l->mod, mod) && !strcasecmp(l->name, name) &&
189: l->instance == instance && l->size == size && l->bytes == 4) {
190: for (i = 0; i < size; i++)
191: data[i] = ((((uint8 *)l->data)[(i << 2)] << 24) |
192: (((uint8 *)l->data)[(i << 2) + 1] << 16) |
193: (((uint8 *)l->data)[(i << 2) + 2] << 8) |
194: (((uint8 *)l->data)[(i << 2) + 3]));
195: LOG_VERBOSE(("Loaded %s %s (%d)", mod, name, instance));
196: break;
197: }
198: }
199: if (l == NULL) {
200: LOG_CRITICAL(("bad %s/%s\n", mod, name));
201: memset(data, 0, size * 4);
1.1 root 202: }
203: }
1.1.1.3 root 204: }
1.1 root 205:
1.1.1.3 root 206: /*** state_dotransfer - do transfer of data, either save or load ***/
1.1 root 207:
1.1.1.4 ! root 208: static void state_dotransfer(unsigned int mode)
1.1.1.3 root 209: {
210: uint8 i8, i8b;
211: uint16 i16;
212:
213: (void)i8b;
214: state_transfermode = mode; /* 0 = save, 1 = load */
215: state_transfer8("ver", "major", 0, &state_major, 1);
216: state_transfer8("ver" ,"minor", 0, &state_minor, 1);
217: state_transfer8("vdp", "vram", 0, vdp_vram, LEN_VRAM);
218: state_transfer8("vdp", "cram", 0, vdp_cram, LEN_CRAM);
219: state_transfer8("vdp", "vsram", 0, vdp_vsram, LEN_VSRAM);
220: state_transfer8("vdp", "regs", 0, vdp_reg, 25);
221: state_transfer8("vdp", "pal", 0, &vdp_pal, 1);
222: state_transfer8("vdp", "overseas", 0, &vdp_overseas, 1);
223: state_transfer8("vdp", "ctrlflag", 0, &vdp_ctrlflag, 1);
224: /* this cast is probably very bad */
225: state_transfer8("vdp", "code", 0, (uint8 *)&vdp_code, 1);
226: state_transfer16("vdp", "first", 0, &vdp_first, 1);
227: state_transfer16("vdp", "second", 0, &vdp_second, 1);
228: state_transfer32("vdp", "dmabytes", 0, &vdp_dmabytes, 1);
229: state_transfer16("vdp", "address", 0, &vdp_address, 1);
230: state_transfer8("68k", "ram", 0, cpu68k_ram, 0x10000);
231: state_transfer32("68k", "regs", 0, regs.regs, 16);
232: state_transfer32("68k", "pc", 0, ®s.pc, 1);
233: state_transfer32("68k", "sp", 0, ®s.sp, 1);
234: state_transfer16("68k", "sr", 0, ®s.sr.sr_int, 1);
235: state_transfer16("68k", "stop", 0, ®s.stop, 1);
236: state_transfer16("68k", "pending", 0, ®s.pending, 1);
237: state_transfer8("z80", "ram", 0, cpuz80_ram, LEN_SRAM);
238: state_transfer8("z80", "active", 0, &cpuz80_active, 1);
239: state_transfer8("z80", "resetting", 0, &cpuz80_resetting, 1);
240: state_transfer32("z80", "bank", 0, &cpuz80_bank, 1);
241: #ifdef RAZE
242: if (state_transfermode == 0) {
243: /* save */
244: i16 = z80_get_reg(Z80_REG_AF); state_transfer16("z80", "af", 0, &i16, 1);
245: i16 = z80_get_reg(Z80_REG_BC); state_transfer16("z80", "bc", 0, &i16, 1);
246: i16 = z80_get_reg(Z80_REG_DE); state_transfer16("z80", "de", 0, &i16, 1);
247: i16 = z80_get_reg(Z80_REG_HL); state_transfer16("z80", "hl", 0, &i16, 1);
248: i16 = z80_get_reg(Z80_REG_AF2); state_transfer16("z80", "af2", 0, &i16, 1);
249: i16 = z80_get_reg(Z80_REG_BC2); state_transfer16("z80", "bc2", 0, &i16, 1);
250: i16 = z80_get_reg(Z80_REG_DE2); state_transfer16("z80", "de2", 0, &i16, 1);
251: i16 = z80_get_reg(Z80_REG_HL2); state_transfer16("z80", "hl2", 0, &i16, 1);
252: i16 = z80_get_reg(Z80_REG_IX); state_transfer16("z80", "ix", 0, &i16, 1);
253: i16 = z80_get_reg(Z80_REG_IY); state_transfer16("z80", "iy", 0, &i16, 1);
254: i16 = z80_get_reg(Z80_REG_SP); state_transfer16("z80", "sp", 0, &i16, 1);
255: i16 = z80_get_reg(Z80_REG_PC); state_transfer16("z80", "pc", 0, &i16, 1);
256: i8 = (z80_get_reg(Z80_REG_IR) >> 8) & 0xff;
257: state_transfer8("z80", "i", 0, &i8, 1);
258: i8 = z80_get_reg(Z80_REG_IR) & 0xff;
259: state_transfer8("z80", "r", 0, &i8, 1);
260: i8 = z80_get_reg(Z80_REG_IFF1); state_transfer8("z80", "iff1", 0, &i8, 1);
261: i8 = z80_get_reg(Z80_REG_IFF2); state_transfer8("z80", "iff2", 0, &i8, 1);
262: i8 = z80_get_reg(Z80_REG_IM); state_transfer8("z80", "im", 0, &i8, 1);
263: i8 = z80_get_reg(Z80_REG_Halted);
264: state_transfer8("z80", "halted", 0, &i8, 1);
265: } else {
266: /* load */
267: state_transfer16("z80", "af", 0, &i16, 1); z80_set_reg(Z80_REG_AF, i16);
268: state_transfer16("z80", "bc", 0, &i16, 1); z80_set_reg(Z80_REG_BC, i16);
269: state_transfer16("z80", "de", 0, &i16, 1); z80_set_reg(Z80_REG_DE, i16);
270: state_transfer16("z80", "hl", 0, &i16, 1); z80_set_reg(Z80_REG_HL, i16);
271: state_transfer16("z80", "af2", 0, &i16, 1); z80_set_reg(Z80_REG_AF2, i16);
272: state_transfer16("z80", "bc2", 0, &i16, 1); z80_set_reg(Z80_REG_BC2, i16);
273: state_transfer16("z80", "de2", 0, &i16, 1); z80_set_reg(Z80_REG_DE2, i16);
274: state_transfer16("z80", "hl2", 0, &i16, 1); z80_set_reg(Z80_REG_HL2, i16);
275: state_transfer16("z80", "ix", 0, &i16, 1); z80_set_reg(Z80_REG_IX, i16);
276: state_transfer16("z80", "iy", 0, &i16, 1); z80_set_reg(Z80_REG_IY, i16);
277: state_transfer16("z80", "sp", 0, &i16, 1); z80_set_reg(Z80_REG_SP, i16);
278: state_transfer16("z80", "pc", 0, &i16, 1); z80_set_reg(Z80_REG_PC, i16);
279: state_transfer8("z80", "i", 0, &i8, 1);
280: state_transfer8("z80", "r", 0, &i8b, 1);
281: z80_set_reg(Z80_REG_IR, ((uint16)i8 << 8) | i8b);
282: state_transfer8("z80", "iff1", 0, &i8, 1); z80_set_reg(Z80_REG_IFF1, i8);
283: state_transfer8("z80", "iff2", 0, &i8, 1); z80_set_reg(Z80_REG_IFF2, i8);
284: state_transfer8("z80", "im", 0, &i8, 1); z80_set_reg(Z80_REG_IM, i8);
285: state_transfer8("z80", "halted", 0, &i8, 1);
286: z80_set_reg(Z80_REG_Halted, i8);
1.1 root 287: }
1.1.1.3 root 288: #else
289: state_transfer16("z80", "af", 0, &cpuz80_z80.z80af, 1);
290: state_transfer16("z80", "bc", 0, &cpuz80_z80.z80bc, 1);
291: state_transfer16("z80", "de", 0, &cpuz80_z80.z80de, 1);
292: state_transfer16("z80", "hl", 0, &cpuz80_z80.z80hl, 1);
293: state_transfer16("z80", "af2", 0, &cpuz80_z80.z80afprime, 1);
294: state_transfer16("z80", "bc2", 0, &cpuz80_z80.z80bcprime, 1);
295: state_transfer16("z80", "de2", 0, &cpuz80_z80.z80deprime, 1);
296: state_transfer16("z80", "hl2", 0, &cpuz80_z80.z80hlprime, 1);
297: state_transfer16("z80", "ix", 0, &cpuz80_z80.z80ix, 1);
298: state_transfer16("z80", "iy", 0, &cpuz80_z80.z80iy, 1);
299: state_transfer16("z80", "sp", 0, &cpuz80_z80.z80sp, 1);
300: state_transfer16("z80", "pc", 0, &cpuz80_z80.z80pc, 1);
301: state_transfer8("z80", "i", 0, &cpuz80_z80.z80i, 1);
302: state_transfer8("z80", "r", 0, &cpuz80_z80.z80r, 1);
303: if (state_transfermode == 0) {
304: /* save */
305: i8 = cpuz80_z80.z80inInterrupt;
306: state_transfer8("z80", "iff1", 0, &i8, 1);
307: i8 = cpuz80_z80.z80interruptState;
308: state_transfer8("z80", "iff2", 0, &i8, 1);
309: i8 = cpuz80_z80.z80interruptMode;
310: state_transfer8("z80", "im", 0, &i8, 1);
311: i8 = cpuz80_z80.z80halted;
312: state_transfer8("z80", "halted", 0, &i8, 1);
313: } else {
314: /* load */
315: state_transfer8("z80", "iff1", 0, &i8, 1);
316: cpuz80_z80.z80inInterrupt = i8;
317: state_transfer8("z80", "iff2", 0, &i8, 1);
318: cpuz80_z80.z80interruptState = i8;
319: state_transfer8("z80", "im", 0, &i8, 1);
320: cpuz80_z80.z80interruptMode = i8;
321: state_transfer8("z80", "halted", 0, &i8, 1);
322: cpuz80_z80.z80halted = i8;
1.1 root 323: }
1.1.1.3 root 324: #endif
325: YM2612_save_state();
1.1 root 326:
1.1.1.3 root 327: /* XXX: FIX ME!
1.1.1.2 root 328: Z80_REG_IRQVector, 0x00 to 0xff
329: Z80_REG_IRQLine, boolean - 1 or 0
330: */
1.1.1.3 root 331:
332: /* XXX: FIX ME!
1.1.1.2 root 333: c -> z80intAddr = z80intAddr;
334: c -> z80nmiAddr = z80nmiAddr;
335: */
1.1.1.3 root 336: }
1.1 root 337:
1.1.1.3 root 338: /*** state_savefile - save to the given filename */
1.1 root 339:
1.1.1.3 root 340: int state_savefile(const char *filename)
341: {
342: if ((state_outputfile = fopen(filename, "wb")) == NULL) {
343: LOG_CRITICAL(("Failed to open '%s' for writing: %s",
344: filename, strerror(errno)));
345: return -1;
1.1 root 346: }
1.1.1.3 root 347: fprintf(state_outputfile, "Generator " VERSION " saved state\n");
348: state_major = 2;
349: state_minor = 0;
350: state_dotransfer(0); /* save */
351: fclose(state_outputfile);
1.1 root 352: return 0;
353: }
354:
1.1.1.3 root 355: /*** state_loadfile - load the given filename ***/
1.1 root 356:
1.1.1.3 root 357: int state_loadfile(const char *filename)
1.1 root 358: {
1.1.1.3 root 359: char *blk;
360: uint8 *p, *e;
1.1 root 361: struct stat statbuf;
1.1.1.3 root 362: FILE *f;
363: t_statelist *ent;
1.1 root 364:
1.1.1.3 root 365: if (stat(filename, &statbuf) != 0) {
366: errno = ENOENT;
1.1 root 367: return -1;
368: }
1.1.1.3 root 369:
370: if ((blk = malloc(statbuf.st_size)) == NULL) {
371: LOG_CRITICAL(("Failed to allocate memory whilst loading '%s'", filename));
372: return -1;
373: }
374: if ((f = fopen(filename, "rb")) == NULL) {
375: LOG_CRITICAL(("Failed to open '%s': %s", filename, strerror(errno)));
1.1.1.4 ! root 376: free(blk);
1.1.1.3 root 377: return -1;
378: }
379: if (fread(blk, statbuf.st_size, 1, f) != 1) {
380: if (feof(f)) {
381: LOG_CRITICAL(("EOF whilst reading save state file '%s'", filename));
1.1.1.4 ! root 382: free(blk);
1.1.1.3 root 383: return -1;
384: }
385: LOG_CRITICAL(("Error whilst reading save state file '%s': %s", filename,
1.1.1.2 root 386: strerror(errno)));
1.1.1.4 ! root 387: free(blk);
1.1 root 388: return -1;
389: }
390: fclose(f);
1.1.1.3 root 391:
392: p = blk;
393: e = blk + statbuf.st_size;
394:
395: /* skip first line comment */
396: while (p < e && *p++ != '\n') ;
397: if (p >= e)
398: goto OVERRUN;
399:
400: /* loop around blocks creating structure */
401: state_statelist = NULL;
402: for (;;) {
403: /* mod(1+), name(1+), instance(1), bytes(1), size(4), data(0+) */
404: if (e == p)
405: /* EOF */
406: break;
407: if ((ent = malloc(sizeof(t_statelist))) == NULL)
408: ui_err("out of memory");
409: if ((e-p) < 8)
410: goto OVERRUN;
411: ent->mod = p;
412: while (p < e && *p++) ;
413: if ((e-p) < 7)
414: goto OVERRUN;
415: ent->name = p;
416: while (p < e && *p++) ;
417: if ((e-p) < 6)
418: goto OVERRUN;
419: ent->instance = p[0];
420: ent->bytes = p[1];
421: ent->size = (p[2] << 24) | (p[3] << 16) | (p[4] << 8) | p[5];
422: if ((e-p) < (int)(ent->bytes * ent->size))
423: goto OVERRUN;
424: p+= 6;
425: ent->data = p;
426: p+= ent->bytes * ent->size;
427: ent->next = state_statelist;
428: state_statelist = ent;
429: }
430:
431: /* reset */
432: gen_reset();
433:
434: state_dotransfer(1); /* load into place */
435:
1.1.1.4 ! root 436: /* free memory */
! 437: free(blk);
! 438: while (state_statelist) {
! 439: ent = state_statelist;
! 440: state_statelist = state_statelist->next;
! 441: free(ent);
! 442: }
! 443:
1.1.1.3 root 444: if (state_major != 2) {
445: LOG_CRITICAL(("Save state file '%s' is version %d, and we're version 2",
446: filename, state_major));
447: errno = EINVAL;
448: return -1;
449: }
450:
451: /* reset some other run-time stuff that isn't important enough to save */
452: vdp_setupvideo();
453: vdp_dmabusy = vdp_dmabytes > 0 ? 1 : 0;
454: cpuz80_updatecontext();
1.1 root 455: return 0;
1.1.1.3 root 456: OVERRUN:
457: LOG_CRITICAL(("Invalid state file '%s': overrun encountered", filename));
458: errno = EINVAL;
1.1.1.4 ! root 459: free(blk);
! 460: while (state_statelist) {
! 461: ent = state_statelist;
! 462: state_statelist = state_statelist->next;
! 463: free(ent);
! 464: }
1.1.1.3 root 465: return -1;
1.1 root 466: }
1.1.1.3 root 467:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.