rcvars: add comment explaining the args
[rofl0r-gnuboy.git] / loader.c
blob4f93f68f7b611ba2fb23fd9ec0595e6da211fef0
1 #undef _POSIX_C_SOURCE
2 #define _POSIX_C_SOURCE 200809L
3 #undef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <time.h>
12 #include "defs.h"
13 #include "regs.h"
14 #include "mem.h"
15 #include "hw.h"
16 #include "rtc.h"
17 #include "rc.h"
18 #include "lcd.h"
19 #include "inflate.h"
20 #define XZ_USE_CRC64
21 #include "xz/xz.h"
22 #include "save.h"
23 #include "sound.h"
24 #include "sys.h"
26 static int mbc_table[256] =
28 0, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3,
29 3, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, MBC_RUMBLE, MBC_RUMBLE, MBC_RUMBLE, 0,
30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MBC_HUC3, MBC_HUC1
49 static int rtc_table[256] =
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
52 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 static int batt_table[256] =
58 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
59 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
63 static int romsize_table[256] =
65 2, 4, 8, 16, 32, 64, 128, 256, 512,
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 128, 128, 128
76 /* 0, 0, 72, 80, 96 -- actual values but bad to use these! */
79 static int ramsize_table[256] =
81 1, 1, 1, 4, 16,
82 4 /* FIXME - what value should this be?! */
86 static char *bootroms[2];
87 static char *romfile;
88 static char *sramfile;
89 static char *rtcfile;
90 static char *saveprefix;
92 static char *savename;
93 static char *savedir;
95 static int saveslot;
97 static int forcebatt, nobatt;
98 static int forcedmg, gbamode;
100 static int memfill = -1, memrand = -1;
103 static void initmem(void *mem, int size)
105 char *p = mem;
106 if (memrand >= 0)
108 srand(memrand ? memrand : time(0));
109 while(size--) *(p++) = rand();
111 else if (memfill >= 0)
112 memset(p, memfill, size);
115 static byte *loadfile(FILE *f, int *len)
117 int c, l = 0, p = 0;
118 byte *d = 0, buf[512];
120 for(;;)
122 c = fread(buf, 1, sizeof buf, f);
123 if (c <= 0) break;
124 l += c;
125 d = realloc(d, l);
126 if (!d) return 0;
127 memcpy(d+p, buf, c);
128 p += c;
130 *len = l;
131 return d;
134 static byte *inf_buf;
135 static int inf_pos, inf_len;
137 static void inflate_callback(byte b)
139 if (inf_pos >= inf_len)
141 inf_len += 512;
142 inf_buf = realloc(inf_buf, inf_len);
143 if (!inf_buf) die("out of memory inflating file @ %d bytes\n", inf_pos);
145 inf_buf[inf_pos++] = b;
148 static byte *gunzip(byte *data, int *len) {
149 long pos = 0;
150 inf_buf = 0;
151 inf_pos = inf_len = 0;
152 if (unzip(data, &pos, inflate_callback) < 0)
153 return data;
154 *len = inf_pos;
155 return inf_buf;
158 static void write_dec(byte *data, int len) {
159 int i;
160 for(i=0; i < len; i++)
161 inflate_callback(data[i]);
164 static int unxz(byte *data, int len) {
165 struct xz_buf b;
166 struct xz_dec *s;
167 enum xz_ret ret;
168 unsigned char out[4096];
171 * Support up to 64 MiB dictionary. The actually needed memory
172 * is allocated once the headers have been parsed.
174 s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
175 if(!s) goto err;
177 b.in = data;
178 b.in_pos = 0;
179 b.in_size = len;
180 b.out = out;
181 b.out_pos = 0;
182 b.out_size = sizeof(out);
184 while (1) {
185 ret = xz_dec_run(s, &b);
186 if(b.out_pos == sizeof(out)) {
187 write_dec(out, sizeof(out));
188 b.out_pos = 0;
191 if(ret == XZ_OK) continue;
193 write_dec(out, b.out_pos);
195 if(ret == XZ_STREAM_END) {
196 xz_dec_end(s);
197 return 0;
199 goto err;
202 err:
203 xz_dec_end(s);
204 return -1;
207 static byte *do_unxz(byte *data, int *len) {
208 xz_crc32_init();
209 xz_crc64_init();
210 inf_buf = 0;
211 inf_pos = inf_len = 0;
212 if (unxz(data, *len) < 0)
213 return data;
214 *len = inf_pos;
215 return inf_buf;
218 static byte *decompress(byte *data, int *len)
220 if (data[0] == 0x1f && data[1] == 0x8b)
221 return gunzip(data, len);
222 if(data[0] == 0xFD && !memcmp(data+1, "7zXZ", 4))
223 return do_unxz(data, len);
224 return data;
227 static FILE* rom_loadfile(char *fn, byte** data, int *len) {
228 FILE *f;
229 if (strcmp(fn, "-")) f = fopen(fn, "rb");
230 else f = stdin;
231 if (!f) die("cannot open rom file: %s\n", fn);
232 *data = loadfile(f, len);
233 *data = decompress(*data, len);
234 return f;
237 int bootrom_load() {
238 byte *data;
239 int len;
240 FILE *f;
241 REG(RI_BOOT) = 0xff;
242 if (!bootroms[hw.cgb] || !bootroms[hw.cgb][0]) return 0;
243 f = rom_loadfile(bootroms[hw.cgb], &data, &len);
244 bootrom.bank = realloc(data, 16384);
245 memset(bootrom.bank[0]+len, 0xff, 16384-len);
246 memcpy(bootrom.bank[0]+0x100, rom.bank[0]+0x100, 0x100);
247 fclose(f);
248 REG(RI_BOOT) = 0xfe;
249 return 0;
252 int rom_load()
254 FILE *f;
255 byte c, *data, *header;
256 int len = 0, rlen;
257 f = rom_loadfile(romfile, &data, &len);
258 header = data;
260 memcpy(rom.name, header+0x0134, 16);
261 if (rom.name[14] & 0x80) rom.name[14] = 0;
262 if (rom.name[15] & 0x80) rom.name[15] = 0;
263 rom.name[16] = 0;
265 c = header[0x0147];
266 mbc.type = mbc_table[c];
267 mbc.batt = (batt_table[c] && !nobatt) || forcebatt;
268 rtc.batt = rtc_table[c];
269 mbc.romsize = romsize_table[header[0x0148]];
270 mbc.ramsize = ramsize_table[header[0x0149]];
272 if (!mbc.romsize) die("unknown ROM size %02X\n", header[0x0148]);
273 if (!mbc.ramsize) die("unknown SRAM size %02X\n", header[0x0149]);
275 rlen = 16384 * mbc.romsize;
276 rom.bank = realloc(data, rlen);
277 if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len);
279 ram.sbank = malloc(8192 * mbc.ramsize);
281 initmem(ram.sbank, 8192 * mbc.ramsize);
282 initmem(ram.ibank, 4096 * 8);
284 mbc.rombank = 1;
285 mbc.rambank = 0;
287 c = header[0x0143];
288 hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg;
289 hw.gba = (hw.cgb && gbamode);
291 if (strcmp(romfile, "-")) fclose(f);
293 return 0;
296 int rom_load_simple(char *fn) {
297 romfile = fn;
298 return rom_load();
301 int sram_load()
303 FILE *f;
305 if (!mbc.batt || !sramfile || !*sramfile) return -1;
307 /* Consider sram loaded at this point, even if file doesn't exist */
308 ram.loaded = 1;
310 f = fopen(sramfile, "rb");
311 if (!f) return -1;
312 fread(ram.sbank, 8192, mbc.ramsize, f);
313 fclose(f);
315 return 0;
319 int sram_save()
321 FILE *f;
323 /* If we crash before we ever loaded sram, DO NOT SAVE! */
324 if (!mbc.batt || !sramfile || !ram.loaded || !mbc.ramsize)
325 return -1;
327 f = fopen(sramfile, "wb");
328 if (!f) return -1;
329 fwrite(ram.sbank, 8192, mbc.ramsize, f);
330 fclose(f);
332 return 0;
336 void state_save(int n)
338 FILE *f;
339 char *name;
341 if (n < 0) n = saveslot;
342 if (n < 0) n = 0;
343 name = malloc(strlen(saveprefix) + 5);
344 sprintf(name, "%s.%03d", saveprefix, n);
346 if ((f = fopen(name, "wb")))
348 savestate(f);
349 fclose(f);
351 free(name);
355 void state_load(int n)
357 FILE *f;
358 char *name;
360 if (n < 0) n = saveslot;
361 if (n < 0) n = 0;
362 name = malloc(strlen(saveprefix) + 5);
363 sprintf(name, "%s.%03d", saveprefix, n);
365 if ((f = fopen(name, "rb")))
367 loadstate(f);
368 fclose(f);
369 vram_dirty();
370 pal_dirty();
371 sound_dirty();
372 mem_updatemap();
374 free(name);
377 void rtc_save()
379 FILE *f;
380 if (!rtc.batt) return;
381 if (!(f = fopen(rtcfile, "wb"))) return;
382 rtc_save_internal(f);
383 fclose(f);
386 void rtc_load()
388 FILE *f;
389 if (!rtc.batt) return;
390 if (!(f = fopen(rtcfile, "r"))) return;
391 rtc_load_internal(f);
392 fclose(f);
396 void loader_unload()
398 sram_save();
399 if (romfile) free(romfile);
400 if (sramfile) free(sramfile);
401 if (saveprefix) free(saveprefix);
402 if (rom.bank) free(rom.bank);
403 if (ram.sbank) free(ram.sbank);
404 romfile = sramfile = saveprefix = 0;
405 rom.bank = 0;
406 ram.sbank = 0;
407 mbc.type = mbc.romsize = mbc.ramsize = mbc.batt = 0;
410 static char *base(char *s)
412 char *p;
413 p = strrchr(s, '/');
414 if (p) return p+1;
415 return s;
418 static char *ldup(char *s)
420 int i;
421 char *n, *p;
422 p = n = malloc(strlen(s));
423 for (i = 0; s[i]; i++) if (isalnum(s[i])) *(p++) = tolower(s[i]);
424 *p = 0;
425 return n;
428 static void cleanup()
430 sram_save();
431 rtc_save();
432 /* IDEA - if error, write emergency savestate..? */
435 void loader_init(char *s)
437 char *name, *p;
439 sys_checkdir(savedir, 1); /* needs to be writable */
441 romfile = s;
442 rom_load();
443 bootrom_load();
444 vid_settitle(rom.name);
445 if (savename && *savename)
447 if (savename[0] == '-' && savename[1] == 0)
448 name = ldup(rom.name);
449 else name = strdup(savename);
451 else if (romfile && *base(romfile) && strcmp(romfile, "-"))
453 name = strdup(base(romfile));
454 p = strchr(name, '.');
455 if (p) *p = 0;
457 else name = ldup(rom.name);
459 saveprefix = malloc(strlen(savedir) + strlen(name) + 2);
460 sprintf(saveprefix, "%s/%s", savedir, name);
462 sramfile = malloc(strlen(saveprefix) + 5);
463 strcpy(sramfile, saveprefix);
464 strcat(sramfile, ".sav");
466 rtcfile = malloc(strlen(saveprefix) + 5);
467 strcpy(rtcfile, saveprefix);
468 strcat(rtcfile, ".rtc");
470 sram_load();
471 rtc_load();
473 atexit(cleanup);
476 rcvar_t loader_exports[] =
478 RCV_STRING("bootrom_dmg", &bootroms[0], "bootrom for DMG games"),
479 RCV_STRING("bootrom_cgb", &bootroms[1], "bootrom for CGB games"),
480 RCV_STRING("savedir", &savedir, "save directory"),
481 RCV_STRING("savename", &savename, "base filename for saves"),
482 RCV_INT("saveslot", &saveslot, "which savestate slot to use"),
483 RCV_BOOL("forcebatt", &forcebatt, "save SRAM even on carts w/o battery"),
484 RCV_BOOL("nobatt", &nobatt, "never save SRAM"),
485 RCV_BOOL("forcedmg", &forcedmg, "force DMG mode for CGB carts"),
486 RCV_BOOL("gbamode", &gbamode, "simulate cart being used on a GBA"),
487 RCV_INT("memfill", &memfill, ""),
488 RCV_INT("memrand", &memrand, ""),
489 RCV_END