tinyboy-emulator/mem.c
Hojun-Cho bc76c36ed4 add loadsave
loadsave: only for BAT features cartidge
[load|save] state: for all cartidge. It's like snapshot
2024-07-18 20:24:34 +09:00

266 lines
4.7 KiB
C

#include "gb.h"
static int
mbc0(int a, int _);
static int
mbc1(int a, int _);
u8* rom;
u8 *romb, *vramb, *wramb, *eramb;
u8 wram[32768], vram[16384], oam[256], reg[256];
u8* back;
u32 pal[64];
int nrom, nback, nbackbank;
u64 clock;
u32 divclock;
int prish;
u32 moncols[4];
u32 white;
int (*mappers[])(int, int) = { mbc0, mbc1 };
int (*mapper)(int, int);
Var memvars[] = {ARR(wram), ARR(vram), ARR(oam), ARR(reg), VAR(clock), VAR(divclock), {nil, 0, 0}};
static u8
regread(u16 a)
{
u8 v;
switch (a) {
case JOYP:
v = 0xff;
if ((reg[a] & 0x10) == 0)
v &= 0xf0 | ~keys;
if ((reg[a] & 0x20) == 0)
v &= 0xf0 | ~(keys >> 4);
return v;
case DIV:
return reg[DIV] + (clock - divclock >> 7 - ((mode & TURBO) != 0));
case STAT:
return reg[a] & 0xf8 | (reg[LYC] == ppuy) << 2 | ppustate;
case LY:
return ppuy;
default:
return reg[a];
}
}
static void
regwrite(u16 a, u8 v)
{
int i;
switch (a) {
case JOYP:
v |= 0xCF;/* all disabled */
break;
case DIV:
divclock = clock;
v = 0;
break;
case STAT:
v |= 0x80;
if ((v & IRQLYC) != 0 && ppuy == reg[LYC])
reg[IF] |= IRQLCDS;
break;
case LYC:
if ((reg[STAT] & IRQLYC) != 0 && ppuy == v)
reg[IF] |= IRQLCDS;
break;
case LCDC:
ppusync();
if ((~v & reg[a] & LCDEN) != 0) {
ppuy = 0;
ppuw = 0;
ppustate = 0;
delevent(&evhblank);
}
if ((v & ~reg[a] & LCDEN) != 0)
addevent(&evhblank, 456 * 2);
break;
case SCY:
case SCX:
case WY:
case WX:
ppusync();
break;
case BGP:
case OBP0:
case OBP1:
ppusync();
i = a - BGP << 2;
pal[i] = moncols[~v & 3];
pal[i + 1] = moncols[~v >> 2 & 3];
pal[i + 2] = moncols[~v >> 4 & 3];
pal[i + 3] = moncols[~v >> 6 & 3];
break;
case IE:
v &= 0x1f;
break;
case DMA:
for (i = 0; i < 160; ++i)
oam[i] = memread((u16)v << 8 | i);
break;
default:
if (a >= 0x80)
break;
v = 0xff;
}
reg[a] = v;
}
u8
memread(u16 a)
{
switch (a >> 12) {
case 0:
case 1:
case 2:
case 3:
return rom[a];
case 4:
case 5:
case 6:
case 7:
return romb[a - 0x4000];
case 8:
case 9:
return vramb[a - 0x8000];
case 10:
case 11:
if (eramb != nil)
return eramb[a - 0xa000];
return mapper(READ, a);
case 12:
case 14:
return wram[a & 0xFFF];
case 13:
return wramb[a & 0xFFF];
case 15:
if (a >= 0xFF00)
return regread(a - 0xFF00);
else if (a >= 0xFE00)
return oam[a - 0xFE00];
}
return 0xFF;
}
void
memwrite(u16 a, u8 v)
{
switch (a >> 12) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
mapper(a, v);
return;
case 8: case 9:
vramb[a - 0x8000] = v;
return;
case 10: case 11:
if (eramb != nil)
eramb[a - 0xa000] = v;
else
mapper(a, v);
writeback();
return;
case 12: case 14:
wram[a & 0xFFF] = v;
return;
case 13:
wramb[a & 0xFFF] = v;
return;
case 15:
if (a >= 0xFF00)
regwrite(a - 0xFF00, v);
else if (a >= 0xFE00)
oam[a - 0xFE00] = v;
return;
}
}
static int
mbc0(int a, int _)
{
if (a >= 0)
return 0;
switch (a) {
case INIT:
return 0;
case SAVE:
case RSTR:
return 0;
case READ:
return -1;
default:
panic("MBC0 does not have function of %d", a);
}
return 0;
}
static int
mbc1(int a, int v)
{
static u8 ramen, b0, b1, romram;
static Var mbc1vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(romram),
{nil, 0,0}};
u16 b;
if (a < 0) {
switch(a) {
case INIT: return 0;
case SAVE: putvars(mbc1vars); break;
case RSTR: getvars(mbc1vars); break;
case READ: return -1;
default: panic("MBC1 does not have function of %d", a);
}
}
switch (a >> 13) {
case 0: ramen = (v & 0xF) == 0xA; break;
case 1: v &= 0x1F; b0 = v != 0 ? v : 1; break;
case 2: b1 = v & 3; b1 %= nbackbank; break;
case 3: romram = v & 1; break;
}
b = b0;
if (romram == 0)
b |= b1 << 5;
b %= nrom >> 14;
romb = rom + (b << 14);
if (ramen) {
if (romram)
eramb = back + (b1 << 13);
else
eramb = back;
} else {
eramb = nil;
}
return 0;
}
void
meminit(void)
{
union
{
u8 c[4];
u32 l;
} c;
c.c[0] = c.c[1] = c.c[2] = 0;
c.c[3] = 1;
for (; c.l != 1; prish++)
c.l >>= 1;
c.c[0] = c.c[1] = c.c[2] = 0xff;
c.c[3] = 0;
white = c.l;
romb = rom + 0x4000;
wramb = wram + 0x1000;
vramb = vram;
mapper = mappers[mbc];
mapper(INIT, 0);
reg[LCDC] = 0x91;
reg[IF] = 0xE0;
reg[SVBK] = 0xff;
reg[VBK] = 0xff;
}