diff --git a/.gitignore b/.gitignore index c6127b3..81af666 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.ko *.obj *.elf +.*.swp # Linker output *.ilk diff --git a/cpu.c b/cpu.c index 2b12e6d..0d44d93 100644 --- a/cpu.c +++ b/cpu.c @@ -30,6 +30,9 @@ u8 r[8], ime; u16 pc, sp, curpc; int halt; +Var cpuvars[] = {ARR(r), VAR(ime), VAR(pc), VAR(curpc), VAR(sp), VAR(halt), + {nil, 0, 0}}; + void state(void) { diff --git a/ev.c b/ev.c index fd68525..d711036 100644 --- a/ev.c +++ b/ev.c @@ -1,8 +1,11 @@ #include "gb.h" Event evhblank, evjoypad; +Event *events[NEVENT] = {&evhblank, &evjoypad, nil}; Event* elist; +Var evvars[] = {{nil, 0, 0}}; + void addevent(Event* ev, int time) { diff --git a/gb.c b/gb.c index fcf722e..d2c90b0 100644 --- a/gb.c +++ b/gb.c @@ -5,7 +5,6 @@ int cpuhalt; int backup; int savefd = -1; -u64 clock; u8 mbc, feat, mode; static void diff --git a/gb.h b/gb.h index b408d20..eedb964 100644 --- a/gb.h +++ b/gb.h @@ -1,5 +1,9 @@ #include +#define nelem(x) (sizeof(x)/sizeof(x[0])) + +#define VAR(a) {&a, sizeof(a), 1} +#define ARR(a) {a, sizeof(*a), nelem(a)} #define nil ((void*)0) #define JOYPAD_CYCLE (30) @@ -128,6 +132,8 @@ enum GB_KEY_START = 0x80 }; +enum { NEVENT = 2 + 1}; + typedef uint8_t u8; typedef uint16_t u16; typedef int8_t i8; @@ -136,6 +142,7 @@ typedef int32_t i32; typedef uint64_t u64; typedef int64_t i64; typedef struct Event Event; +typedef struct Var Var; struct Event { @@ -145,6 +152,15 @@ struct Event void* aux; }; +struct Var +{ + void *a; + int s, n; +}; + +#define VAR(a) {&a, sizeof(a), 1} +#define ARR(a) {a, sizeof(*a), nelem(a)} + extern u8 *rom, *back, reg[256], oam[256]; extern u8 vram[16384]; extern int nrom, nback, nbackbank; @@ -163,6 +179,7 @@ extern u32 moncols[4]; extern u32 white; extern u8* pic; extern int (*mapper)(int, int); +extern Event *events[NEVENT]; /* joypad */ void @@ -206,6 +223,11 @@ flush(); void initwindow(int scale); +/* save */ +void +putvars(Var *v); +void +getvars(Var *v); /* error */ void error(const char*, ...); diff --git a/mem.c b/mem.c index 3967f55..7701ee9 100644 --- a/mem.c +++ b/mem.c @@ -9,17 +9,18 @@ u8* rom; u8 *romb, *vramb, *wramb, *eramb; u8 wram[32768], vram[16384], oam[256], reg[256]; u8* back; -u8 palm[128]; u32 pal[64]; int nrom, nback, nbackbank; +u64 clock; u32 divclock; int prish; -u8 dma; 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) { @@ -198,29 +199,29 @@ 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: - case RSTR: - break; - case READ: - return -1; + 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 2: b1 = v & 3; b1 %= nbackbank; break; case 3: romram = v & 1; break; } b = b0; if (romram == 0) b |= b1 << 5; - b %= nrom >> 14; /* 32KB => 2bank */ + b %= nrom >> 14; romb = rom + (b << 14); if (ramen) { if (romram) diff --git a/ppu.c b/ppu.c index 87cf4b6..0791908 100644 --- a/ppu.c +++ b/ppu.c @@ -36,6 +36,9 @@ u64 hblclock, rendclock; static int cyc, ppux, ppux0; sprite spr[10], *sprm; +Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock), + {nil, 0, 0}}; + void pputask(void* _) { diff --git a/save.c b/save.c new file mode 100644 index 0000000..12ff12e --- /dev/null +++ b/save.c @@ -0,0 +1,165 @@ +#include "gb.h" +#include + +extern Var cpuvars[], ppuvars[], memvars[], evvars[]; +static FILE *fp; + +void +putevents(void) +{ + u8 i, j; + Event *e; + + for(i = 0; i < NEVENT; ++i) + if(elist == events[i]) /* find head */ + break; + if(i == NEVENT && elist != nil) + error("Unkown event in chain [%p]", e->next); + fputc(i, fp); + for(i = 0; i < NEVENT; ++i){ + e = events[i]; + fputc(e->time & 0x000000ff, fp); + fputc(e->time & 0x0000ff00, fp); + fputc(e->time & 0x00ff0000, fp); + fputc(e->time & 0xff000000, fp); + for(j = 0; j < NEVENT; ++j) + if(e->next == events[j]) /* find next */ + break; + if(j == NEVENT && e->next != nil) + error("Unkown event in chain [%p]", e->next); + fputc(j, fp); + } +} + +void +putvars(Var *v) +{ + int n; + u16 *p; + u32 *q; + + for(; v->a != nil; v++){ + switch(v->s){ + case 1: + fwrite(v->a, 1, v->n, fp); + break; + case 2: + n = v->n; + p = v->a; + while(n--){ + fputc(*p & 0xff, fp); + fputc(*p++ >> 8, fp); + } + break; + case 4: + n = v->n; + q = v->a; + while(n--){ + fputc(*q, fp); + fputc(*q >> 8, fp); + fputc(*q >> 16, fp); + fputc(*q >> 24, fp); + } + break; + } + } +} + +void +getvars(Var *v) +{ + int n; + u16 *p, w; + u32 *q, l; + + for(; v->a != nil; v++){ + switch(v->s){ + case 1: fread(v->a, v->n, 1, fp); break; + case 2: + n = v->n; + p = v->a; + while(n--){ + w = fgetc(fp); + w |= fgetc(fp) << 8; + *p++ = w; + } + break; + case 4: + n = v->n; + q = v->a; + while(n--){ + l |= fgetc(fp); + l |= fgetc(fp) << 8; + l |= fgetc(fp) << 16; + l |= fgetc(fp) << 24; + *q++ = l; + } + break; + } + } +} + +int +savestate(const char *fname) +{ + fp = fopen(fname, "w"); + if(fp == 0){ + error("Can't open '%s'", fname); + return -1; + } + putvars(cpuvars); + putvars(ppuvars); + putvars(memvars); + putvars(evvars); + putevents(); + mapper(SAVE, 0); + fclose(fp); + fp = 0; + return 0; +} + +static void +getevents(void) +{ + int i, j; + Event *e; + + i = fgetc(fp); + if(i > NEVENT){ + error("Unkown event index [%d]", i); + elist = nil; + } + for(i = 0; i < NEVENT; ++i){ + e = events[i]; + e->time = fgetc(fp); + e->time |= fgetc(fp) << 8; + e->time |= fgetc(fp) << 16; + e->time |= fgetc(fp) << 24; + j = fgetc(fp); + if(j >= NEVENT){ + error("Unkown event index [%d]", j); + e->next = nil; + }else{ + e->next = events[j]; + } + } +} + +int +loadstate(const char *fname) +{ + fp = fopen(fname, "r"); + if(fp == 0){ + error("Can't load '%s'", fname); + return -1; + } + getvars(cpuvars); + getvars(ppuvars); + getvars(memvars); + getvars(evvars); + getevents(); + mapper(RSTR, 0); + fclose(fp); + fp = 0; + return 0; +}