Refactoring 65C02 registers and flags
authorNick Downing <nick@ndcode.org>
Thu, 21 Jul 2022 01:01:41 +0000 (11:01 +1000)
committerNick Downing <nick@ndcode.org>
Thu, 21 Jul 2022 02:43:21 +0000 (12:43 +1000)
cpu_65c02.c
cpu_65c02.h
emu_65c02.c

index 31e52ef..e54e39e 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include "cpu_65c02.h"
 #define INLINE __attribute__((always_inline))
 
 // convenient byte register access
-#define A (self->regs.b[CPU_65C02_REG_A])
-#define X (self->regs.b[CPU_65C02_REG_X])
-#define Y (self->regs.b[CPU_65C02_REG_Y])
-#define P (self->regs.b[CPU_65C02_REG_P])
-#define S (self->regs.b[CPU_65C02_REG_S])
+#define A (self->regs.byte.a)
+#define X (self->regs.byte.x)
+#define Y (self->regs.byte.y)
+#define P (self->regs.byte.p)
+#define S (self->regs.byte.s)
 
 // convenient word register access
-#define SP (self->regs.w[CPU_65C02_REG_SP >> 1])
-#define PC (self->regs.w[CPU_65C02_REG_PC >> 1])
+#define SP (self->regs.word.sp)
+#define PC (self->regs.word.pc)
 
 // convenient flags bit access
 #define FLAG_C (1 << CPU_65C02_REG_P_BIT_C)
@@ -201,9 +202,9 @@ void cpu_65c02_init(
   void (*write_byte)(int addr, int data)
 ) {
   memset(self, 0, sizeof(struct cpu_65c02));
-  self->regs.w[CPU_65C02_REG_PC >> 1] = pc;
-  self->regs.b[CPU_65C02_REG_P] = 0x30;
-  self->regs.w[CPU_65C02_REG_SP >> 1] = 0x1ff;
+  self->regs.byte.p = 0x30; // unused bits are hard coded to 1
+  self->regs.word.sp = 0x1ff; // unused byte is hard coded to 01
+  self->regs.word.pc = pc;
   self->read_byte = read_byte;
   self->write_byte = write_byte;
 }
@@ -211,7 +212,7 @@ void cpu_65c02_init(
 // memory (or internal register memory) access
 INLINE int cpu_65c02_rb(struct cpu_65c02 *self, int addr) {
   if (addr < 0)
-    return self->regs.b[CPU_65C02_N_REGS + addr];
+    return self->regs.mem[CPU_65C02_N_REGS + addr];
   self->cycles += 1;
   return self->read_byte(addr & 0xffff);
 }
@@ -229,7 +230,7 @@ INLINE int cpu_65c02_rw_zpg(struct cpu_65c02 *self, int addr) {
 INLINE void cpu_65c02_wb(struct cpu_65c02 *self, int addr, int data) {
   self->cycles += 1;
   if (addr < 0)
-    self->regs.b[CPU_65C02_N_REGS + addr] = data;
+    self->regs.mem[CPU_65C02_N_REGS + addr] = data;
   else
     self->write_byte(addr, data);
 }
@@ -318,48 +319,42 @@ INLINE int cpu_65c02_ea_zpg_ind_idx(struct cpu_65c02 *self, int rvalue) {
 // instruction execute
 INLINE void cpu_65c02_adc(struct cpu_65c02 *self, int rvalue) {
   int result0, result1, result2;
-  if (P & FLAG_D) {
-    result0 = (A & 0xf) + (rvalue & 0xf) + (P & FLAG_C);
+  if (self->regs.bit.df) {
+    result0 = (A & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
     if (result0 >= 0xa)
-      result0 += 6;
+      result0 = (result0 + 6) & 0x1f;
     result0 += (A & 0x70) + (rvalue & 0x70);
     result1 = (A & 0x80) + (rvalue & 0x80) + result0;
     result2 = result1;
     if (result2 >= 0xa0)
-      result2 += 0x60;
+      result2 = (result2 + 0x60) & 0x1ff;
   }
   else {
-    result0 = (A & 0x7f) + (rvalue & 0x7f) + (P & FLAG_C);
+    result0 = (A & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
     result1 = (A & 0x80) + (rvalue & 0x80) + result0;
     result2 = result1;
   }
   A = result2 & 0xff;
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_V | FLAG_N)) |
-    ((result2 >> 8) & FLAG_C) | // C
-    (((result2 & 0xff) == 0) << 1) | // Z
-    (((result0 >> 1) ^ (result1 >> 2)) & FLAG_V) |
-    (result2 & FLAG_N);
+  self->regs.bit.cf = result2 >> 8;
+  self->regs.bit.zf = (result2 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.nf = (result2 >> 7) & 1;
 }
 
 INLINE void cpu_65c02_and(struct cpu_65c02 *self, int rvalue) {
   int result = A & rvalue;
   A = result;
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int lvalue) {
   int result = RB(lvalue) << 1;
   ++self->cycles;
   WB(lvalue, result & 0xff);
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_N)) |
-    (result >> 8) | // C
-    (((result & 0xff) == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_bbr(struct cpu_65c02 *self, int rvalue, int lvalue) {
@@ -392,17 +387,14 @@ INLINE void cpu_65c02_bs(struct cpu_65c02 *self, int flag, int lvalue) {
 
 INLINE void cpu_65c02_bit(struct cpu_65c02 *self, int rvalue) {
   int result = A & rvalue;
-  P =
-    (P & ~(FLAG_Z | FLAG_V | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (rvalue & (FLAG_V | FLAG_N));
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = (rvalue >> 6) & 1;
+  self->regs.bit.nf = (rvalue >> 7) & 1;
 }
 
 INLINE void cpu_65c02_bit_imm(struct cpu_65c02 *self, int rvalue) {
   int result = A & rvalue;
-  P =
-    (P & ~FLAG_Z) |
-    ((result == 0) << 1); // Z
+  self->regs.bit.zf = result == 0;
 }
 
 INLINE void cpu_65c02_brk(struct cpu_65c02 *self) {
@@ -410,7 +402,8 @@ INLINE void cpu_65c02_brk(struct cpu_65c02 *self) {
   PHW((PC + 1) & 0xffff);
   PHB(P); // already has break flag set
   PC = RW(IRQ_VECTOR);
-  P = (P & ~FLAG_D) | FLAG_I;
+  self->regs.bit._if = true;
+  self->regs.bit.df = false;
 }
 
 INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int flag) {
@@ -420,30 +413,24 @@ INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int flag) {
 INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, int rvalue0, int rvalue1) {
   rvalue1 ^= 0xff;
   int result = rvalue0 + rvalue1 + 1;
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_N)) |
-    (result >> 8) | // C
-    (((result & 0xff) == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_dec(struct cpu_65c02 *self, int lvalue) {
   int result = (RB(lvalue) - 1) & 0xff;
   ++self->cycles;
   WB(lvalue, result);
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_eor(struct cpu_65c02 *self, int rvalue) {
   int result = A ^ rvalue;
   A = result;
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_ill11(struct cpu_65c02 *self) {
@@ -478,10 +465,8 @@ INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int lvalue) {
   int result = (RB(lvalue) + 1) & 0xff;
   ++self->cycles;
   WB(lvalue, result);
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
@@ -495,20 +480,17 @@ INLINE void cpu_65c02_jsr(struct cpu_65c02 *self, int lvalue) {
 
 INLINE void cpu_65c02_ld(struct cpu_65c02 *self, int lvalue, int rvalue) {
   WB(lvalue, rvalue);
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((rvalue == 0) << 1) | // Z
-    (rvalue & FLAG_N);
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.nf = (rvalue >> 7) & 1;
 }
 
 INLINE void cpu_65c02_lsr(struct cpu_65c02 *self, int lvalue) {
   int result = RB(lvalue);
   ++self->cycles;
   WB(lvalue, result >> 1);
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_N)) |
-    (result & FLAG_C) |
-    (((result & 0xfe) == 0) << 1); // Z
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0xfe) == 0;
+  self->regs.bit.nf = false;
 }
 
 INLINE void cpu_65c02_nop(struct cpu_65c02 *self) {
@@ -517,10 +499,8 @@ INLINE void cpu_65c02_nop(struct cpu_65c02 *self) {
 INLINE void cpu_65c02_ora(struct cpu_65c02 *self, int rvalue) {
   int result = A | rvalue;
   A = result;
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
@@ -530,10 +510,8 @@ INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
 INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int lvalue) {
   int result = PLB();
   WB(lvalue, result);
-  P =
-    (P & ~(FLAG_Z | FLAG_N)) |
-    ((result == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
@@ -547,25 +525,21 @@ INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int rvalue, int lvalue) {
 }
 
 INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int lvalue) {
-  int result = (RB(lvalue) << 1) | (P & FLAG_C);
+  int result = (RB(lvalue) << 1) | self->regs.bit.cf;
   ++self->cycles;
   WB(lvalue, result & 0xff);
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_N)) |
-    (result >> 8) | // C
-    (((result & 0xff) == 0) << 1) | // Z
-    (result & FLAG_N);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
 }
 
 INLINE void cpu_65c02_ror(struct cpu_65c02 *self, int lvalue) {
-  int result = RB(lvalue) | ((P & FLAG_C) << 8);
+  int result = RB(lvalue) | (self->regs.bit.cf << 8);
   ++self->cycles;
   WB(lvalue, result >> 1);
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_N)) |
-    (result & FLAG_C) |
-    (((result & 0x1fe) == 0) << 1) | // Z
-    ((result >> 1) & FLAG_N);
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0x1fe) == 0;
+  self->regs.bit.nf = (result >> 8) & 1;
 }
 
 INLINE void cpu_65c02_rti(struct cpu_65c02 *self) {
@@ -580,28 +554,26 @@ INLINE void cpu_65c02_rts(struct cpu_65c02 *self) {
 INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, int rvalue) {
   rvalue ^= 0xff;
   int result0, result1, result2;
-  if (P & FLAG_D) {
-    result0 = (A & 0xf) + (rvalue & 0xf) + (P & FLAG_C);
+  if (self->regs.bit.df) {
+    result0 = (A & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
     if (result0 < 0x10)
-      result0 -= 6;
+      result0 = (result0 - 6) & 0x1f;
     result0 += (A & 0x70) + (rvalue & 0x70);
     result1 = (A & 0x80) + (rvalue & 0x80) + result0;
     result2 = result1;
     if (result2 < 0x100)
-      result2 -= 0x60;
+      result2 = (result2 - 0x60) & 0x1ff;
   }
   else {
-    result0 = (A & 0x7f) + (rvalue & 0x7f) + (P & FLAG_C);
+    result0 = (A & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
     result1 = (A & 0x80) + (rvalue & 0x80) + result0;
     result2 = result1;
   }
   A = result2 & 0xff;
-  P =
-    (P & ~(FLAG_C | FLAG_Z | FLAG_V | FLAG_N)) |
-    ((result2 >> 8) & FLAG_C) | // C
-    (((result2 & 0xff) == 0) << 1) | // Z
-    (((result0 >> 1) ^ (result1 >> 2)) & FLAG_V) |
-    (result2 & FLAG_N);
+  self->regs.bit.cf = result2 >> 8;
+  self->regs.bit.zf = (result2 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.nf = (result2 >> 7) & 1;
 }
 
 INLINE void cpu_65c02_se(struct cpu_65c02 *self, int flag) {
@@ -627,9 +599,7 @@ INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int lvalue) {
   ++self->cycles;
   WB(lvalue, result & ~A);
   result &= A;
-  P =
-    (P & ~FLAG_Z) |
-    ((result == 0) << 1); // Z
+  self->regs.bit.zf = result == 0;
 }
 
 INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int lvalue) {
@@ -637,9 +607,7 @@ INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int lvalue) {
   ++self->cycles;
   WB(lvalue, result | A);
   result &= A;
-  P =
-    (P & ~FLAG_Z) |
-    ((result == 0) << 1); // Z
+  self->regs.bit.zf = result == 0;
 }
 
 INLINE void cpu_65c02_wai(struct cpu_65c02 *self) {
index 0638f23..9d8ef57 100644 (file)
 #define CPU_65C02_REG_P_BIT_V 6
 #define CPU_65C02_REG_P_BIT_N 7
 
+union cpu_65c02_regs {
+  struct {
+    uint8_t _fill0[3];
+    uint8_t cf : 1;
+    uint8_t zf : 1;
+    uint8_t _if : 1;
+    uint8_t df : 1;
+    uint8_t _fill1: 2;
+    uint8_t vf : 1;
+    uint8_t nf : 1;
+  } bit;
+  struct {
+    uint8_t a;
+    uint8_t x;
+    uint8_t y;
+    uint8_t p;
+    uint8_t s;
+  } byte;
+  struct {
+    uint16_t _fill0[2];
+    uint16_t sp;
+    uint16_t pc;
+  } word;
+  uint8_t mem[CPU_65C02_N_REGS];
+};
+
 struct cpu_65c02 {
   int cycles;
   int (*read_byte)(int addr);
   void (*write_byte)(int addr, int data);
-  union {
-    uint8_t b[CPU_65C02_N_REGS];
-    uint16_t w[CPU_65C02_N_REGS >> 1];
-  } regs;
+  union cpu_65c02_regs regs;
 };
 
 void cpu_65c02_init(
index 1a001f3..f556d75 100644 (file)
@@ -9,8 +9,8 @@
 #include "cpu_65c02.h"
 #endif
 
-#define REG_TRACE 1
-#define MEM_TRACE 1
+#define REG_TRACE 0
+#define MEM_TRACE 0
 
 #define MEM_SIZE 0x10000
 uint8_t mem[MEM_SIZE];
@@ -178,7 +178,7 @@ int main(int argc, char **argv) {
   while (true) {
 #if REG_TRACE
     printf(
-      "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
+      "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x cf=%d zf=%d if=%d df=%d vf=%d nf=%d\n",
       vrEmu6502GetPC(cpu),
       vrEmu6502GetAcc(cpu),
       vrEmu6502GetX(cpu),
@@ -209,25 +209,25 @@ int main(int argc, char **argv) {
   while (true) {
 #if REG_TRACE
     printf(
-      "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
-      cpu.regs.w[CPU_65C02_REG_PC >> 1],
-      cpu.regs.b[CPU_65C02_REG_A],
-      cpu.regs.b[CPU_65C02_REG_X],
-      cpu.regs.b[CPU_65C02_REG_Y],
-      cpu.regs.b[CPU_65C02_REG_P],
-      cpu.regs.b[CPU_65C02_REG_S],
-      (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_C) & 1,
-      (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_Z) & 1,
-      (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_I) & 1,
-      (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_D) & 1,
-      (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_V) & 1,
-      (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_N) & 1
+      "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x cf=%d zf=%d if=%d df=%d vf=%d nf=%d\n",
+      cpu.regs.word.pc,
+      cpu.regs.byte.a,
+      cpu.regs.byte.x,
+      cpu.regs.byte.y,
+      cpu.regs.byte.p,
+      cpu.regs.byte.s,
+      cpu.regs.bit.cf,
+      cpu.regs.bit.zf,
+      cpu.regs.bit._if,
+      cpu.regs.bit.df,
+      cpu.regs.bit.vf,
+      cpu.regs.bit.nf
     );
 #endif
 
-    int pc = cpu.regs.w[CPU_65C02_REG_PC >> 1];
+    int pc = cpu.regs.word.pc;
     cpu_65c02_execute(&cpu);
-    if (pc == cpu.regs.w[CPU_65C02_REG_PC >> 1]) {
+    if (pc == cpu.regs.word.pc) {
       printf("hung at %04x\n", pc);
       break;
     }