2 #define _POSIX_C_SOURCE 200809L
24 static int mbc_table
[256] =
26 0, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3,
27 3, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, MBC_RUMBLE
, MBC_RUMBLE
, MBC_RUMBLE
, 0,
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29 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,
32 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,
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 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,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42 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, MBC_HUC3
, MBC_HUC1
47 static int rtc_table
[256] =
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
50 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 static int batt_table
[256] =
56 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
57 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
61 static int romsize_table
[256] =
63 2, 4, 8, 16, 32, 64, 128, 256, 512,
64 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0,
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,
74 /* 0, 0, 72, 80, 96 -- actual values but bad to use these! */
77 static int ramsize_table
[256] =
80 4 /* FIXME - what value should this be?! */
85 static char *sramfile
;
87 static char *saveprefix
;
89 static char *savename
;
94 static int forcebatt
, nobatt
;
95 static int forcedmg
, gbamode
;
97 static int memfill
= -1, memrand
= -1;
100 static void initmem(void *mem
, int size
)
105 srand(memrand
? memrand
: time(0));
106 while(size
--) *(p
++) = rand();
108 else if (memfill
>= 0)
109 memset(p
, memfill
, size
);
112 static byte
*loadfile(FILE *f
, int *len
)
115 byte
*d
= 0, buf
[512];
119 c
= fread(buf
, 1, sizeof buf
, f
);
131 static byte
*inf_buf
;
132 static int inf_pos
, inf_len
;
134 static void inflate_callback(byte b
)
136 if (inf_pos
>= inf_len
)
139 inf_buf
= realloc(inf_buf
, inf_len
);
140 if (!inf_buf
) die("out of memory inflating file @ %d bytes\n", inf_pos
);
142 inf_buf
[inf_pos
++] = b
;
145 static byte
*decompress(byte
*data
, int *len
)
147 unsigned long pos
= 0;
148 if (data
[0] != 0x1f || data
[1] != 0x8b)
151 inf_pos
= inf_len
= 0;
152 if (unzip(data
, &pos
, inflate_callback
) < 0)
162 byte c
, *data
, *header
;
165 if (strcmp(romfile
, "-")) f
= fopen(romfile
, "rb");
167 if (!f
) die("cannot open rom file: %s\n", romfile
);
169 data
= loadfile(f
, &len
);
170 header
= data
= decompress(data
, &len
);
172 memcpy(rom
.name
, header
+0x0134, 16);
173 if (rom
.name
[14] & 0x80) rom
.name
[14] = 0;
174 if (rom
.name
[15] & 0x80) rom
.name
[15] = 0;
178 mbc
.type
= mbc_table
[c
];
179 mbc
.batt
= (batt_table
[c
] && !nobatt
) || forcebatt
;
180 rtc
.batt
= rtc_table
[c
];
181 mbc
.romsize
= romsize_table
[header
[0x0148]];
182 mbc
.ramsize
= ramsize_table
[header
[0x0149]];
184 if (!mbc
.romsize
) die("unknown ROM size %02X\n", header
[0x0148]);
185 if (!mbc
.ramsize
) die("unknown SRAM size %02X\n", header
[0x0149]);
187 rlen
= 16384 * mbc
.romsize
;
188 rom
.bank
= realloc(data
, rlen
);
189 if (rlen
> len
) memset(rom
.bank
[0]+len
, 0xff, rlen
- len
);
191 ram
.sbank
= malloc(8192 * mbc
.ramsize
);
193 initmem(ram
.sbank
, 8192 * mbc
.ramsize
);
194 initmem(ram
.ibank
, 4096 * 8);
200 hw
.cgb
= ((c
== 0x80) || (c
== 0xc0)) && !forcedmg
;
201 hw
.gba
= (hw
.cgb
&& gbamode
);
203 if (strcmp(romfile
, "-")) fclose(f
);
212 if (!mbc
.batt
|| !sramfile
|| !*sramfile
) return -1;
214 /* Consider sram loaded at this point, even if file doesn't exist */
217 f
= fopen(sramfile
, "rb");
219 fread(ram
.sbank
, 8192, mbc
.ramsize
, f
);
230 /* If we crash before we ever loaded sram, DO NOT SAVE! */
231 if (!mbc
.batt
|| !sramfile
|| !ram
.loaded
|| !mbc
.ramsize
)
234 f
= fopen(sramfile
, "wb");
236 fwrite(ram
.sbank
, 8192, mbc
.ramsize
, f
);
243 void state_save(int n
)
248 if (n
< 0) n
= saveslot
;
250 name
= malloc(strlen(saveprefix
) + 5);
251 sprintf(name
, "%s.%03d", saveprefix
, n
);
253 if ((f
= fopen(name
, "wb")))
262 void state_load(int n
)
267 if (n
< 0) n
= saveslot
;
269 name
= malloc(strlen(saveprefix
) + 5);
270 sprintf(name
, "%s.%03d", saveprefix
, n
);
272 if ((f
= fopen(name
, "rb")))
287 if (!rtc
.batt
) return;
288 if (!(f
= fopen(rtcfile
, "wb"))) return;
289 rtc_save_internal(f
);
296 if (!rtc
.batt
) return;
297 if (!(f
= fopen(rtcfile
, "r"))) return;
298 rtc_load_internal(f
);
306 if (romfile
) free(romfile
);
307 if (sramfile
) free(sramfile
);
308 if (saveprefix
) free(saveprefix
);
309 if (rom
.bank
) free(rom
.bank
);
310 if (ram
.sbank
) free(ram
.sbank
);
311 romfile
= sramfile
= saveprefix
= 0;
314 mbc
.type
= mbc
.romsize
= mbc
.ramsize
= mbc
.batt
= 0;
317 static char *base(char *s
)
325 static char *ldup(char *s
)
329 p
= n
= malloc(strlen(s
));
330 for (i
= 0; s
[i
]; i
++) if (isalnum(s
[i
])) *(p
++) = tolower(s
[i
]);
335 static void cleanup()
339 /* IDEA - if error, write emergency savestate..? */
342 void loader_init(char *s
)
346 sys_checkdir(savedir
, 1); /* needs to be writable */
350 vid_settitle(rom
.name
);
351 if (savename
&& *savename
)
353 if (savename
[0] == '-' && savename
[1] == 0)
354 name
= ldup(rom
.name
);
355 else name
= strdup(savename
);
357 else if (romfile
&& *base(romfile
) && strcmp(romfile
, "-"))
359 name
= strdup(base(romfile
));
360 p
= strchr(name
, '.');
363 else name
= ldup(rom
.name
);
365 saveprefix
= malloc(strlen(savedir
) + strlen(name
) + 2);
366 sprintf(saveprefix
, "%s/%s", savedir
, name
);
368 sramfile
= malloc(strlen(saveprefix
) + 5);
369 strcpy(sramfile
, saveprefix
);
370 strcat(sramfile
, ".sav");
372 rtcfile
= malloc(strlen(saveprefix
) + 5);
373 strcpy(rtcfile
, saveprefix
);
374 strcat(rtcfile
, ".rtc");
382 rcvar_t loader_exports
[] =
384 RCV_STRING("savedir", &savedir
),
385 RCV_STRING("savename", &savename
),
386 RCV_INT("saveslot", &saveslot
),
387 RCV_BOOL("forcebatt", &forcebatt
),
388 RCV_BOOL("nobatt", &nobatt
),
389 RCV_BOOL("forcedmg", &forcedmg
),
390 RCV_BOOL("gbamode", &gbamode
),
391 RCV_INT("memfill", &memfill
),
392 RCV_INT("memrand", &memrand
),