f19d6a5e1d
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29819 a1c6a512-1295-4272-9138-f99709370657
315 lines
7.2 KiB
C
315 lines
7.2 KiB
C
#include "rockmacros.h"
|
|
#include "defs.h"
|
|
#include "regs.h"
|
|
#include "mem.h"
|
|
#include "hw.h"
|
|
#include "lcd-gb.h"
|
|
#include "rtc-gb.h"
|
|
#include "save.h"
|
|
#include "sound.h"
|
|
|
|
/* From http://www.semis.demon.co.uk/Gameboy/Gbspec.txt (4/17/2007)
|
|
* Cartridge type:
|
|
* 0 - ROM ONLY 12 - ROM+MBC3+RAM
|
|
* 1 - ROM+MBC1 13 - ROM+MBC3+RAM+BATT
|
|
* 2 - ROM+MBC1+RAM 19 - ROM+MBC5
|
|
* 3 - ROM+MBC1+RAM+BATT 1A - ROM+MBC5+RAM
|
|
* 5 - ROM+MBC2 1B - ROM+MBC5+RAM+BATT
|
|
* 6 - ROM+MBC2+BATTERY 1C - ROM+MBC5+RUMBLE
|
|
* 8 - ROM+RAM 1D - ROM+MBC5+RUMBLE+SRAM
|
|
* 9 - ROM+RAM+BATTERY 1E - ROM+MBC5+RUMBLE+SRAM+BATT
|
|
* B - ROM+MMM01 1F - Pocket Camera
|
|
* C - ROM+MMM01+SRAM FD - Bandai TAMA5
|
|
* D - ROM+MMM01+SRAM+BATT FE - Hudson HuC-3
|
|
* F - ROM+MBC3+TIMER+BATT FF - Hudson HuC-1
|
|
* 10 - ROM+MBC3+TIMER+RAM+BATT
|
|
* 11 - ROM+MBC3
|
|
*/
|
|
|
|
static const int mbc_table[256] =
|
|
{
|
|
MBC_NONE,
|
|
MBC_MBC1,
|
|
MBC_MBC1,
|
|
MBC_MBC1 | MBC_BAT,
|
|
0,
|
|
MBC_MBC2,
|
|
MBC_MBC2 | MBC_BAT,
|
|
0,
|
|
0,
|
|
MBC_BAT,
|
|
0,
|
|
0,
|
|
0,
|
|
MBC_BAT,
|
|
0,
|
|
MBC_MBC3 | MBC_BAT | MBC_RTC,
|
|
MBC_MBC3 | MBC_BAT | MBC_RTC,
|
|
MBC_MBC3,
|
|
MBC_MBC3,
|
|
MBC_MBC3 | MBC_BAT,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
MBC_MBC5,
|
|
MBC_MBC5,
|
|
MBC_MBC5 | MBC_BAT,
|
|
MBC_RUMBLE,
|
|
MBC_RUMBLE,
|
|
MBC_RUMBLE | MBC_BAT,
|
|
0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
MBC_HUC3,
|
|
MBC_HUC1
|
|
};
|
|
|
|
static const unsigned short romsize_table[56] =
|
|
{
|
|
2, 4, 8, 16, 32, 64, 128, 256,
|
|
512, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 128, 128, 128, 0
|
|
/* 0, 0, 0, 0, 72, 80, 96 -- actual values but bad to use these! */
|
|
};
|
|
|
|
/* Ram size should be no larger then 16 banks 1Mbit */
|
|
static const unsigned char ramsize_table[5] =
|
|
{
|
|
0, 1, 1, 4, 16
|
|
};
|
|
|
|
static const char *romfile;
|
|
static char sramfile[500];
|
|
static char rtcfile[500];
|
|
static char snfile[500];
|
|
static char saveprefix[500];
|
|
|
|
static int forcebatt, nobatt;
|
|
static int forcedmg;
|
|
|
|
static int memfill = -1, memrand = -1;
|
|
|
|
static void initmem(void *mem, int size)
|
|
{
|
|
char *p = mem;
|
|
if (memrand >= 0)
|
|
{
|
|
srand(memrand ? memrand : -6 ); /* time(0)); */
|
|
while(size--) *(p++) = rand();
|
|
}
|
|
else if (memfill >= 0)
|
|
memset(p, memfill, size);
|
|
}
|
|
|
|
static byte *loadfile(int fd, int *len)
|
|
{
|
|
byte *d;
|
|
|
|
*len=lseek(fd,0,SEEK_END);
|
|
d=malloc((*len)*sizeof(char)+64);
|
|
if(d==0)
|
|
{
|
|
die("Not enough memory");
|
|
return 0;
|
|
}
|
|
lseek(fd,0,SEEK_SET);
|
|
|
|
read(fd, d, *len);
|
|
|
|
return d;
|
|
}
|
|
|
|
static int rom_load(void)
|
|
{
|
|
int fd;
|
|
byte c, *data, *header;
|
|
int len = 0, rlen;
|
|
|
|
fd = open(romfile, O_RDONLY);
|
|
|
|
if (fd<0)
|
|
{
|
|
die("cannot open rom file %s", romfile);
|
|
return 1;
|
|
}
|
|
|
|
data = loadfile(fd, &len);
|
|
close(fd);
|
|
if(data==0)
|
|
{
|
|
die("Not Enough Memory");
|
|
return 1;
|
|
}
|
|
header = data; /* no zip. = decompress(data, &len); */
|
|
|
|
memcpy(rom.name, header+0x0134, 16);
|
|
if (rom.name[14] & 0x80) rom.name[14] = 0;
|
|
if (rom.name[15] & 0x80) rom.name[15] = 0;
|
|
rom.name[16] = 0;
|
|
|
|
c = header[0x0147];
|
|
mbc.type = mbc_table[c]&(MBC_MBC1|MBC_MBC2|MBC_MBC3|MBC_MBC5|MBC_RUMBLE|MBC_HUC1|MBC_HUC3);
|
|
mbc.batt = ((mbc_table[c]&MBC_BAT) && !nobatt) || forcebatt;
|
|
rtc.batt = mbc_table[c]&MBC_RTC;
|
|
|
|
if(header[0x0148]<10 || (header[0x0148]>51 && header[0x0148]<55))
|
|
mbc.romsize = romsize_table[header[0x0148]];
|
|
else
|
|
{
|
|
die("unknown ROM size %02X\n", header[0x0148]);
|
|
return 1;
|
|
}
|
|
|
|
if(header[0x0149]<5)
|
|
mbc.ramsize = ramsize_table[header[0x0149]];
|
|
else
|
|
{
|
|
die("unknown SRAM size %02X\n", header[0x0149]);
|
|
return 1;
|
|
}
|
|
|
|
rlen = 16384 * mbc.romsize;
|
|
rom.bank = (void *) data; /* realloc(data, rlen); */
|
|
if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len);
|
|
|
|
/* This is the size of the ram on the cartridge
|
|
* See http://www.semis.demon.co.uk/Gameboy/Gbspec.txt
|
|
* for a full description. (8192*number of banks)
|
|
*/
|
|
ram.sbank = malloc(8192 * mbc.ramsize);
|
|
if(ram.sbank==0 && mbc.ramsize!=0)
|
|
{
|
|
die("Not enough Memory");
|
|
return 1;
|
|
}
|
|
|
|
/* ram.ibank = malloc(4096*8); */
|
|
|
|
initmem(ram.sbank, 8192 * mbc.ramsize);
|
|
initmem(ram.ibank, 4096 * 8);
|
|
|
|
mbc.rombank = 1;
|
|
mbc.rambank = 0;
|
|
|
|
c = header[0x0143];
|
|
hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sram_load(void)
|
|
{
|
|
int fd;
|
|
|
|
if (!mbc.batt || !*sramfile) return -1;
|
|
|
|
/* Consider sram loaded at this point, even if file doesn't exist */
|
|
ram.loaded = 1;
|
|
|
|
fd = open(sramfile, O_RDONLY);
|
|
if (fd<0) return -1;
|
|
read(fd,ram.sbank, 8192*mbc.ramsize);
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int sram_save(void)
|
|
{
|
|
int fd;
|
|
|
|
/* If we crash before we ever loaded sram, DO NOT SAVE! */
|
|
if (!mbc.batt || !ram.loaded || !mbc.ramsize)
|
|
return -1;
|
|
fd = open(sramfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
|
if (fd<0) return -1;
|
|
write(fd,ram.sbank, 8192*mbc.ramsize);
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void rtc_save(void)
|
|
{
|
|
int fd;
|
|
if (!rtc.batt) return;
|
|
if ((fd = open(rtcfile, O_WRONLY|O_CREAT|O_TRUNC, 0666))<0) return;
|
|
rtc_save_internal(fd);
|
|
close(fd);
|
|
}
|
|
|
|
static void rtc_load(void)
|
|
{
|
|
int fd;
|
|
if (!rtc.batt) return;
|
|
if ((fd = open(rtcfile, O_RDONLY))<0) return;
|
|
rtc_load_internal(fd);
|
|
close(fd);
|
|
}
|
|
|
|
void sn_save(void)
|
|
{
|
|
int fd;
|
|
if ((fd = open(snfile, O_WRONLY | O_CREAT, 0666)) < 0)
|
|
return;
|
|
savestate(fd);
|
|
close(fd);
|
|
}
|
|
|
|
void sn_load(void)
|
|
{
|
|
int fd;
|
|
if ((fd = open(snfile, O_RDONLY, 0666)) < 0)
|
|
return;
|
|
loadstate(fd);
|
|
close(fd);
|
|
}
|
|
|
|
void cleanup(void)
|
|
{
|
|
sram_save();
|
|
rtc_save();
|
|
/* IDEA - if error, write emergency savestate..? */
|
|
}
|
|
|
|
void loader_init(const char *s)
|
|
{
|
|
romfile = s;
|
|
if(rom_load())
|
|
return;
|
|
|
|
snprintf(saveprefix, 499, "%s/%s", savedir, rom.name);
|
|
|
|
strcpy(sramfile, saveprefix);
|
|
strcat(sramfile, ".sav");
|
|
|
|
strcpy(rtcfile, saveprefix);
|
|
strcat(rtcfile, ".rtc");
|
|
strcpy(snfile, saveprefix);
|
|
strcat(snfile, ".sn");
|
|
|
|
sram_load();
|
|
rtc_load();
|
|
}
|