A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1#include "rockmacros.h"
2
3#include "defs.h"
4#include "cpu-gb.h"
5#include "cpuregs.h"
6#include "hw.h"
7#include "regs.h"
8#include "lcd-gb.h"
9#include "rtc-gb.h"
10#include "mem.h"
11#include "sound.h"
12#include "save.h"
13
14#ifdef ROCKBOX_LITTLE_ENDIAN
15#define LIL(x) (x)
16#else
17#define LIL(x) ((x<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|(x>>24))
18#endif
19
20#define I1(s, p) { 1, { s }, p }
21#define I2(s, p) { 2, { s }, p }
22#define I4(s, p) { 4, { s }, p }
23#define R(r) I1(#r, &R_##r)
24#define NOSAVE { -1, { "\0\0\0\0" }, 0 }
25#define END { 0, { "\0\0\0\0" }, 0 }
26
27struct svar
28{
29 int len;
30 union
31 {
32 char _key[4] __NONSTRING;
33 un32 key;
34 } k;
35 void *ptr;
36};
37
38static int ver;
39static int sramblock, iramblock, vramblock;
40static int hramofs, hiofs, palofs, oamofs, wavofs;
41
42struct svar svars[] =
43{
44 I4("GbSs", &ver),
45
46 I2("PC ", &PC),
47 I2("SP ", &SP),
48 I2("HL ", &HL),
49#ifdef DYNAREC
50 I1("A ", &A),
51 I1("B ", &A),
52 I1("C ", &A),
53 I1("D ", &A),
54 I1("E ", &A),
55 I1("F ", &A),
56#else
57 I2("BC ", &BC),
58 I2("DE ", &DE),
59 I2("AF ", &AF),
60#endif
61 I4("IME ", &cpu.ime),
62 I4("ima ", &cpu.ima),
63 I4("spd ", &cpu.speed),
64 I4("halt", &cpu.halt),
65 I4("div ", &cpu.div),
66 I4("tim ", &cpu.tim),
67 I4("lcdc", &cpu.lcdc),
68 I4("snd ", &cpu.snd),
69
70 I1("ints", &hw.ilines),
71 I1("pad ", &hw.pad),
72 I4("cgb ", &hw.cgb),
73
74 I4("mbcm", &mbc.model),
75 I4("romb", &mbc.rombank),
76 I4("ramb", &mbc.rambank),
77 I4("enab", &mbc.enableram),
78 I4("batt", &mbc.batt),
79
80 I4("rtcR", &rtc.sel),
81 I4("rtcL", &rtc.latch),
82 I4("rtcC", &rtc.carry),
83 I4("rtcS", &rtc.stop),
84 I4("rtcd", &rtc.d),
85 I4("rtch", &rtc.h),
86 I4("rtcm", &rtc.m),
87 I4("rtcs", &rtc.s),
88 I4("rtct", &rtc.t),
89 I1("rtR8", &rtc.regs[0]),
90 I1("rtR9", &rtc.regs[1]),
91 I1("rtRA", &rtc.regs[2]),
92 I1("rtRB", &rtc.regs[3]),
93 I1("rtRC", &rtc.regs[4]),
94
95 I4("S1on", &snd.ch[0].on),
96 I4("S1p ", &snd.ch[0].pos),
97 I4("S1c ", &snd.ch[0].len),
98 I4("S1ec", &snd.ch[0].enlen),
99 I4("S1sc", &snd.ch[0].swlen),
100
101 I4("S2on", &snd.ch[1].on),
102 I4("S2p ", &snd.ch[1].pos),
103 I4("S2c ", &snd.ch[1].len),
104 I4("S2ec", &snd.ch[1].enlen),
105
106 I4("S3on", &snd.ch[2].on),
107 I4("S3p ", &snd.ch[2].pos),
108 I4("S3c ", &snd.ch[2].len),
109
110 I4("S4on", &snd.ch[3].on),
111 I4("S4p ", &snd.ch[3].pos),
112 I4("S4c ", &snd.ch[3].len),
113 I4("S4ec", &snd.ch[3].enlen),
114
115 I4("hdma", &hw.hdma),
116
117 I4("sram", &sramblock),
118 I4("iram", &iramblock),
119 I4("vram", &vramblock),
120 I4("hi ", &hiofs),
121 I4("pal ", &palofs),
122 I4("oam ", &oamofs),
123
124 /* NOSAVE is a special code to prevent the rest of the table
125 * from being saved, used to support old stuff for backwards
126 * compatibility... */
127 NOSAVE,
128
129 /* the following are obsolete as of 0x104 */
130
131 I4("hram", &hramofs),
132 /* I4("gba ", &hw.gba), */
133 /* I4("S1sf", &snd.ch[0].swfreq), */
134 I4("wav ", &wavofs),
135
136 R(P1), R(SB), R(SC),
137 R(DIV), R(TIMA), R(TMA), R(TAC),
138 R(IE), R(IF),
139 R(LCDC), R(STAT), R(LY), R(LYC),
140 R(SCX), R(SCY), R(WX), R(WY),
141 R(BGP), R(OBP0), R(OBP1),
142 R(DMA),
143
144 R(VBK), R(SVBK), R(KEY1),
145 R(BCPS), R(BCPD), R(OCPS), R(OCPD),
146
147 R(NR10), R(NR11), R(NR12), R(NR13), R(NR14),
148 R(NR21), R(NR22), R(NR23), R(NR24),
149 R(NR30), R(NR31), R(NR32), R(NR33), R(NR34),
150 R(NR41), R(NR42), R(NR43), R(NR44),
151 R(NR50), R(NR51), R(NR52),
152
153 I1("DMA1", &R_HDMA1),
154 I1("DMA2", &R_HDMA2),
155 I1("DMA3", &R_HDMA3),
156 I1("DMA4", &R_HDMA4),
157 I1("DMA5", &R_HDMA5),
158
159 END
160};
161
162
163void loadstate(int fd)
164{
165 int i, j;
166 byte buf[4096];
167 un32 (*header)[2] = (un32 (*)[2])buf;
168 un32 d;
169 int irl = hw.cgb ? 8 : 2;
170 int vrl = hw.cgb ? 4 : 2;
171 int srl = mbc.ramsize << 1;
172 size_t base_offset;
173
174 ver = hramofs = hiofs = palofs = oamofs = wavofs = 0;
175
176 base_offset = lseek(fd, 0, SEEK_CUR);
177
178 read(fd,buf, 4096);
179
180 for (j = 0; header[j][0]; j++)
181 {
182 for (i = 0; svars[i].ptr; i++)
183 {
184 if (header[j][0] != svars[i].k.key)
185 continue;
186 d = LIL(header[j][1]);
187 switch (svars[i].len)
188 {
189 case 1:
190 *(byte *)svars[i].ptr = d;
191 break;
192 case 2:
193 *(un16 *)svars[i].ptr = d;
194 break;
195 case 4:
196 *(un32 *)svars[i].ptr = d;
197 break;
198 }
199 break;
200 }
201 }
202
203 /* obsolete as of version 0x104 */
204 if (hramofs) memcpy(ram.hi+128, buf+hramofs, 127);
205 if (wavofs) memcpy(ram.hi+48, buf+wavofs, 16);
206
207 if (hiofs) memcpy(ram.hi, buf+hiofs, sizeof ram.hi);
208 if (palofs) memcpy(lcd.pal, buf+palofs, sizeof lcd.pal);
209 if (oamofs) memcpy(lcd.oam.mem, buf+oamofs, sizeof lcd.oam);
210
211 lseek(fd, base_offset + (iramblock << 12), SEEK_SET);
212 read(fd,ram.ibank, 4096*irl);
213
214 lseek(fd, base_offset + (vramblock << 12), SEEK_SET);
215 read(fd,lcd.vbank, 4096*vrl);
216
217 lseek(fd, base_offset + (sramblock << 12), SEEK_SET);
218 read(fd,ram.sbank, 4096*srl);
219 vram_dirty();
220 pal_dirty();
221 sound_dirty();
222 mem_updatemap();
223}
224
225void savestate(int fd)
226{
227 int i;
228 byte buf[4096];
229 un32 (*header)[2] = (un32 (*)[2])buf;
230 un32 d = 0;
231 int irl = hw.cgb ? 8 : 2;
232 int vrl = hw.cgb ? 4 : 2;
233 int srl = mbc.ramsize << 1;
234 size_t base_offset;
235
236 ver = 0x104;
237 iramblock = 1;
238 vramblock = 1+irl;
239 sramblock = 1+irl+vrl;
240 hiofs = 4096 - 768;
241 palofs = 4096 - 512;
242 oamofs = 4096 - 256;
243 memset(buf, 0, sizeof buf);
244
245 for (i = 0; svars[i].len > 0; i++)
246 {
247 header[i][0] = svars[i].k.key;
248 switch (svars[i].len)
249 {
250 case 1:
251 d = *(byte *)svars[i].ptr;
252 break;
253 case 2:
254 d = *(un16 *)svars[i].ptr;
255 break;
256 case 4:
257 d = *(un32 *)svars[i].ptr;
258 break;
259 }
260 header[i][1] = LIL(d);
261 }
262 header[i][0] = header[i][1] = 0;
263
264 memcpy(buf+hiofs, ram.hi, sizeof ram.hi);
265 memcpy(buf+palofs, lcd.pal, sizeof lcd.pal);
266 memcpy(buf+oamofs, lcd.oam.mem, sizeof lcd.oam);
267
268 /* calculate base offset for output file */
269 /* (we'll seek relative to that from now on) */
270 base_offset = lseek(fd, 0, SEEK_CUR);
271 write(fd,buf, 4096);
272
273 lseek(fd, base_offset + (iramblock << 12), SEEK_SET);
274 write(fd,ram.ibank, 4096*irl);
275
276 lseek(fd, base_offset + (vramblock << 12), SEEK_SET);
277 write(fd,lcd.vbank, 4096*vrl);
278
279 lseek(fd, base_offset + (sramblock << 12), SEEK_SET);
280 write(fd,ram.sbank, 4096*srl);
281}