games/nes: basic audio support, battery backup, bug fixes
This commit is contained in:
parent
f82e3e8657
commit
ad9047ab2c
8 changed files with 385 additions and 18 deletions
248
sys/src/games/nes/apu.c
Normal file
248
sys/src/games/nes/apu.c
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
u8int apuseq, apuctr[10];
|
||||||
|
static int fd;
|
||||||
|
|
||||||
|
enum { RATE = 44100 };
|
||||||
|
|
||||||
|
int
|
||||||
|
targperiod(int i)
|
||||||
|
{
|
||||||
|
int m, p, t;
|
||||||
|
|
||||||
|
m = mem[0x4001 + i * 4];
|
||||||
|
p = mem[0x4002 + i * 4];
|
||||||
|
p |= (mem[0x4003 + i * 4] & 7) << 8;
|
||||||
|
t = p >> (m & 7);
|
||||||
|
if((m & 8) != 0){
|
||||||
|
if(i == 0 && t != 0)
|
||||||
|
t--;
|
||||||
|
t = p - t;
|
||||||
|
}else
|
||||||
|
t += p;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
declen(void)
|
||||||
|
{
|
||||||
|
int i, m, p;
|
||||||
|
u8int *a;
|
||||||
|
|
||||||
|
for(i = 0; i < 4; i++){
|
||||||
|
m = mem[0x4000 + i * 4];
|
||||||
|
if(i == 2)
|
||||||
|
m >>= 2;
|
||||||
|
if((m & 0x20) != 0)
|
||||||
|
continue;
|
||||||
|
if(apuctr[i] != 0)
|
||||||
|
apuctr[i]--;
|
||||||
|
}
|
||||||
|
for(i = 0, a = apuctr + 8; i < 2; i++, a++){
|
||||||
|
m = mem[0x4001 + i * 4];
|
||||||
|
if((m & 0x80) != 0 && (m & 0x07) != 0 && (*a & 7) == 0){
|
||||||
|
p = targperiod(i);
|
||||||
|
if(p <= 0x7ff){
|
||||||
|
mem[0x4002 + i * 4] = p;
|
||||||
|
mem[0x4003 + i * 4] = p >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((*a & 0x80) != 0 || (*a & 7) == 0 && (m & 0x80) != 0)
|
||||||
|
*a = (m & 0x70) >> 4;
|
||||||
|
else if(*a != 0)
|
||||||
|
(*a)--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
doenv(void)
|
||||||
|
{
|
||||||
|
int i, m;
|
||||||
|
u8int *a;
|
||||||
|
|
||||||
|
for(i = 0, a = apuctr + 4; i < 4; i++, a++){
|
||||||
|
if(i == 2)
|
||||||
|
continue;
|
||||||
|
m = mem[0x4000 + 4 * i];
|
||||||
|
if((*a & 0x80) != 0)
|
||||||
|
*a = *a & 0x70 | 0x0f;
|
||||||
|
else if(*a == 0){
|
||||||
|
if((m & 0x20) != 0)
|
||||||
|
*a |= 0x0f;
|
||||||
|
}else
|
||||||
|
(*a)--;
|
||||||
|
}
|
||||||
|
a = apuctr + 6;
|
||||||
|
if((*a & 0x80) != 0)
|
||||||
|
*a = mem[0x4008];
|
||||||
|
else if(*a != 0)
|
||||||
|
(*a)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
apustep(void)
|
||||||
|
{
|
||||||
|
int mode, len, env;
|
||||||
|
|
||||||
|
mode = mem[APUFRAME];
|
||||||
|
if((mode & 0x80) != 0){
|
||||||
|
if(apuseq >= 4){
|
||||||
|
env = len = 0;
|
||||||
|
apuseq = 0;
|
||||||
|
}else{
|
||||||
|
env = 1;
|
||||||
|
len = (apuseq & 1) == 0;
|
||||||
|
apuseq++;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
env = 1;
|
||||||
|
len = (apuseq & 1) != 0;
|
||||||
|
if(apuseq >= 3){
|
||||||
|
if((mode & 0x40) == 0)
|
||||||
|
irq |= IRQFRAME;
|
||||||
|
apuseq = 0;
|
||||||
|
}else
|
||||||
|
apuseq++;
|
||||||
|
}
|
||||||
|
if(len)
|
||||||
|
declen();
|
||||||
|
if(env)
|
||||||
|
doenv();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
freq(int i)
|
||||||
|
{
|
||||||
|
int f;
|
||||||
|
|
||||||
|
f = mem[0x4002 + 4 * i];
|
||||||
|
f |= (mem[0x4003 + 4 * i] & 0x7) << 8;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pulse(int i)
|
||||||
|
{
|
||||||
|
static int c[2];
|
||||||
|
int m, s, f;
|
||||||
|
|
||||||
|
f = freq(i);
|
||||||
|
if(f < 8 || targperiod(i) > 0x7ff)
|
||||||
|
f = -1;
|
||||||
|
else
|
||||||
|
f = muldiv(16 * (f + 1), RATE, FREQ/12);
|
||||||
|
if(c[i] >= f)
|
||||||
|
c[i] = 0;
|
||||||
|
else
|
||||||
|
c[i]++;
|
||||||
|
m = mem[0x4000 + 4 * i];
|
||||||
|
if((m & 0x10) != 0)
|
||||||
|
s = m;
|
||||||
|
else
|
||||||
|
s = apuctr[i+4];
|
||||||
|
s &= 0x0f;
|
||||||
|
if(c[i] >= f/2 || apuctr[i] == 0)
|
||||||
|
s = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tri(void)
|
||||||
|
{
|
||||||
|
static int c;
|
||||||
|
int f, i;
|
||||||
|
|
||||||
|
f = freq(2);
|
||||||
|
if(f <= 2)
|
||||||
|
return 7;
|
||||||
|
f = muldiv(32 * (f + 1), RATE, FREQ / 12);
|
||||||
|
if(c >= f)
|
||||||
|
c = 0;
|
||||||
|
else
|
||||||
|
c++;
|
||||||
|
i = 32 * c / f;
|
||||||
|
i ^= (i < 16) ? 0xf : 0x10;
|
||||||
|
if(apuctr[2] == 0 || (apuctr[6] & 0x7f) == 0)
|
||||||
|
return 0;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
noise(void)
|
||||||
|
{
|
||||||
|
static int c, r=1;
|
||||||
|
int m, f;
|
||||||
|
static int per[] = {
|
||||||
|
0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0,
|
||||||
|
0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4,
|
||||||
|
};
|
||||||
|
|
||||||
|
m = mem[0x400E];
|
||||||
|
f = muldiv(per[m & 0x0f], RATE * 1000, FREQ/24);
|
||||||
|
c += 1000;
|
||||||
|
while(c >= f){
|
||||||
|
r |= ((r ^ (r >> ((m & 0x80) != 0 ? 6 : 1))) & 1) << 15;
|
||||||
|
r >>= 1;
|
||||||
|
c -= f;
|
||||||
|
}
|
||||||
|
if(apuctr[3] == 0 || (r & 1) != 0)
|
||||||
|
return 0;
|
||||||
|
m = mem[0x400C];
|
||||||
|
if((m & 0x10) != 0)
|
||||||
|
return m & 0xf;
|
||||||
|
return apuctr[7] & 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dmc(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sample(short *s)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
|
||||||
|
d = 95.88 / (8128.0 / (0.01 + pulse(0) + pulse(1)) + 100);
|
||||||
|
d += 159.79 / (1.0 / (0.01 + tri()/8227.0 + noise()/12241.0 + dmc()/22638.0) + 100.0);
|
||||||
|
*s++ = d * 20000;
|
||||||
|
*s = d * 20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
audioproc(void *)
|
||||||
|
{
|
||||||
|
static short samples[500 * 2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
if(paused)
|
||||||
|
memset(samples, 0, sizeof samples);
|
||||||
|
else
|
||||||
|
for(i = 0; i < sizeof samples/4; i++)
|
||||||
|
sample(samples + 2 * i);
|
||||||
|
write(fd, samples, sizeof samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
initaudio(void)
|
||||||
|
{
|
||||||
|
fd = open("/dev/audio", OWRITE);
|
||||||
|
if(fd < 0)
|
||||||
|
return;
|
||||||
|
proccreate(audioproc, nil, 8192);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8int apulen[32] = {
|
||||||
|
0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06,
|
||||||
|
0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E,
|
||||||
|
0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16,
|
||||||
|
0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E,
|
||||||
|
};
|
|
@ -10,7 +10,9 @@ extern int map, scale, mmc3hack, oflag;
|
||||||
extern uchar *prg, *chr;
|
extern uchar *prg, *chr;
|
||||||
extern int nprg, nchr, map, chrram;
|
extern int nprg, nchr, map, chrram;
|
||||||
|
|
||||||
extern int keys, clock, ppuclock;
|
extern u8int apuseq, apuctr[10];
|
||||||
|
|
||||||
|
extern int keys, clock, ppuclock, apuclock, saveclock, paused;
|
||||||
|
|
||||||
extern void (*mapper[])(int, u8int);
|
extern void (*mapper[])(int, u8int);
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@ enum {
|
||||||
PPUMASK = 0x2001,
|
PPUMASK = 0x2001,
|
||||||
PPUSTATUS = 0x2002,
|
PPUSTATUS = 0x2002,
|
||||||
PPUSCROLL = 0x2005,
|
PPUSCROLL = 0x2005,
|
||||||
|
APUSTATUS = 0x4015,
|
||||||
|
APUFRAME = 0x4017,
|
||||||
|
|
||||||
PPUNMI = 1<<7,
|
PPUNMI = 1<<7,
|
||||||
BIGSPRITE = 1<<5,
|
BIGSPRITE = 1<<5,
|
||||||
|
@ -71,6 +75,8 @@ enum {
|
||||||
FREQ = 21477272,
|
FREQ = 21477272,
|
||||||
MILLION = 1000000,
|
MILLION = 1000000,
|
||||||
BILLION = 1000000000,
|
BILLION = 1000000000,
|
||||||
|
APUDIV = 89490,
|
||||||
|
SAVEFREQ = FREQ/5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -87,3 +93,9 @@ enum {
|
||||||
RSTR = -3,
|
RSTR = -3,
|
||||||
SCAN = -4,
|
SCAN = -4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IRQFRAME = 1,
|
||||||
|
IRQDMC = 2,
|
||||||
|
IRQMMC = 4,
|
||||||
|
};
|
||||||
|
|
|
@ -9,3 +9,5 @@ void savestate(char *);
|
||||||
void message(char *, ...);
|
void message(char *, ...);
|
||||||
void put8(u8int);
|
void put8(u8int);
|
||||||
int get8(void);
|
int get8(void);
|
||||||
|
void apustep(void);
|
||||||
|
void initaudio(void);
|
||||||
|
|
|
@ -158,7 +158,7 @@ mmc3(int p, u8int v)
|
||||||
else
|
else
|
||||||
n--;
|
n--;
|
||||||
if(n == 0 && en)
|
if(n == 0 && en)
|
||||||
irq |= 2;
|
irq |= IRQMMC;
|
||||||
return;
|
return;
|
||||||
case SAVE:
|
case SAVE:
|
||||||
put8(m);
|
put8(m);
|
||||||
|
@ -204,7 +204,7 @@ mmc3(int p, u8int v)
|
||||||
break;
|
break;
|
||||||
case 0xC000: l = v; break;
|
case 0xC000: l = v; break;
|
||||||
case 0xC001: n = 0; break;
|
case 0xC001: n = 0; break;
|
||||||
case 0xE000: en = 0; irq &= ~2; break;
|
case 0xE000: en = 0; irq &= ~IRQMMC; break;
|
||||||
case 0xE001: en = 1; break;
|
case 0xE001: en = 1; break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -281,6 +281,7 @@ u8int
|
||||||
memread(u16int p)
|
memread(u16int p)
|
||||||
{
|
{
|
||||||
u8int v;
|
u8int v;
|
||||||
|
int i;
|
||||||
|
|
||||||
if(p < 0x2000){
|
if(p < 0x2000){
|
||||||
p &= 0x7FF;
|
p &= 0x7FF;
|
||||||
|
@ -305,6 +306,16 @@ memread(u16int p)
|
||||||
vrambuf = ppuread(ppuv);
|
vrambuf = ppuread(ppuv);
|
||||||
incvram();
|
incvram();
|
||||||
return vrambuf;
|
return vrambuf;
|
||||||
|
case APUSTATUS:
|
||||||
|
v = (irq & 3) << 6;
|
||||||
|
for(i = 0; i < 4; i++){
|
||||||
|
if(apuctr[i] != 0)
|
||||||
|
v |= (1<<i);
|
||||||
|
}
|
||||||
|
if(mem[0x4013] != 0)
|
||||||
|
v |= (1<<4);
|
||||||
|
irq &= ~IRQFRAME;
|
||||||
|
return v;
|
||||||
case 0x4016:
|
case 0x4016:
|
||||||
if((mem[p] & 1) != 0)
|
if((mem[p] & 1) != 0)
|
||||||
return keys & 1;
|
return keys & 1;
|
||||||
|
@ -325,6 +336,9 @@ memread(u16int p)
|
||||||
void
|
void
|
||||||
memwrite(u16int p, u8int v)
|
memwrite(u16int p, u8int v)
|
||||||
{
|
{
|
||||||
|
extern u8int apulen[32];
|
||||||
|
int i;
|
||||||
|
|
||||||
if(p < 0x2000){
|
if(p < 0x2000){
|
||||||
p &= 0x7FF;
|
p &= 0x7FF;
|
||||||
}else if(p < 0x6000){
|
}else if(p < 0x6000){
|
||||||
|
@ -365,15 +379,48 @@ memwrite(u16int p, u8int v)
|
||||||
ppuwrite(ppuv, v);
|
ppuwrite(ppuv, v);
|
||||||
incvram();
|
incvram();
|
||||||
return;
|
return;
|
||||||
|
case 0x4001:
|
||||||
|
case 0x4005:
|
||||||
|
i = (p & 0xC) >> 2;
|
||||||
|
apuctr[i+8] |= 0x80;
|
||||||
|
break;
|
||||||
|
case 0x4003:
|
||||||
|
case 0x4007:
|
||||||
|
case 0x400B:
|
||||||
|
case 0x400F:
|
||||||
|
i = (p & 0xC) >> 2;
|
||||||
|
if((mem[APUSTATUS] & (1<<i)) != 0){
|
||||||
|
apuctr[i] = apulen[v >> 3];
|
||||||
|
apuctr[i+4] |= 0x80;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0x4014:
|
case 0x4014:
|
||||||
memcpy(oam, mem + (v<<8), sizeof(oam));
|
memcpy(oam, mem + (v<<8), sizeof(oam));
|
||||||
return;
|
return;
|
||||||
|
case APUSTATUS:
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
if((v & (1<<i)) == 0)
|
||||||
|
apuctr[i] = 0;
|
||||||
|
irq &= ~IRQDMC;
|
||||||
|
break;
|
||||||
case 0x4016:
|
case 0x4016:
|
||||||
if((mem[p] & 1) != 0 && (v & 1) == 0)
|
if((mem[p] & 1) != 0 && (v & 1) == 0)
|
||||||
keylatch = keys;
|
keylatch = keys;
|
||||||
break;
|
break;
|
||||||
|
case APUFRAME:
|
||||||
|
apuseq = 0;
|
||||||
|
if((v & 0x80) != 0)
|
||||||
|
apuclock = APUDIV;
|
||||||
|
else
|
||||||
|
apuclock = 0;
|
||||||
|
if((v & 0x40) != 0)
|
||||||
|
irq &= ~IRQFRAME;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}else if(p >= 0x8000){
|
}else if(p < 0x8000){
|
||||||
|
if(saveclock == 0)
|
||||||
|
saveclock = SAVEFREQ;
|
||||||
|
}else{
|
||||||
if(mapper[map] != nil)
|
if(mapper[map] != nil)
|
||||||
mapper[map](p, v);
|
mapper[map](p, v);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -8,6 +8,7 @@ OFILES=\
|
||||||
nes.$O\
|
nes.$O\
|
||||||
ppu.$O\
|
ppu.$O\
|
||||||
state.$O\
|
state.$O\
|
||||||
|
apu.$O\
|
||||||
|
|
||||||
HFILES=dat.h fns.h
|
HFILES=dat.h fns.h
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ uchar *prg, *chr;
|
||||||
int scale;
|
int scale;
|
||||||
Rectangle picr;
|
Rectangle picr;
|
||||||
Image *tmp, *bg;
|
Image *tmp, *bg;
|
||||||
int clock, ppuclock, syncclock, syncfreq, checkclock, msgclock, sleeps;
|
int clock, ppuclock, apuclock, syncclock, syncfreq, checkclock, msgclock, saveclock, sleeps;
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
int keys, paused, savereq, loadreq, oflag;
|
int keys, paused, savereq, loadreq, oflag, savefd = -1;
|
||||||
int mirr;
|
int mirr;
|
||||||
QLock pauselock;
|
QLock pauselock;
|
||||||
|
|
||||||
|
@ -33,12 +33,22 @@ message(char *fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
loadrom(char *file)
|
flushram(void)
|
||||||
|
{
|
||||||
|
if(savefd >= 0)
|
||||||
|
pwrite(savefd, mem + 0x6000, 0x2000, 0);
|
||||||
|
saveclock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
loadrom(char *file, int sflag)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int nes20;
|
int nes20;
|
||||||
|
char *s;
|
||||||
static uchar header[16];
|
static uchar header[16];
|
||||||
static u32int flags;
|
static u32int flags;
|
||||||
|
static char buf[512];
|
||||||
|
|
||||||
fd = open(file, OREAD);
|
fd = open(file, OREAD);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
|
@ -94,7 +104,22 @@ loadrom(char *file)
|
||||||
mirr = MVERT;
|
mirr = MVERT;
|
||||||
else
|
else
|
||||||
mirr = MHORZ;
|
mirr = MHORZ;
|
||||||
mapper[map](-1, 0);
|
if(sflag){
|
||||||
|
strncpy(buf, file, sizeof buf - 5);
|
||||||
|
s = buf + strlen(buf) - 4;
|
||||||
|
if(s < buf || strcmp(s, ".nes") != 0)
|
||||||
|
s += 4;
|
||||||
|
strcpy(s, ".sav");
|
||||||
|
savefd = create(buf, ORDWR | OEXCL, 0666);
|
||||||
|
if(savefd < 0)
|
||||||
|
savefd = open(buf, ORDWR);
|
||||||
|
if(savefd < 0)
|
||||||
|
message("open: %r");
|
||||||
|
else
|
||||||
|
readn(savefd, mem + 0x6000, 0x2000);
|
||||||
|
atexit(flushram);
|
||||||
|
}
|
||||||
|
mapper[map](INIT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int trace;
|
extern int trace;
|
||||||
|
@ -114,8 +139,10 @@ keyproc(void *)
|
||||||
if(read(fd, buf, sizeof(buf) - 1) <= 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)){
|
||||||
|
close(fd);
|
||||||
threadexitsall(nil);
|
threadexitsall(nil);
|
||||||
|
}
|
||||||
if(utfrune(buf, KF|5))
|
if(utfrune(buf, KF|5))
|
||||||
savereq = 1;
|
savereq = 1;
|
||||||
if(utfrune(buf, KF|6))
|
if(utfrune(buf, KF|6))
|
||||||
|
@ -130,7 +157,7 @@ keyproc(void *)
|
||||||
while(*s != 0){
|
while(*s != 0){
|
||||||
s += chartorune(&r, s);
|
s += chartorune(&r, s);
|
||||||
switch(r){
|
switch(r){
|
||||||
case Kdel: threadexitsall(nil);
|
case Kdel: close(fd); threadexitsall(nil);
|
||||||
case 'x': k |= 1<<0; break;
|
case 'x': k |= 1<<0; break;
|
||||||
case 'z': k |= 1<<1; break;
|
case 'z': k |= 1<<1; break;
|
||||||
case Kshift: k |= 1<<2; break;
|
case Kshift: k |= 1<<2; break;
|
||||||
|
@ -155,13 +182,17 @@ keyproc(void *)
|
||||||
void
|
void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int t, h;
|
int t, h, sflag;
|
||||||
Point p;
|
Point p;
|
||||||
uvlong old, new, diff;
|
uvlong old, new, diff;
|
||||||
|
|
||||||
scale = 1;
|
scale = 1;
|
||||||
h = 240;
|
h = 240;
|
||||||
|
sflag = 0;
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
|
case 'a':
|
||||||
|
initaudio();
|
||||||
|
break;
|
||||||
case '2':
|
case '2':
|
||||||
scale = 2;
|
scale = 2;
|
||||||
break;
|
break;
|
||||||
|
@ -172,11 +203,19 @@ threadmain(int argc, char **argv)
|
||||||
oflag = 1;
|
oflag = 1;
|
||||||
h -= 16;
|
h -= 16;
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto usage;
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
|
||||||
if(argc < 1)
|
if(argc != 1){
|
||||||
sysfatal("missing argument");
|
usage:
|
||||||
loadrom(argv[0]);
|
fprint(2, "usage: %s [-23aos] rom\n", argv0);
|
||||||
|
threadexitsall("usage");
|
||||||
|
}
|
||||||
|
loadrom(argv[0], sflag);
|
||||||
if(initdraw(nil, nil, nil) < 0)
|
if(initdraw(nil, nil, nil) < 0)
|
||||||
sysfatal("initdraw: %r");
|
sysfatal("initdraw: %r");
|
||||||
mc = initmouse(nil, screen);
|
mc = initmouse(nil, screen);
|
||||||
|
@ -186,7 +225,6 @@ threadmain(int argc, char **argv)
|
||||||
originwindow(screen, Pt(0, 0), screen->r.min);
|
originwindow(screen, Pt(0, 0), screen->r.min);
|
||||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
||||||
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
|
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
|
||||||
if(screen->chan != XRGB32)
|
|
||||||
tmp = allocimage(display, Rect(0, 0, scale * 256, scale * h), XRGB32, 0, 0);
|
tmp = allocimage(display, Rect(0, 0, scale * 256, scale * h), XRGB32, 0, 0);
|
||||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||||
draw(screen, screen->r, bg, nil, ZP);
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
|
@ -211,12 +249,17 @@ threadmain(int argc, char **argv)
|
||||||
t = step() * 12;
|
t = step() * 12;
|
||||||
clock += t;
|
clock += t;
|
||||||
ppuclock += t;
|
ppuclock += t;
|
||||||
|
apuclock += t;
|
||||||
syncclock += t;
|
syncclock += t;
|
||||||
checkclock += t;
|
checkclock += t;
|
||||||
while(ppuclock >= 4){
|
while(ppuclock >= 4){
|
||||||
ppustep();
|
ppustep();
|
||||||
ppuclock -= 4;
|
ppuclock -= 4;
|
||||||
}
|
}
|
||||||
|
if(apuclock >= APUDIV){
|
||||||
|
apustep();
|
||||||
|
apuclock -= APUDIV;
|
||||||
|
}
|
||||||
if(syncclock >= syncfreq){
|
if(syncclock >= syncfreq){
|
||||||
sleep(10);
|
sleep(10);
|
||||||
sleeps++;
|
sleeps++;
|
||||||
|
@ -243,5 +286,10 @@ threadmain(int argc, char **argv)
|
||||||
msgclock = 0;
|
msgclock = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(saveclock > 0){
|
||||||
|
saveclock -= t;
|
||||||
|
if(saveclock <= 0)
|
||||||
|
flushram();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,10 +269,13 @@ flush(void)
|
||||||
sysfatal("resize failed: %r");
|
sysfatal("resize failed: %r");
|
||||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
||||||
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
|
picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
|
||||||
|
if(bg->chan != screen->chan){
|
||||||
|
freeimage(bg);
|
||||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||||
|
}
|
||||||
draw(screen, screen->r, bg, nil, ZP);
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
}
|
}
|
||||||
if(tmp){
|
if(screen->chan != tmp->chan || !rectinrect(picr, screen->r)){
|
||||||
loadimage(tmp, tmp->r, pic + oflag*8*256*4*scale*scale, 256*h*4*scale*scale);
|
loadimage(tmp, tmp->r, pic + oflag*8*256*4*scale*scale, 256*h*4*scale*scale);
|
||||||
draw(screen, picr, tmp, nil, ZP);
|
draw(screen, picr, tmp, nil, ZP);
|
||||||
}else
|
}else
|
||||||
|
|
|
@ -92,6 +92,9 @@ loadstate(char *file)
|
||||||
vrambuf = get8();
|
vrambuf = get8();
|
||||||
clock = get32();
|
clock = get32();
|
||||||
ppuclock = get32();
|
ppuclock = get32();
|
||||||
|
apuclock = get32();
|
||||||
|
apuseq = get8();
|
||||||
|
read(fd, apuctr, sizeof(apuctr));
|
||||||
mapper[map](RSTR, 0);
|
mapper[map](RSTR, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
@ -128,6 +131,9 @@ savestate(char *file)
|
||||||
put8(vrambuf);
|
put8(vrambuf);
|
||||||
put32(clock);
|
put32(clock);
|
||||||
put32(ppuclock);
|
put32(ppuclock);
|
||||||
|
put32(apuclock);
|
||||||
|
put8(apuseq);
|
||||||
|
write(fd, apuctr, sizeof(apuctr));
|
||||||
mapper[map](SAVE, 0);
|
mapper[map](SAVE, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue