shithub: riscv

Download patch

ref: 76b51dc816a4e6ad1d21b6b40b8ea32a57bd47a6
parent: 60c3c3b3dbf4e1ae03c1a376babec80900c14ecb
author: aiju <devnull@localhost>
date: Mon Feb 24 17:50:05 EST 2014

games/nes: added dmc, fixed envelope, added cnrom

--- 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);