shithub: riscv

Download patch

ref: af8c91cf6d30628c17c7d7cb9733dee9e7488ab0
parent: 2bfcea9197d7b18219a7f2dea1a079ec91cf2cc5
author: aiju <devnull@localhost>
date: Sat Feb 22 12:43:15 EST 2014

games/nes: mmc3 and bugfixes

--- a/sys/src/games/nes/cpu.c
+++ b/sys/src/games/nes/cpu.c
@@ -5,7 +5,7 @@
 
 u16int pc, curpc;
 u8int rA, rX, rY, rS, rP;
-int nmi;
+u8int irq, nmi;
 
 static u8int
 fetch8(void)
@@ -247,6 +247,10 @@
 	if(nmi){
 		interrupt(1, 0);
 		nmi = 0;
+		return 7;
+	}
+	if(irq && (rP & 4) == 0){
+		interrupt(0, 0);
 		return 7;
 	}
 	curpc = pc;
--- a/sys/src/games/nes/dat.h
+++ b/sys/src/games/nes/dat.h
@@ -1,13 +1,14 @@
 extern u16int pc, curpc;
 extern u8int rA, rX, rY, rS, rP;
+extern u8int irq, nmi;
 extern uchar mem[32768], ppuram[16384], oam[256];
 extern u16int pput, ppuv;
 extern u8int ppusx, vrambuf;
 extern int mirr, ppux, ppuy, odd, vramlatch, keylatch;
 
-extern int map, scale;
+extern int map, scale, mmc3hack;
 extern uchar *prg, *chr;
-extern int nprg, nchr, nmi, map, chrram;
+extern int nprg, nchr, map, chrram;
 
 extern int keys, clock, ppuclock;
 
@@ -37,7 +38,7 @@
 
 	GRAYSCALE = 1<<0,
 	BG8DISP = 1<<1,
-	BG8SPRITE = 1<<2,
+	SPRITE8DISP = 1<<2,
 	BGDISP = 1<<3,
 	SPRITEDISP = 1<<4,
 
@@ -84,4 +85,5 @@
 	INIT = -1,
 	SAVE = -2,
 	RSTR = -3,
+	SCAN = -4,
 };
--- a/sys/src/games/nes/mem.c
+++ b/sys/src/games/nes/mem.c
@@ -8,10 +8,11 @@
 uchar mem[32768];
 uchar ppuram[16384];
 uchar oam[256];
-uchar *prgb[2], *chrb[2];
+uchar *prgb[16], *chrb[16];
 u16int pput, ppuv;
 u8int ppusx, vrambuf;
 int vramlatch = 1, keylatch = 0xFF;
+int prgsh, chrsh, mmc3hack;
 
 static void
 nope(int p)
@@ -32,10 +33,12 @@
 			prgb[1] = prg;
 		else
 			prgb[1] = prg + 0x4000;
+		prgsh = 14;
 		chrb[0] = chr;
-		chrb[1] = chr + 0x1000;
+		chrsh = 13;
 		break;
 	case SAVE:
+	case SCAN:
 		break;
 	default:
 		nope(p);
@@ -52,6 +55,8 @@
 		switch(v){
 		case INIT:
 			mode = 0x0C;
+			prgsh = 14;
+			chrsh = 12;
 			goto t;
 		case RSTR:
 			mode = get8();
@@ -71,6 +76,8 @@
 			break;
 		default:
 			nope(v);
+		case SCAN:
+			break;
 		}
 		return;
 	}
@@ -131,14 +138,103 @@
 }
 
 static void
-mmc7(int v, u8int p)
+mmc3(int p, u8int v)
 {
+	static u8int m, b[8], l, n, en;
+	int i, j, c;
+
+	if(p < 0){
+		switch(p){
+		case INIT:
+			prgsh = 13;
+			chrsh = 10;
+			mmc3hack = 1;
+			prgb[2] = prg + (2 * nprg - 2) * 0x2000;
+			prgb[3] = prgb[2] + 0x2000;
+			goto t;
+		case SCAN:
+			if(n == 0)
+				n = l;
+			else
+				n--;
+			if(n == 0 && en)
+				irq |= 2;
+			return;
+		case SAVE:
+			put8(m);
+			for(i = 0; i < 8; i++)
+				put8(b[i]);
+			put8(l);
+			put8(n);
+			put8(en);
+			return;
+		case RSTR:
+			m = get8();
+			for(i = 0; i < 8; i++)
+				b[i] = get8();
+			l = get8();
+			n = get8();
+			en = get8();
+			goto t;
+		}
+	}
+	switch(p & 0xE001){
+	case 0x8000:
+		if(((m ^ v) & 0xc0) != 0){
+			m = v;
+			goto t;
+		}
+		m = v;
+		break;
+	case 0x8001:
+		i = m & 7;
+		if(i < 6)
+			v %= 8 * nchr;
+		else
+			v %= 2 * nprg;
+		b[i] = v;
+		goto t;
+	case 0xA000:
+		if(mirr == MFOUR)
+			break;
+		if(v & 1)
+			mirr = MHORZ;
+		else
+			mirr = MVERT;
+		break;
+	case 0xC000: l = v; break;
+	case 0xC001: n = 0; break;
+	case 0xE000: en = 0; irq &= ~2; break;
+	case 0xE001: en = 1; break;
+	}
+	return;
+t:
+	if((m & 0x40) != 0){
+		prgb[0] = prg + (2 * nprg - 2) * 0x2000;
+		prgb[2] = prg + b[6] * 0x2000;
+	}else{
+		prgb[0] = prg + b[6] * 0x2000;
+		prgb[2] = prg + (2 * nprg - 2) * 0x2000;
+	}
+	prgb[1] = prg + b[7] * 0x2000;
+	c = (m & 0x80) >> 6;
+	for(i = 0; i < 2; i++){
+		chrb[j = (i << 1) ^ c] = chr + (b[i] >> 1) * 0x800;
+		chrb[j+1] = chrb[j] + 0x400;
+	}
+	for(i = 2; i < 6; i++)
+		chrb[(i + 2) ^ c] = chr + b[i] * 0x400;
+}
+
+static void
+mmc7(int p, u8int v)
+{
 	static int b;
 
-	if(v >= 0)
-		b = p;
+	if(p >= 0)
+		b = v;
 	else
-		switch(v){
+		switch(p){
 		case INIT:
 			nrom(INIT, 0);
 			b = 0;
@@ -150,7 +246,7 @@
 			b = get8();
 			break;
 		default:
-			nope(v);
+			nope(p);
 			return;
 		}
 	prgb[0] = prg + (b & 3) * 0x8000;
@@ -160,6 +256,7 @@
 void (*mapper[256])(int, u8int) = {
 	[0] nrom,
 	[1] mmc1,
+	[4] mmc3,
 	[7] mmc7,
 };
 
@@ -166,11 +263,16 @@
 static void
 incvram(void)
 {
+	int old;
+	
+	old = ppuv;
 	if((mem[PPUCTRL] & VRAMINC) != 0)
 		ppuv += 32;
 	else
 		ppuv += 1;
 	ppuv &= 0x3FFF;
+	if(mmc3hack && (old & (1<<12)) == 0 && (ppuv & (1<<12)) != 0)
+		mapper[map](SCAN, 0);
 }
 
 u8int
@@ -212,10 +314,8 @@
 		}
 	}
 	if(p >= 0x8000){
-		if((p & 0x4000) != 0)
-			return prgb[1][p - 0xC000];
-		else
-			return prgb[0][p - 0x8000];
+		p -= 0x8000;
+		return prgb[p >> prgsh][p & ((1 << prgsh) - 1)];
 	}
 	return mem[p];
 }
@@ -253,6 +353,8 @@
 				pput = (pput & 0xFF) | (v << 8) & 0x3F00;
 			else{
 				pput = (pput & 0xFF00) | v;
+				if(mmc3hack && (ppuv & (1<<12)) == 0 && (pput & (1<<12)) != 0)
+					mapper[map](SCAN, 0);
 				ppuv = pput;
 			}
 			vramlatch ^= 1;
@@ -295,10 +397,8 @@
 		case MSINGA: p &= ~0xC00; break;
 		case MSINGB: p |= 0xC00; break;
 		}
-	if(p < 0x1000)
-		return chrb[0] + p;
-	else if(p < 0x2000)
-		return chrb[1] + p - 0x1000;
+	if(p < 0x2000)
+		return chrb[p >> chrsh] + (p & ((1 << chrsh) - 1));
 	else
 		return ppuram + p;
 }
--- a/sys/src/games/nes/ppu.c
+++ b/sys/src/games/nes/ppu.c
@@ -167,7 +167,7 @@
 drawsprites(void)
 {
 	uchar *p;
-	int big, dx, dy, i, x;
+	int big, dx, dy, i, x, cc, pri;
 	u8int r1, r2, c;
 	static int n, m, nz, s0, t0;
 	static struct { u8int x, a; u16int t; } s[8], *sp;
@@ -212,6 +212,8 @@
 				mem[PPUSTATUS] |= SPRITE0HIT;
 			nz >>= 1;
 		}
+		cc = -1;
+		pri = 0;
 		for(i = m - 1; i >= 0; i--){
 			dx = x - t[i].x;
 			if(dx < 0 || dx > 7)
@@ -218,12 +220,14 @@
 				continue;
 			c = (t[i].r1 & 1) | (t[i].r2 & 1) << 1;
 			if(c != 0){
-				if((t[i].a & (1<<5)) == 0 || !iscolor(x, ppuy))
-					pixel(x, ppuy, pal(c, t[i].a & 3, 1), 0);
+				cc = pal(c, t[i].a & 3, 1);
+				pri = (t[i].a & (1<<5)) == 0;
 			}
 			t[i].r1 >>= 1;
 			t[i].r2 >>= 1;
 		}
+		if(cc != -1 && (pri || !iscolor(x, ppuy)))
+			pixel(x, ppuy, cc, 0);
 	}
 	if(ppux == 257){
 		for(i = 0; i < n; i++){
@@ -276,18 +280,22 @@
 ppustep(void)
 {
 	extern int nmi;
-	int bg;
+	int mask;
 
 	if(ppuy < 240 || ppuy == 261){
-		bg = (mem[PPUMASK] & BGDISP) != 0;
-		if(bg)
+		mask = mem[PPUMASK];
+		if((mask & BGDISP) != 0)
 			drawbg();
-		if((mem[PPUMASK] & SPRITEDISP) != 0 && ppuy != 261)
+		if(((mask & BGDISP) == 0 && ppux <= 257 || ppux <= 10 && (mask & BG8DISP) == 0) && ppux >= 2)
+			pixel(ppux - 2, ppuy, ppuread(0x3F00), 1);
+		if((mask & SPRITEDISP) != 0 && ppuy != 261 && (ppux > 10 || (mask & SPRITE8DISP) != 0))
 			drawsprites();
+		if(ppux == 240 && (mask & SPRITEDISP) != 0)
+			mapper[map](SCAN, 0);
 		if(ppuy == 261){
 			if(ppux == 1)
 				mem[PPUSTATUS] &= ~(PPUVBLANK|SPRITE0HIT);
-			else if(ppux >= 280 && ppux <= 304 && bg)
+			else if(ppux >= 280 && ppux <= 304 && (mask & BGDISP) != 0)
 				ppuv = (pput & 0x7BE0) | (ppuv & 0x041F);
 		}
 	}else if(ppuy == 241){
@@ -304,7 +312,7 @@
 		ppuy++;
 		if(ppuy > 261){
 			ppuy = 0;
-			if(odd && (mem[PPUCTRL] & (BGDISP | SPRITEDISP)) != 0)
+			if(odd && (mem[PPUMASK] & (BGDISP | SPRITEDISP)) != 0)
 				ppux++;
 			odd ^= 1;
 		}