ref: d8489586ecaa1c80a93537f20dcf2a28757f4340
parent: 5e353e17c6d4410487bc33aaa07fdb3121962c16
parent: 76b51dc816a4e6ad1d21b6b40b8ea32a57bd47a6
author: aiju <aiju@phicode.de>
date: Mon Feb 24 17:50:29 EST 2014
merge
--- a/sys/src/games/nes/apu.c
+++ b/sys/src/games/nes/apu.c
@@ -7,7 +7,17 @@
enum { MAXBUF = 2000 };
-u8int apuseq, apuctr[10];
+enum {
+ LEN = 0,
+ ENV = 4,
+ TRILIN = 6,
+ SWEEP = 8,
+ RELOAD = 10,
+ DMCCTR = 11,
+ DMCSHFT = 12,
+};
+u8int apuseq, apuctr[13];
+u16int dmcaddr, dmccnt;
static int fd;
static short sbuf[2*MAXBUF], *sbufp;
@@ -41,10 +51,10 @@
m >>= 2;
if((m & 0x20) != 0)
continue;
- if(apuctr[i] != 0)
- apuctr[i]--;
+ if(apuctr[LEN + i] != 0)
+ apuctr[LEN + i]--;
}
- for(i = 0, a = apuctr + 8; i < 2; i++, a++){
+ for(i = 0, a = apuctr + SWEEP; i < 2; i++, a++){
m = mem[0x4001 + i * 4];
if((m & 0x80) != 0 && (m & 0x07) != 0 && (*a & 7) == 0){
p = targperiod(i);
@@ -66,19 +76,23 @@
int i, m;
u8int *a;
- for(i = 0, a = apuctr + 4; i < 4; i++, a++){
+ for(i = 0, a = apuctr + ENV; 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;
+ if((apuctr[RELOAD] & (1<<i)) != 0)
+ *a = 0xf0 | m & 0x0f;
+ else if((*a & 0x0f) == 0){
+ *a |= m & 0x0f;
+ if((*a & 0xf0) == 0){
+ if((m & 0x20) != 0)
+ *a |= 0xf0;
+ }else
+ *a -= 0x10;
}else
(*a)--;
}
- a = apuctr + 6;
+ a = apuctr + TRILIN;
if((*a & 0x80) != 0)
*a = mem[0x4008];
else if(*a != 0)
@@ -143,11 +157,10 @@
c[i]++;
m = mem[0x4000 + 4 * i];
if((m & 0x10) != 0)
- s = m;
+ s = m & 0x0f;
else
- s = apuctr[i+4];
- s &= 0x0f;
- if(c[i] >= f/2 || apuctr[i] == 0)
+ s = apuctr[ENV + i] >> 4;
+ if(c[i] >= f/2 || apuctr[LEN + i] == 0)
s = 0;
return s;
}
@@ -168,7 +181,7 @@
c++;
i = 32 * c / f;
i ^= (i < 16) ? 0xf : 0x10;
- if(apuctr[2] == 0 || (apuctr[6] & 0x7f) == 0)
+ if(apuctr[LEN + 2] == 0 || (apuctr[TRILIN] & 0x7f) == 0)
return 0;
return i;
}
@@ -191,18 +204,18 @@
r >>= 1;
c -= f;
}
- if(apuctr[3] == 0 || (r & 1) != 0)
+ if(apuctr[LEN + 3] == 0 || (r & 1) != 0)
return 0;
m = mem[0x400C];
if((m & 0x10) != 0)
return m & 0xf;
- return apuctr[7] & 0xf;
+ return apuctr[ENV + 3] >> 4;
}
static int
dmc(void)
{
- return 0;
+ return mem[DMCBUF];
}
void
@@ -220,6 +233,40 @@
}
}
+void
+dmcstep(void)
+{
+ if((apuctr[DMCCTR] & 7) == 0){
+ apuctr[DMCCTR] = 8;
+ if(dmccnt != 0){
+ apuctr[DMCSHFT] = memread(dmcaddr);
+ if(dmcaddr == 0xFFFF)
+ dmcaddr = 0x8000;
+ else
+ dmcaddr++;
+ if(--dmccnt == 0){
+ if((mem[DMCCTRL] & 0x40) != 0){
+ dmcaddr = mem[DMCADDR] * 0x40 + 0xC000;
+ dmccnt = mem[DMCLEN] * 0x10 + 1;
+ }else if((mem[DMCCTRL] & 0x80) != 0)
+ irq |= IRQDMC;
+ }
+ }else
+ apuctr[DMCCTR] |= 0x80;
+ }
+ if((apuctr[DMCCTR] & 0x80) == 0){
+ if((apuctr[DMCSHFT] & 1) != 0){
+ if(mem[DMCBUF] < 126)
+ mem[DMCBUF] += 2;
+ }else{
+ if(mem[DMCBUF] > 1)
+ mem[DMCBUF] -= 2;
+ }
+ }
+ apuctr[DMCSHFT] >>= 1;
+ apuctr[DMCCTR]--;
+}
+
int
audioout(void)
{
@@ -251,4 +298,9 @@
0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E,
0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16,
0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E,
+};
+
+u16int dmclen[16] = {
+ 0x1AC, 0x17C, 0x154, 0x140, 0x11E, 0x0FE, 0x0E2, 0x0D6,
+ 0x0BE, 0x0A0, 0x08E, 0x080, 0x06A, 0x054, 0x048, 0x036,
};
--- a/sys/src/games/nes/dat.h
+++ b/sys/src/games/nes/dat.h
@@ -10,9 +10,10 @@
extern uchar *prg, *chr;
extern int nprg, nchr, map, chrram;
-extern u8int apuseq, apuctr[10];
+extern u8int apuseq, apuctr[13];
+extern u16int dmcaddr, dmccnt;
-extern int keys, clock, ppuclock, apuclock, saveclock, paused;
+extern int keys, clock, ppuclock, apuclock, dmcclock, dmcfreq, saveclock, paused;
extern void (*mapper[])(int, u8int);
@@ -31,6 +32,10 @@
PPUMASK = 0x2001,
PPUSTATUS = 0x2002,
PPUSCROLL = 0x2005,
+ DMCCTRL = 0x4010,
+ DMCBUF = 0x4011,
+ DMCADDR = 0x4012,
+ DMCLEN = 0x4013,
APUSTATUS = 0x4015,
APUFRAME = 0x4017,
--- a/sys/src/games/nes/fns.h
+++ b/sys/src/games/nes/fns.h
@@ -13,3 +13,4 @@
void initaudio(void);
void audiosample(void);
int audioout(void);
+void dmcstep(void);
--- a/sys/src/games/nes/mem.c
+++ b/sys/src/games/nes/mem.c
@@ -168,6 +168,40 @@
}
static void
+cnrom(int p, u8int v)
+{
+ static u8int b;
+
+ if(p < 0)
+ switch(p){
+ case INIT:
+ prgsh = 14;
+ chrsh = 13;
+ prgb[0] = prg;
+ if(nprg == 1)
+ prgb[1] = prg;
+ else
+ prgb[1] = prg + 0x4000;
+ break;
+ case SAVE:
+ put8(b);
+ return;
+ case RSTR:
+ b = get8();
+ break;
+ case SCAN:
+ return;
+ default:
+ nope(p);
+ return;
+ }
+ else
+ b = v % nchr;
+ chrb[0] = chr + b * 0x2000;
+
+}
+
+static void
mmc3(int p, u8int v)
{
static u8int m, b[8], l, n, en;
@@ -289,6 +323,7 @@
[0] nrom,
[1] mmc1,
[2] uxrom,
+ [3] cnrom,
[4] mmc3,
[7] axrom,
};
@@ -368,6 +403,7 @@
memwrite(u16int p, u8int v)
{
extern u8int apulen[32];
+ extern u16int dmclen[16];
int i;
if(p < 0x2000){
@@ -422,9 +458,17 @@
i = (p & 0xC) >> 2;
if((mem[APUSTATUS] & (1<<i)) != 0){
apuctr[i] = apulen[v >> 3];
- apuctr[i+4] |= 0x80;
+ apuctr[10] |= (1<<i);
}
break;
+ case DMCCTRL:
+ if((v & 0x80) == 0)
+ irq &= ~IRQDMC;
+ dmcfreq = 12 * dmclen[v & 0xf];
+ break;
+ case DMCBUF:
+ v &= ~0x80;
+ break;
case 0x4014:
memcpy(oam, mem + (v<<8), sizeof(oam));
return;
@@ -432,6 +476,10 @@
for(i = 0; i < 4; i++)
if((v & (1<<i)) == 0)
apuctr[i] = 0;
+ if((v & 0x10) != 0 && dmccnt == 0){
+ dmcaddr = mem[DMCADDR] * 0x40 + 0xC000;
+ dmccnt = mem[DMCLEN] * 0x10 + 1;
+ }
irq &= ~IRQDMC;
break;
case 0x4016:
--- a/sys/src/games/nes/nes.c
+++ b/sys/src/games/nes/nes.c
@@ -13,7 +13,7 @@
int scale;
Rectangle picr;
Image *tmp, *bg;
-int clock, ppuclock, apuclock, sampclock, msgclock, saveclock;
+int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock;
Mousectl *mc;
int keys, paused, savereq, loadreq, oflag, savefd = -1;
int mirr;
@@ -230,6 +230,7 @@
pc = memread(0xFFFC) | memread(0xFFFD) << 8;
rP = FLAGI;
+ dmcfreq = 12 * 428;
for(;;){
if(savereq){
savestate("nes.save");
@@ -248,8 +249,7 @@
ppuclock += t;
apuclock += t;
sampclock += t;
- //syncclock += t;
- //checkclock += t;
+ dmcclock += t;
while(ppuclock >= 4){
ppustep();
ppuclock -= 4;
@@ -261,6 +261,10 @@
if(sampclock >= SAMPDIV){
audiosample();
sampclock -= SAMPDIV;
+ }
+ if(dmcclock >= dmcfreq){
+ dmcstep();
+ dmcclock -= dmcfreq;
}
if(msgclock > 0){
msgclock -= t;
--- a/sys/src/games/nes/state.c
+++ b/sys/src/games/nes/state.c
@@ -94,6 +94,8 @@
ppuclock = get32();
apuclock = get32();
apuseq = get8();
+ dmcaddr = get16();
+ dmccnt = get16();
read(fd, apuctr, sizeof(apuctr));
mapper[map](RSTR, 0);
close(fd);
@@ -133,6 +135,8 @@
put32(ppuclock);
put32(apuclock);
put8(apuseq);
+ put16(dmcaddr);
+ put16(dmccnt);
write(fd, apuctr, sizeof(apuctr));
mapper[map](SAVE, 0);
close(fd);