In /star_blazer_emu, add 65c02 emulator from multi_emu.git commit 900d9fa3 instead...
authorNick Downing <nick@ndcode.org>
Sun, 11 Aug 2024 20:55:48 +0000 (06:55 +1000)
committerNick Downing <nick@mary.local>
Sun, 22 Sep 2024 03:51:39 +0000 (13:51 +1000)
.gitmodules
star_blazer_emu/Makefile
star_blazer_emu/cpu_65c02.c [new file with mode: 0644]
star_blazer_emu/cpu_65c02.h [new file with mode: 0644]
star_blazer_emu/star_blazer_emu.c
utils/disasm_to_c.py

index e026680..60cb12d 100644 (file)
@@ -10,6 +10,3 @@
 [submodule "dsk2nib"]
        path = dsk2nib
        url = https://github.com/nickd4/dsk2nib.git
-[submodule "star_blazer_emu/vrEmu6502"]
-       path = star_blazer_emu/vrEmu6502
-       url = https://github.com/nickd4/vrEmu6502.git
index 11023b8..2702f42 100644 (file)
@@ -1,4 +1,4 @@
-CFLAGS=-g -Wall -O3 -DVR_6502_EMU_STATIC=1
+CFLAGS=-g -Wall -Wno-attributes -Wno-unused-function -O3
 LDFLAGS=-g
 
 DOS33=../dos33fsprogs/utils/dos33fs-utils/dos33
@@ -8,7 +8,7 @@ all: \
 star_blazer_emu \
 star_blazer.c
 
-star_blazer_emu: star_blazer_emu.o star_blazer.o vrEmu6502/src/vrEmu6502.o
+star_blazer_emu: star_blazer_emu.o star_blazer.o cpu_65c02.o
        ${CC} ${LDFLAGS} -o $@ $^ -lSDL2 -lm
 
 # make sure star_blazer.h has been built
diff --git a/star_blazer_emu/cpu_65c02.c b/star_blazer_emu/cpu_65c02.c
new file mode 100644 (file)
index 0000000..8789d63
--- /dev/null
@@ -0,0 +1,879 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpu_65c02.h"
+
+// initialization
+void cpu_65c02_init(
+  struct cpu_65c02 *self,
+  uint8_t (*read_byte)(void *context, uint16_t addr),
+  void *read_byte_context,
+  void (*write_byte)(void *context, uint16_t addr, uint8_t data),
+  void *write_byte_context
+) {
+  memset(self, 0, sizeof(struct cpu_65c02));
+  self->regs.byte.p = 0x30; // unused bits are hard coded to 1
+  self->read_byte = read_byte;
+  self->read_byte_context = read_byte_context;
+  self->write_byte = write_byte;
+  self->write_byte_context = write_byte_context;
+}
+
+void cpu_65c02_reset(struct cpu_65c02 *self) {
+  self->regs.word.pc = cpu_65c02_read_word(self, CPU_65C02_RESET_VECTOR);
+  self->regs.byte.iflags = 0;
+  self->regs.bit._if = true;
+  self->regs.bit.df = false;
+}
+
+// instruction decode
+void cpu_65c02_execute(struct cpu_65c02 *self) {
+  if (self->regs.bit.stp_flag) {
+    ++self->cycles;
+    return;
+  }
+
+  if (self->regs.bit.nmi_pending) {
+    self->regs.bit.nmi_pending = false;
+    self->regs.bit.wai_flag = false;
+    cpu_65c02_irq(self, false, CPU_65C02_NMI_VECTOR);
+    return;
+  }
+
+  if (self->regs.bit.irq_pending) {
+    if (self->regs.bit._if == 0) {
+      self->regs.bit.irq_pending = false;
+      self->regs.bit.wai_flag = false;
+      cpu_65c02_irq(self, false, CPU_65C02_IRQ_VECTOR);
+      return;
+    }
+    if (self->regs.bit.wai_flag) {
+      self->regs.bit.irq_pending = false;
+      self->regs.bit.wai_flag = false;
+    }
+  }
+  else if (self->regs.bit.wai_flag) {
+    ++self->cycles;
+    return;
+  }
+
+  switch (cpu_65c02_fetch_byte(self)) {
+  case 0x00:
+    ++self->regs.word.pc;
+    cpu_65c02_irq(self, true, CPU_65C02_IRQ_VECTOR);
+    break;
+  case 0x01:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0x02:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0x03:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x04:
+    cpu_65c02_tsb(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x05:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0x06:
+    cpu_65c02_asl(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x07:
+    cpu_65c02_rmb(self, 0, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x08:
+    cpu_65c02_ph(self, self->regs.byte.p);
+    break;
+  case 0x09:
+    cpu_65c02_ora(self, cpu_65c02_fetch_byte(self));
+    break;
+  case 0x0a:
+    cpu_65c02_asl(self, CPU_65C02_EA_A);
+    break;
+  case 0x0b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x0c:
+    cpu_65c02_tsb(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x0d:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0x0e:
+    cpu_65c02_asl(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x0f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !(rvalue & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x10:
+    cpu_65c02_bra(self, !self->regs.bit.nf, cpu_65c02_ea_relative(self));
+    break;
+  case 0x11:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x12:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0x13:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x14:
+    cpu_65c02_trb(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x15:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x16:
+    cpu_65c02_asl(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x17:
+    cpu_65c02_rmb(self, 1, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x18:
+    cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_C);
+    break;
+  case 0x19:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x1a:
+    cpu_65c02_inc(self, CPU_65C02_EA_A);
+    break;
+  case 0x1b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x1c:
+    cpu_65c02_trb(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x1d:
+    cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x1e:
+    cpu_65c02_asl(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0x1f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 1) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x20:
+    cpu_65c02_jsr(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x21:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0x22:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0x23:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x24:
+    cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0x25:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0x26:
+    cpu_65c02_rol(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x27:
+    cpu_65c02_rmb(self, 2, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x28:
+    cpu_65c02_plp(self);
+    break;
+  case 0x29:
+    cpu_65c02_and(self, cpu_65c02_fetch_byte(self));
+    break;
+  case 0x2a:
+    cpu_65c02_rol(self, CPU_65C02_EA_A);
+    break;
+  case 0x2b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x2c:
+    cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0x2d:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0x2e:
+    cpu_65c02_rol(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x2f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 2) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x30:
+    cpu_65c02_bra(self, self->regs.bit.nf, cpu_65c02_ea_relative(self));
+    break;
+  case 0x31:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x32:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0x33:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x34:
+    cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x35:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x36:
+    cpu_65c02_rol(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x37:
+    cpu_65c02_rmb(self, 3, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x38:
+    cpu_65c02_se(self, CPU_65C02_REG_P_BIT_C);
+    break;
+  case 0x39:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x3a:
+    cpu_65c02_dec(self, CPU_65C02_EA_A);
+    break;
+  case 0x3b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x3c:
+    cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x3d:
+    cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x3e:
+    cpu_65c02_rol(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0x3f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 3) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x40:
+    cpu_65c02_rti(self);
+    break;
+  case 0x41:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0x42:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0x43:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x44:
+    cpu_65c02_illegal_opcode23(self);
+    break;
+  case 0x45:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0x46:
+    cpu_65c02_lsr(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x47:
+    cpu_65c02_rmb(self, 4, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x48:
+    cpu_65c02_ph(self, self->regs.byte.a);
+    break;
+  case 0x49:
+    cpu_65c02_eor(self, cpu_65c02_fetch_byte(self));
+    break;
+  case 0x4a:
+    cpu_65c02_lsr(self, CPU_65C02_EA_A);
+    break;
+  case 0x4b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x4c:
+    cpu_65c02_jmp(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x4d:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0x4e:
+    cpu_65c02_lsr(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x4f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 4) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x50:
+    cpu_65c02_bra(self, !self->regs.bit.vf, cpu_65c02_ea_relative(self));
+    break;
+  case 0x51:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x52:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0x53:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x54:
+    cpu_65c02_illegal_opcode24(self);
+    break;
+  case 0x55:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x56:
+    cpu_65c02_lsr(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x57:
+    cpu_65c02_rmb(self, 5, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x58:
+    cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_I);
+    break;
+  case 0x59:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x5a:
+    cpu_65c02_ph(self, self->regs.byte.y);
+    break;
+  case 0x5b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x5c:
+    cpu_65c02_illegal_opcode38(self);
+    break;
+  case 0x5d:
+    cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x5e:
+    cpu_65c02_lsr(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0x5f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 5) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x60:
+    cpu_65c02_rts(self);
+    break;
+  case 0x61:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0x62:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0x63:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x64:
+    cpu_65c02_st(self, 0, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x65:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0x66:
+    cpu_65c02_ror(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x67:
+    cpu_65c02_rmb(self, 6, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x68:
+    cpu_65c02_pl(self, CPU_65C02_EA_A);
+    break;
+  case 0x69:
+    cpu_65c02_adc(self, cpu_65c02_fetch_byte(self));
+    break;
+  case 0x6a:
+    cpu_65c02_ror(self, CPU_65C02_EA_A);
+    break;
+  case 0x6b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x6c:
+    cpu_65c02_jmp(self, cpu_65c02_ea_absolute_indirect(self));
+    break;
+  case 0x6d:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0x6e:
+    cpu_65c02_ror(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x6f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 6) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x70:
+    cpu_65c02_bra(self, self->regs.bit.vf, cpu_65c02_ea_relative(self));
+    break;
+  case 0x71:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x72:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0x73:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x74:
+    cpu_65c02_st(self, 0, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x75:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x76:
+    cpu_65c02_ror(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x77:
+    cpu_65c02_rmb(self, 7, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x78:
+    cpu_65c02_se(self, CPU_65C02_REG_P_BIT_I);
+    break;
+  case 0x79:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0x7a:
+    cpu_65c02_pl(self, CPU_65C02_EA_Y);
+    break;
+  case 0x7b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x7c:
+    cpu_65c02_jmp(self, cpu_65c02_ea_absolute_indexed_indirect(self, self->regs.byte.x));
+    break;
+  case 0x7d:
+    cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0x7e:
+    cpu_65c02_ror(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0x7f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, !((rvalue >> 7) & 1), cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x80:
+    cpu_65c02_bra(self, true, cpu_65c02_ea_relative(self));
+    break;
+  case 0x81:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x));
+    break;
+  case 0x82:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0x83:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x84:
+    cpu_65c02_st(self, self->regs.byte.y, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x85:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x86:
+    cpu_65c02_st(self, self->regs.byte.x, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x87:
+    cpu_65c02_smb(self, 0, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x88:
+    cpu_65c02_dec(self, CPU_65C02_EA_Y);
+    break;
+  case 0x89:
+    cpu_65c02_bit_imm(self, cpu_65c02_fetch_byte(self));
+    break;
+  case 0x8a:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, self->regs.byte.x);
+    break;
+  case 0x8b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x8c:
+    cpu_65c02_st(self, self->regs.byte.y, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x8d:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x8e:
+    cpu_65c02_st(self, self->regs.byte.x, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x8f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, rvalue & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0x90:
+    cpu_65c02_bra(self, !self->regs.bit.cf, cpu_65c02_ea_relative(self));
+    break;
+  case 0x91:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y));
+    break;
+  case 0x92:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indirect(self));
+    break;
+  case 0x93:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x94:
+    cpu_65c02_st(self, self->regs.byte.y, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x95:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0x96:
+    cpu_65c02_st(self, self->regs.byte.x, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.y));
+    break;
+  case 0x97:
+    cpu_65c02_smb(self, 1, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0x98:
+    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_absolute_indexed(self, self->regs.byte.y));
+    break;
+  case 0x9a:
+    cpu_65c02_st(self, self->regs.byte.x, CPU_65C02_EA_S);
+    break;
+  case 0x9b:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0x9c:
+    cpu_65c02_st(self, 0, cpu_65c02_ea_absolute(self));
+    break;
+  case 0x9d:
+    cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0x9e:
+    cpu_65c02_st(self, 0, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0x9f:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 1) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0xa0:
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xa1:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0xa2:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xa3:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xa4:
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xa5:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xa6:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xa7:
+    cpu_65c02_smb(self, 2, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xa8:
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, self->regs.byte.a);
+    break;
+  case 0xa9:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xaa:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, self->regs.byte.a);
+    break;
+  case 0xab:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xac:
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xad:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xae:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xaf:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 2) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0xb0:
+    cpu_65c02_bra(self, self->regs.bit.cf, cpu_65c02_ea_relative(self));
+    break;
+  case 0xb1:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xb2:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0xb3:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xb4:
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xb5:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xb6:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xb7:
+    cpu_65c02_smb(self, 3, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xb8:
+    cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_V);
+    break;
+  case 0xb9:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xba:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, self->regs.byte.s);
+    break;
+  case 0xbb:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xbc:
+    cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xbd:
+    cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xbe:
+    cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xbf:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 3) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0xc0:
+    cpu_65c02_cmp(self, self->regs.byte.y, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xc1:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0xc2:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0xc3:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xc4:
+    cpu_65c02_cmp(self, self->regs.byte.y, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xc5:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xc6:
+    cpu_65c02_dec(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xc7:
+    cpu_65c02_smb(self, 4, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xc8:
+    cpu_65c02_inc(self, CPU_65C02_EA_Y);
+    break;
+  case 0xc9:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xca:
+    cpu_65c02_dec(self, CPU_65C02_EA_X);
+    break;
+  case 0xcb:
+    cpu_65c02_wai(self);
+    break;
+  case 0xcc:
+    cpu_65c02_cmp(self, self->regs.byte.y, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xcd:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xce:
+    cpu_65c02_dec(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0xcf:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 4) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0xd0:
+    cpu_65c02_bra(self, !self->regs.bit.zf, cpu_65c02_ea_relative(self));
+    break;
+  case 0xd1:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xd2:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0xd3:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xd4:
+    cpu_65c02_illegal_opcode24(self);
+    break;
+  case 0xd5:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xd6:
+    cpu_65c02_dec(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0xd7:
+    cpu_65c02_smb(self, 5, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xd8:
+    cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_D);
+    break;
+  case 0xd9:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xda:
+    cpu_65c02_ph(self, self->regs.byte.x);
+    break;
+  case 0xdb:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xdc:
+    cpu_65c02_illegal_opcode34(self);
+    break;
+  case 0xdd:
+    cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xde:
+    cpu_65c02_dec(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0xdf:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 5) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0xe0:
+    cpu_65c02_cmp(self, self->regs.byte.x, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xe1:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)));
+    break;
+  case 0xe2:
+    cpu_65c02_illegal_opcode22(self);
+    break;
+  case 0xe3:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xe4:
+    cpu_65c02_cmp(self, self->regs.byte.x, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xe5:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)));
+    break;
+  case 0xe6:
+    cpu_65c02_inc(self, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xe7:
+    cpu_65c02_smb(self, 6, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xe8:
+    cpu_65c02_inc(self, CPU_65C02_EA_X);
+    break;
+  case 0xe9:
+    cpu_65c02_sbc(self, cpu_65c02_fetch_byte(self));
+    break;
+  case 0xea:
+    cpu_65c02_nop(self);
+    break;
+  case 0xeb:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xec:
+    cpu_65c02_cmp(self, self->regs.byte.x, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xed:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self)));
+    break;
+  case 0xee:
+    cpu_65c02_inc(self, cpu_65c02_ea_absolute(self));
+    break;
+  case 0xef:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 6) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  case 0xf0:
+    cpu_65c02_bra(self, self->regs.bit.zf, cpu_65c02_ea_relative(self));
+    break;
+  case 0xf1:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xf2:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self)));
+    break;
+  case 0xf3:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xf4:
+    cpu_65c02_illegal_opcode24(self);
+    break;
+  case 0xf5:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xf6:
+    cpu_65c02_inc(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x));
+    break;
+  case 0xf7:
+    cpu_65c02_smb(self, 7, cpu_65c02_ea_zero_page(self));
+    break;
+  case 0xf8:
+    cpu_65c02_se(self, CPU_65C02_REG_P_BIT_D);
+    break;
+  case 0xf9:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)));
+    break;
+  case 0xfa:
+    cpu_65c02_pl(self, CPU_65C02_EA_X);
+    break;
+  case 0xfb:
+    cpu_65c02_illegal_opcode11(self);
+    break;
+  case 0xfc:
+    cpu_65c02_illegal_opcode34(self);
+    break;
+  case 0xfd:
+    cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)));
+    break;
+  case 0xfe:
+    cpu_65c02_inc(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x));
+    break;
+  case 0xff:
+    {
+      int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self));
+      cpu_65c02_bra(self, (rvalue >> 7) & 1, cpu_65c02_ea_relative(self));
+    }
+    break;
+  }
+}
diff --git a/star_blazer_emu/cpu_65c02.h b/star_blazer_emu/cpu_65c02.h
new file mode 100644 (file)
index 0000000..0a506db
--- /dev/null
@@ -0,0 +1,535 @@
+#ifndef _CPU_65C02_H
+#define _CPU_65C02_H
+
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+// gcc specific
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE __attribute__((always_inline))
+#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_Z 1
+#define CPU_65C02_REG_P_BIT_I 2
+#define CPU_65C02_REG_P_BIT_D 3
+#define CPU_65C02_REG_P_BIT_B 4
+#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_PC (-8)
+#define CPU_65C02_EA_A (-6)
+#define CPU_65C02_EA_X (-5)
+#define CPU_65C02_EA_Y (-4)
+#define CPU_65C02_EA_S (-3)
+#define CPU_65C02_EA_P (-2)
+#define CPU_65C02_EA_IFLAGS (-1)
+
+// 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 {
+#if __BYTE_ORDER == __BIG_ENDIAN
+  struct {
+    uint8_t _fill_iflags : 4;
+    uint8_t stp_flag : 1;
+    uint8_t wai_flag : 1;
+    uint8_t irq_pending : 1;
+    uint8_t nmi_pending : 1;
+    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_s;
+    uint8_t _fill_y;
+    uint8_t _fill_x;
+    uint8_t _fill_a;
+    uint16_t _fill_pc;
+  } bit;
+  struct {
+    uint8_t iflags;
+    uint8_t p;
+    uint8_t s;
+    uint8_t y;
+    uint8_t x;
+    uint8_t a;
+    uint16_t _fill_pc;
+  } byte;
+  struct {
+    uint8_t _fill_iflags;
+    uint8_t _fill_p;
+    uint8_t _fill_s;
+    uint8_t _fill_y;
+    uint8_t _fill_x;
+    uint8_t _fill_a;
+    uint16_t pc;
+  } word;
+  uint8_t mem_be[8];
+#else
+  struct {
+    uint16_t _fill_pc;
+    uint8_t _fill_a;
+    uint8_t _fill_x;
+    uint8_t _fill_y;
+    uint8_t _fill_s;
+    uint8_t cf : 1;
+    uint8_t zf : 1;
+    uint8_t _if : 1;
+    uint8_t df : 1;
+    uint8_t _fill_4f: 1;
+    uint8_t _fill_5f: 1;
+    uint8_t vf : 1;
+    uint8_t nf : 1;
+    uint8_t nmi_pending : 1;
+    uint8_t irq_pending : 1;
+    uint8_t wai_flag : 1;
+    uint8_t stp_flag : 1;
+    uint8_t _fill_iflags : 4;
+  } bit;
+  struct {
+    uint16_t _fill_pc;
+    uint8_t a;
+    uint8_t x;
+    uint8_t y;
+    uint8_t s;
+    uint8_t p;
+    uint8_t iflags;
+  } byte;
+  struct {
+    uint16_t pc;
+    uint8_t _fill_a;
+    uint8_t _fill_x;
+    uint8_t _fill_y;
+    uint8_t _fill_s;
+    uint8_t _fill_p;
+    uint8_t _fill_iflags;
+  } word;
+  uint8_t mem_le[8];
+#endif
+};
+
+struct cpu_65c02 {
+  int cycles;
+  uint8_t (*read_byte)(void *context, uint16_t addr);
+  void *read_byte_context;
+  void (*write_byte)(void *context, uint16_t addr, uint8_t data);
+  void *write_byte_context;
+  union cpu_65c02_regs regs;
+};
+
+// memory or special memory access
+static ALWAYS_INLINE uint8_t cpu_65c02_read_byte(struct cpu_65c02 *self, int32_t addr) {
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    return self->regs.mem_be[~addr];
+#else
+    return self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr];
+#endif
+  self->cycles += 1;
+  return self->read_byte(self->read_byte_context, addr & 0xffff);
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_read_word(struct cpu_65c02 *self, int32_t addr) {
+  int data = cpu_65c02_read_byte(self, addr);
+  return data | (cpu_65c02_read_byte(self, addr + 1) << 8);
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_read_word_zero_page(struct cpu_65c02 *self, uint8_t addr) {
+  int data = cpu_65c02_read_byte(self, addr & 0xff);
+  return data | (cpu_65c02_read_byte(self, (addr + 1) & 0xff) << 8);
+}
+
+static ALWAYS_INLINE void cpu_65c02_write_byte(struct cpu_65c02 *self, int32_t addr, uint8_t data) {
+  self->cycles += 1;
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    self->regs.mem_be[~addr] = data;
+#else
+    self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr] = data;
+#endif
+  else
+    self->write_byte(self->write_byte_context, addr, data);
+}
+
+static ALWAYS_INLINE void cpu_65c02_write_word(struct cpu_65c02 *self, int32_t addr, uint16_t data) {
+  cpu_65c02_write_byte(self, addr, data & 0xff);
+  cpu_65c02_write_byte(self, addr + 1, data >> 8);
+}
+
+static ALWAYS_INLINE uint8_t cpu_65c02_fetch_byte(struct cpu_65c02 *self) {
+  int data = cpu_65c02_read_byte(self, self->regs.word.pc++);
+  return data;
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_fetch_word(struct cpu_65c02 *self) {
+  int data = cpu_65c02_fetch_byte(self);
+  return data | (cpu_65c02_fetch_byte(self) << 8);
+}
+
+static ALWAYS_INLINE void cpu_65c02_push_byte(struct cpu_65c02 *self, uint8_t data) {
+  cpu_65c02_write_byte(self, self->regs.byte.s-- | 0x100, data);
+}
+
+static ALWAYS_INLINE void cpu_65c02_push_word(struct cpu_65c02 *self, uint16_t data) {
+  cpu_65c02_push_byte(self, data >> 8);
+  cpu_65c02_push_byte(self, data & 0xff);
+}
+
+static ALWAYS_INLINE uint8_t cpu_65c02_pop_byte(struct cpu_65c02 *self) {
+  return cpu_65c02_read_byte(self, ++self->regs.byte.s | 0x100);
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_pop_word(struct cpu_65c02 *self) {
+  int data = cpu_65c02_pop_byte(self);
+  return data | (cpu_65c02_pop_byte(self) << 8);
+}
+
+// effective address calculation
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute(struct cpu_65c02 *self) {
+  return cpu_65c02_fetch_word(self);
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute_indexed(struct cpu_65c02 *self, uint8_t rvalue) {
+  int addr = cpu_65c02_ea_absolute(self);
+  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
+  return addr + rvalue;
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute_indexed_indirect(struct cpu_65c02 *self, uint8_t rvalue) {
+  return cpu_65c02_read_word(self, cpu_65c02_ea_absolute_indexed(self, rvalue));
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute_indirect(struct cpu_65c02 *self) {
+  return cpu_65c02_read_word(self, cpu_65c02_ea_absolute(self));
+}
+
+static ALWAYS_INLINE int8_t cpu_65c02_ea_relative(struct cpu_65c02 *self) {
+  return (int8_t)cpu_65c02_fetch_byte(self);
+}
+
+static ALWAYS_INLINE uint8_t cpu_65c02_ea_zero_page(struct cpu_65c02 *self) {
+  return cpu_65c02_fetch_byte(self);
+}
+
+static ALWAYS_INLINE uint8_t cpu_65c02_ea_zero_page_indexed(struct cpu_65c02 *self, uint8_t rvalue) {
+  return (cpu_65c02_ea_zero_page(self) + rvalue) & 0xff;
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_zero_page_indexed_indirect(struct cpu_65c02 *self, uint8_t rvalue) {
+  return cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page_indexed(self, rvalue));
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_zero_page_indirect(struct cpu_65c02 *self) {
+  return cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page(self));
+}
+
+static ALWAYS_INLINE uint16_t cpu_65c02_ea_zero_page_indirect_indexed(struct cpu_65c02 *self, uint8_t rvalue) {
+  int addr = cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page(self));
+  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
+  return addr + rvalue;
+}
+
+// instruction execute
+static ALWAYS_INLINE void cpu_65c02_adc(struct cpu_65c02 *self, uint8_t rvalue) {
+  int result0, result1, result2;
+  if (self->regs.bit.df) {
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
+    if (result0 >= 0xa)
+      result0 = (result0 + 6) & 0x1f;
+    result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+    result2 = result1;
+    if (result2 >= 0xa0)
+      result2 = (result2 + 0x60) & 0x1ff;
+  }
+  else {
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+    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, uint8_t 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;
+}
+
+static ALWAYS_INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue) << 1;
+  ++self->cycles;
+  cpu_65c02_write_byte(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_bit(struct cpu_65c02 *self, uint8_t 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, uint8_t rvalue) {
+  int result = self->regs.byte.a & rvalue;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_65c02_bra(struct cpu_65c02 *self, bool pred, int8_t rvalue) {
+  if (pred) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (rvalue & 0xff)) >> 8;
+    self->regs.word.pc += rvalue;
+  }
+}
+
+static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int n) {
+  self->regs.byte.p &= ~(1 << n);
+}
+
+static ALWAYS_INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, uint8_t rvalue0, uint8_t rvalue1) {
+  rvalue1 ^= 0xff;
+  int result = 1 + rvalue0 + rvalue1;
+  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, int32_t lvalue) {
+  int result = (cpu_65c02_read_byte(self, lvalue) - 1) & 0xff;
+  ++self->cycles;
+  cpu_65c02_write_byte(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_65c02_eor(struct cpu_65c02 *self, uint8_t 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;
+}
+
+static ALWAYS_INLINE void cpu_65c02_illegal_opcode11(struct cpu_65c02 *self) {
+}
+
+static ALWAYS_INLINE void cpu_65c02_illegal_opcode22(struct cpu_65c02 *self) {
+  ++self->cycles;
+  self->regs.word.pc += 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_illegal_opcode23(struct cpu_65c02 *self) {
+  self->cycles += 2;
+  self->regs.word.pc += 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_illegal_opcode24(struct cpu_65c02 *self) {
+  self->cycles += 3;
+  self->regs.word.pc += 1;
+}
+
+static ALWAYS_INLINE void cpu_65c02_illegal_opcode34(struct cpu_65c02 *self) {
+  self->cycles += 3;
+  self->regs.word.pc += 2;
+}
+
+static ALWAYS_INLINE void cpu_65c02_illegal_opcode38(struct cpu_65c02 *self) {
+  self->cycles += 7;
+  self->regs.word.pc += 2;
+}
+
+static ALWAYS_INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int32_t lvalue) {
+  int result = (cpu_65c02_read_byte(self, lvalue) + 1) & 0xff;
+  ++self->cycles;
+  cpu_65c02_write_byte(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_65c02_irq(struct cpu_65c02 *self, bool brk, int32_t lvalue) {
+  ++self->cycles;
+  cpu_65c02_push_word(self, self->regs.word.pc);
+  cpu_65c02_push_byte(
+    self,
+    ((self->regs.byte.p) & ~(1 << CPU_65C02_REG_P_BIT_B)) |
+    (brk << CPU_65C02_REG_P_BIT_B)
+  );
+  self->regs.word.pc = cpu_65c02_read_word(self, lvalue);
+  self->regs.bit._if = true;
+  self->regs.bit.df = false;
+}
+
+static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int32_t lvalue) {
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_65c02_jsr(struct cpu_65c02 *self, int32_t lvalue) {
+  cpu_65c02_push_word(self, (self->regs.word.pc - 1) & 0xffff);
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ld(struct cpu_65c02 *self, int32_t lvalue, uint8_t rvalue) {
+  cpu_65c02_write_byte(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, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue);
+  ++self->cycles;
+  cpu_65c02_write_byte(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, uint8_t 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;
+}
+
+static ALWAYS_INLINE void cpu_65c02_ph(struct cpu_65c02 *self, uint8_t rvalue) {
+  cpu_65c02_push_byte(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int32_t lvalue) {
+  int result = cpu_65c02_pop_byte(self);
+  cpu_65c02_write_byte(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
+  self->regs.byte.p = cpu_65c02_pop_byte(self) | 0x30;
+}
+
+static ALWAYS_INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int n, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue) & ~(1 << n);
+  ++self->cycles;
+  cpu_65c02_write_byte(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int32_t lvalue) {
+  int result = self->regs.bit.cf | (cpu_65c02_read_byte(self, lvalue) << 1);
+  ++self->cycles;
+  cpu_65c02_write_byte(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, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue) | (self->regs.bit.cf << 8);
+  ++self->cycles;
+  cpu_65c02_write_byte(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_pop_byte(self) | 0x30;
+  self->regs.word.pc = cpu_65c02_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_65c02_rts(struct cpu_65c02 *self) {
+  self->regs.word.pc = (cpu_65c02_pop_word(self) + 1) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, uint8_t rvalue) {
+  rvalue ^= 0xff;
+  int result0, result1, result2;
+  if (self->regs.bit.df) {
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
+    if (result0 < 0x10)
+      result0 = (result0 - 6) & 0x1f;
+    result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+    result2 = result1;
+    if (result2 < 0x100)
+      result2 = (result2 - 0x60) & 0x1ff;
+  }
+  else {
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+    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 n) {
+  self->regs.byte.p |= 1 << n;
+}
+
+static ALWAYS_INLINE void cpu_65c02_smb(struct cpu_65c02 *self, int n, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue) | (1 << n);
+  ++self->cycles;
+  cpu_65c02_write_byte(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_65c02_st(struct cpu_65c02 *self, uint8_t rvalue, int32_t lvalue) {
+  cpu_65c02_write_byte(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_65c02_stp(struct cpu_65c02 *self) {
+  self->regs.bit.stp_flag = true;
+}
+
+static ALWAYS_INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue);
+  ++self->cycles;
+  cpu_65c02_write_byte(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, int32_t lvalue) {
+  int result = cpu_65c02_read_byte(self, lvalue);
+  ++self->cycles;
+  cpu_65c02_write_byte(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) {
+  self->regs.bit.wai_flag = true;
+}
+
+// prototypes
+void cpu_65c02_init(
+  struct cpu_65c02 *self,
+  uint8_t (*read_byte)(void *context, uint16_t addr),
+  void *read_byte_context,
+  void (*write_byte)(void *context, uint16_t addr, uint8_t data),
+  void *write_byte_context
+);
+void cpu_65c02_reset(struct cpu_65c02 *self);
+void cpu_65c02_execute(struct cpu_65c02 *self);
+#endif
index d7b0d1a..4bc35d5 100644 (file)
@@ -70,10 +70,8 @@ uint32_t palette[0x10] = {
   0xffffffff,
 };
 
-// can make this green or amber to be more realistic
-uint32_t mono_palette[2] = {0xff000000, 0xffffffff};
-
-VrEmu6502 *cpu;
+struct cpu_65c02 cpu;
+bool jam_flag;
 
 #define MEM_SIZE 0x10000
 uint8_t mem[MEM_SIZE];
@@ -367,7 +365,7 @@ int load(char *name) {
   exit(EXIT_FAILURE);
 }
 
-uint8_t mem_read(uint16_t addr/*, bool isDbg*/) {
+uint8_t read_byte(void *context, uint16_t addr) {
   // for joystick, for now count memory accesses as proxy for cycles
   if (joystick_count < JOYSTICK_COUNT) {
     ++joystick_count;
@@ -386,10 +384,10 @@ uint8_t mem_read(uint16_t addr/*, bool isDbg*/) {
     //if (addr >= 0x8c08 && addr < 0x8e00) { // data fetch
     //if (addr >= 0x9580 && addr < 0x9600) { // data fetch
     if (addr >= 0x5c00 && addr < 0x5c1b) { // data fetch
-      int pc = vrEmu6502GetPC(cpu);
+      int pc = cpu.regs.word.pc;
       fprintf(stderr, "pc=%04x addr=%04x\n", pc, addr);
       exit_flag = 0x101;
-      vrEmu6502Jam(cpu);
+      jam_flag = true;
     } 
 #endif
 
@@ -411,12 +409,12 @@ uint8_t mem_read(uint16_t addr/*, bool isDbg*/) {
 
 #if 0 // start at mission
     if (addr == 0x1726) // opcode fetch
-      vrEmu6502SetX(cpu, start_at_mission);
+      cpu.regs.byte.x = start_at_mission;
 #endif
 
 #if MEM_TRACE
     {
-      int pc = cpu ? vrEmu6502GetPC(cpu) : 0;
+      int pc = cpu ? cpu.regs.word.pc : 0;
       fprintf(stderr, "pc=%04x addr=%05x rd=%02x\n", pc, addr, mem[addr]);
     }
 #endif
@@ -450,7 +448,7 @@ uint8_t mem_read(uint16_t addr/*, bool isDbg*/) {
   return 0xff;
 }
 
-void mem_write(uint16_t addr, uint8_t val) {
+void write_byte(void *context, uint16_t addr, uint8_t data) {
   // for joystick, for now count memory accesses as proxy for cycles
   if (joystick_count < JOYSTICK_COUNT) {
     ++joystick_count;
@@ -467,11 +465,11 @@ void mem_write(uint16_t addr, uint8_t val) {
   if ((addr & 0xff00) != IO_PAGE) {
 #if MEM_TRACE
     {
-      int pc = cpu ? vrEmu6502GetPC(cpu) : 0;
-      fprintf(stderr, "pc=%04x addr=%05x wr=%02x\n", pc, addr, val);
+      int pc = cpu ? cpu.regs.word.pc : 0;
+      fprintf(stderr, "pc=%04x addr=%05x wr=%02x\n", pc, addr, data);
     }
 #endif
-    mem[addr] = val;
+    mem[addr] = data;
     return;
   }
 
@@ -507,12 +505,6 @@ int main(int argc, char **argv) {
     entry_point = load(p);
   }
 
-  // do this before creating the CPU
-  if (entry_point != -1) {
-    mem[RESET_VECTOR] = (uint8_t)(entry_point & 0xff);
-    mem[RESET_VECTOR + 1] = (uint8_t)(entry_point >> 8);
-  }
-
   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
     fprintf(stderr, "SDL_Init(): %s\n\n", SDL_GetError());
     exit(EXIT_FAILURE);
@@ -603,11 +595,10 @@ int main(int argc, char **argv) {
       joystick_axes[i] = JOYSTICK_COUNT >> 1;
   }
 
-  cpu = vrEmu6502New(CPU_65C02, mem_read, mem_write);
-  if (cpu == NULL) {
-    perror("malloc()");
-    exit(EXIT_FAILURE);
-  }
+  cpu_65c02_init(&cpu, read_byte, NULL, write_byte, NULL);
+  cpu_65c02_reset(&cpu);
+  if (entry_point != -1)
+    cpu.regs.word.pc = entry_point;
 
   // main loop
   int update_count = 0;
@@ -842,11 +833,15 @@ int main(int argc, char **argv) {
       SDL_Delay(1);
     }
     else {
-      for (int j = 0; j < CYCLES_PER_SAMPLE; )
-        j += execute(cpu);
+      for (cpu.cycles = 0; cpu.cycles < CYCLES_PER_SAMPLE; ) {
+        cpu_65c02_execute(&cpu);
+        if (jam_flag) {
+          jam_flag = false;
+          break;
+        }
+      }
       if (exit_flag)
         break;
-      vrEmu6502Unjam(cpu);
 
       // sample tape and speaker outputs at CYCLES_PER_SAMPLE rate
 #if 0
@@ -866,8 +861,6 @@ int main(int argc, char **argv) {
   }
 
 quit:
-  vrEmu6502Destroy(cpu);
-
   if (joystick)
     SDL_JoystickClose(joystick);
   SDL_CloseAudioDevice(audio_device_id);
index be6836c..f10eea6 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/env python3
 
 import bisect
+import py65.devices.mpu65c02
+import py65.disassembler
 import re
 import sys
 from intelhex import IntelHex
@@ -28,303 +30,6 @@ item_types = {
   'code_m1': ITEM_CODE_M1,
 }
 
-# from vrEmu6502.c
-opcodes = [
-  # 0x00
-  ('brk', 'imp', 7),
-  ('ora', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('tsb', 'zp', 5),
-  ('ora', 'zp', 3),
-  ('asl', 'zp', 5),
-  ('nop', 'imp', 1),
-  ('php', 'imp', 3),
-  ('ora', 'imm', 2),
-  ('asl', 'acc', 2),
-  ('nop', 'imp', 1),
-  ('tsb', 'ab', 6),
-  ('ora', 'ab', 4),
-  ('asl', 'ab', 6),
-  ('nop', 'imp', 1),
-  # 0x10
-  ('bpl', 'rel', 2),
-  ('ora', 'yip', 5),
-  ('ora', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('trb', 'zp', 5),
-  ('ora', 'zpx', 4),
-  ('asl', 'zpx', 6),
-  ('nop', 'imp', 1),
-  ('clc', 'imp', 2),
-  ('ora', 'ayp', 4),
-  ('inc', 'acc', 2),
-  ('nop', 'imp', 1),
-  ('trb', 'ab', 6),
-  ('ora', 'axp', 4),
-  ('asl', 'axp', 6),
-  ('nop', 'imp', 1),
-  # 0x20
-  ('jsr', 'ab', 6),
-  ('and', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('bit', 'zp', 3),
-  ('and', 'zp', 3),
-  ('rol', 'zp', 5),
-  ('nop', 'imp', 1),
-  ('plp', 'imp', 4),
-  ('and', 'imm', 2),
-  ('rol', 'acc', 2),
-  ('nop', 'imp', 1),
-  ('bit', 'ab', 4),
-  ('and', 'ab', 4),
-  ('rol', 'ab', 6),
-  ('nop', 'imp', 1),
-  # 0x30
-  ('bmi', 'rel', 2),
-  ('and', 'yip', 5),
-  ('and', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('bit', 'zpx', 4),
-  ('and', 'zpx', 4),
-  ('rol', 'zpx', 6),
-  ('nop', 'imp', 1),
-  ('sec', 'imp', 2),
-  ('and', 'ayp', 4),
-  ('dec', 'acc', 2),
-  ('nop', 'imp', 1),
-  ('bit', 'abx', 4),
-  ('and', 'axp', 4),
-  ('rol', 'axp', 6),
-  ('nop', 'imp', 1),
-  # 0x40
-  ('rti', 'imp', 6),
-  ('eor', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('ldd', 'zp', 3),
-  ('eor', 'zp', 3),
-  ('lsr', 'zp', 5),
-  ('nop', 'imp', 1),
-  ('pha', 'imp', 3),
-  ('eor', 'imm', 2),
-  ('lsr', 'acc', 2),
-  ('nop', 'imp', 1),
-  ('jmp', 'ab', 3),
-  ('eor', 'ab', 4),
-  ('lsr', 'ab', 6),
-  ('nop', 'imp', 1),
-  # 0x50
-  ('bvc', 'rel', 2),
-  ('eor', 'yip', 5),
-  ('eor', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('ldd', 'zpx', 4),
-  ('eor', 'zpx', 4),
-  ('lsr', 'zpx', 6),
-  ('nop', 'imp', 1),
-  ('cli', 'imp', 2),
-  ('eor', 'ayp', 4),
-  ('phy', 'imp', 3),
-  ('nop', 'imp', 1),
-  ('ldd', 'ab', 8),
-  ('eor', 'axp', 4),
-  ('lsr', 'axp', 6),
-  ('nop', 'imp', 1),
-  # 0x60
-  ('rts', 'imp', 6),
-  ('adc', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('stz', 'zp', 3),
-  ('adc', 'zp', 3),
-  ('ror', 'zp', 5),
-  ('nop', 'imp', 1),
-  ('pla', 'imp', 4),
-  ('adc', 'imm', 2),
-  ('ror', 'acc', 2),
-  ('nop', 'imp', 1),
-  ('jmp', 'ind', 6),
-  ('adc', 'ab', 4),
-  ('ror', 'ab', 6),
-  ('nop', 'imp', 1),
-  # 0x70
-  ('bvs', 'rel', 2),
-  ('adc', 'yip', 5),
-  ('adc', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('stz', 'zpx', 4),
-  ('adc', 'zpx', 4),
-  ('ror', 'zpx', 6),
-  ('nop', 'imp', 1),
-  ('sei', 'imp', 2),
-  ('adc', 'ayp', 4),
-  ('ply', 'imp', 4),
-  ('nop', 'imp', 1),
-  ('jmp', 'indx', 6),
-  ('adc', 'axp', 4),
-  ('ror', 'axp', 6),
-  ('nop', 'imp', 1),
-  # 0x80
-  ('bra', 'rel', 2),
-  ('sta', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('sty', 'zp', 3),
-  ('sta', 'zp', 3),
-  ('stx', 'zp', 3),
-  ('nop', 'imp', 1),
-  ('dey', 'imp', 2),
-  ('bit', 'imm', 2),
-  ('txa', 'imp', 2),
-  ('nop', 'imp', 1),
-  ('sty', 'ab', 4),
-  ('sta', 'ab', 4),
-  ('stx', 'ab', 4),
-  ('nop', 'imp', 1),
-  # 0x90
-  ('bcc', 'rel', 2),
-  ('sta', 'yin', 6),
-  ('sta', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('sty', 'zpx', 4),
-  ('sta', 'zpx', 4),
-  ('stx', 'zpy', 4),
-  ('nop', 'imp', 1),
-  ('tya', 'imp', 2),
-  ('sta', 'aby', 5),
-  ('txs', 'imp', 2),
-  ('nop', 'imp', 1),
-  ('stz', 'ab', 4),
-  ('sta', 'abx', 5),
-  ('stz', 'abx', 5),
-  ('nop', 'imp', 1),
-  # 0xa0
-  ('ldy', 'imm', 2),
-  ('lda', 'xin', 6),
-  ('ldx', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('ldy', 'zp', 3),
-  ('lda', 'zp', 3),
-  ('ldx', 'zp', 3),
-  ('nop', 'imp', 1),
-  ('tay', 'imp', 2),
-  ('lda', 'imm', 2),
-  ('tax', 'imp', 2),
-  ('nop', 'imp', 1),
-  ('ldy', 'ab', 4),
-  ('lda', 'ab', 4),
-  ('ldx', 'ab', 4),
-  ('nop', 'imp', 1),
-  # 0xb0
-  ('bcs', 'rel', 2),
-  ('lda', 'yip', 5),
-  ('lda', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('ldy', 'zpx', 4),
-  ('lda', 'zpx', 4),
-  ('ldx', 'zpy', 4),
-  ('nop', 'imp', 1),
-  ('clv', 'imp', 2),
-  ('lda', 'ayp', 4),
-  ('tsx', 'imp', 2),
-  ('nop', 'imp', 1),
-  ('ldy', 'axp', 4),
-  ('lda', 'axp', 4),
-  ('ldx', 'ayp', 4),
-  ('nop', 'imp', 1),
-  # 0xc0
-  ('cpy', 'imm', 2),
-  ('cmp', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('cpy', 'zp', 3),
-  ('cmp', 'zp', 3),
-  ('dec', 'zp', 5),
-  ('nop', 'imp', 1),
-  ('iny', 'imp', 2),
-  ('cmp', 'imm', 2),
-  ('dex', 'imp', 2),
-  ('nop', 'imp', 1),
-  ('cpy', 'ab', 4),
-  ('cmp', 'ab', 4),
-  ('dec', 'ab', 6),
-  ('nop', 'imp', 1),
-  # 0xd0
-  ('bne', 'rel', 2),
-  ('cmp', 'yip', 5),
-  ('cmp', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('ldd', 'zpx', 4),
-  ('cmp', 'zpx', 4),
-  ('dec', 'zpx', 6),
-  ('nop', 'imp', 1),
-  ('cld', 'imp', 2),
-  ('cmp', 'ayp', 4),
-  ('phx', 'imp', 3),
-  ('nop', 'imp', 1),
-  ('ldd', 'ab', 4),
-  ('cmp', 'axp', 4),
-  ('dec', 'abx', 7),
-  ('nop', 'imp', 1),
-  # 0xe0
-  ('cpx', 'imm', 2),
-  ('sbc', 'xin', 6),
-  ('ldd', 'imm', 2),
-  ('nop', 'imp', 1),
-  ('cpx', 'zp', 3),
-  ('sbc', 'zp', 3),
-  ('inc', 'zp', 5),
-  ('nop', 'imp', 1),
-  ('inx', 'imp', 2),
-  ('sbc', 'imm', 2),
-  ('nop', 'imp', 2),
-  ('nop', 'imp', 1),
-  ('cpx', 'ab', 4),
-  ('sbc', 'ab', 4),
-  ('inc', 'ab', 6),
-  ('nop', 'imp', 1),
-  # 0xf0
-  ('beq', 'rel', 2),
-  ('sbc', 'yip', 5),
-  ('sbc', 'zpi', 5),
-  ('nop', 'imp', 1),
-  ('ldd', 'zpx', 4),
-  ('sbc', 'zpx', 4),
-  ('inc', 'zpx', 6),
-  ('nop', 'imp', 1),
-  ('sed', 'imp', 2),
-  ('sbc', 'ayp', 4),
-  ('plx', 'imp', 4),
-  ('nop', 'imp', 1),
-  ('ldd', 'ab', 4),
-  ('sbc', 'axp', 4),
-  ('inc', 'abx', 7),
-  ('nop', 'imp', 1),
-]
-# instruction length is looked up from addressing mode
-addr_modes = {
-  'ab': 3,
-  'abx': 3,
-  'aby': 3,
-  'acc': 1,
-  'axp': 1,
-  'ayp': 1,
-  'imm': 2,
-  'imp': 1,
-  'ind': 3,
-  'indx': 3,
-  'rel': 2,
-  'xin': 2,
-  'yin': 2,
-  'yip': 2,
-  'zp': 2,
-  'zpi': 2,
-  'zpx': 2,
-  'zpy': 2,
-}
-
 if len(sys.argv) < 5:
   print(f'usage: {sys.argv[0]:s} in_addrs.txt in.ihx out.c out.h')
   sys.exit(EXIT_FAILURE)
@@ -333,6 +38,25 @@ in_ihx = sys.argv[2]
 out_c = sys.argv[3]
 out_h = sys.argv[4]
 
+with open('cpu_65c02.c') as fin:
+  for line in fin:
+    line = line.rstrip()
+    if line == '  switch (cpu_65c02_fetch_byte(self)) {':
+      break
+  else:
+    assert False
+
+  opcodes = []
+  for line in fin:
+    line = line.rstrip()
+    if line == '  }':
+      break
+    if line[:9] == '  case 0x' and line[11:] == ':':
+      assert len(opcodes) == int(line[9:11], 16)
+      opcodes.append('')
+    else:
+      opcodes[-1] += line.replace('self', 'cpu') + '\n'
+
 class AreaInfo:
   def __init__(self, size, name, _type, comment):
     self.size = size
@@ -479,13 +203,17 @@ for i in range(0, len(segments), 2):
   print(f'[{addr0:04x}, {addr1:04x})')
   mem[addr0:addr1] = list(intelhex.tobinstr(addr0, addr1 - 1))
 
+mpu = py65.devices.mpu65c02.MPU(mem, 0)
+disassembler = py65.disassembler.Disassembler(mpu)
+
 with open(out_c, 'w') as fout:
   fout.write(
-    f'''#include "rassert.h"
+    f'''#include <stdlib.h>
+#include "rassert.h"
 #include "{out_h:s}"
 
-int execute(VrEmu6502 *cpu) {{
-  switch (cpu->pc) {{
+void execute(struct cpu_65c02 *cpu) {{
+  switch (cpu->regs.word.pc) {{
 '''
   )
 
@@ -513,16 +241,12 @@ int execute(VrEmu6502 *cpu) {{
             item_info[item].type == ITEM_CODE_IGN
         ):
           opcode = mem[addr]
-          op, addr_mode, cycles = opcodes[opcode]
-          n = addr_modes[addr_mode]
+          n, _ = disassembler.instruction_at(i)
           fout.write(
             f'''  case 0x{addr:04x}:
-    rassert(cpu->readFn(0x{addr:04x}) == 0x{opcode:02x});
-    cpu->pc = 0x{(addr + 1) & 0xffff:04x};
-    cpu->step = {cycles:d};
-    {op:s}(cpu, {addr_mode:s});
-    return cpu->step;
-'''
+    rassert(cpu->read_byte(cpu->read_byte_context, 0x{addr:04x}) == 0x{opcode:02x});
+    cpu->regs.word.pc = 0x{(addr + 1) & 0xffff:04x};
+{opcodes[opcode]:s}'''
           )
         elif item_info[item].type == ITEM_WORD:
           if addr + 1 >= item_addr[item] + item_info[item].size:
@@ -570,9 +294,9 @@ with open(out_h, 'w') as fout:
     f'''#ifndef {include_guard:s}
 #define {include_guard:s}
 
-#include "vrEmu6502/src/vrEmu6502.h"
+#include "cpu_65c02.h"
 
-int execute(VrEmu6502 *cpu);
+void execute(struct cpu_65c02 *cpu);
 
 #endif
 '''