diff options
author | aiju <devnull@localhost> | 2014-10-18 19:08:38 +0200 |
---|---|---|
committer | aiju <devnull@localhost> | 2014-10-18 19:08:38 +0200 |
commit | 040166493db3bd6f528cc08e2d0cc2c638c560a5 (patch) | |
tree | 1948b55853c48e2437401522c7424611afbbb6f7 | |
parent | 99e004c72e5a95a37a5060d273c3c1ce99bed6ec (diff) |
games/gba: add state saving
-rw-r--r-- | sys/src/games/gba/apu.c | 10 | ||||
-rw-r--r-- | sys/src/games/gba/cpu.c | 15 | ||||
-rw-r--r-- | sys/src/games/gba/dat.h | 10 | ||||
-rw-r--r-- | sys/src/games/gba/ev.c | 13 | ||||
-rw-r--r-- | sys/src/games/gba/fns.h | 3 | ||||
-rw-r--r-- | sys/src/games/gba/gba.c | 13 | ||||
-rw-r--r-- | sys/src/games/gba/mem.c | 6 | ||||
-rw-r--r-- | sys/src/games/gba/mkfile | 1 | ||||
-rw-r--r-- | sys/src/games/gba/ppu.c | 7 | ||||
-rw-r--r-- | sys/src/games/gba/state.c | 165 |
10 files changed, 241 insertions, 2 deletions
diff --git a/sys/src/games/gba/apu.c b/sys/src/games/gba/apu.c index 39a0972ff..0e0c01548 100644 --- a/sys/src/games/gba/apu.c +++ b/sys/src/games/gba/apu.c @@ -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) { diff --git a/sys/src/games/gba/cpu.c b/sys/src/games/gba/cpu.c index 3c575abe6..c92e4ff9d 100644 --- a/sys/src/games/gba/cpu.c +++ b/sys/src/games/gba/cpu.c @@ -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; +} diff --git a/sys/src/games/gba/dat.h b/sys/src/games/gba/dat.h index 2e180d68b..4f4651c0a 100644 --- a/sys/src/games/gba/dat.h +++ b/sys/src/games/gba/dat.h @@ -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 }; diff --git a/sys/src/games/gba/ev.c b/sys/src/games/gba/ev.c index d4110a30a..e4612114c 100644 --- a/sys/src/games/gba/ev.c +++ b/sys/src/games/gba/ev.c @@ -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) diff --git a/sys/src/games/gba/fns.h b/sys/src/games/gba/fns.h index 84baeb5ee..555d85d36 100644 --- a/sys/src/games/gba/fns.h +++ b/sys/src/games/gba/fns.h @@ -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); diff --git a/sys/src/games/gba/gba.c b/sys/src/games/gba/gba.c index 94612c06f..bfb65c738 100644 --- a/sys/src/games/gba/gba.c +++ b/sys/src/games/gba/gba.c @@ -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); diff --git a/sys/src/games/gba/mem.c b/sys/src/games/gba/mem.c index be6203678..75ff9d31c 100644 --- a/sys/src/games/gba/mem.c +++ b/sys/src/games/gba/mem.c @@ -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); diff --git a/sys/src/games/gba/mkfile b/sys/src/games/gba/mkfile index 73855b71e..b519b2376 100644 --- a/sys/src/games/gba/mkfile +++ b/sys/src/games/gba/mkfile @@ -9,6 +9,7 @@ OFILES=\ ppu.$O\ ev.$O\ apu.$O\ + state.$O\ HFILES=dat.h fns.h diff --git a/sys/src/games/gba/ppu.c b/sys/src/games/gba/ppu.c index dee1c6a80..43d334d6c 100644 --- a/sys/src/games/gba/ppu.c +++ b/sys/src/games/gba/ppu.c @@ -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; diff --git a/sys/src/games/gba/state.c b/sys/src/games/gba/state.c new file mode 100644 index 000000000..b0155e17d --- /dev/null +++ b/sys/src/games/gba/state.c @@ -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); +} |