|
|
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.3 ! root 208: int state_dotransfer(unsigned int mode)
! 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)));
! 376: return -1;
! 377: }
! 378: if (fread(blk, statbuf.st_size, 1, f) != 1) {
! 379: if (feof(f)) {
! 380: LOG_CRITICAL(("EOF whilst reading save state file '%s'", filename));
! 381: return -1;
! 382: }
! 383: LOG_CRITICAL(("Error whilst reading save state file '%s': %s", filename,
1.1.1.2 root 384: strerror(errno)));
1.1 root 385: return -1;
386: }
387: fclose(f);
1.1.1.3 ! root 388:
! 389: p = blk;
! 390: e = blk + statbuf.st_size;
! 391:
! 392: /* skip first line comment */
! 393: while (p < e && *p++ != '\n') ;
! 394: if (p >= e)
! 395: goto OVERRUN;
! 396:
! 397: /* loop around blocks creating structure */
! 398: state_statelist = NULL;
! 399: for (;;) {
! 400: /* mod(1+), name(1+), instance(1), bytes(1), size(4), data(0+) */
! 401: if (e == p)
! 402: /* EOF */
! 403: break;
! 404: if ((ent = malloc(sizeof(t_statelist))) == NULL)
! 405: ui_err("out of memory");
! 406: if ((e-p) < 8)
! 407: goto OVERRUN;
! 408: ent->mod = p;
! 409: while (p < e && *p++) ;
! 410: if ((e-p) < 7)
! 411: goto OVERRUN;
! 412: ent->name = p;
! 413: while (p < e && *p++) ;
! 414: if ((e-p) < 6)
! 415: goto OVERRUN;
! 416: ent->instance = p[0];
! 417: ent->bytes = p[1];
! 418: ent->size = (p[2] << 24) | (p[3] << 16) | (p[4] << 8) | p[5];
! 419: if ((e-p) < (int)(ent->bytes * ent->size))
! 420: goto OVERRUN;
! 421: p+= 6;
! 422: ent->data = p;
! 423: p+= ent->bytes * ent->size;
! 424: ent->next = state_statelist;
! 425: state_statelist = ent;
! 426: }
! 427:
! 428: /* reset */
! 429: gen_reset();
! 430:
! 431: state_dotransfer(1); /* load into place */
! 432:
! 433: if (state_major != 2) {
! 434: LOG_CRITICAL(("Save state file '%s' is version %d, and we're version 2",
! 435: filename, state_major));
! 436: errno = EINVAL;
! 437: return -1;
! 438: }
! 439:
! 440: /* reset some other run-time stuff that isn't important enough to save */
! 441: vdp_setupvideo();
! 442: vdp_dmabusy = vdp_dmabytes > 0 ? 1 : 0;
! 443: cpuz80_updatecontext();
1.1 root 444: return 0;
1.1.1.3 ! root 445: OVERRUN:
! 446: LOG_CRITICAL(("Invalid state file '%s': overrun encountered", filename));
! 447: errno = EINVAL;
! 448: return -1;
1.1 root 449: }
1.1.1.3 ! root 450:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.