Refactoring 65C02 to support big-endian and make inline functions public
authorNick Downing <nick@ndcode.org>
Thu, 21 Jul 2022 04:45:33 +0000 (14:45 +1000)
committerNick Downing <nick@ndcode.org>
Thu, 21 Jul 2022 04:45:33 +0000 (14:45 +1000)
Makefile
cpu_65c02.c
cpu_65c02.h

index 1ab7b74..b5b1d6a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 BIN2HEX=bin2hex.py
 
-CFLAGS=-g -Wall -Wno-attributes
+CFLAGS=-g -Og -Wall -Wno-attributes -Wno-unused-function
 
 .PHONY: all
 all: \
index da894d7..c521972 100644 (file)
@@ -3,21 +3,6 @@
 #include <string.h>
 #include "cpu_65c02.h"
 
-#define NMI_VECTOR 0xfffa
-#define RESET_VECTOR 0xfffc
-#define IRQ_VECTOR 0xfffe
-
-// gcc specific
-#define INLINE __attribute__((always_inline))
-
-// routines that take an effective address can also operate on a register
-// by means of special memory locations that are inaccessible by software
-#define EA_A (CPU_65C02_REG_A - CPU_65C02_N_REGS)
-#define EA_X (CPU_65C02_REG_X - CPU_65C02_N_REGS)
-#define EA_Y (CPU_65C02_REG_Y - CPU_65C02_N_REGS)
-#define EA_P (CPU_65C02_REG_P - CPU_65C02_N_REGS)
-#define EA_S (CPU_65C02_REG_S - CPU_65C02_N_REGS)
-
 // initialization
 void cpu_65c02_init(
   struct cpu_65c02 *self,
@@ -33,411 +18,6 @@ void cpu_65c02_init(
   self->write_byte = write_byte;
 }
 
-// memory (or internal register memory) access
-INLINE int cpu_65c02_rb(struct cpu_65c02 *self, int addr) {
-  if (addr < 0)
-    return self->regs.mem[CPU_65C02_N_REGS + addr];
-  self->cycles += 1;
-  return self->read_byte(addr & 0xffff);
-}
-
-INLINE int cpu_65c02_rw(struct cpu_65c02 *self, int addr) {
-  int data = cpu_65c02_rb(self, addr);
-  return data | (cpu_65c02_rb(self, addr + 1) << 8);
-}
-
-INLINE int cpu_65c02_rw_zpg(struct cpu_65c02 *self, int addr) {
-  int data = cpu_65c02_rb(self, addr & 0xff);
-  return data | (cpu_65c02_rb(self, (addr + 1) & 0xff) << 8);
-}
-
-INLINE void cpu_65c02_wb(struct cpu_65c02 *self, int addr, int data) {
-  self->cycles += 1;
-  if (addr < 0)
-    self->regs.mem[CPU_65C02_N_REGS + addr] = data;
-  else
-    self->write_byte(addr, data);
-}
-
-INLINE void cpu_65c02_ww(struct cpu_65c02 *self, int addr, int data) {
-  cpu_65c02_wb(self, addr, data & 0xff);
-  cpu_65c02_wb(self, addr + 1, data >> 8);
-}
-
-INLINE int cpu_65c02_fb(struct cpu_65c02 *self) {
-  int data = cpu_65c02_rb(self, self->regs.word.pc++);
-  return data;
-}
-
-INLINE int cpu_65c02_fw(struct cpu_65c02 *self) {
-  int data = cpu_65c02_fb(self);
-  return data | (cpu_65c02_fb(self) << 8);
-}
-
-INLINE void cpu_65c02_phb(struct cpu_65c02 *self, int data) {
-  cpu_65c02_wb(self, self->regs.word.sp, data);
-  --self->regs.byte.s;
-}
-
-INLINE void cpu_65c02_phw(struct cpu_65c02 *self, int data) {
-  cpu_65c02_phb(self, data >> 8);
-  cpu_65c02_phb(self, data & 0xff);
-}
-
-INLINE int cpu_65c02_plb(struct cpu_65c02 *self) {
-  ++self->regs.byte.s;
-  return cpu_65c02_rb(self, self->regs.word.sp);
-}
-
-INLINE int cpu_65c02_plw(struct cpu_65c02 *self) {
-  int data = cpu_65c02_plb(self);
-  return data | (cpu_65c02_plb(self) << 8);
-}
-
-// effective address calculation
-INLINE int cpu_65c02_ea_abs(struct cpu_65c02 *self) {
-  return cpu_65c02_fw(self);
-}
-
-INLINE int cpu_65c02_ea_abs_idx(struct cpu_65c02 *self, int rvalue) {
-  int addr = cpu_65c02_ea_abs(self);
-  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
-  return addr + rvalue;
-}
-
-INLINE int cpu_65c02_ea_abs_idx_ind(struct cpu_65c02 *self, int rvalue) {
-  return cpu_65c02_rw(self, cpu_65c02_ea_abs_idx(self, rvalue));
-}
-
-INLINE int cpu_65c02_ea_abs_ind(struct cpu_65c02 *self) {
-  return cpu_65c02_rw(self, cpu_65c02_ea_abs(self));
-}
-
-INLINE int cpu_65c02_ea_rel(struct cpu_65c02 *self) {
-  int offset = cpu_65c02_fb(self);
-  return offset - ((offset << 1) & 0x100);
-}
-
-INLINE int cpu_65c02_ea_zpg(struct cpu_65c02 *self) {
-  return cpu_65c02_fb(self);
-}
-
-INLINE int cpu_65c02_ea_zpg_idx(struct cpu_65c02 *self, int rvalue) {
-  return (cpu_65c02_ea_zpg(self) + rvalue) & 0xff;
-}
-
-INLINE int cpu_65c02_ea_zpg_idx_ind(struct cpu_65c02 *self, int rvalue) {
-  return cpu_65c02_rw_zpg(self, cpu_65c02_ea_zpg_idx(self, rvalue));
-}
-
-INLINE int cpu_65c02_ea_zpg_ind(struct cpu_65c02 *self) {
-  return cpu_65c02_rw_zpg(self, cpu_65c02_ea_zpg(self));
-}
-
-INLINE int cpu_65c02_ea_zpg_ind_idx(struct cpu_65c02 *self, int rvalue) {
-  int addr = cpu_65c02_rw_zpg(self, cpu_65c02_ea_zpg(self));
-  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
-  return addr + rvalue;
-}
-
-// instruction execute
-INLINE void cpu_65c02_adc(struct cpu_65c02 *self, int rvalue) {
-  int result0, result1, result2;
-  if (self->regs.bit.df) {
-    result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
-    if (result0 >= 0xa)
-      result0 = (result0 + 6) & 0x1f;
-    result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
-    result2 = result1;
-    if (result2 >= 0xa0)
-      result2 = (result2 + 0x60) & 0x1ff;
-  }
-  else {
-    result0 = (self->regs.byte.a & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
-    result2 = result1;
-  }
-  self->regs.byte.a = result2 & 0xff;
-  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 = self->regs.byte.a & rvalue;
-  self->regs.byte.a = result;
-  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 = cpu_65c02_rb(self, lvalue) << 1;
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result & 0xff);
-  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) {
-  if (rvalue == 0) {
-    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
-    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
-  }
-}
-
-INLINE void cpu_65c02_bbs(struct cpu_65c02 *self, int rvalue, int lvalue) {
-  if (rvalue) {
-    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
-    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
-  }
-}
-
-INLINE void cpu_65c02_bc(struct cpu_65c02 *self, int flag, int lvalue) {
-  if ((self->regs.byte.p & flag) == 0) {
-    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
-    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
-  }
-}
-
-INLINE void cpu_65c02_bs(struct cpu_65c02 *self, int flag, int lvalue) {
-  if (self->regs.byte.p & flag) {
-    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
-    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
-  }
-}
-
-INLINE void cpu_65c02_bit(struct cpu_65c02 *self, int rvalue) {
-  int result = self->regs.byte.a & rvalue;
-  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 = self->regs.byte.a & rvalue;
-  self->regs.bit.zf = result == 0;
-}
-
-INLINE void cpu_65c02_brk(struct cpu_65c02 *self) {
-  ++self->cycles;
-  cpu_65c02_phw(self, (self->regs.word.pc + 1) & 0xffff);
-  cpu_65c02_phb(self, self->regs.byte.p);
-  self->regs.word.pc = cpu_65c02_rw(self, IRQ_VECTOR);
-  self->regs.bit._if = true;
-  self->regs.bit.df = false;
-}
-
-INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int flag) {
-  self->regs.byte.p &= ~flag;
-}
-
-INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, int rvalue0, int rvalue1) {
-  rvalue1 ^= 0xff;
-  int result = rvalue0 + rvalue1 + 1;
-  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 = (cpu_65c02_rb(self, lvalue) - 1) & 0xff;
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result);
-  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 = self->regs.byte.a ^ rvalue;
-  self->regs.byte.a = result;
-  self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
-}
-
-INLINE void cpu_65c02_ill11(struct cpu_65c02 *self) {
-}
-
-INLINE void cpu_65c02_ill22(struct cpu_65c02 *self) {
-  ++self->cycles;
-  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
-}
-
-INLINE void cpu_65c02_ill23(struct cpu_65c02 *self) {
-  self->cycles += 2;
-  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
-}
-
-INLINE void cpu_65c02_ill24(struct cpu_65c02 *self) {
-  self->cycles += 3;
-  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
-}
-
-INLINE void cpu_65c02_ill34(struct cpu_65c02 *self) {
-  self->cycles += 3;
-  self->regs.word.pc = (self->regs.word.pc + 2) & 0xffff;
-}
-
-INLINE void cpu_65c02_ill38(struct cpu_65c02 *self) {
-  self->cycles += 7;
-  self->regs.word.pc = (self->regs.word.pc + 2) & 0xffff;
-}
-
-INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int lvalue) {
-  int result = (cpu_65c02_rb(self, lvalue) + 1) & 0xff;
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result);
-  self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
-}
-
-INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
-  self->regs.word.pc = lvalue;
-}
-
-INLINE void cpu_65c02_jsr(struct cpu_65c02 *self, int lvalue) {
-  cpu_65c02_phw(self, (self->regs.word.pc - 1) & 0xffff);
-  self->regs.word.pc = lvalue;
-}
-
-INLINE void cpu_65c02_ld(struct cpu_65c02 *self, int lvalue, int rvalue) {
-  cpu_65c02_wb(self, lvalue, rvalue);
-  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 = cpu_65c02_rb(self, lvalue);
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result >> 1);
-  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) {
-}
-
-INLINE void cpu_65c02_ora(struct cpu_65c02 *self, int rvalue) {
-  int result = self->regs.byte.a | rvalue;
-  self->regs.byte.a = result;
-  self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
-}
-
-INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
-  cpu_65c02_phb(self, rvalue);
-}
-
-INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int lvalue) {
-  int result = cpu_65c02_plb(self);
-  cpu_65c02_wb(self, lvalue, result);
-  self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
-}
-
-INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
-  self->regs.byte.p = cpu_65c02_plb(self) | 0x30;
-}
-
-INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int rvalue, int lvalue) {
-  int result = cpu_65c02_rb(self, lvalue) & ~rvalue;
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result);
-}
-
-INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int lvalue) {
-  int result = (cpu_65c02_rb(self, lvalue) << 1) | self->regs.bit.cf;
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result & 0xff);
-  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 = cpu_65c02_rb(self, lvalue) | (self->regs.bit.cf << 8);
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result >> 1);
-  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) {
-  self->regs.byte.p = cpu_65c02_plb(self) | 0x30;
-  self->regs.word.pc = cpu_65c02_plw(self);
-}
-
-INLINE void cpu_65c02_rts(struct cpu_65c02 *self) {
-  self->regs.word.pc = (cpu_65c02_plw(self) + 1) & 0xffff;
-}
-
-INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, int rvalue) {
-  rvalue ^= 0xff;
-  int result0, result1, result2;
-  if (self->regs.bit.df) {
-    result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
-    if (result0 < 0x10)
-      result0 = (result0 - 6) & 0x1f;
-    result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
-    result2 = result1;
-    if (result2 < 0x100)
-      result2 = (result2 - 0x60) & 0x1ff;
-  }
-  else {
-    result0 = (self->regs.byte.a & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
-    result2 = result1;
-  }
-  self->regs.byte.a = result2 & 0xff;
-  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) {
-  self->regs.byte.p |= flag;
-}
-
-INLINE void cpu_65c02_smb(struct cpu_65c02 *self, int rvalue, int lvalue) {
-  int result = cpu_65c02_rb(self, lvalue) | rvalue;
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result);
-}
-
-INLINE void cpu_65c02_st(struct cpu_65c02 *self, int rvalue, int lvalue) {
-  cpu_65c02_wb(self, lvalue, rvalue);
-}
-
-INLINE void cpu_65c02_stp(struct cpu_65c02 *self) {
-  abort();
-}
-
-INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int lvalue) {
-  int result = cpu_65c02_rb(self, lvalue);
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result & ~self->regs.byte.a);
-  result &= self->regs.byte.a;
-  self->regs.bit.zf = result == 0;
-}
-
-INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int lvalue) {
-  int result = cpu_65c02_rb(self, lvalue);
-  ++self->cycles;
-  cpu_65c02_wb(self, lvalue, result | self->regs.byte.a);
-  result &= self->regs.byte.a;
-  self->regs.bit.zf = result == 0;
-}
-
-INLINE void cpu_65c02_wai(struct cpu_65c02 *self) {
-  abort();
-}
-
 // instruction decode
 void cpu_65c02_execute(struct cpu_65c02 *self) {
   switch (cpu_65c02_fb(self)) {
@@ -472,7 +52,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_ora(self, cpu_65c02_fb(self));
     break;
   case 0x0a:
-    cpu_65c02_asl(self, EA_A);
+    cpu_65c02_asl(self, CPU_65C02_EA_A);
     break;
   case 0x0b:
     cpu_65c02_ill11(self);
@@ -523,7 +103,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_ora(self, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
     break;
   case 0x1a:
-    cpu_65c02_inc(self, EA_A);
+    cpu_65c02_inc(self, CPU_65C02_EA_A);
     break;
   case 0x1b:
     cpu_65c02_ill11(self);
@@ -574,7 +154,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_and(self, cpu_65c02_fb(self));
     break;
   case 0x2a:
-    cpu_65c02_rol(self, EA_A);
+    cpu_65c02_rol(self, CPU_65C02_EA_A);
     break;
   case 0x2b:
     cpu_65c02_ill11(self);
@@ -625,7 +205,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_and(self, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
     break;
   case 0x3a:
-    cpu_65c02_dec(self, EA_A);
+    cpu_65c02_dec(self, CPU_65C02_EA_A);
     break;
   case 0x3b:
     cpu_65c02_ill11(self);
@@ -676,7 +256,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_eor(self, cpu_65c02_fb(self));
     break;
   case 0x4a:
-    cpu_65c02_lsr(self, EA_A);
+    cpu_65c02_lsr(self, CPU_65C02_EA_A);
     break;
   case 0x4b:
     cpu_65c02_ill11(self);
@@ -772,13 +352,13 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_rmb(self, 0x40, cpu_65c02_ea_zpg(self));
     break;
   case 0x68:
-    cpu_65c02_pl(self, EA_A);
+    cpu_65c02_pl(self, CPU_65C02_EA_A);
     break;
   case 0x69:
     cpu_65c02_adc(self, cpu_65c02_fb(self));
     break;
   case 0x6a:
-    cpu_65c02_ror(self, EA_A);
+    cpu_65c02_ror(self, CPU_65C02_EA_A);
     break;
   case 0x6b:
     cpu_65c02_ill11(self);
@@ -829,7 +409,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_adc(self, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
     break;
   case 0x7a:
-    cpu_65c02_pl(self, EA_Y);
+    cpu_65c02_pl(self, CPU_65C02_EA_Y);
     break;
   case 0x7b:
     cpu_65c02_ill11(self);
@@ -874,13 +454,13 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_smb(self, 1, cpu_65c02_ea_zpg(self));
     break;
   case 0x88:
-    cpu_65c02_dec(self, EA_Y);
+    cpu_65c02_dec(self, CPU_65C02_EA_Y);
     break;
   case 0x89:
     cpu_65c02_bit_imm(self, cpu_65c02_fb(self));
     break;
   case 0x8a:
-    cpu_65c02_ld(self, EA_A, self->regs.byte.x);
+    cpu_65c02_ld(self, CPU_65C02_EA_A, self->regs.byte.x);
     break;
   case 0x8b:
     cpu_65c02_ill11(self);
@@ -925,13 +505,13 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_smb(self, 2, cpu_65c02_ea_zpg(self));
     break;
   case 0x98:
-    cpu_65c02_ld(self, EA_A, self->regs.byte.y);
+    cpu_65c02_ld(self, CPU_65C02_EA_A, self->regs.byte.y);
     break;
   case 0x99:
     cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_abs_idx(self, self->regs.byte.y));
     break;
   case 0x9a:
-    cpu_65c02_st(self, self->regs.byte.x, EA_S);
+    cpu_65c02_st(self, self->regs.byte.x, CPU_65C02_EA_S);
     break;
   case 0x9b:
     cpu_65c02_ill11(self);
@@ -952,49 +532,49 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     }
     break;
   case 0xa0:
-    cpu_65c02_ld(self, EA_Y, cpu_65c02_fb(self));
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_fb(self));
     break;
   case 0xa1:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx_ind(self, self->regs.byte.x)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx_ind(self, self->regs.byte.x)));
     break;
   case 0xa2:
-    cpu_65c02_ld(self, EA_X, cpu_65c02_fb(self));
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_fb(self));
     break;
   case 0xa3:
     cpu_65c02_ill11(self);
     break;
   case 0xa4:
-    cpu_65c02_ld(self, EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_zpg(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_zpg(self)));
     break;
   case 0xa5:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg(self)));
     break;
   case 0xa6:
-    cpu_65c02_ld(self, EA_X, cpu_65c02_rb(self, cpu_65c02_ea_zpg(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_rb(self, cpu_65c02_ea_zpg(self)));
     break;
   case 0xa7:
     cpu_65c02_smb(self, 4, cpu_65c02_ea_zpg(self));
     break;
   case 0xa8:
-    cpu_65c02_ld(self, EA_Y, self->regs.byte.a);
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, self->regs.byte.a);
     break;
   case 0xa9:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_fb(self));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_fb(self));
     break;
   case 0xaa:
-    cpu_65c02_ld(self, EA_X, self->regs.byte.a);
+    cpu_65c02_ld(self, CPU_65C02_EA_X, self->regs.byte.a);
     break;
   case 0xab:
     cpu_65c02_ill11(self);
     break;
   case 0xac:
-    cpu_65c02_ld(self, EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_abs(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_abs(self)));
     break;
   case 0xad:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_abs(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_abs(self)));
     break;
   case 0xae:
-    cpu_65c02_ld(self, EA_X, cpu_65c02_rb(self, cpu_65c02_ea_abs(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_rb(self, cpu_65c02_ea_abs(self)));
     break;
   case 0xaf:
     {
@@ -1006,22 +586,22 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_bs(self, (1 << CPU_65C02_REG_P_BIT_C), cpu_65c02_ea_rel(self));
     break;
   case 0xb1:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_ind_idx(self, self->regs.byte.y)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_ind_idx(self, self->regs.byte.y)));
     break;
   case 0xb2:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_ind(self)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_ind(self)));
     break;
   case 0xb3:
     cpu_65c02_ill11(self);
     break;
   case 0xb4:
-    cpu_65c02_ld(self, EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx(self, self->regs.byte.x)));
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx(self, self->regs.byte.x)));
     break;
   case 0xb5:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx(self, self->regs.byte.x)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx(self, self->regs.byte.x)));
     break;
   case 0xb6:
-    cpu_65c02_ld(self, EA_X, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx(self, self->regs.byte.y)));
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_rb(self, cpu_65c02_ea_zpg_idx(self, self->regs.byte.y)));
     break;
   case 0xb7:
     cpu_65c02_smb(self, 8, cpu_65c02_ea_zpg(self));
@@ -1030,22 +610,22 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_cl(self, (1 << CPU_65C02_REG_P_BIT_V));
     break;
   case 0xb9:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
     break;
   case 0xba:
-    cpu_65c02_ld(self, EA_X, self->regs.byte.s);
+    cpu_65c02_ld(self, CPU_65C02_EA_X, self->regs.byte.s);
     break;
   case 0xbb:
     cpu_65c02_ill11(self);
     break;
   case 0xbc:
-    cpu_65c02_ld(self, EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.x)));
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.x)));
     break;
   case 0xbd:
-    cpu_65c02_ld(self, EA_A, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.x)));
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.x)));
     break;
   case 0xbe:
-    cpu_65c02_ld(self, EA_X, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
     break;
   case 0xbf:
     {
@@ -1078,13 +658,13 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_smb(self, 0x10, cpu_65c02_ea_zpg(self));
     break;
   case 0xc8:
-    cpu_65c02_inc(self, EA_Y);
+    cpu_65c02_inc(self, CPU_65C02_EA_Y);
     break;
   case 0xc9:
     cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_fb(self));
     break;
   case 0xca:
-    cpu_65c02_dec(self, EA_X);
+    cpu_65c02_dec(self, CPU_65C02_EA_X);
     break;
   case 0xcb:
     cpu_65c02_wai(self);
@@ -1180,7 +760,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_smb(self, 0x40, cpu_65c02_ea_zpg(self));
     break;
   case 0xe8:
-    cpu_65c02_inc(self, EA_X);
+    cpu_65c02_inc(self, CPU_65C02_EA_X);
     break;
   case 0xe9:
     cpu_65c02_sbc(self, cpu_65c02_fb(self));
@@ -1237,7 +817,7 @@ void cpu_65c02_execute(struct cpu_65c02 *self) {
     cpu_65c02_sbc(self, cpu_65c02_rb(self, cpu_65c02_ea_abs_idx(self, self->regs.byte.y)));
     break;
   case 0xfa:
-    cpu_65c02_pl(self, EA_X);
+    cpu_65c02_pl(self, CPU_65C02_EA_X);
     break;
   case 0xfb:
     cpu_65c02_ill11(self);
index 9d8ef57..ea4b167 100644 (file)
@@ -1,17 +1,21 @@
 #ifndef _CPU_65C02_H
 #define _CPU_65C02_H
 
+#include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 
-// internal register numbering
-#define CPU_65C02_REG_A 0
-#define CPU_65C02_REG_X 1
-#define CPU_65C02_REG_Y 2
-#define CPU_65C02_REG_P 3
-#define CPU_65C02_REG_SP 4
-#define CPU_65C02_REG_S 4
-#define CPU_65C02_REG_PC 6
-#define CPU_65C02_N_REGS 8
+// gcc specific
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE __attribute__((always_inline))
+#endif
+#ifndef PACKED
+#define PACKED __attribute__((__packed__))
+#endif
+
+#define CPU_65C02_NMI_VECTOR 0xfffa
+#define CPU_65C02_RESET_VECTOR 0xfffc
+#define CPU_65C02_IRQ_VECTOR 0xfffe
 
 // bits within REG_P
 #define CPU_65C02_REG_P_BIT_C 0
 #define CPU_65C02_REG_P_BIT_V 6
 #define CPU_65C02_REG_P_BIT_N 7
 
+// special memory locations (negative address)
+#define CPU_65C02_EA_A (-8)
+#define CPU_65C02_EA_X (-7)
+#define CPU_65C02_EA_Y (-6)
+#define CPU_65C02_EA_P (-5)
+#define CPU_65C02_EA_S (-4)
+
+// registers, in same order as special memory locations, but reversed on
+// big endian hardware where special memory address will be complemented
+// (this allows special memory to always look like it is little endian)
 union cpu_65c02_regs {
-  struct {
-    uint8_t _fill0[3];
+#if __BYTE_ORDER == __BIG_ENDIAN
+  PACKED struct {
+    uint16_t _fill_pc;
+    uint16_t _fill_sp;
+    uint8_t nf : 1;
+    uint8_t vf : 1;
+    uint8_t _fill_5f: 1;
+    uint8_t _fill_4f: 1;
+    uint8_t df : 1;
+    uint8_t _if : 1;
+    uint8_t zf : 1;
+    uint8_t cf : 1;
+    uint8_t _fill_y;
+    uint8_t _fill_x;
+    uint8_t _fill_a;
+  } bit;
+  PACKED struct {
+    uint16_t _fill_pc;
+    uint8_t _fill_sph;
+    uint8_t s;
+    uint8_t p;
+    uint8_t y;
+    uint8_t x;
+    uint8_t a;
+  } byte;
+  PACKED struct {
+    uint16_t pc;
+    uint16_t sp;
+    uint8_t _fill_p;
+    uint8_t _fill_y;
+    uint8_t _fill_x;
+    uint8_t _fill_a;
+  } word;
+  uint8_t mem_be[8];
+#else
+  PACKED struct {
+    uint8_t _fill_a;
+    uint8_t _fill_x;
+    uint8_t _fill_y;
     uint8_t cf : 1;
     uint8_t zf : 1;
     uint8_t _if : 1;
     uint8_t df : 1;
-    uint8_t _fill1: 2;
+    uint8_t _fill_4f: 1;
+    uint8_t _fill_5f: 1;
     uint8_t vf : 1;
     uint8_t nf : 1;
+    uint16_t _fill_sp;
+    uint16_t _fill_pc;
   } bit;
-  struct {
+  PACKED struct {
     uint8_t a;
     uint8_t x;
     uint8_t y;
     uint8_t p;
     uint8_t s;
+    uint8_t _fill_sph;
+    uint16_t _fill_pc;
   } byte;
-  struct {
-    uint16_t _fill0[2];
+  PACKED struct {
+    uint8_t _fill_a;
+    uint8_t _fill_x;
+    uint8_t _fill_y;
+    uint8_t _fill_p;
     uint16_t sp;
     uint16_t pc;
   } word;
-  uint8_t mem[CPU_65C02_N_REGS];
+  uint8_t mem_le[8];
+#endif
 };
 
 struct cpu_65c02 {
@@ -54,6 +114,420 @@ struct cpu_65c02 {
   union cpu_65c02_regs regs;
 };
 
+// memory (or internal register memory) access
+static ALWAYS_INLINE int cpu_65c02_rb(struct cpu_65c02 *self, int addr) {
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    return self->regs.mem_be[~addr];
+#else
+    return self->regs.mem_le[addr - CPU_65C02_EA_A];
+#endif
+  self->cycles += 1;
+  return self->read_byte(addr & 0xffff);
+}
+
+static ALWAYS_INLINE int cpu_65c02_rw(struct cpu_65c02 *self, int addr) {
+  int data = cpu_65c02_rb(self, addr);
+  return data | (cpu_65c02_rb(self, addr + 1) << 8);
+}
+
+static ALWAYS_INLINE int cpu_65c02_rw_zpg(struct cpu_65c02 *self, int addr) {
+  int data = cpu_65c02_rb(self, addr & 0xff);
+  return data | (cpu_65c02_rb(self, (addr + 1) & 0xff) << 8);
+}
+
+static ALWAYS_INLINE void cpu_65c02_wb(struct cpu_65c02 *self, int addr, int data) {
+  self->cycles += 1;
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    self->regs.mem_be[~addr] = data;
+#else
+    self->regs.mem_le[addr - CPU_65C02_EA_A] = data;
+#endif
+  else
+    self->write_byte(addr, data);
+}
+
+static ALWAYS_INLINE void cpu_65c02_ww(struct cpu_65c02 *self, int addr, int data) {
+  cpu_65c02_wb(self, addr, data & 0xff);
+  cpu_65c02_wb(self, addr + 1, data >> 8);
+}
+
+static ALWAYS_INLINE int cpu_65c02_fb(struct cpu_65c02 *self) {
+  int data = cpu_65c02_rb(self, self->regs.word.pc++);
+  return data;
+}
+
+static ALWAYS_INLINE int cpu_65c02_fw(struct cpu_65c02 *self) {
+  int data = cpu_65c02_fb(self);
+  return data | (cpu_65c02_fb(self) << 8);
+}
+
+static ALWAYS_INLINE void cpu_65c02_phb(struct cpu_65c02 *self, int data) {
+  cpu_65c02_wb(self, self->regs.word.sp, data);
+  --self->regs.byte.s;
+}
+
+static ALWAYS_INLINE void cpu_65c02_phw(struct cpu_65c02 *self, int data) {
+  cpu_65c02_phb(self, data >> 8);
+  cpu_65c02_phb(self, data & 0xff);
+}
+
+static ALWAYS_INLINE int cpu_65c02_plb(struct cpu_65c02 *self) {
+  ++self->regs.byte.s;
+  return cpu_65c02_rb(self, self->regs.word.sp);
+}
+
+static ALWAYS_INLINE int cpu_65c02_plw(struct cpu_65c02 *self) {
+  int data = cpu_65c02_plb(self);
+  return data | (cpu_65c02_plb(self) << 8);
+}
+
+// effective address calculation
+static ALWAYS_INLINE int cpu_65c02_ea_abs(struct cpu_65c02 *self) {
+  return cpu_65c02_fw(self);
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_abs_idx(struct cpu_65c02 *self, int rvalue) {
+  int addr = cpu_65c02_ea_abs(self);
+  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
+  return addr + rvalue;
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_abs_idx_ind(struct cpu_65c02 *self, int rvalue) {
+  return cpu_65c02_rw(self, cpu_65c02_ea_abs_idx(self, rvalue));
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_abs_ind(struct cpu_65c02 *self) {
+  return cpu_65c02_rw(self, cpu_65c02_ea_abs(self));
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_rel(struct cpu_65c02 *self) {
+  int offset = cpu_65c02_fb(self);
+  return offset - ((offset << 1) & 0x100);
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_zpg(struct cpu_65c02 *self) {
+  return cpu_65c02_fb(self);
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_zpg_idx(struct cpu_65c02 *self, int rvalue) {
+  return (cpu_65c02_ea_zpg(self) + rvalue) & 0xff;
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_zpg_idx_ind(struct cpu_65c02 *self, int rvalue) {
+  return cpu_65c02_rw_zpg(self, cpu_65c02_ea_zpg_idx(self, rvalue));
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_zpg_ind(struct cpu_65c02 *self) {
+  return cpu_65c02_rw_zpg(self, cpu_65c02_ea_zpg(self));
+}
+
+static ALWAYS_INLINE int cpu_65c02_ea_zpg_ind_idx(struct cpu_65c02 *self, int rvalue) {
+  int addr = cpu_65c02_rw_zpg(self, cpu_65c02_ea_zpg(self));
+  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
+  return addr + rvalue;
+}
+
+// instruction execute
+static ALWAYS_INLINE void cpu_65c02_adc(struct cpu_65c02 *self, int rvalue) {
+  int result0, result1, result2;
+  if (self->regs.bit.df) {
+    result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+    if (result0 >= 0xa)
+      result0 = (result0 + 6) & 0x1f;
+    result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result2 = result1;
+    if (result2 >= 0xa0)
+      result2 = (result2 + 0x60) & 0x1ff;
+  }
+  else {
+    result0 = (self->regs.byte.a & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
+    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result2 = result1;
+  }
+  self->regs.byte.a = result2 & 0xff;
+  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;
+}
+
+static ALWAYS_INLINE void cpu_65c02_and(struct cpu_65c02 *self, int rvalue) {
+  int result = self->regs.byte.a & rvalue;
+  self->regs.byte.a = result;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue) << 1;
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result & 0xff);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_bbr(struct cpu_65c02 *self, int rvalue, int lvalue) {
+  if (rvalue == 0) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
+  }
+}
+
+static ALWAYS_INLINE void cpu_65c02_bbs(struct cpu_65c02 *self, int rvalue, int lvalue) {
+  if (rvalue) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
+  }
+}
+
+static ALWAYS_INLINE void cpu_65c02_bc(struct cpu_65c02 *self, int flag, int lvalue) {
+  if ((self->regs.byte.p & flag) == 0) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
+  }
+}
+
+static ALWAYS_INLINE void cpu_65c02_bs(struct cpu_65c02 *self, int flag, int lvalue) {
+  if (self->regs.byte.p & flag) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
+  }
+}
+
+static ALWAYS_INLINE void cpu_65c02_bit(struct cpu_65c02 *self, int rvalue) {
+  int result = self->regs.byte.a & rvalue;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = (rvalue >> 6) & 1;
+  self->regs.bit.nf = (rvalue >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_bit_imm(struct cpu_65c02 *self, int rvalue) {
+  int result = self->regs.byte.a & rvalue;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_65c02_brk(struct cpu_65c02 *self) {
+  ++self->cycles;
+  cpu_65c02_phw(self, (self->regs.word.pc + 1) & 0xffff);
+  cpu_65c02_phb(self, self->regs.byte.p);
+  self->regs.word.pc = cpu_65c02_rw(self, CPU_65C02_IRQ_VECTOR);
+  self->regs.bit._if = true;
+  self->regs.bit.df = false;
+}
+
+static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int flag) {
+  self->regs.byte.p &= ~flag;
+}
+
+static ALWAYS_INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, int rvalue0, int rvalue1) {
+  rvalue1 ^= 0xff;
+  int result = rvalue0 + rvalue1 + 1;
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_dec(struct cpu_65c02 *self, int lvalue) {
+  int result = (cpu_65c02_rb(self, lvalue) - 1) & 0xff;
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_eor(struct cpu_65c02 *self, int rvalue) {
+  int result = self->regs.byte.a ^ rvalue;
+  self->regs.byte.a = result;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ill11(struct cpu_65c02 *self) {
+}
+
+static ALWAYS_INLINE void cpu_65c02_ill22(struct cpu_65c02 *self) {
+  ++self->cycles;
+  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ill23(struct cpu_65c02 *self) {
+  self->cycles += 2;
+  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ill24(struct cpu_65c02 *self) {
+  self->cycles += 3;
+  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ill34(struct cpu_65c02 *self) {
+  self->cycles += 3;
+  self->regs.word.pc = (self->regs.word.pc + 2) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ill38(struct cpu_65c02 *self) {
+  self->cycles += 7;
+  self->regs.word.pc = (self->regs.word.pc + 2) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int lvalue) {
+  int result = (cpu_65c02_rb(self, lvalue) + 1) & 0xff;
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_65c02_jsr(struct cpu_65c02 *self, int lvalue) {
+  cpu_65c02_phw(self, (self->regs.word.pc - 1) & 0xffff);
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ld(struct cpu_65c02 *self, int lvalue, int rvalue) {
+  cpu_65c02_wb(self, lvalue, rvalue);
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.nf = (rvalue >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_lsr(struct cpu_65c02 *self, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue);
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result >> 1);
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0xfe) == 0;
+  self->regs.bit.nf = false;
+}
+
+static ALWAYS_INLINE void cpu_65c02_nop(struct cpu_65c02 *self) {
+}
+
+static ALWAYS_INLINE void cpu_65c02_ora(struct cpu_65c02 *self, int rvalue) {
+  int result = self->regs.byte.a | rvalue;
+  self->regs.byte.a = result;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
+  cpu_65c02_phb(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int lvalue) {
+  int result = cpu_65c02_plb(self);
+  cpu_65c02_wb(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
+  self->regs.byte.p = cpu_65c02_plb(self) | 0x30;
+}
+
+static ALWAYS_INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int rvalue, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue) & ~rvalue;
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int lvalue) {
+  int result = (cpu_65c02_rb(self, lvalue) << 1) | self->regs.bit.cf;
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result & 0xff);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ror(struct cpu_65c02 *self, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue) | (self->regs.bit.cf << 8);
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result >> 1);
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0x1fe) == 0;
+  self->regs.bit.nf = (result >> 8) & 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_rti(struct cpu_65c02 *self) {
+  self->regs.byte.p = cpu_65c02_plb(self) | 0x30;
+  self->regs.word.pc = cpu_65c02_plw(self);
+}
+
+static ALWAYS_INLINE void cpu_65c02_rts(struct cpu_65c02 *self) {
+  self->regs.word.pc = (cpu_65c02_plw(self) + 1) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, int rvalue) {
+  rvalue ^= 0xff;
+  int result0, result1, result2;
+  if (self->regs.bit.df) {
+    result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+    if (result0 < 0x10)
+      result0 = (result0 - 6) & 0x1f;
+    result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result2 = result1;
+    if (result2 < 0x100)
+      result2 = (result2 - 0x60) & 0x1ff;
+  }
+  else {
+    result0 = (self->regs.byte.a & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
+    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result2 = result1;
+  }
+  self->regs.byte.a = result2 & 0xff;
+  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;
+}
+
+static ALWAYS_INLINE void cpu_65c02_se(struct cpu_65c02 *self, int flag) {
+  self->regs.byte.p |= flag;
+}
+
+static ALWAYS_INLINE void cpu_65c02_smb(struct cpu_65c02 *self, int rvalue, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue) | rvalue;
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_65c02_st(struct cpu_65c02 *self, int rvalue, int lvalue) {
+  cpu_65c02_wb(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_65c02_stp(struct cpu_65c02 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue);
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result & ~self->regs.byte.a);
+  result &= self->regs.byte.a;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int lvalue) {
+  int result = cpu_65c02_rb(self, lvalue);
+  ++self->cycles;
+  cpu_65c02_wb(self, lvalue, result | self->regs.byte.a);
+  result &= self->regs.byte.a;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_65c02_wai(struct cpu_65c02 *self) {
+  abort();
+}
+
+// prototypes
 void cpu_65c02_init(
   struct cpu_65c02 *self,
   int pc,