git: 9front

Download patch

ref: 22f6a61b0c841b9a045f50eae7c331c25665d1a1
parent: 2a6b39431850b40e58fc376e9b5796e9f9a0effe
author: rodri <rgl@antares-labs.eu>
date: Sat Jan 10 06:19:26 EST 2026

games/nes: improve the cpu to better match the console behavior (thanks yuvia!)

it was developed with AccuracyCoin[1] as a reference.

[1]: https://github.com/100thCoin/AccuracyCoin

--- a/sys/src/games/nes/cpu.c
+++ b/sys/src/games/nes/cpu.c
@@ -17,7 +17,7 @@
 fetch16(void)
 {
 	u16int r;
-	
+
 	r = memread(pc++);
 	r |= memread(pc++) << 8;
 	return r;
@@ -46,7 +46,7 @@
 pop16(void)
 {
 	u16int v;
-	
+
 	v = memread(0x100 | ++rS);
 	v |= memread(0x100 | ++rS) << 8;
 	return v;
@@ -67,7 +67,7 @@
 {
 	u8int r;
 	u16int a;
-	
+
 	r = fetch8() + rX;
 	a = memread(r++);
 	a |= memread(r) << 8;
@@ -79,7 +79,7 @@
 {
 	u8int r;
 	u16int a;
-	
+
 	r = fetch8();
 	a = memread(r++) + rY;
 	*c = a > 0xFF;
@@ -91,7 +91,7 @@
 adc(u8int d)
 {
 	int r;
-	
+
 	r = rA + d + (rP & FLAGC);
 	rP &= ~(FLAGN | FLAGZ | FLAGV | FLAGC);
 	if(r > 0xFF) rP |= FLAGC;
@@ -143,7 +143,7 @@
 {
 	signed char t;
 	u16int npc;
-	
+
 	t = fetch8();
 	npc = pc + t;
 	if((npc ^ pc) >> 8){
@@ -185,7 +185,7 @@
 rol(u16int a)
 {
 	u8int v, b;
-	
+
 	v = memread(a);
 	b = rP & FLAGC;
 	rP &= ~(FLAGC | FLAGN | FLAGZ);
@@ -200,7 +200,7 @@
 ror(u16int a)
 {
 	u8int v, b;
-	
+
 	v = memread(a);
 	b = rP & FLAGC;
 	rP &= ~(FLAGC | FLAGN | FLAGZ);
@@ -215,7 +215,7 @@
 sbc(u8int d)
 {
 	int r;
-	
+
 	r = rA + (u8int)~d + (rP & FLAGC);
 	rP &= ~(FLAGZ | FLAGV | FLAGC | FLAGN);
 	if(r > 0xFF) rP |= FLAGC;
@@ -226,6 +226,48 @@
 }
 
 static void
+axs(u8int d)
+{
+	int r;
+
+	rX &= rA;
+	r = rX - d;
+	rP &= ~(FLAGZ | FLAGC | FLAGN);
+	if(r >= 0) rP |= FLAGC;
+	rX = (u8int)r;
+	if(rX == 0) rP |= FLAGZ;
+	if(rX & 0x80) rP |= FLAGN;
+}
+
+static void
+slo(u16int a)
+{
+	asl(a);
+	nz(rA |= memread(a));
+}
+
+static void
+rla(u16int a)
+{
+	rol(a);
+	nz(rA &= memread(a));
+}
+
+static void
+sre(u16int a)
+{
+	lsr(a);
+	nz(rA ^= memread(a)); 
+}
+
+static void
+rra(u16int a)
+{
+	ror(a);
+	adc(memread(a));
+}
+
+static void
 interrupt(int nmi, int brk)
 {
 	push16(pc);
@@ -261,8 +303,12 @@
 	switch(op){
 	case 0x00: pc++; interrupt(0, 1); return 7;
 	case 0x01: nz(rA |= indX()); return 6;
+	case 0x02: return 7;
+	case 0x03: slo(aindX()); return 7;
+	case 0x04: zp(); return 2;
 	case 0x05: nz(rA |= zp()); return 3;
 	case 0x06: asl(fetch8()); return 5;
+	case 0x07: slo(fetch8()); return 4;
 	case 0x08: push8(rP | 0x30); return 3;
 	case 0x09: nz(rA |= imm()); return 2;
 	case 0x0A:
@@ -272,18 +318,35 @@
 		if(rA == 0) rP |= FLAGZ;
 		if(rA & 0x80) rP |= FLAGN;
 		return 2;
+	case 0x0B:
+		rP &= ~(FLAGN | FLAGZ | FLAGC);
+		rA = rA & imm();
+		nz(rA);
+		if(rA & 0x80) rP |= FLAGC;
+		return 2;
+	case 0x0C: abso(); return 4;
 	case 0x0D: nz(rA |= abso()); return 4;
 	case 0x0E: asl(fetch16()); return 6;
+	case 0x0F: slo(fetch16()); return 6;
 	case 0x10: if((rP & FLAGN) == 0) return branch(); pc++; return 2;
 	case 0x11: nz(rA |= indY(&c)); return 5+c;
+	case 0x12: return 7;
+	case 0x13: slo(aindY(&c)); return 8;
+	case 0x14: zpX(); return 4;
 	case 0x15: nz(rA |= zpX()); return 4;
 	case 0x16: asl((u8int)(fetch8() + rX)); return 6;
+	case 0x17: slo((u8int)(fetch8() + rX)); return 3;
 	case 0x18: rP &= ~FLAGC; return 2;
 	case 0x19: nz(rA |= absY()); return 4 + ((u8int)a < rY);
+	case 0x1A: return 2;
+	case 0x1B: slo(fetch16() + rY); return 6;
+	case 0x1C: abso(); return 5;
 	case 0x1D: nz(rA |= absX()); return 4 + ((u8int)a < rX);
 	case 0x1E: asl(fetch16() + rX); return 7;
+	case 0x1F: slo(fetch16() + rX); return 6;
 	case 0x20: push16(pc+1); pc = fetch16(); return 6;
 	case 0x21: nz(rA &= indX()); return 6;
+	case 0x23: rla(aindX()); return 8;
 	case 0x24:
 		a = memread(fetch8());
 		rP &= ~(FLAGN | FLAGZ | FLAGV);
@@ -292,6 +355,7 @@
 		return 3;
 	case 0x25: nz(rA &= zp()); return 3;
 	case 0x26: rol(fetch8()); return 5;
+	case 0x27: rla(fetch8()); return 5;
 	case 0x28: rP = pop8() & 0xcf; return 4;
 	case 0x29: nz(rA &= imm()); return 2;
 	case 0x2A:
@@ -302,6 +366,12 @@
 		if(rA & 0x80) rP |= FLAGN;
 		if(rA == 0) rP |= FLAGZ;
 		return 2;
+	case 0x2B:
+		rP &= ~(FLAGN | FLAGZ | FLAGC);
+		rA = rA & imm();
+		nz(rA);
+		if(rA & 0x80) rP |= FLAGC;
+		return 2;
 	case 0x2C:
 		a = memread(fetch16());
 		rP &= ~(FLAGN | FLAGZ | FLAGV);
@@ -310,42 +380,69 @@
 		return 4;
 	case 0x2D: nz(rA &= abso()); return 4;
 	case 0x2E: rol(fetch16()); return 6;
+	case 0x2F: rla(fetch16()); return 6;
 	case 0x30: if((rP & FLAGN) != 0) return branch(); pc++; return 3;
 	case 0x31: nz(rA &= indY(&c)); return 5+c;
+	case 0x33: rla(aindY(&c)); return 6+c;
+	case 0x34: zp(); return 4;
 	case 0x35: nz(rA &= zpX()); return 4;
 	case 0x36: rol((u8int)(fetch8() + rX)); return 6;
+	case 0x37: rla((u8int)(fetch8() + rX)); return 6;
 	case 0x38: rP |= FLAGC; return 2;
 	case 0x39: nz(rA &= absY()); return 4 + ((u8int)a < rY);
+	case 0x3A: return 2;
+	case 0x3B: rla(fetch16() + rY); return 7;
+	case 0x3C: abso(); return 4;
 	case 0x3E: rol(fetch16() + rX); return 7;
+	case 0x3F: rla(fetch16() + rX); return 7;
 	case 0x3D: nz(rA &= absX()); return 4 + ((u8int)a < rX);
 	case 0x40: rP = pop8() & 0xcf; pc = pop16(); return 6;
 	case 0x41: nz(rA ^= indX()); return 6;
+	case 0x42: return 7;
+	case 0x43: sre(aindX()); return 8;
+	case 0x44: zp(); return 3;
 	case 0x45: nz(rA ^= zp()); return 3;
 	case 0x46: lsr(fetch8()); return 5;
+	case 0x47: sre(fetch8()); return 5;
 	case 0x48: push8(rA); return 3;
 	case 0x49: nz(rA ^= imm()); return 2;
 	case 0x4A:
 		rP &= ~(FLAGN | FLAGZ | FLAGC);
 		rP |= rA & 1;
-		rA >>= 1;
-		if(rA == 0) rP |= FLAGZ;
-		if(rA & 0x80) rP |= FLAGN;
+		nz(rA >>= 1);
 		return 2;
+	case 0x4B:
+		rA &= imm();
+		rP &= ~(FLAGN | FLAGZ | FLAGC);
+		rP |= rA & 1;
+		nz(rA >>= 1);
+		return 2;
 	case 0x4C: pc = fetch16(); return 3;
 	case 0x4D: nz(rA ^= abso()); return 4;
 	case 0x4E: lsr(fetch16()); return 6;
+	case 0x4F: sre(fetch16()); return 6;
 	case 0x51: nz(rA ^= indY(&c)); return 5+c;
+	case 0x53: sre(aindY(&c)); return 8;
+	case 0x54: zp(); return 2;
 	case 0x56: lsr((u8int)(fetch8() + rX)); return 6;
+	case 0x57: sre((u8int)(fetch8() + rX)); return 6;
 	case 0x58: rP &= ~FLAGI; return 2;
 	case 0x50: if((rP & FLAGV) == 0) return branch(); pc++; return 3;
 	case 0x55: nz(rA ^= zpX()); return 4;
 	case 0x59: nz(rA ^= absY()); return 4 + ((u8int)a < rX);
+	case 0x5A: return 2;
+	case 0x5B: sre(fetch16() + rY); return 7;
+	case 0x5C: abso(); return 4;
 	case 0x5D: nz(rA ^= absX()); return 4 + ((u8int)a < rX);
 	case 0x5E: lsr(fetch16() + rX); return 7;
+	case 0x5F: sre(fetch16() + rX); return 7;
 	case 0x60: pc = pop16() + 1; return 6;
 	case 0x61: adc(indX()); return 6;
+	case 0x63: rra(aindX()); return 8;
+	case 0x64: zp(); return 3;
 	case 0x65: adc(zp()); return 3;
 	case 0x66: ror(fetch8()); return 5;
+	case 0x67: rra(fetch8()); return 5;
 	case 0x68: nz(rA = pop8()); return 4;
 	case 0x69: adc(imm()); return 2;
 	case 0x6A:
@@ -356,68 +453,154 @@
 		if(rA & 0x80) rP |= FLAGN;
 		if(rA == 0) rP |= FLAGZ;
 		return 2;
-	case 0x6C: v = fetch16(); pc = memread(v) | (memread((v & 0xFF00) | (u8int)(v+1)) << 8); return 5;
+	case 0x6B:
+		rA &= imm();
+		a = rP & FLAGC;
+		rP &= ~(FLAGV | FLAGC | FLAGN | FLAGZ);
+		rA = (rA >> 1) | (a << 7);
+		nz(rA);
+		if(rA & 0x40) rP |= FLAGC;
+		if(rA & 0x20) rP |= FLAGV;
+		if(rP & FLAGC) rP &= ~FLAGV;
+		return 2;
+	case 0x6C:
+		v = fetch16();
+		pc = memread(v) | (memread((v & 0xFF00) | (u8int)(v+1)) << 8);
+		return 5;
 	case 0x6D: adc(abso()); return 4;
 	case 0x6E: ror(fetch16()); return 6;
+	case 0x6F: rra(fetch16()); return 6;
 	case 0x70: if((rP & FLAGV) != 0) return branch(); pc++; return 3;
 	case 0x71: adc(indY(&c)); return 5+c;
+	case 0x73: rra(aindY(&c)); return 8;
+	case 0x74: zp(); return 3;
 	case 0x75: adc(zpX()); return 4;
 	case 0x76: ror((u8int)(fetch8() + rX)); return 6;
+	case 0x77: rra((u8int)(fetch8() + rX)); return 6;
 	case 0x78: rP |= FLAGI; return 2;
 	case 0x79: adc(absY()); return 4 + ((u8int)a < rY);
+	case 0x7A: return 2;
+	case 0x7B: rra(fetch16() + rY); return 6;
+	case 0x7C: abso(); return 4;
 	case 0x7D: adc(absX()); return 4 + ((u8int)a < rX);
 	case 0x7E: ror(fetch16() + rX); return 7;
+	case 0x7F: rra(fetch16() + rX); return 6;
+	case 0x80: imm(); return 2;
 	case 0x81: memwrite(aindX(), rA); return 6;
+	case 0x82: imm(); return 2;
+	case 0x83: memwrite(aindX(), rA & rX); return 6;
 	case 0x84: memwrite(fetch8(), rY); return 3;
 	case 0x85: memwrite(fetch8(), rA); return 3;
 	case 0x86: memwrite(fetch8(), rX); return 3;
+	case 0x87: memwrite(fetch8(), rA & rX); return 3;
 	case 0x88: nz(--rY); return 2;
+	case 0x89: imm(); return 2;
 	case 0x8A: nz(rA = rX); return 2;
+	case 0x8B: nz(rA = 0xFF & rX & imm()); return 2;
 	case 0x8C: memwrite(fetch16(), rY); return 4;
 	case 0x8D: memwrite(fetch16(), rA); return 4;
 	case 0x8E: memwrite(fetch16(), rX); return 4;
+	case 0x8F: memwrite(fetch16(), rA & rX); return 4;
 	case 0x90: if((rP & FLAGC) == 0) return branch(); pc++; return 3;
 	case 0x91: memwrite(aindY(&c), rA); return 6;
+	case 0x93:
+		a = aindY(&c);
+		if(c)
+			a = (u8int)a | ((a>>8) & rX) << 8;
+		memwrite(a, rA & (rX | 0xF5));
+		return 5;
 	case 0x94: memwrite((u8int)(fetch8() + rX), rY); return 4;
 	case 0x95: memwrite((u8int)(fetch8() + rX), rA); return 4;
 	case 0x96: memwrite((u8int)(fetch8() + rY), rX); return 4;
+	case 0x97: memwrite((u8int)(fetch8() + rY), rA & rX); return 4;
 	case 0x98: nz(rA = rY); return 2;
 	case 0x99: memwrite(fetch16() + rY, rA); return 5;
 	case 0x9A: rS = rX; return 2;
+	case 0x9B:
+		a = fetch16();
+		v = a + rY;
+		if((a & 0xFF00) != (v & 0xFF00))
+			v = (u16int)((u8int)v | ((v >> 8) & rX) << 8);
+		rS = rA & rX;
+		a = v >> 8;
+		if(a == 0) a = 0xFF;
+		memwrite(v, rA & (rX | 0xF5) & a);
+		return 5;
+	case 0x9C:
+		a = fetch16();
+		v = a + rX;
+		if((a & 0xFF00) != (v & 0xFF00))
+			v = (u8int)v | ((v>>8) & rY) << 8;
+		memwrite(v, rY & (v >> 8));
+		return 5;
 	case 0x9D: memwrite(fetch16() + rX, rA); return 5;
+	case 0x9E:
+		a = fetch16();
+		v = a + rY;
+		if((a & 0xFF00) != (v & 0xFF00))
+			v = (u8int)v | ((v>>8) & rX) << 8;
+		memwrite(v, rX);
+		return 5;
+	case 0x9F:
+		a = fetch16();
+		v = a + rY;
+		if((a & 0xFF00) != (v & 0xFF00))
+			v = (u8int)v | ((v>>8) & rX) << 8;
+		memwrite(v, rA & (rX | 0xF5));
+		return 5;
 	case 0xA0: nz(rY = imm()); return 2;
 	case 0xA1: nz(rA = indX()); return 6;
 	case 0xA2: nz(rX = imm()); return 2;
+	case 0xA3: rA = indX(); nz(rX = rA); return 6;
 	case 0xA4: nz(rY = zp()); return 3;
 	case 0xA5: nz(rA = zp()); return 3;
 	case 0xA6: nz(rX = zp()); return 3;
+	case 0xA7: rA = zp(); nz(rX = rA); return 3;
 	case 0xA8: nz(rY = rA); return 2;
 	case 0xA9: nz(rA = imm()); return 2;
 	case 0xAA: nz(rX = rA); return 2;
+	case 0xAB: nz(rX = rA = (rA | 0xEE) & imm()); return 2;
 	case 0xAC: nz(rY = abso()); return 4;
 	case 0xAE: nz(rX = abso()); return 4;
 	case 0xAD: nz(rA = abso()); return 4;
+	case 0xAF: rA = abso(); nz(rX = rA); return 4;
 	case 0xB0: if((rP & FLAGC) != 0) return branch(); pc++; return 3;
 	case 0xB1: nz(rA = indY(&c)); return 5+c;
+	case 0xB3: rA = indY(&c); nz(rX = rA); return 5+c;
 	case 0xB4: nz(rY = zpX()); return 4;
 	case 0xB5: nz(rA = zpX()); return 4;
 	case 0xB6: nz(rX = zpY()); return 4;
+	case 0xB7: rA = zpY(); nz(rX = rA); return 4;
 	case 0xB8: rP &= ~FLAGV; return 2;
 	case 0xB9: nz(rA = absY()); return 4 + ((u8int)a < rY);
 	case 0xBA: nz(rX = rS); return 2;
+	case 0xBB: v = absY(); USED(a); nz(rA = rX = rS = v & rS); return 5;
 	case 0xBC: nz(rY = absX()); return 4 + ((u8int)a < rX);
 	case 0xBD: nz(rA = absX()); return 4 + ((u8int)a < rX);
 	case 0xBE: nz(rX = absY()); return 4 + ((u8int)a < rY);
+	case 0xBF: rA = absY(); nz(rX = rA); return 4 + ((u8int)a < rX);
 	case 0xC1: cmp(rA, indX()); return 6;
+	case 0xC2: imm(); return 2;
+	case 0xC3: a = aindX(); dec(a); cmp(rA, memread(a)); return 8;
 	case 0xC5: cmp(rA, zp()); return 3;
+	case 0xC7: a = fetch8(); dec(a); cmp(rA, memread(a)); return 5;
 	case 0xC9: cmp(rA, imm()); return 2;
+	case 0xCB: axs(imm()); return 2;
 	case 0xCD: cmp(rA, abso()); return 4;
+	case 0xCF: a = fetch16(); dec(a); cmp(rA, memread(a)); return 6;
 	case 0xD0: if((rP & FLAGZ) == 0) return branch(); pc++; return 3;
 	case 0xD1: cmp(rA, indY(&c)); return 5 + c;
+	case 0xD3: a = aindY(&c); dec(a); cmp(rA, memread(a)); return 8;
+	case 0xD4: zp(); return 3;
 	case 0xD5: cmp(rA, zpX()); return 4;
+	case 0xD7: a = (u8int)(fetch8() + rX); dec(a); cmp(rA, memread(a)); return 6;
 	case 0xD8: rP &= ~FLAGD; return 2;
 	case 0xD9: cmp(rA, absY()); return 4 + ((u8int)a < rY);
+	case 0xDA: return 2;
+	case 0xDB: a = fetch16() + rY; dec(a); cmp(rA, memread(a)); return 7;
+	case 0xDC: abso(); return 4;
 	case 0xDD: cmp(rA, absX()); return 4 + ((u8int)a < rX);
+	case 0xDF: a = fetch16() + rX; dec(a); cmp(rA, memread(a)); return 7;
 	case 0xC0: cmp(rY, imm()); return 2;
 	case 0xC4: cmp(rY, zp()); return 3;
 	case 0xC6: dec(fetch8()); return 5;
@@ -429,23 +612,35 @@
 	case 0xDE: dec(fetch16() + rX); return 7;
 	case 0xE0: cmp(rX, imm()); return 2;
 	case 0xE1: sbc(indX()); return 6;
+	case 0xE2: imm(); return 2;
+	case 0xE3: a = aindX(); inc(a); sbc(memread(a)); return 8;
 	case 0xE4: cmp(rX, zp()); return 3;
 	case 0xE5: sbc(zp()); return 3;
 	case 0xE6: inc(fetch8()); return 5;
+	case 0xE7: a = fetch8(); inc(a); sbc(memread(a)); return 5;
 	case 0xE8: nz(++rX); return 2;
 	case 0xE9: sbc(imm()); return 2;
 	case 0xEA: return 2;
+	case 0xEB: sbc(imm()); return 2;
 	case 0xEC: cmp(rX, abso()); return 4;
 	case 0xED: sbc(abso()); return 4;
 	case 0xEE: inc(fetch16()); return 6;
+	case 0xEF: a = fetch16(); inc(a); sbc(memread(a)); return 6;
 	case 0xF0: if((rP & FLAGZ) != 0) return branch(); pc++; return 3;
 	case 0xF1: sbc(indY(&c)); return 5+c;
+	case 0xF3: a = aindY(&c); inc(a); sbc(memread(a)); return 8;
+	case 0xF4: zp(); return 3;
 	case 0xF5: sbc(zpX()); return 4;
 	case 0xF6: inc((u8int)(fetch8() + rX)); return 6;
+	case 0xF7: a = (u8int)(fetch8() + rX); inc(a); sbc(memread(a)); return 6;
 	case 0xF8: rP |= FLAGD; return 2;
 	case 0xF9: sbc(absY()); return 4 + ((u8int)a < rY);
+	case 0xFA: return 2;
+	case 0xFB: a = fetch16() + rY; inc(a); sbc(memread(a)); return 7;
+	case 0xFC: abso(); return 4;
 	case 0xFD: sbc(absX()); return 4 + ((u8int)a < rX);
 	case 0xFE: inc(fetch16() + rX); return 7;
+	case 0xFF: a = fetch16() + rX; inc(a); sbc(memread(a)); return 7;
 	default:
 		print("undefined %#x (pc %#x)\n", op, curpc);
 		return 2;
--