add load and save function

This commit is contained in:
Hojun-Cho 2024-07-17 15:12:33 +09:00
parent c8c2a4fc19
commit 4661fc35bb
8 changed files with 207 additions and 10 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@
*.ko *.ko
*.obj *.obj
*.elf *.elf
.*.swp
# Linker output # Linker output
*.ilk *.ilk

3
cpu.c
View File

@ -30,6 +30,9 @@ u8 r[8], ime;
u16 pc, sp, curpc; u16 pc, sp, curpc;
int halt; int halt;
Var cpuvars[] = {ARR(r), VAR(ime), VAR(pc), VAR(curpc), VAR(sp), VAR(halt),
{nil, 0, 0}};
void void
state(void) state(void)
{ {

3
ev.c
View File

@ -1,8 +1,11 @@
#include "gb.h" #include "gb.h"
Event evhblank, evjoypad; Event evhblank, evjoypad;
Event *events[NEVENT] = {&evhblank, &evjoypad, nil};
Event* elist; Event* elist;
Var evvars[] = {{nil, 0, 0}};
void void
addevent(Event* ev, int time) addevent(Event* ev, int time)
{ {

1
gb.c
View File

@ -5,7 +5,6 @@
int cpuhalt; int cpuhalt;
int backup; int backup;
int savefd = -1; int savefd = -1;
u64 clock;
u8 mbc, feat, mode; u8 mbc, feat, mode;
static void static void

22
gb.h
View File

@ -1,5 +1,9 @@
#include <stdint.h> #include <stdint.h>
#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 nil ((void*)0)
#define JOYPAD_CYCLE (30) #define JOYPAD_CYCLE (30)
@ -128,6 +132,8 @@ enum
GB_KEY_START = 0x80 GB_KEY_START = 0x80
}; };
enum { NEVENT = 2 + 1};
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
typedef int8_t i8; typedef int8_t i8;
@ -136,6 +142,7 @@ typedef int32_t i32;
typedef uint64_t u64; typedef uint64_t u64;
typedef int64_t i64; typedef int64_t i64;
typedef struct Event Event; typedef struct Event Event;
typedef struct Var Var;
struct Event struct Event
{ {
@ -145,6 +152,15 @@ struct Event
void* aux; 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 *rom, *back, reg[256], oam[256];
extern u8 vram[16384]; extern u8 vram[16384];
extern int nrom, nback, nbackbank; extern int nrom, nback, nbackbank;
@ -163,6 +179,7 @@ extern u32 moncols[4];
extern u32 white; extern u32 white;
extern u8* pic; extern u8* pic;
extern int (*mapper)(int, int); extern int (*mapper)(int, int);
extern Event *events[NEVENT];
/* joypad */ /* joypad */
void void
@ -206,6 +223,11 @@ flush();
void void
initwindow(int scale); initwindow(int scale);
/* save */
void
putvars(Var *v);
void
getvars(Var *v);
/* error */ /* error */
void void
error(const char*, ...); error(const char*, ...);

19
mem.c
View File

@ -9,17 +9,18 @@ u8* rom;
u8 *romb, *vramb, *wramb, *eramb; u8 *romb, *vramb, *wramb, *eramb;
u8 wram[32768], vram[16384], oam[256], reg[256]; u8 wram[32768], vram[16384], oam[256], reg[256];
u8* back; u8* back;
u8 palm[128];
u32 pal[64]; u32 pal[64];
int nrom, nback, nbackbank; int nrom, nback, nbackbank;
u64 clock;
u32 divclock; u32 divclock;
int prish; int prish;
u8 dma;
u32 moncols[4]; u32 moncols[4];
u32 white; u32 white;
int (*mappers[])(int, int) = { mbc0, mbc1 }; int (*mappers[])(int, int) = { mbc0, mbc1 };
int (*mapper)(int, int); int (*mapper)(int, int);
Var memvars[] = {ARR(wram), ARR(vram), ARR(oam), ARR(reg), VAR(clock), VAR(divclock), {nil, 0, 0}};
static u8 static u8
regread(u16 a) regread(u16 a)
{ {
@ -198,29 +199,29 @@ static int
mbc1(int a, int v) mbc1(int a, int v)
{ {
static u8 ramen, b0, b1, romram; static u8 ramen, b0, b1, romram;
static Var mbc1vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(romram),
{nil, 0,0}};
u16 b; u16 b;
if (a < 0) { if (a < 0) {
switch(a) { switch(a) {
case INIT: return 0; case INIT: return 0;
case SAVE: case SAVE: putvars(mbc1vars); break;
case RSTR: case RSTR: getvars(mbc1vars); break;
break; case READ: return -1;
case READ:
return -1;
default: panic("MBC1 does not have function of %d", a); default: panic("MBC1 does not have function of %d", a);
} }
} }
switch (a >> 13) { switch (a >> 13) {
case 0: ramen = (v & 0xF) == 0xA; break; case 0: ramen = (v & 0xF) == 0xA; break;
case 1: v &= 0x1F; b0 = v != 0 ? v : 1; 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; case 3: romram = v & 1; break;
} }
b = b0; b = b0;
if (romram == 0) if (romram == 0)
b |= b1 << 5; b |= b1 << 5;
b %= nrom >> 14; /* 32KB => 2bank */ b %= nrom >> 14;
romb = rom + (b << 14); romb = rom + (b << 14);
if (ramen) { if (ramen) {
if (romram) if (romram)

3
ppu.c
View File

@ -36,6 +36,9 @@ u64 hblclock, rendclock;
static int cyc, ppux, ppux0; static int cyc, ppux, ppux0;
sprite spr[10], *sprm; sprite spr[10], *sprm;
Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock),
{nil, 0, 0}};
void void
pputask(void* _) pputask(void* _)
{ {

165
save.c Normal file
View File

@ -0,0 +1,165 @@
#include "gb.h"
#include <stdio.h>
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;
}