|
|
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.