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#include "defs.h"
3#include "regs.h"
4#include "mem.h"
5#include "hw.h"
6#include "lcd-gb.h"
7#include "rtc-gb.h"
8#include "save.h"
9#include "sound.h"
10#include "loader.h"
11
12/* From http://www.semis.demon.co.uk/Gameboy/Gbspec.txt (4/17/2007)
13 * Cartridge type:
14 * 0 - ROM ONLY 12 - ROM+MBC3+RAM
15 * 1 - ROM+MBC1 13 - ROM+MBC3+RAM+BATT
16 * 2 - ROM+MBC1+RAM 19 - ROM+MBC5
17 * 3 - ROM+MBC1+RAM+BATT 1A - ROM+MBC5+RAM
18 * 5 - ROM+MBC2 1B - ROM+MBC5+RAM+BATT
19 * 6 - ROM+MBC2+BATTERY 1C - ROM+MBC5+RUMBLE
20 * 8 - ROM+RAM 1D - ROM+MBC5+RUMBLE+SRAM
21 * 9 - ROM+RAM+BATTERY 1E - ROM+MBC5+RUMBLE+SRAM+BATT
22 * B - ROM+MMM01 1F - Pocket Camera
23 * C - ROM+MMM01+SRAM FD - Bandai TAMA5
24 * D - ROM+MMM01+SRAM+BATT FE - Hudson HuC-3
25 * F - ROM+MBC3+TIMER+BATT FF - Hudson HuC-1
26 * 10 - ROM+MBC3+TIMER+RAM+BATT
27 * 11 - ROM+MBC3
28 */
29
30static const int mbc_table[256] =
31{
32 MBC_NONE,
33 MBC_MBC1,
34 MBC_MBC1,
35 MBC_MBC1 | MBC_BAT,
36 0,
37 MBC_MBC2,
38 MBC_MBC2 | MBC_BAT,
39 0,
40 0,
41 MBC_BAT,
42 0,
43 0,
44 0,
45 MBC_BAT,
46 0,
47 MBC_MBC3 | MBC_BAT | MBC_RTC,
48 MBC_MBC3 | MBC_BAT | MBC_RTC,
49 MBC_MBC3,
50 MBC_MBC3,
51 MBC_MBC3 | MBC_BAT,
52 0,
53 0,
54 0,
55 0,
56 0,
57 MBC_MBC5,
58 MBC_MBC5,
59 MBC_MBC5 | MBC_BAT,
60 MBC_RUMBLE,
61 MBC_RUMBLE,
62 MBC_RUMBLE | MBC_BAT,
63 0,
64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 MBC_HUC3,
82 MBC_HUC1
83};
84
85static const unsigned short romsize_table[56] =
86{
87 2, 4, 8, 16, 32, 64, 128, 256,
88 512, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0,
92 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 128, 128, 128, 0
94 /* 0, 0, 0, 0, 72, 80, 96 -- actual values but bad to use these! */
95};
96
97/* Ram size should be no larger then 16 banks 1Mbit */
98static const unsigned char ramsize_table[5] =
99{
100 0, 1, 1, 4, 16
101};
102
103static const char *romfile;
104static char sramfile[500];
105static char rtcfile[500];
106static char snfile[500];
107static char saveprefix[500];
108
109static int forcebatt, nobatt;
110static int forcedmg;
111
112static int memfill = -1, memrand = -1;
113
114static void initmem(void *mem, int size)
115{
116 char *p = mem;
117 if (memrand >= 0)
118 {
119 srand(memrand ? memrand : -6 ); /* time(0)); */
120 while(size--) *(p++) = rand();
121 }
122 else if (memfill >= 0)
123 memset(p, memfill, size);
124}
125
126static byte *loadfile(int fd, int *len)
127{
128 byte *d;
129
130 *len=lseek(fd,0,SEEK_END);
131 d=malloc((*len)*sizeof(char)+64);
132 if(d==0)
133 {
134 die("Not enough memory");
135 return 0;
136 }
137 lseek(fd,0,SEEK_SET);
138
139 read(fd, d, *len);
140
141 return d;
142}
143
144static int rom_load(void)
145{
146 int fd;
147 byte c, *data, *header;
148 int len = 0, rlen;
149
150 fd = open(romfile, O_RDONLY);
151
152 if (fd<0)
153 {
154 die("cannot open rom file %s", romfile);
155 return 1;
156 }
157
158 data = loadfile(fd, &len);
159 close(fd);
160 if(data==0)
161 {
162 die("Not Enough Memory");
163 return 1;
164 }
165 header = data; /* no zip. = decompress(data, &len); */
166
167 memcpy(rom.name, header+0x0134, 16);
168 if (rom.name[14] & 0x80) rom.name[14] = 0;
169 if (rom.name[15] & 0x80) rom.name[15] = 0;
170 rom.name[16] = 0;
171
172 c = header[0x0147];
173 mbc.type = mbc_table[c]&(MBC_MBC1|MBC_MBC2|MBC_MBC3|MBC_MBC5|MBC_RUMBLE|MBC_HUC1|MBC_HUC3);
174 mbc.batt = ((mbc_table[c]&MBC_BAT) && !nobatt) || forcebatt;
175 rtc.batt = mbc_table[c]&MBC_RTC;
176
177 if(header[0x0148]<10 || (header[0x0148]>51 && header[0x0148]<55))
178 mbc.romsize = romsize_table[header[0x0148]];
179 else
180 {
181 die("unknown ROM size %02X\n", header[0x0148]);
182 return 1;
183 }
184
185 if(header[0x0149]<5)
186 mbc.ramsize = ramsize_table[header[0x0149]];
187 else
188 {
189 die("unknown SRAM size %02X\n", header[0x0149]);
190 return 1;
191 }
192
193 rlen = 16384 * mbc.romsize;
194 rom.bank = (void *) data; /* realloc(data, rlen); */
195 if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len);
196
197 /* This is the size of the ram on the cartridge
198 * See http://www.semis.demon.co.uk/Gameboy/Gbspec.txt
199 * for a full description. (8192*number of banks)
200 */
201 ram.sbank = malloc(8192 * mbc.ramsize);
202 if(ram.sbank==0 && mbc.ramsize!=0)
203 {
204 die("Not enough Memory");
205 return 1;
206 }
207
208 /* ram.ibank = malloc(4096*8); */
209
210 initmem(ram.sbank, 8192 * mbc.ramsize);
211 initmem(ram.ibank, 4096 * 8);
212
213 mbc.rombank = 1;
214 mbc.rambank = 0;
215
216 c = header[0x0143];
217 hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg;
218
219 return 0;
220}
221
222static int sram_load(void)
223{
224 int fd;
225
226 if (!mbc.batt || !*sramfile) return -1;
227
228 /* Consider sram loaded at this point, even if file doesn't exist */
229 ram.loaded = 1;
230
231 fd = open(sramfile, O_RDONLY);
232 if (fd<0) return -1;
233 read(fd,ram.sbank, 8192*mbc.ramsize);
234 close(fd);
235
236 return 0;
237}
238
239
240static int sram_save(void)
241{
242 int fd;
243
244 /* If we crash before we ever loaded sram, DO NOT SAVE! */
245 if (!mbc.batt || !ram.loaded || !mbc.ramsize)
246 return -1;
247 fd = open(sramfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
248 if (fd<0) return -1;
249 write(fd,ram.sbank, 8192*mbc.ramsize);
250 close(fd);
251
252 return 0;
253}
254
255static void rtc_save(void)
256{
257 int fd;
258 if (!rtc.batt) return;
259 if ((fd = open(rtcfile, O_WRONLY|O_CREAT|O_TRUNC, 0666))<0) return;
260 rtc_save_internal(fd);
261 close(fd);
262}
263
264static void rtc_load(void)
265{
266 int fd;
267 if (!rtc.batt) return;
268 if ((fd = open(rtcfile, O_RDONLY))<0) return;
269 rtc_load_internal(fd);
270 close(fd);
271}
272
273void sn_save(void)
274{
275 int fd;
276 if ((fd = open(snfile, O_WRONLY | O_CREAT, 0666)) < 0)
277 return;
278 savestate(fd);
279 close(fd);
280}
281
282void sn_load(void)
283{
284 int fd;
285 if ((fd = open(snfile, O_RDONLY, 0666)) < 0)
286 return;
287 loadstate(fd);
288 close(fd);
289}
290
291void cleanup(void)
292{
293 sram_save();
294 rtc_save();
295 /* IDEA - if error, write emergency savestate..? */
296}
297
298void loader_init(const char *s)
299{
300 romfile = s;
301 if(rom_load())
302 return;
303
304 snprintf(saveprefix, 499, "%s/%s", savedir, rom.name);
305
306 strcpy(sramfile, saveprefix);
307 strcat(sramfile, ".sav");
308
309 strcpy(rtcfile, saveprefix);
310 strcat(rtcfile, ".rtc");
311 strcpy(snfile, saveprefix);
312 strcat(snfile, ".sn");
313
314 sram_load();
315 rtc_load();
316}