fix crash when specifying --source on command line
[rofl0r-gnuboy.git] / save.c
blob6cc633f95153defe97c7ff3a2f8ab44e3f21cf75
2 #include <string.h>
3 #include <stdio.h>
5 #include "defs.h"
6 #include "cpu.h"
7 #include "cpuregs.h"
8 #include "hw.h"
9 #include "regs.h"
10 #include "lcd.h"
11 #include "rtc.h"
12 #include "mem.h"
13 #include "sound.h"
16 #define I1(s, p) { 1, s, p }
17 #define I2(s, p) { 2, s, p }
18 #define I4(s, p) { 4, s, p }
19 #define R(r) I1(#r, &R_##r)
20 #define NOSAVE { -1, "\0\0\0\0", 0 }
21 #define END { 0, "\0\0\0\0", 0 }
23 struct svar
25 int len;
26 char key[4];
27 void *ptr;
30 static int ver;
31 static int sramblock, iramblock, vramblock;
32 static int hramofs, hiofs, palofs, oamofs, wavofs;
34 struct svar svars[] =
36 I4("GbSs", &ver),
38 I2("PC ", &PC),
39 I2("SP ", &SP),
40 I2("BC ", &BC),
41 I2("DE ", &DE),
42 I2("HL ", &HL),
43 I2("AF ", &AF),
45 I4("IME ", &cpu.ime),
46 I4("ima ", &cpu.ima),
47 I4("spd ", &cpu.speed),
48 I4("halt", &cpu.halt),
49 I4("div ", &cpu.div),
50 I4("tim ", &cpu.tim),
51 I4("lcdc", &cpu.lcdc),
52 I4("snd ", &cpu.snd),
54 I1("ints", &hw.ilines),
55 I1("pad ", &hw.pad),
56 I4("cgb ", &hw.cgb),
57 I4("gba ", &hw.gba),
59 I4("mbcm", &mbc.model),
60 I4("romb", &mbc.rombank),
61 I4("ramb", &mbc.rambank),
62 I4("enab", &mbc.enableram),
63 I4("batt", &mbc.batt),
65 I4("rtcR", &rtc.sel),
66 I4("rtcL", &rtc.latch),
67 I4("rtcC", &rtc.carry),
68 I4("rtcS", &rtc.stop),
69 I4("rtcd", &rtc.d),
70 I4("rtch", &rtc.h),
71 I4("rtcm", &rtc.m),
72 I4("rtcs", &rtc.s),
73 I4("rtct", &rtc.t),
74 I1("rtR8", &rtc.regs[0]),
75 I1("rtR9", &rtc.regs[1]),
76 I1("rtRA", &rtc.regs[2]),
77 I1("rtRB", &rtc.regs[3]),
78 I1("rtRC", &rtc.regs[4]),
80 I4("S1on", &snd.ch[0].on),
81 I4("S1p ", &snd.ch[0].pos),
82 I4("S1c ", &snd.ch[0].cnt),
83 I4("S1ec", &snd.ch[0].encnt),
84 I4("S1sc", &snd.ch[0].swcnt),
85 I4("S1sf", &snd.ch[0].swfreq),
87 I4("S2on", &snd.ch[1].on),
88 I4("S2p ", &snd.ch[1].pos),
89 I4("S2c ", &snd.ch[1].cnt),
90 I4("S2ec", &snd.ch[1].encnt),
92 I4("S3on", &snd.ch[2].on),
93 I4("S3p ", &snd.ch[2].pos),
94 I4("S3c ", &snd.ch[2].cnt),
96 I4("S4on", &snd.ch[3].on),
97 I4("S4p ", &snd.ch[3].pos),
98 I4("S4c ", &snd.ch[3].cnt),
99 I4("S4ec", &snd.ch[3].encnt),
101 I4("hdma", &hw.hdma),
103 I4("sram", &sramblock),
104 I4("iram", &iramblock),
105 I4("vram", &vramblock),
106 I4("hi ", &hiofs),
107 I4("pal ", &palofs),
108 I4("oam ", &oamofs),
109 I4("wav ", &wavofs),
111 /* NOSAVE is a special code to prevent the rest of the table
112 * from being saved, used to support old stuff for backwards
113 * compatibility... */
114 NOSAVE,
116 /* the following are obsolete as of 0x104 */
118 I4("hram", &hramofs),
120 R(P1), R(SB), R(SC),
121 R(DIV), R(TIMA), R(TMA), R(TAC),
122 R(IE), R(IF),
123 R(LCDC), R(STAT), R(LY), R(LYC),
124 R(SCX), R(SCY), R(WX), R(WY),
125 R(BGP), R(OBP0), R(OBP1),
126 R(DMA),
128 R(VBK), R(SVBK), R(KEY1),
129 R(BCPS), R(BCPD), R(OCPS), R(OCPD),
131 R(NR10), R(NR11), R(NR12), R(NR13), R(NR14),
132 R(NR21), R(NR22), R(NR23), R(NR24),
133 R(NR30), R(NR31), R(NR32), R(NR33), R(NR34),
134 R(NR41), R(NR42), R(NR43), R(NR44),
135 R(NR50), R(NR51), R(NR52),
137 I1("DMA1", &R_HDMA1),
138 I1("DMA2", &R_HDMA2),
139 I1("DMA3", &R_HDMA3),
140 I1("DMA4", &R_HDMA4),
141 I1("DMA5", &R_HDMA5),
147 void loadstate(FILE *f)
149 int i, j;
150 byte buf[4096];
151 un32 (*header)[2] = (un32 (*)[2])buf;
152 un32 d;
153 int irl = hw.cgb ? 8 : 2;
154 int vrl = hw.cgb ? 4 : 2;
155 int srl = mbc.ramsize << 1;
157 ver = hramofs = hiofs = palofs = oamofs = wavofs = 0;
159 fseek(f, 0, SEEK_SET);
160 fread(buf, 4096, 1, f);
162 for (j = 0; header[j][0]; j++)
164 for (i = 0; svars[i].ptr; i++)
166 if (memcmp(&header[j][0], svars[i].key, 4))
167 continue;
168 d = LIL(header[j][1]);
169 switch (svars[i].len)
171 case 1:
172 *(byte *)svars[i].ptr = d;
173 break;
174 case 2:
175 *(un16 *)svars[i].ptr = d;
176 break;
177 case 4:
178 *(un32 *)svars[i].ptr = d;
179 break;
181 break;
185 /* obsolete as of version 0x104 */
186 if (hramofs) memcpy(ram.hi+128, buf+hramofs, 127);
188 if (hiofs) memcpy(ram.hi, buf+hiofs, sizeof ram.hi);
189 if (palofs) memcpy(lcd.pal, buf+palofs, sizeof lcd.pal);
190 if (oamofs) memcpy(lcd.oam.mem, buf+oamofs, sizeof lcd.oam);
192 if (wavofs) memcpy(snd.wave, buf+wavofs, sizeof snd.wave);
193 else memcpy(snd.wave, ram.hi+0x30, 16); /* patch data from older files */
195 fseek(f, iramblock<<12, SEEK_SET);
196 fread(ram.ibank, 4096, irl, f);
198 fseek(f, vramblock<<12, SEEK_SET);
199 fread(lcd.vbank, 4096, vrl, f);
201 fseek(f, sramblock<<12, SEEK_SET);
202 fread(ram.sbank, 4096, srl, f);
205 void savestate(FILE *f)
207 int i;
208 byte buf[4096];
209 un32 (*header)[2] = (un32 (*)[2])buf;
210 un32 d = 0;
211 int irl = hw.cgb ? 8 : 2;
212 int vrl = hw.cgb ? 4 : 2;
213 int srl = mbc.ramsize << 1;
215 ver = 0x105;
216 iramblock = 1;
217 vramblock = 1+irl;
218 sramblock = 1+irl+vrl;
219 wavofs = 4096 - 784;
220 hiofs = 4096 - 768;
221 palofs = 4096 - 512;
222 oamofs = 4096 - 256;
223 memset(buf, 0, sizeof buf);
225 for (i = 0; svars[i].len > 0; i++)
227 memcpy(&header[i][0], svars[i].key, 4);
228 switch (svars[i].len)
230 case 1:
231 d = *(byte *)svars[i].ptr;
232 break;
233 case 2:
234 d = *(un16 *)svars[i].ptr;
235 break;
236 case 4:
237 d = *(un32 *)svars[i].ptr;
238 break;
240 header[i][1] = LIL(d);
242 header[i][0] = header[i][1] = 0;
244 memcpy(buf+hiofs, ram.hi, sizeof ram.hi);
245 memcpy(buf+palofs, lcd.pal, sizeof lcd.pal);
246 memcpy(buf+oamofs, lcd.oam.mem, sizeof lcd.oam);
247 memcpy(buf+wavofs, snd.wave, sizeof snd.wave);
249 fseek(f, 0, SEEK_SET);
250 fwrite(buf, 4096, 1, f);
252 fseek(f, iramblock<<12, SEEK_SET);
253 fwrite(ram.ibank, 4096, irl, f);
255 fseek(f, vramblock<<12, SEEK_SET);
256 fwrite(lcd.vbank, 4096, vrl, f);
258 fseek(f, sramblock<<12, SEEK_SET);
259 fwrite(ram.sbank, 4096, srl, f);