games/gba: add state saving

front
aiju 2014-10-18 19:08:38 +02:00
parent 99e004c72e
commit 040166493d
10 changed files with 241 additions and 2 deletions

View File

@ -50,6 +50,16 @@ chan sndch[4] = {
}
};
Var apuvars[] = {
ARR(snddma), VAR(envctr), VAR(envrel), VAR(envmod), VAR(sweepen),
VAR(sweepctr), VAR(sweepfreq), ARR(wave), VAR(wpos), VAR(wbank), VAR(lfsr),
VAR(sndch[0].ectr), VAR(sndch[0].len), VAR(sndch[0].fctr), VAR(sndch[0].fthr), VAR(sndch[0].finc), VAR(sndch[0].vol),
VAR(sndch[1].ectr), VAR(sndch[1].len), VAR(sndch[1].fctr), VAR(sndch[1].fthr), VAR(sndch[1].finc), VAR(sndch[1].vol),
VAR(sndch[2].ectr), VAR(sndch[2].len), VAR(sndch[2].fctr), VAR(sndch[2].fthr), VAR(sndch[2].finc), VAR(sndch[2].vol),
VAR(sndch[3].ectr), VAR(sndch[3].len), VAR(sndch[3].fctr), VAR(sndch[3].fthr), VAR(sndch[3].finc), VAR(sndch[3].vol),
{nil, 0, 0},
};
void
rate(int i, u16int v)
{

View File

@ -36,6 +36,12 @@ int irq;
u32int instr0, instr1, pipel = -1;
int cyc, trace;
Var cpuvars[] = {
ARR(r), VAR(cpsr), VAR(spsr), ARR(saver), VAR(irq),
VAR(instr0), VAR(instr1), VAR(pipel),
{nil, 0, 0},
};
#define pipeflush() {io(); pipel = -1;}
#define io() cyc++
@ -1267,3 +1273,12 @@ reset(void)
r[15] = 0;
pipel = -1;
}
void
cpuload(void)
{
if((cpsr & FLAGT) != 0)
step = stepthumb;
else
step = steparm;
}

View File

@ -142,3 +142,13 @@ enum {
BACKTYPELEN = 64,
HZ = 16777216,
};
typedef struct Var Var;
struct Var {
void *a;
int s, n;
};
#define VAR(a) {&a, sizeof(a), 1}
#define ARR(a) {a, sizeof(*a), nelem(a)}
enum { NEVENT = 6 };

View File

@ -22,6 +22,19 @@ fifo sndfifo[2];
Event *elist;
Timer timers[4];
Event evhblank;
extern Event evsamp;
Event *events[NEVENT] = {&timers[0].Event, &timers[1].Event, &timers[2].Event, &timers[3].Event, &evhblank, &evsamp};
Var evvars[] = {
VAR(clock),
ARR(sndfifo[0].d), VAR(sndfifo[0].head), VAR(sndfifo[0].level), VAR(sndfifo[0].headpos),
ARR(sndfifo[1].d), VAR(sndfifo[1].head), VAR(sndfifo[1].level), VAR(sndfifo[1].headpos),
VAR(timers[0].val), VAR(timers[0].clock), VAR(timers[0].sh), VAR(timers[0].snd),
VAR(timers[1].val), VAR(timers[1].clock), VAR(timers[1].sh), VAR(timers[1].snd),
VAR(timers[2].val), VAR(timers[2].clock), VAR(timers[2].sh), VAR(timers[2].snd),
VAR(timers[3].val), VAR(timers[3].clock), VAR(timers[3].sh), VAR(timers[3].snd),
{nil, 0, 0},
};
void
addevent(Event *ev, int time)

View File

@ -23,3 +23,6 @@ void soundbias(u16int);
void audioinit(void);
int audioout(void);
void sndwrite(u16int, u16int);
void loadstate(char *);
void savestate(char *);
void cpuload(void);

View File

@ -16,6 +16,7 @@ int keys, paused, framestep, backup;
QLock pauselock;
int savefd, saveframes;
int clock;
int savereq, loadreq;
char *biosfile = "/sys/games/lib/gbabios.bin";
@ -237,10 +238,10 @@ keyproc(void *)
if(read(fd, buf, sizeof(buf) - 1) <= 0)
sysfatal("read /dev/kbd: %r");
if(buf[0] == 'c'){
/*if(utfrune(buf, KF|5))
if(utfrune(buf, KF|5))
savereq = 1;
if(utfrune(buf, KF|6))
loadreq = 1;*/
loadreq = 1;
if(utfrune(buf, Kdel)){
close(fd);
threadexitsall(nil);
@ -424,6 +425,14 @@ threadmain(int argc, char **argv)
memreset();
reset();
for(;;){
if(savereq){
savestate("gba.save");
savereq = 0;
}
if(loadreq){
loadstate("gba.save");
loadreq = 0;
}
if(paused){
qlock(&pauselock);
qunlock(&pauselock);

View File

@ -20,6 +20,12 @@ u32int dmar[16];
u8int waitst[16] = {5, 5, 5, 5, 3, 5, 5, 9, 8, 10, 10, 14};
u32int eepstart;
Var memvars[] = {
ARR(wram0), ARR(wram1), ARR(vram), ARR(pram), ARR(oam), ARR(reg),
VAR(dmaact), ARR(dmar), ARR(waitst),
{nil, 0, 0},
};
extern int cyc;
static int eepromread(void);

View File

@ -9,6 +9,7 @@ OFILES=\
ppu.$O\
ev.$O\
apu.$O\
state.$O\
HFILES=dat.h fns.h

View File

@ -27,6 +27,13 @@ struct bg {
};
static bg bgst[4] = {{.n = 0}, {.n = 1}, {.n = 2}, {.n = 3}};
Var ppuvars[] = {
VAR(hblank), VAR(ppuy), VAR(hblclock),
VAR(bldy), VAR(blda), VAR(bldb), VAR(objalpha),
VAR(bgst[2].rpx0), VAR(bgst[2].rpy0), VAR(bgst[3].rpx0), VAR(bgst[3].rpy0),
{nil, 0, 0},
};
typedef struct sprite sprite;
struct sprite {
uchar w, wb, h;

165
sys/src/games/gba/state.c Normal file
View File

@ -0,0 +1,165 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <bio.h>
#include "dat.h"
#include "fns.h"
extern Var cpuvars[], ppuvars[], memvars[], apuvars[], evvars[];
extern Event *events[NEVENT], *elist;
static void
putevents(Biobuf *bp)
{
int i, j;
Event *e;
for(i = 0; i < NEVENT; i++)
if(elist == events[i])
break;
if(i == NEVENT && elist != nil)
print("unknown event %p in chain\n", elist);
Bputc(bp, i);
for(i = 0; i < NEVENT; i++){
e = events[i];
Bputc(bp, e->time);
Bputc(bp, e->time >> 8);
Bputc(bp, e->time >> 16);
Bputc(bp, e->time >> 24);
for(j = 0; j < NEVENT; j++)
if(e->next == events[j])
break;
if(j == NEVENT && e->next != nil)
print("unknown event %p in chain\n", e->next);
Bputc(bp, j);
}
}
static void
getevents(Biobuf *bp)
{
int i, j;
Event *e;
i = Bgetc(bp);
elist = i >= NEVENT ? nil : events[i];
for(i = 0; i < NEVENT; i++){
e = events[i];
e->time = Bgetc(bp);
e->time |= Bgetc(bp) << 8;
e->time |= Bgetc(bp) << 16;
e->time |= Bgetc(bp) << 24;
j = Bgetc(bp);
e->next = j >= NEVENT ? nil : events[j];
}
}
static void
getvars(Biobuf *bp, Var *v)
{
int n;
u16int *p, w;
u32int *q, l;
for(; v->a != nil; v++)
switch(v->s){
case 1:
Bread(bp, v->a, v->n);
break;
case 2:
n = v->n;
p = v->a;
while(n--){
w = Bgetc(bp);
*p++ = w | Bgetc(bp) << 8;
}
break;
case 4:
n = v->n;
q = v->a;
while(n--){
l = Bgetc(bp);
l |= Bgetc(bp) << 8;
l |= Bgetc(bp) << 16;
*q++ = l | Bgetc(bp) << 24;
}
break;
}
}
static void
putvars(Biobuf *bp, Var *v)
{
int n;
u16int *p;
u32int *q;
for(; v->a != nil; v++)
switch(v->s){
case 1:
Bwrite(bp, v->a, v->n);
break;
case 2:
n = v->n;
p = v->a;
while(n--){
Bputc(bp, *p & 0xff);
Bputc(bp, *p++ >> 8);
}
break;
case 4:
n = v->n;
q = v->a;
while(n--){
Bputc(bp, *q);
Bputc(bp, *q >> 8);
Bputc(bp, *q >> 16);
Bputc(bp, *q++ >> 24);
}
break;
}
}
void
savestate(char *file)
{
Biobuf *bp;
flushback();
bp = Bopen(file, OWRITE);
if(bp == nil){
print("open: %r\n");
return;
}
putvars(bp, cpuvars);
putvars(bp, ppuvars);
putvars(bp, memvars);
putvars(bp, apuvars);
putvars(bp, evvars);
putevents(bp);
Bterm(bp);
}
void
loadstate(char *file)
{
Biobuf *bp;
extern u32int r[16];
bp = Bopen(file, OREAD);
if(bp == nil){
print("open: %r\n");
return;
}
getvars(bp, cpuvars);
getvars(bp, ppuvars);
getvars(bp, memvars);
getvars(bp, apuvars);
getvars(bp, evvars);
getevents(bp);
cpuload();
Bterm(bp);
}