summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaxwell Beck <max@rastertail.net>2024-12-28 16:19:19 -0600
committerMaxwell Beck <max@rastertail.net>2024-12-28 16:19:19 -0600
commitd20a72c10d707f4f85ea848b7bfd0929ff4e1a97 (patch)
tree25dbb318c9b8807c83cfc810a12612da2d5db064
parent8a797cdbee3d4a35562b33d38072c6c0ba34423c (diff)
Implement most 6502 illegals + some timing fixes
-rw-r--r--src/6502.c368
1 files changed, 350 insertions, 18 deletions
diff --git a/src/6502.c b/src/6502.c
index 06ba198..5d38029 100644
--- a/src/6502.c
+++ b/src/6502.c
@@ -214,6 +214,25 @@
 		} \
 	} while (0)
 
+#define R_INDY_RMW() \
+	do { \
+		cpu->pc++; \
+		ea = bus_read(operand, cycles); \
+		cycles++; \
+		ea += cpu->y; \
+		uint16_t carry = ea & 0x0100; \
+		ea &= 0xff; \
+		ea |= bus_read((operand + 1) & 0xff, cycles) << 8; \
+		cycles++; \
+		a = bus_read(ea, cycles); \
+		cycles++; \
+		if (carry) { \
+			ea += 0x100; \
+		} \
+		a = bus_read(ea, cycles); \
+		cycles++; \
+	} while (0)
+
 #define W_R(r) \
 	do { \
 		cpu->r = a; \
@@ -268,16 +287,13 @@
 		ea |= bus_read(cpu->pc, cycles) << 8; \
 		cpu->pc++; \
 		cycles++; \
-		if (!carry) { \
-			bus_write(ea, a, cycles); \
-			cycles++; \
-		} else { \
-			bus_read(ea, cycles); \
-			cycles++; \
+		bus_read(ea, cycles); \
+		cycles++; \
+		if (carry) { \
 			ea += 0x100; \
-			bus_write(ea, a, cycles); \
-			cycles++; \
 		} \
+		bus_write(ea, a, cycles); \
+		cycles++; \
 	} while (0)
 
 #define W_ABSX() W_ABSI(x)
@@ -306,16 +322,13 @@
 		ea &= 0xff; \
 		ea |= bus_read((operand + 1) & 0xff, cycles) << 8; \
 		cycles++; \
-		if (!carry) { \
-			bus_write(ea, a, cycles); \
-			cycles++; \
-		} else { \
-			bus_read(ea, cycles); \
-			cycles++; \
+		bus_read(ea, cycles); \
+		cycles++; \
+		if (carry) { \
 			ea += 0x100; \
-			bus_write(ea, a, cycles); \
-			cycles++; \
 		} \
+		bus_write(ea, a, cycles); \
+		cycles++; \
 	} while (0)
 
 #define W_EA() \
@@ -373,6 +386,135 @@
 
 #define LOAD() r = a
 
+#define ALR() \
+	do { \
+		r = r & a; \
+		FLAG_SET(C, r & 1); \
+		r = r >> 1; \
+	} while (0) \
+
+#define ANC() \
+	do { \
+		r = r & a; \
+		FLAG_SET(C, (r & 0x80) >> 7); \
+	} while (0) \
+
+#define ARR() \
+	do { \
+		uint8_t c = FLAG_GET(C); \
+		r = r & a; \
+		uint16_t res = r + a + c; \
+		FLAG_SET(N, (res & 0x100) >> 8); \
+		FLAG_SET(V, ((r ^ res) & (a ^ res) & 0x80) >> 7); \
+		FLAG_SET(C, r & 1); \
+		r = (r >> 1) | (r << 7); \
+	} while (0);
+
+#define DCP(src, dst) \
+	do { \
+		uint8_t a; \
+		uint16_t ea = 0; \
+		src(); \
+		dst(); \
+		a = a - 1; \
+		uint16_t res = cpu->a - a; \
+		FLAG_SET(C, (~res & 0x100) >> 8); \
+		FLAG_SET(N, (res & 0x80) >> 7); \
+		FLAG_SET(Z, ((res & 0xff) == 0) ? 1 : 0); \
+		dst(); \
+	} while (0); break
+
+#define ISC(src, dst) \
+	do { \
+		uint8_t a; \
+		uint16_t ea = 0; \
+		src(); \
+		dst(); \
+		a = a + 1; \
+		dst(); \
+		uint8_t r = cpu->a; \
+		SBC(); \
+		FLAG_SET(N, (r & 0x80) >> 7); \
+		FLAG_SET(Z, (r == 0) ? 1 : 0); \
+		cpu->a = r; \
+	} while (0); break
+
+#define LAX(src) \
+	do { \
+		uint8_t r = cpu->a; \
+		uint16_t ea = 0; \
+		uint8_t a; \
+		src(); \
+		LOAD(); \
+		FLAG_SET(N, (r & 0x80) >> 7); \
+		FLAG_SET(Z, (r == 0) ? 1 : 0); \
+		cpu->a = r; \
+		cpu->x = r; \
+	} while (0); break
+
+#define RLA(src, dst) \
+	do { \
+		uint8_t a; \
+		uint16_t ea = 0; \
+		src(); \
+		dst(); \
+		ROL(); \
+		dst(); \
+		uint8_t r = cpu->a & a; \
+		FLAG_SET(N, (r & 0x80) >> 7); \
+		FLAG_SET(Z, (r == 0) ? 1 : 0); \
+		cpu->a = r; \
+	} while (0); break
+
+#define RRA(src, dst) \
+	do { \
+		uint8_t a; \
+		uint16_t ea = 0; \
+		src(); \
+		dst(); \
+		ROR(); \
+		dst(); \
+		uint8_t r = cpu->a; \
+		ADC(); \
+		FLAG_SET(N, (r & 0x80) >> 7); \
+		FLAG_SET(Z, (r == 0) ? 1 : 0); \
+		cpu->a = r; \
+	} while (0); break
+
+#define SAX(dst) \
+	do { \
+		uint8_t a = cpu-> a & cpu->x; \
+		dst(); \
+	} while (0); break
+
+#define SLO(src, dst) \
+	do { \
+		uint8_t a; \
+		uint16_t ea = 0; \
+		src(); \
+		dst(); \
+		ASL(); \
+		dst(); \
+		uint8_t r = cpu->a | a; \
+		FLAG_SET(N, (r & 0x80) >> 7); \
+		FLAG_SET(Z, (r == 0) ? 1 : 0); \
+		cpu->a = r; \
+	} while (0); break
+
+#define SRE(src, dst) \
+	do { \
+		uint8_t a; \
+		uint16_t ea = 0; \
+		src(); \
+		dst(); \
+		LSR(); \
+		dst(); \
+		uint8_t r = cpu->a ^ a; \
+		FLAG_SET(N, (r & 0x80) >> 7); \
+		FLAG_SET(Z, (r == 0) ? 1 : 0); \
+		cpu->a = r; \
+	} while (0); break
+
 void cpu_reset(cpu_t *cpu) {
 	cpu->a = 0;
 	cpu->x = 0;
@@ -471,6 +613,7 @@ uint8_t cpu_step(cpu_t *cpu) {
 		case 0x71: OP(a, R_INDY, ADC);
 
 		// SBC
+		case 0xeb:
 		case 0xe9: OP(a, R_IMM, SBC);
 		case 0xe5: OP(a, R_ZP, SBC);
 		case 0xf5: OP(a, R_ZPX, SBC);
@@ -714,13 +857,202 @@ uint8_t cpu_step(cpu_t *cpu) {
 
 		case 0x9a: cpu->sp = cpu->x; break;
 
-		// NOP
-		case 0xea: break;
+		// NOPs
+		case 0x1a:
+		case 0x3a:
+		case 0x5a:
+		case 0x7a:
+		case 0xda:
+		case 0xea:
+		case 0xfa:
+			break;
+
+		case 0x80:
+		case 0x82:
+		case 0x89:
+		case 0xc2:
+		case 0xe2:
+			do {
+				uint8_t a;
+				R_IMM();
+			} while (0);
+			break;
+
+		case 0x04:
+		case 0x44:
+		case 0x64:
+			do {
+				uint8_t a;
+				uint16_t ea;
+				R_ZP();
+			} while (0);
+			break;
+
+		case 0x14:
+		case 0x34:
+		case 0x54:
+		case 0x74:
+		case 0xd4:
+		case 0xf4:
+			do {
+				uint8_t a;
+				uint16_t ea;
+				R_ZPX();
+			} while (0);
+			break;
+
+		case 0x0c:
+			do {
+				uint8_t a;
+				uint16_t ea;
+				R_ABS();
+			} while (0);
+			break;
+
+		case 0x1c:
+		case 0x3c:
+		case 0x5c:
+		case 0x7c:
+		case 0xdc:
+		case 0xfc:
+			do {
+				uint8_t a;
+				uint16_t ea;
+				R_ABSX();
+			} while (0);
+			break;
 
 		// BIT
 		case 0x24: BIT(R_ZP);
 		case 0x2C: BIT(R_ABS);
 
+		// Illegals
+
+		// ALR
+		case 0x4b: OP(a, R_IMM, ALR);
+
+		// ANC
+		case 0x0b:
+		case 0x2b:
+			OP(a, R_IMM, ANC);
+
+		// SKIP ANE
+
+		// ARR (FIXME INCORRECT FLAGS)
+		case 0x6b:
+			do {
+				uint8_t r = cpu->a;
+				uint16_t ea = 0;
+				uint8_t a;
+				R_IMM();
+				ARR();
+				FLAG_SET(Z, (r == 0) ? 1 : 0);
+				cpu->a = r;
+			} while (0);
+			break;
+
+		// DCP
+		case 0xc7: DCP(R_ZP, W_EA);
+		case 0xd7: DCP(R_ZPX, W_EA);
+		case 0xcf: DCP(R_ABS, W_EA);
+		case 0xdf: DCP(R_ABSX, W_EA);
+		case 0xdb: DCP(R_ABSY, W_EA);
+		case 0xc3: DCP(R_INDX, W_EA);
+		case 0xd3: DCP(R_INDY_RMW, W_EA);
+
+		// ISC
+		case 0xe7: ISC(R_ZP, W_EA);
+		case 0xf7: ISC(R_ZPX, W_EA);
+		case 0xef: ISC(R_ABS, W_EA);
+		case 0xff: ISC(R_ABSX, W_EA);
+		case 0xfb: ISC(R_ABSY, W_EA);
+		case 0xe3: ISC(R_INDX, W_EA);
+		case 0xf3: ISC(R_INDY_RMW, W_EA);
+
+		// LAS
+		case 0xbb:
+			do {
+				uint16_t ea = 0;
+				uint8_t a;
+				R_ABSY();
+				uint8_t r = a & cpu->sp;
+				FLAG_SET(N, (r & 0x80) >> 7);
+				FLAG_SET(Z, (r == 0) ? 1 : 0);
+				cpu->a = r;
+				cpu->x = r;
+				cpu->sp = r;
+			} while (0);
+			break;
+
+		// LAX
+		case 0xa7: LAX(R_ZP);
+		case 0xb7: LAX(R_ZPY);
+		case 0xaf: LAX(R_ABS);
+		case 0xbf: LAX(R_ABSY);
+		case 0xa3: LAX(R_INDX);
+		case 0xb3: LAX(R_INDY);
+
+		// SKIP LXA
+
+		// RLA
+		case 0x27: RLA(R_ZP, W_EA);
+		case 0x37: RLA(R_ZPX, W_EA);
+		case 0x2f: RLA(R_ABS, W_EA);
+		case 0x3f: RLA(R_ABSX, W_EA);
+		case 0x3b: RLA(R_ABSY, W_EA);
+		case 0x23: RLA(R_INDX, W_EA);
+		case 0x33: RLA(R_INDY_RMW, W_EA);
+
+		// RRA
+		case 0x67: RRA(R_ZP, W_EA);
+		case 0x77: RRA(R_ZPX, W_EA);
+		case 0x6f: RRA(R_ABS, W_EA);
+		case 0x7f: RRA(R_ABSX, W_EA);
+		case 0x7b: RRA(R_ABSY, W_EA);
+		case 0x63: RRA(R_INDX, W_EA);
+		case 0x73: RRA(R_INDY_RMW, W_EA);
+
+		// SAX
+		case 0x87: SAX(W_ZP);
+		case 0x97: SAX(W_ZPY);
+		case 0x8f: SAX(W_ABS);
+		case 0x83: SAX(W_INDX);
+
+		// SBX
+		case 0xcb:
+			do { \
+				uint8_t a; \
+				R_IMM(); \
+				uint16_t res = (cpu->a & cpu->x) - a; \
+				FLAG_SET(C, (~res & 0x100) >> 8); \
+				FLAG_SET(N, (res & 0x80) >> 7); \
+				FLAG_SET(Z, ((res & 0xff) == 0) ? 1 : 0); \
+				cpu->x = res;
+			} while (0);
+			break;
+
+		// SKIP SHA, SHX, SHY
+
+		// SLO
+		case 0x07: SLO(R_ZP, W_EA);
+		case 0x17: SLO(R_ZPX, W_EA);
+		case 0x0f: SLO(R_ABS, W_EA);
+		case 0x1f: SLO(R_ABSX, W_EA);
+		case 0x1b: SLO(R_ABSY, W_EA);
+		case 0x03: SLO(R_INDX, W_EA);
+		case 0x13: SLO(R_INDY_RMW, W_EA);
+
+		// SRE
+		case 0x47: SRE(R_ZP, W_EA);
+		case 0x57: SRE(R_ZPX, W_EA);
+		case 0x4f: SRE(R_ABS, W_EA);
+		case 0x5f: SRE(R_ABSX, W_EA);
+		case 0x5b: SRE(R_ABSY, W_EA);
+		case 0x43: SRE(R_INDX, W_EA);
+		case 0x53: SRE(R_INDY_RMW, W_EA);
+
+		// SKIP TAS
+
 		// Jam on everything else
 		default:
 			cpu->jammed = true;