update README
[rofl0r-gnuboy.git] / save.c
blobbf085b0f7ce68133b6f76f0d7d559b66bad8ac51
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"
17 #ifdef IS_LITTLE_ENDIAN
18 #define LIL(x) (x)
19 #else
20 #define LIL(x) ((x<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|(x>>24))
21 #endif
23 #define I1(s, p) { 1, s, p }
24 #define I2(s, p) { 2, s, p }
25 #define I4(s, p) { 4, s, p }
26 #define R(r) I1(#r, &R_##r)
27 #define NOSAVE { -1, "\0\0\0\0", 0 }
28 #define END { 0, "\0\0\0\0", 0 }
30 struct svar
32 int len;
33 char key[4];
34 void *ptr;
37 static int ver;
38 static int sramblock, iramblock, vramblock;
39 static int hramofs, hiofs, palofs, oamofs, wavofs;
41 struct svar svars[] =
43 I4("GbSs", &ver),
45 I2("PC ", &PC),
46 I2("SP ", &SP),
47 I2("BC ", &BC),
48 I2("DE ", &DE),
49 I2("HL ", &HL),
50 I2("AF ", &AF),
52 I4("IME ", &cpu.ime),
53 I4("ima ", &cpu.ima),
54 I4("spd ", &cpu.speed),
55 I4("halt", &cpu.halt),
56 I4("div ", &cpu.div),
57 I4("tim ", &cpu.tim),
58 I4("lcdc", &cpu.lcdc),
59 I4("snd ", &cpu.snd),
61 I1("ints", &hw.ilines),
62 I1("pad ", &hw.pad),
63 I4("cgb ", &hw.cgb),
64 I4("gba ", &hw.gba),
66 I4("mbcm", &mbc.model),
67 I4("romb", &mbc.rombank),
68 I4("ramb", &mbc.rambank),
69 I4("enab", &mbc.enableram),
70 I4("batt", &mbc.batt),
72 I4("rtcR", &rtc.sel),
73 I4("rtcL", &rtc.latch),
74 I4("rtcC", &rtc.carry),
75 I4("rtcS", &rtc.stop),
76 I4("rtcd", &rtc.d),
77 I4("rtch", &rtc.h),
78 I4("rtcm", &rtc.m),
79 I4("rtcs", &rtc.s),
80 I4("rtct", &rtc.t),
81 I1("rtR8", &rtc.regs[0]),
82 I1("rtR9", &rtc.regs[1]),
83 I1("rtRA", &rtc.regs[2]),
84 I1("rtRB", &rtc.regs[3]),
85 I1("rtRC", &rtc.regs[4]),
87 I4("S1on", &snd.ch[0].on),
88 I4("S1p ", &snd.ch[0].pos),
89 I4("S1c ", &snd.ch[0].cnt),
90 I4("S1ec", &snd.ch[0].encnt),
91 I4("S1sc", &snd.ch[0].swcnt),
92 I4("S1sf", &snd.ch[0].swfreq),
94 I4("S2on", &snd.ch[1].on),
95 I4("S2p ", &snd.ch[1].pos),
96 I4("S2c ", &snd.ch[1].cnt),
97 I4("S2ec", &snd.ch[1].encnt),
99 I4("S3on", &snd.ch[2].on),
100 I4("S3p ", &snd.ch[2].pos),
101 I4("S3c ", &snd.ch[2].cnt),
103 I4("S4on", &snd.ch[3].on),
104 I4("S4p ", &snd.ch[3].pos),
105 I4("S4c ", &snd.ch[3].cnt),
106 I4("S4ec", &snd.ch[3].encnt),
108 I4("hdma", &hw.hdma),
110 I4("sram", &sramblock),
111 I4("iram", &iramblock),
112 I4("vram", &vramblock),
113 I4("hi ", &hiofs),
114 I4("pal ", &palofs),
115 I4("oam ", &oamofs),
116 I4("wav ", &wavofs),
118 /* NOSAVE is a special code to prevent the rest of the table
119 * from being saved, used to support old stuff for backwards
120 * compatibility... */
121 NOSAVE,
123 /* the following are obsolete as of 0x104 */
125 I4("hram", &hramofs),
127 R(P1), R(SB), R(SC),
128 R(DIV), R(TIMA), R(TMA), R(TAC),
129 R(IE), R(IF),
130 R(LCDC), R(STAT), R(LY), R(LYC),
131 R(SCX), R(SCY), R(WX), R(WY),
132 R(BGP), R(OBP0), R(OBP1),
133 R(DMA),
135 R(VBK), R(SVBK), R(KEY1),
136 R(BCPS), R(BCPD), R(OCPS), R(OCPD),
138 R(NR10), R(NR11), R(NR12), R(NR13), R(NR14),
139 R(NR21), R(NR22), R(NR23), R(NR24),
140 R(NR30), R(NR31), R(NR32), R(NR33), R(NR34),
141 R(NR41), R(NR42), R(NR43), R(NR44),
142 R(NR50), R(NR51), R(NR52),
144 I1("DMA1", &R_HDMA1),
145 I1("DMA2", &R_HDMA2),
146 I1("DMA3", &R_HDMA3),
147 I1("DMA4", &R_HDMA4),
148 I1("DMA5", &R_HDMA5),
154 void loadstate(FILE *f)
156 int i, j;
157 byte buf[4096];
158 un32 (*header)[2] = (un32 (*)[2])buf;
159 un32 d;
160 int irl = hw.cgb ? 8 : 2;
161 int vrl = hw.cgb ? 4 : 2;
162 int srl = mbc.ramsize << 1;
164 ver = hramofs = hiofs = palofs = oamofs = wavofs = 0;
166 fseek(f, 0, SEEK_SET);
167 fread(buf, 4096, 1, f);
169 for (j = 0; header[j][0]; j++)
171 for (i = 0; svars[i].ptr; i++)
173 if (memcmp(&header[j][0], svars[i].key, 4))
174 continue;
175 d = LIL(header[j][1]);
176 switch (svars[i].len)
178 case 1:
179 *(byte *)svars[i].ptr = d;
180 break;
181 case 2:
182 *(un16 *)svars[i].ptr = d;
183 break;
184 case 4:
185 *(un32 *)svars[i].ptr = d;
186 break;
188 break;
192 /* obsolete as of version 0x104 */
193 if (hramofs) memcpy(ram.hi+128, buf+hramofs, 127);
195 if (hiofs) memcpy(ram.hi, buf+hiofs, sizeof ram.hi);
196 if (palofs) memcpy(lcd.pal, buf+palofs, sizeof lcd.pal);
197 if (oamofs) memcpy(lcd.oam.mem, buf+oamofs, sizeof lcd.oam);
199 if (wavofs) memcpy(snd.wave, buf+wavofs, sizeof snd.wave);
200 else memcpy(snd.wave, ram.hi+0x30, 16); /* patch data from older files */
202 fseek(f, iramblock<<12, SEEK_SET);
203 fread(ram.ibank, 4096, irl, f);
205 fseek(f, vramblock<<12, SEEK_SET);
206 fread(lcd.vbank, 4096, vrl, f);
208 fseek(f, sramblock<<12, SEEK_SET);
209 fread(ram.sbank, 4096, srl, f);
212 void savestate(FILE *f)
214 int i;
215 byte buf[4096];
216 un32 (*header)[2] = (un32 (*)[2])buf;
217 un32 d = 0;
218 int irl = hw.cgb ? 8 : 2;
219 int vrl = hw.cgb ? 4 : 2;
220 int srl = mbc.ramsize << 1;
222 ver = 0x105;
223 iramblock = 1;
224 vramblock = 1+irl;
225 sramblock = 1+irl+vrl;
226 wavofs = 4096 - 784;
227 hiofs = 4096 - 768;
228 palofs = 4096 - 512;
229 oamofs = 4096 - 256;
230 memset(buf, 0, sizeof buf);
232 for (i = 0; svars[i].len > 0; i++)
234 memcpy(&header[i][0], svars[i].key, 4);
235 switch (svars[i].len)
237 case 1:
238 d = *(byte *)svars[i].ptr;
239 break;
240 case 2:
241 d = *(un16 *)svars[i].ptr;
242 break;
243 case 4:
244 d = *(un32 *)svars[i].ptr;
245 break;
247 header[i][1] = LIL(d);
249 header[i][0] = header[i][1] = 0;
251 memcpy(buf+hiofs, ram.hi, sizeof ram.hi);
252 memcpy(buf+palofs, lcd.pal, sizeof lcd.pal);
253 memcpy(buf+oamofs, lcd.oam.mem, sizeof lcd.oam);
254 memcpy(buf+wavofs, snd.wave, sizeof snd.wave);
256 fseek(f, 0, SEEK_SET);
257 fwrite(buf, 4096, 1, f);
259 fseek(f, iramblock<<12, SEEK_SET);
260 fwrite(ram.ibank, 4096, irl, f);
262 fseek(f, vramblock<<12, SEEK_SET);
263 fwrite(lcd.vbank, 4096, vrl, f);
265 fseek(f, sramblock<<12, SEEK_SET);
266 fwrite(ram.sbank, 4096, srl, f);