games/nes: added state saving & bug fixes
This commit is contained in:
parent
0181117b5f
commit
830a9b59c9
6 changed files with 300 additions and 67 deletions
|
@ -2,14 +2,16 @@ extern u16int pc, curpc;
|
||||||
extern u8int rA, rX, rY, rS, rP;
|
extern u8int rA, rX, rY, rS, rP;
|
||||||
extern uchar mem[32768], ppuram[16384], oam[256];
|
extern uchar mem[32768], ppuram[16384], oam[256];
|
||||||
extern u16int pput, ppuv;
|
extern u16int pput, ppuv;
|
||||||
extern u8int ppusx;
|
extern u8int ppusx, vrambuf;
|
||||||
extern int mirr;
|
extern int mirr, ppux, ppuy, odd, vramlatch, keylatch;
|
||||||
|
|
||||||
extern int map, scale;
|
extern int map, scale;
|
||||||
extern uchar *prg, *chr;
|
extern uchar *prg, *chr;
|
||||||
extern int nprg, nchr, nmi, map;
|
extern int nprg, nchr, nmi, map, chrram;
|
||||||
|
|
||||||
extern int keys;
|
extern int keys, clock, ppuclock;
|
||||||
|
|
||||||
|
extern void (*mapper[])(int, u8int);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FLAGC = 1<<0,
|
FLAGC = 1<<0,
|
||||||
|
@ -77,3 +79,9 @@ enum {
|
||||||
MSINGB,
|
MSINGB,
|
||||||
MFOUR
|
MFOUR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INIT = -1,
|
||||||
|
SAVE = -2,
|
||||||
|
RSTR = -3,
|
||||||
|
};
|
||||||
|
|
|
@ -4,3 +4,8 @@ void memwrite(u16int, u8int);
|
||||||
u8int ppuread(u16int);
|
u8int ppuread(u16int);
|
||||||
void ppuwrite(u16int, u8int);
|
void ppuwrite(u16int, u8int);
|
||||||
void ppustep(void);
|
void ppustep(void);
|
||||||
|
void loadstate(char *);
|
||||||
|
void savestate(char *);
|
||||||
|
void message(char *, ...);
|
||||||
|
void put8(u8int);
|
||||||
|
int get8(void);
|
||||||
|
|
|
@ -10,13 +10,23 @@ uchar ppuram[16384];
|
||||||
uchar oam[256];
|
uchar oam[256];
|
||||||
uchar *prgb[2], *chrb[2];
|
uchar *prgb[2], *chrb[2];
|
||||||
u16int pput, ppuv;
|
u16int pput, ppuv;
|
||||||
u8int ppusx;
|
u8int ppusx, vrambuf;
|
||||||
static int vramlatch = 1, keylatch = 0xFF;
|
int vramlatch = 1, keylatch = 0xFF;
|
||||||
|
|
||||||
|
static void
|
||||||
|
nope(int p)
|
||||||
|
{
|
||||||
|
print("unimplemented mapper function %d (mapper %d)\n", p, map);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nrom(int p, u8int)
|
nrom(int p, u8int)
|
||||||
{
|
{
|
||||||
if(p < 0){
|
if(p >= 0)
|
||||||
|
return;
|
||||||
|
switch(p){
|
||||||
|
case INIT:
|
||||||
|
case RSTR:
|
||||||
prgb[0] = prg;
|
prgb[0] = prg;
|
||||||
if(nprg == 1)
|
if(nprg == 1)
|
||||||
prgb[1] = prg;
|
prgb[1] = prg;
|
||||||
|
@ -24,22 +34,45 @@ nrom(int p, u8int)
|
||||||
prgb[1] = prg + 0x4000;
|
prgb[1] = prg + 0x4000;
|
||||||
chrb[0] = chr;
|
chrb[0] = chr;
|
||||||
chrb[1] = chr + 0x1000;
|
chrb[1] = chr + 0x1000;
|
||||||
|
break;
|
||||||
|
case SAVE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nope(p);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mmc1(int v, u8int p)
|
mmc1(int v, u8int p)
|
||||||
{
|
{
|
||||||
static u8int n, s, mode, c0, c1, pr;
|
static u8int n, s, mode, c0, c1, pr;
|
||||||
int wchr, wprg;
|
|
||||||
static int mirrs[] = {MSINGB, MSINGA, MVERT, MHORZ};
|
static int mirrs[] = {MSINGB, MSINGA, MVERT, MHORZ};
|
||||||
|
|
||||||
if(v < 0){
|
if(v < 0){
|
||||||
wchr = 1;
|
switch(v){
|
||||||
wprg = 1;
|
case INIT:
|
||||||
mode = 0x0C;
|
mode = 0x0C;
|
||||||
goto t;
|
goto t;
|
||||||
|
case RSTR:
|
||||||
|
mode = get8();
|
||||||
|
c0 = get8();
|
||||||
|
c1 = get8();
|
||||||
|
pr = get8();
|
||||||
|
n = get8();
|
||||||
|
s = get8();
|
||||||
|
goto t;
|
||||||
|
case SAVE:
|
||||||
|
put8(mode);
|
||||||
|
put8(c0);
|
||||||
|
put8(c1);
|
||||||
|
put8(pr);
|
||||||
|
put8(n);
|
||||||
|
put8(s);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nope(v);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if((p & 0x80) != 0){
|
if((p & 0x80) != 0){
|
||||||
n = 0;
|
n = 0;
|
||||||
|
@ -53,32 +86,27 @@ mmc1(int v, u8int p)
|
||||||
s >>= 1;
|
s >>= 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wchr = wprg = 1;
|
|
||||||
switch(v & 0xE000){
|
switch(v & 0xE000){
|
||||||
case 0x8000:
|
case 0x8000:
|
||||||
mode = s;
|
mode = s;
|
||||||
mirr = mirrs[mode & 3];
|
mirr = mirrs[mode & 3];
|
||||||
wchr = wprg = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0xA000:
|
case 0xA000:
|
||||||
c0 = s & 0x1f;
|
c0 = s & 0x1f;
|
||||||
c0 %= 2*nchr;
|
c0 %= 2*nchr;
|
||||||
wchr = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0xC000:
|
case 0xC000:
|
||||||
c1 = s & 0x1f;
|
c1 = s & 0x1f;
|
||||||
c1 %= 2*nchr;
|
c1 %= 2*nchr;
|
||||||
if((mode & 0x10) != 0)
|
|
||||||
wchr = 1;
|
|
||||||
break;
|
break;
|
||||||
case 0xE000:
|
case 0xE000:
|
||||||
pr = s & 0x0f;
|
pr = s & 0x0f;
|
||||||
pr %= nprg;
|
pr %= nprg;
|
||||||
wprg = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
s = 0;
|
||||||
|
n = 0;
|
||||||
t:
|
t:
|
||||||
if(wprg)
|
|
||||||
switch(mode & 0x0c){
|
switch(mode & 0x0c){
|
||||||
case 0x08:
|
case 0x08:
|
||||||
prgb[0] = prg;
|
prgb[0] = prg;
|
||||||
|
@ -93,7 +121,6 @@ t:
|
||||||
prgb[1] = prg + (pr | 1) * 0x4000;
|
prgb[1] = prg + (pr | 1) * 0x4000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(wchr)
|
|
||||||
if((mode & 0x10) != 0){
|
if((mode & 0x10) != 0){
|
||||||
chrb[0] = chr + c0 * 0x1000;
|
chrb[0] = chr + c0 * 0x1000;
|
||||||
chrb[1] = chr + c1 * 0x1000;
|
chrb[1] = chr + c1 * 0x1000;
|
||||||
|
@ -101,18 +128,32 @@ t:
|
||||||
chrb[0] = chr + (c0 & 0xfe) * 0x1000;
|
chrb[0] = chr + (c0 & 0xfe) * 0x1000;
|
||||||
chrb[1] = chr + (c0 | 1) * 0x1000;
|
chrb[1] = chr + (c0 | 1) * 0x1000;
|
||||||
}
|
}
|
||||||
s = 0;
|
|
||||||
n = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mmc7(int v, u8int p)
|
mmc7(int v, u8int p)
|
||||||
{
|
{
|
||||||
if(v < 0){
|
static int b;
|
||||||
nrom(-1, 0);
|
|
||||||
p = 0;
|
if(v >= 0)
|
||||||
|
b = p;
|
||||||
|
else
|
||||||
|
switch(v){
|
||||||
|
case INIT:
|
||||||
|
nrom(INIT, 0);
|
||||||
|
b = 0;
|
||||||
|
break;
|
||||||
|
case SAVE:
|
||||||
|
put8(b);
|
||||||
|
return;
|
||||||
|
case RSTR:
|
||||||
|
b = get8();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nope(v);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
prgb[0] = prg + (p & 3) * 0x8000;
|
prgb[0] = prg + (b & 3) * 0x8000;
|
||||||
prgb[1] = prgb[0] + 0x4000;
|
prgb[1] = prgb[0] + 0x4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +176,6 @@ incvram(void)
|
||||||
u8int
|
u8int
|
||||||
memread(u16int p)
|
memread(u16int p)
|
||||||
{
|
{
|
||||||
static u8int vrambuf;
|
|
||||||
u8int v;
|
u8int v;
|
||||||
|
|
||||||
if(p < 0x2000){
|
if(p < 0x2000){
|
||||||
|
|
|
@ -7,6 +7,7 @@ OFILES=\
|
||||||
mem.$O\
|
mem.$O\
|
||||||
nes.$O\
|
nes.$O\
|
||||||
ppu.$O\
|
ppu.$O\
|
||||||
|
state.$O\
|
||||||
|
|
||||||
HFILES=dat.h fns.h
|
HFILES=dat.h fns.h
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,29 @@
|
||||||
#include "fns.h"
|
#include "fns.h"
|
||||||
|
|
||||||
extern uchar ppuram[16384];
|
extern uchar ppuram[16384];
|
||||||
int nprg, nchr, map;
|
int nprg, nchr, map, chrram;
|
||||||
uchar *prg, *chr;
|
uchar *prg, *chr;
|
||||||
int scale;
|
int scale;
|
||||||
Rectangle picr;
|
Rectangle picr;
|
||||||
Image *tmp, *bg;
|
Image *tmp, *bg;
|
||||||
int clock, ppuclock, syncclock, syncfreq, checkclock, sleeps;
|
int clock, ppuclock, syncclock, syncfreq, checkclock, msgclock, sleeps;
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
int keys;
|
int keys, paused, savereq, loadreq;
|
||||||
extern void (*mapper[])(int, u8int);
|
|
||||||
int mirr;
|
int mirr;
|
||||||
|
QLock pauselock;
|
||||||
|
|
||||||
|
void
|
||||||
|
message(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
static char buf[512];
|
||||||
|
|
||||||
|
va_start(va, fmt);
|
||||||
|
vsnprint(buf, sizeof buf, fmt, va);
|
||||||
|
string(screen, Pt(10, 10), display->black, ZP, display->defaultfont, buf);
|
||||||
|
msgclock = FREQ;
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
loadrom(char *file)
|
loadrom(char *file)
|
||||||
|
@ -62,6 +75,7 @@ loadrom(char *file)
|
||||||
sysfatal("malloc: %r");
|
sysfatal("malloc: %r");
|
||||||
if(readn(fd, prg, nprg * PRGSZ) < nprg * PRGSZ)
|
if(readn(fd, prg, nprg * PRGSZ) < nprg * PRGSZ)
|
||||||
sysfatal("read: %r");
|
sysfatal("read: %r");
|
||||||
|
chrram = nchr == 0;
|
||||||
if(nchr != 0){
|
if(nchr != 0){
|
||||||
chr = malloc(nchr * CHRSZ);
|
chr = malloc(nchr * CHRSZ);
|
||||||
if(chr == nil)
|
if(chr == nil)
|
||||||
|
@ -70,7 +84,7 @@ loadrom(char *file)
|
||||||
sysfatal("read: %r");
|
sysfatal("read: %r");
|
||||||
}else{
|
}else{
|
||||||
nchr = 16;
|
nchr = 16;
|
||||||
chr = malloc(16 * CHRSZ);
|
chr = malloc(nchr * CHRSZ);
|
||||||
if(chr == nil)
|
if(chr == nil)
|
||||||
sysfatal("malloc: %r");
|
sysfatal("malloc: %r");
|
||||||
}
|
}
|
||||||
|
@ -88,40 +102,53 @@ extern int trace;
|
||||||
void
|
void
|
||||||
keyproc(void *)
|
keyproc(void *)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd, k;
|
||||||
char buf[256], *s;
|
static char buf[256];
|
||||||
|
char *s;
|
||||||
Rune r;
|
Rune r;
|
||||||
|
|
||||||
fd = open("/dev/kbd", OREAD);
|
fd = open("/dev/kbd", OREAD);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
sysfatal("open: %r");
|
sysfatal("open: %r");
|
||||||
for(;;){
|
for(;;){
|
||||||
if(read(fd, buf, 256) <= 0)
|
if(read(fd, buf, sizeof(buf) - 1) <= 0)
|
||||||
sysfatal("read /dev/kbd: %r");
|
sysfatal("read /dev/kbd: %r");
|
||||||
if(buf[0] == 'c'){
|
if(buf[0] == 'c'){
|
||||||
if(utfrune(buf, Kdel))
|
if(utfrune(buf, Kdel))
|
||||||
threadexitsall(nil);
|
threadexitsall(nil);
|
||||||
|
if(utfrune(buf, KF|5))
|
||||||
|
savereq = 1;
|
||||||
|
if(utfrune(buf, KF|6))
|
||||||
|
loadreq = 1;
|
||||||
if(utfrune(buf, 't'))
|
if(utfrune(buf, 't'))
|
||||||
trace ^= 1;
|
trace ^= 1;
|
||||||
}
|
}
|
||||||
if(buf[0] != 'k' && buf[0] != 'K')
|
if(buf[0] != 'k' && buf[0] != 'K')
|
||||||
continue;
|
continue;
|
||||||
s = buf + 1;
|
s = buf + 1;
|
||||||
keys = 0;
|
k = 0;
|
||||||
while(*s != 0){
|
while(*s != 0){
|
||||||
s += chartorune(&r, s);
|
s += chartorune(&r, s);
|
||||||
switch(r){
|
switch(r){
|
||||||
case Kdel: threadexitsall(nil);
|
case Kdel: threadexitsall(nil);
|
||||||
case 'x': keys |= 1<<0; break;
|
case 'x': k |= 1<<0; break;
|
||||||
case 'z': keys |= 1<<1; break;
|
case 'z': k |= 1<<1; break;
|
||||||
case Kshift: keys |= 1<<2; break;
|
case Kshift: k |= 1<<2; break;
|
||||||
case 10: keys |= 1<<3; break;
|
case 10: k |= 1<<3; break;
|
||||||
case Kup: keys |= 1<<4; break;
|
case Kup: k |= 1<<4; break;
|
||||||
case Kdown: keys |= 1<<5; break;
|
case Kdown: k |= 1<<5; break;
|
||||||
case Kleft: keys |= 1<<6; break;
|
case Kleft: k |= 1<<6; break;
|
||||||
case Kright: keys |= 1<<7; break;
|
case Kright: k |= 1<<7; break;
|
||||||
|
case Kesc:
|
||||||
|
if(paused)
|
||||||
|
qunlock(&pauselock);
|
||||||
|
else
|
||||||
|
qlock(&pauselock);
|
||||||
|
paused = !paused;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
keys = k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +191,18 @@ threadmain(int argc, char **argv)
|
||||||
syncfreq = FREQ / 30;
|
syncfreq = FREQ / 30;
|
||||||
old = nsec();
|
old = nsec();
|
||||||
for(;;){
|
for(;;){
|
||||||
|
if(savereq){
|
||||||
|
savestate("nes.save");
|
||||||
|
savereq = 0;
|
||||||
|
}
|
||||||
|
if(loadreq){
|
||||||
|
loadstate("nes.save");
|
||||||
|
loadreq = 0;
|
||||||
|
}
|
||||||
|
if(paused){
|
||||||
|
qlock(&pauselock);
|
||||||
|
qunlock(&pauselock);
|
||||||
|
}
|
||||||
t = step() * 12;
|
t = step() * 12;
|
||||||
clock += t;
|
clock += t;
|
||||||
ppuclock += t;
|
ppuclock += t;
|
||||||
|
@ -192,5 +231,12 @@ threadmain(int argc, char **argv)
|
||||||
checkclock = 0;
|
checkclock = 0;
|
||||||
sleeps = 0;
|
sleeps = 0;
|
||||||
}
|
}
|
||||||
|
if(msgclock > 0){
|
||||||
|
msgclock -= t;
|
||||||
|
if(msgclock <= 0){
|
||||||
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
|
msgclock = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
133
sys/src/games/nes/state.c
Normal file
133
sys/src/games/nes/state.c
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static int fd;
|
||||||
|
|
||||||
|
void
|
||||||
|
put8(u8int i)
|
||||||
|
{
|
||||||
|
write(fd, &i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
put16(u16int i)
|
||||||
|
{
|
||||||
|
put8(i);
|
||||||
|
put8(i >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
put32(u32int i)
|
||||||
|
{
|
||||||
|
put8(i);
|
||||||
|
put8(i >> 8);
|
||||||
|
put8(i >> 16);
|
||||||
|
put8(i >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get8(void)
|
||||||
|
{
|
||||||
|
u8int c;
|
||||||
|
|
||||||
|
read(fd, &c, 1);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get16(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = get8();
|
||||||
|
i |= get8() << 8;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get32(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = get8();
|
||||||
|
i |= get8() << 8;
|
||||||
|
i |= get8() << 16;
|
||||||
|
i |= get8() << 24;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
loadstate(char *file)
|
||||||
|
{
|
||||||
|
fd = open(file, OREAD);
|
||||||
|
if(fd < 0){
|
||||||
|
message("open: %r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
read(fd, mem, sizeof(mem));
|
||||||
|
read(fd, ppuram, sizeof(ppuram));
|
||||||
|
read(fd, oam, sizeof(oam));
|
||||||
|
if(chrram)
|
||||||
|
read(fd, chr, nchr * CHRSZ);
|
||||||
|
rA = get8();
|
||||||
|
rX = get8();
|
||||||
|
rY = get8();
|
||||||
|
rS = get8();
|
||||||
|
rP = get8();
|
||||||
|
nmi = get8();
|
||||||
|
pc = get16();
|
||||||
|
pput = get16();
|
||||||
|
ppuv = get16();
|
||||||
|
ppusx = get8();
|
||||||
|
ppux = get16();
|
||||||
|
ppuy = get16();
|
||||||
|
mirr = get8();
|
||||||
|
odd = get8();
|
||||||
|
vramlatch = get8();
|
||||||
|
keylatch = get8();
|
||||||
|
vrambuf = get8();
|
||||||
|
clock = get32();
|
||||||
|
ppuclock = get32();
|
||||||
|
mapper[map](RSTR, 0);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
savestate(char *file)
|
||||||
|
{
|
||||||
|
fd = create(file, ORDWR, 0666);
|
||||||
|
if(fd < 0){
|
||||||
|
message("create: %r");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write(fd, mem, sizeof(mem));
|
||||||
|
write(fd, ppuram, sizeof(ppuram));
|
||||||
|
write(fd, oam, sizeof(oam));
|
||||||
|
if(chrram)
|
||||||
|
write(fd, chr, nchr * CHRSZ);
|
||||||
|
put8(rA);
|
||||||
|
put8(rX);
|
||||||
|
put8(rY);
|
||||||
|
put8(rS);
|
||||||
|
put8(rP);
|
||||||
|
put8(nmi);
|
||||||
|
put16(pc);
|
||||||
|
put16(pput);
|
||||||
|
put16(ppuv);
|
||||||
|
put8(ppusx);
|
||||||
|
put16(ppux);
|
||||||
|
put16(ppuy);
|
||||||
|
put8(mirr);
|
||||||
|
put8(odd);
|
||||||
|
put8(vramlatch);
|
||||||
|
put8(keylatch);
|
||||||
|
put8(vrambuf);
|
||||||
|
put32(clock);
|
||||||
|
put32(ppuclock);
|
||||||
|
mapper[map](SAVE, 0);
|
||||||
|
close(fd);
|
||||||
|
}
|
Loading…
Reference in a new issue