|
|
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 "gensoundi.h" ! 22: #include "snd/fm.h" ! 23: ! 24: /* ! 25: * NB: ! 26: * states are only loaded/saved at the end of the frame ! 27: * all local values are stored in network / 68k format (big endian) ! 28: */ ! 29: ! 30: struct savestate { ! 31: /* must ensure everything is aligned as expected */ ! 32: char s_majorver[1]; ! 33: char s_minorver[1]; ! 34: char reserved1[2]; /* align */ ! 35: char s_ram[0x10000]; ! 36: char s_vram[0x10000]; ! 37: char s_z80ram[0x2000]; ! 38: char s_cram[0x80]; ! 39: char s_vsram[0x50]; ! 40: char s_68k_regs[4*16]; ! 41: char s_68k_pc[4]; ! 42: char s_68k_sp[4]; ! 43: char s_68k_sr[2]; ! 44: char s_68k_stop[1]; ! 45: char s_68k_pending[1]; ! 46: char s_z80_af[2]; ! 47: char s_z80_bc[2]; ! 48: char s_z80_de[2]; ! 49: char s_z80_hl[2]; ! 50: char s_z80_afprime[2]; ! 51: char s_z80_bcprime[2]; ! 52: char s_z80_deprime[2]; ! 53: char s_z80_hlprime[2]; ! 54: char s_z80_ix[2]; ! 55: char s_z80_iy[2]; ! 56: char s_z80_sp[2]; ! 57: char s_z80_pc[2]; ! 58: char s_z80_i[1]; ! 59: char s_z80_r[1]; ! 60: char s_z80_active[1]; ! 61: char reserved2[1]; /* align */ ! 62: char s_z80_bank[4]; ! 63: char s_fmregs1[256]; ! 64: char s_fmregs2[256]; ! 65: char s_fmaddr1[1]; ! 66: char s_fmaddr2[1]; ! 67: char s_vdp_regs[25]; ! 68: char reserved[1]; /* align */ ! 69: char s_vdp_pal[1]; ! 70: char s_vdp_overseas[1]; ! 71: char s_vdp_ctrlflag[1]; ! 72: char s_vdp_code[1]; ! 73: char s_vdp_first[2]; /* possibly only top two bits required here */ ! 74: char s_vdp_second[2]; /* used for unterminated ctrl writes */ ! 75: char s_vdp_dmabytes[4]; ! 76: char s_vdp_address[2]; ! 77: char reserved3[2]; /* align */ ! 78: }; ! 79: ! 80: /*** state_date - return the modification date or 0 for non-existant ***/ ! 81: ! 82: time_t state_date(const int slot) ! 83: { ! 84: char filename[256]; ! 85: struct stat statbuf; ! 86: ! 87: snprintf(filename, sizeof(filename), "%s.gt%d", gen_leafname, slot); ! 88: ! 89: if (stat(filename, &statbuf) != 0) ! 90: return 0; ! 91: return statbuf.st_mtime; ! 92: } ! 93: ! 94: /*** state_load - load the given slot ***/ ! 95: ! 96: int state_load(const int slot) ! 97: { ! 98: char filename[256]; ! 99: struct savestate *ssp; ! 100: char *ss; ! 101: struct stat statbuf; ! 102: FILE *f, *a; ! 103: int i; ! 104: ! 105: snprintf(filename, sizeof(filename), "%s.gt%d", gen_leafname, slot); ! 106: if (stat(filename, &statbuf) != 0) ! 107: return -1; ! 108: ! 109: if ((ss = malloc(statbuf.st_size)) == NULL) { ! 110: LOG_CRITICAL(("Failed to allocate memory whilst loading '%s'", ! 111: filename)); ! 112: return -1; ! 113: } ! 114: if ((f = fopen(filename, "rb")) == NULL) { ! 115: LOG_CRITICAL(("Failed to open '%s': %s", filename, strerror(errno))); ! 116: return -1; ! 117: } ! 118: if (fread(ss, statbuf.st_size, 1, f) != 1) { ! 119: if (feof(f)) { ! 120: LOG_CRITICAL(("EOF whilst reading GTR file '%s'", filename)); ! 121: return -1; ! 122: } ! 123: LOG_CRITICAL(("Error whilst reading GTR file '%s': %s", filename, ! 124: strerror(errno))); ! 125: return -1; ! 126: } ! 127: fclose(f); ! 128: ! 129: ssp = (struct savestate *)ss; ! 130: ! 131: if (ssp->s_majorver[0] != 1) { ! 132: LOG_CRITICAL(("GTR file '%s' is version %d, and we're version 1", ! 133: filename, ssp->s_majorver)); ! 134: return -1; ! 135: } ! 136: if (statbuf.st_size != sizeof(struct savestate)) { ! 137: LOG_CRITICAL(("GTR file '%s' is corrupt - it is not %d bytes long", ! 138: filename, sizeof(struct savestate))); ! 139: return -1; ! 140: } ! 141: ! 142: gen_reset(); ! 143: memcpy(cpu68k_ram, ssp->s_ram, sizeof(ssp->s_ram)); ! 144: memcpy(vdp_vram, ssp->s_vram, sizeof(ssp->s_vram)); ! 145: memcpy(cpuz80_ram, ssp->s_z80ram, sizeof(ssp->s_z80ram)); ! 146: memcpy(vdp_cram, ssp->s_cram, sizeof(ssp->s_cram)); ! 147: memcpy(vdp_vsram, ssp->s_vsram, sizeof(ssp->s_vsram)); ! 148: for (i = 0; i < 16; i++) ! 149: regs.regs[i] = LOCENDIAN32(((uint32 *)ssp->s_68k_regs)[i]); ! 150: regs.pc = LOCENDIAN32(*(uint32 *)ssp->s_68k_pc); ! 151: regs.sp = LOCENDIAN32(*(uint32 *)ssp->s_68k_sp); ! 152: regs.sr.sr_int = LOCENDIAN16(*(uint16 *)ssp->s_68k_sr); ! 153: regs.stop = ssp->s_68k_stop[0]; ! 154: regs.pending = ssp->s_68k_pending[0]; ! 155: cpuz80_z80.z80af = LOCENDIAN16(*(uint16 *)ssp->s_z80_af); ! 156: cpuz80_z80.z80bc = LOCENDIAN16(*(uint16 *)ssp->s_z80_bc); ! 157: cpuz80_z80.z80de = LOCENDIAN16(*(uint16 *)ssp->s_z80_de); ! 158: cpuz80_z80.z80hl = LOCENDIAN16(*(uint16 *)ssp->s_z80_hl); ! 159: cpuz80_z80.z80afprime = LOCENDIAN16(*(uint16 *)ssp->s_z80_afprime); ! 160: cpuz80_z80.z80bcprime = LOCENDIAN16(*(uint16 *)ssp->s_z80_bcprime); ! 161: cpuz80_z80.z80deprime = LOCENDIAN16(*(uint16 *)ssp->s_z80_deprime); ! 162: cpuz80_z80.z80hlprime = LOCENDIAN16(*(uint16 *)ssp->s_z80_hlprime); ! 163: cpuz80_z80.z80ix = LOCENDIAN16(*(uint16 *)ssp->s_z80_ix); ! 164: cpuz80_z80.z80iy = LOCENDIAN16(*(uint16 *)ssp->s_z80_iy); ! 165: cpuz80_z80.z80sp = LOCENDIAN16(*(uint16 *)ssp->s_z80_sp); ! 166: cpuz80_z80.z80pc = LOCENDIAN16(*(uint16 *)ssp->s_z80_pc); ! 167: cpuz80_z80.z80i = ssp->s_z80_i[0]; ! 168: cpuz80_z80.z80r = ssp->s_z80_r[0]; ! 169: cpuz80_bank = LOCENDIAN32(*(uint32 *)ssp->s_z80_bank); ! 170: memcpy(vdp_reg, ssp->s_vdp_regs, sizeof(ssp->s_vdp_regs)); ! 171: vdp_pal = ssp->s_vdp_pal[0]; ! 172: vdp_overseas = ssp->s_vdp_overseas[0]; ! 173: vdp_ctrlflag = ssp->s_vdp_ctrlflag[0]; ! 174: vdp_code = ssp->s_vdp_code[0]; ! 175: vdp_first = LOCENDIAN16(*(uint16 *)ssp->s_vdp_first); ! 176: vdp_second = LOCENDIAN16(*(uint16 *)ssp->s_vdp_second); ! 177: vdp_dmabytes = LOCENDIAN32(*(uint32 *)ssp->s_vdp_dmabytes); ! 178: vdp_address = LOCENDIAN16(*(uint16 *)ssp->s_vdp_address); ! 179: ! 180: /* reset some other run-time stuff that isn't important enough to save */ ! 181: vdp_setupvideo(); ! 182: vdp_dmabusy = vdp_dmabytes > 0 ? 1 : 0; ! 183: ! 184: for (i = 0; i < 256; i++) { ! 185: soundi_ym2612store(0, i); ! 186: soundi_ym2612store(1, ssp->s_fmregs1[i]); ! 187: soundi_ym2612store(2, i); ! 188: soundi_ym2612store(3, ssp->s_fmregs2[i]); ! 189: } ! 190: soundi_ym2612store(0, ssp->s_fmaddr1[0]); ! 191: soundi_ym2612store(1, ssp->s_fmaddr2[0]); ! 192: cpuz80_updatecontext(); ! 193: return 0; ! 194: } ! 195: ! 196: /*** state_save - save to the given slot ***/ ! 197: ! 198: int state_save(const int slot) ! 199: { ! 200: char filename[256]; ! 201: struct savestate ss; ! 202: struct savestate *ssp = &ss; /* I want a pointer like the load routines */ ! 203: struct stat statbuf; ! 204: FILE *f, *a; ! 205: int i; ! 206: ! 207: snprintf(filename, sizeof(filename), "%s.gt%d", gen_leafname, slot); ! 208: if ((f = fopen(filename, "wb")) == NULL) { ! 209: LOG_CRITICAL(("Failed to open '%s' for writing: %s", ! 210: filename, strerror(errno))); ! 211: return -1; ! 212: } ! 213: memset(ssp, 0, sizeof(ss)); ! 214: ssp->s_majorver[0] = 1; ! 215: ssp->s_minorver[0] = 1; ! 216: memcpy(ssp->s_ram, cpu68k_ram, sizeof(ssp->s_ram)); ! 217: memcpy(ssp->s_vram, vdp_vram, sizeof(ssp->s_vram)); ! 218: memcpy(ssp->s_z80ram, cpuz80_ram, sizeof(ssp->s_z80ram)); ! 219: memcpy(ssp->s_cram, vdp_cram, sizeof(ssp->s_cram)); ! 220: memcpy(ssp->s_vsram, vdp_vsram, sizeof(ssp->s_vsram)); ! 221: for (i = 0; i < 16; i++) ! 222: ((uint32 *)ssp->s_68k_regs)[i] = LOCENDIAN32(regs.regs[i]); ! 223: *(uint32 *)ssp->s_68k_pc = LOCENDIAN32(regs.pc); ! 224: *(uint32 *)ssp->s_68k_sp = LOCENDIAN32(regs.sp); ! 225: *(uint16 *)ssp->s_68k_sr = LOCENDIAN16(regs.sr.sr_int); ! 226: ssp->s_68k_stop[0] = regs.stop; ! 227: ssp->s_68k_pending[0] = regs.pending; ! 228: *(uint16 *)ssp->s_z80_af = LOCENDIAN16(cpuz80_z80.z80af); ! 229: *(uint16 *)ssp->s_z80_bc = LOCENDIAN16(cpuz80_z80.z80bc); ! 230: *(uint16 *)ssp->s_z80_de = LOCENDIAN16(cpuz80_z80.z80de); ! 231: *(uint16 *)ssp->s_z80_hl = LOCENDIAN16(cpuz80_z80.z80hl); ! 232: *(uint16 *)ssp->s_z80_afprime = LOCENDIAN16(cpuz80_z80.z80afprime); ! 233: *(uint16 *)ssp->s_z80_bcprime = LOCENDIAN16(cpuz80_z80.z80bcprime); ! 234: *(uint16 *)ssp->s_z80_deprime = LOCENDIAN16(cpuz80_z80.z80deprime); ! 235: *(uint16 *)ssp->s_z80_hlprime = LOCENDIAN16(cpuz80_z80.z80hlprime); ! 236: *(uint16 *)ssp->s_z80_ix = LOCENDIAN16(cpuz80_z80.z80ix); ! 237: *(uint16 *)ssp->s_z80_iy = LOCENDIAN16(cpuz80_z80.z80iy); ! 238: *(uint16 *)ssp->s_z80_sp = LOCENDIAN16(cpuz80_z80.z80sp); ! 239: *(uint16 *)ssp->s_z80_pc = LOCENDIAN16(cpuz80_z80.z80pc); ! 240: ssp->s_z80_i[0] = cpuz80_z80.z80i; ! 241: ssp->s_z80_r[0] = cpuz80_z80.z80r; ! 242: *(uint32 *)ssp->s_z80_bank = LOCENDIAN32(cpuz80_bank); ! 243: memcpy(ssp->s_vdp_regs, vdp_reg, sizeof(ssp->s_vdp_regs)); ! 244: ssp->s_vdp_pal[0] = vdp_pal; ! 245: ssp->s_vdp_overseas[0] = vdp_overseas; ! 246: ssp->s_vdp_ctrlflag[0] = vdp_ctrlflag; ! 247: ssp->s_vdp_code[0] = vdp_code; ! 248: *(uint16 *)ssp->s_vdp_first = LOCENDIAN16(vdp_first); ! 249: *(uint16 *)ssp->s_vdp_second = LOCENDIAN16(vdp_second); ! 250: *(uint32 *)ssp->s_vdp_dmabytes = LOCENDIAN32(vdp_dmabytes); ! 251: *(uint16 *)ssp->s_vdp_address = LOCENDIAN16(vdp_address); ! 252: memcpy(ssp->s_fmregs1, soundi_regs1, sizeof(ssp->s_fmregs1)); ! 253: memcpy(ssp->s_fmregs2, soundi_regs2, sizeof(ssp->s_fmregs2)); ! 254: ssp->s_fmaddr1[0] = soundi_address1; ! 255: ssp->s_fmaddr2[0] = soundi_address2; ! 256: if (fwrite(ssp, sizeof(ss), 1, f) != 1) { ! 257: LOG_CRITICAL(("Error whilst writing GTR file '%s': %s", filename, ! 258: strerror(errno))); ! 259: return -1; ! 260: } ! 261: fclose(f); ! 262: return 0; ! 263: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.