Preliminary 6809 CPU emulation, can compile but is not accurate yet
authorNick Downing <nick@ndcode.org>
Sun, 31 Jul 2022 01:51:40 +0000 (11:51 +1000)
committerNick Downing <nick@ndcode.org>
Sun, 31 Jul 2022 10:09:46 +0000 (20:09 +1000)
17 files changed:
.gitignore
.gitmodules
Makefile
VCC [new submodule]
basic_6800_test.txt [moved from basic_test.txt with 100% similarity]
basic_6809_test.txt [new file with mode: 0644]
cpu_65c02.h
cpu_6800.h
cpu_6809.c [new file with mode: 0644]
cpu_6809.h [new file with mode: 0644]
cpu_z80.h
decode_6809.py [new file with mode: 0755]
decode_6809.sh [new file with mode: 0755]
decode_6809_post.sed [new file with mode: 0644]
decode_6809_pre.sed [new file with mode: 0644]
emu_6800.c
emu_6809.c [new file with mode: 0644]

index 650b28f..b1823ec 100644 (file)
@@ -1,11 +1,16 @@
 *.ihx
 *.o
+/ExBasROM.hex
+/ExBasRom.zip
 /decode_65c02.txt
 /decode_6800.txt
+/decode_6809.txt
 /decode_z80.txt
 /emu_65c02
 /emu_65c02_alt
 /emu_6800
 /emu_6800_alt
+/emu_6809
+/emu_6809_alt
 /emu_z80
 /emu_z80_alt
index 7cd996f..6329dd7 100644 (file)
@@ -16,3 +16,6 @@
 [submodule "dasm09"]
        path = dasm09
        url = https://github.com/nickd4/dasm09.git
+[submodule "VCC"]
+       path = VCC
+       url = https://github.com/nickd4/VCC.git
index 7dafed7..0ecd5e5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ BIN2HEX=bin2hex.py
 CFLAGS=-g -Og -Wall -Wno-attributes -Wno-unused-function
 ALT_65C02_CFLAGS=-DALT_BACKEND=1 -DVR_6502_EMU_STATIC=1
 ALT_6800_CFLAGS=-DALT_BACKEND=1 -DUSE_PROTOTYPES -DM6800 -Isim68xx/inc/arch/m6800 -Isim68xx/inc/arch/m68xx -Isim68xx/inc/base
+ALT_6809_CFLAGS=-DALT_BACKEND=1 -IVCC
 
 .PHONY: all
 all: \
@@ -12,10 +13,15 @@ emu_65c02_alt \
 65C02_extended_opcodes_test.ihx \
 emu_6800 \
 emu_6800_alt \
+emu_6809 \
+emu_6809_alt \
+basic_6809.ihx \
+emu_8086_alt \
 emu_z80 \
 emu_z80_alt \
 zexall.ihx \
 zexdoc.ihx
+#emu_8086
 
 # 65C02
 emu_65c02: emu_65c02.o cpu_65c02.o
@@ -65,7 +71,6 @@ m6800_symtab.o \
 m6800_opfunc.o \
 m6800_optab.o
        ${CC} ${CFLAGS} -o $@ $^
-#m6800_alu.o
 
 emu_6800_alt.o: \
 emu_6800.c \
@@ -73,9 +78,6 @@ sim68xx/inc/arch/m68xx/instr.h \
 sim68xx/inc/arch/m68xx/reg.h
        ${CC} ${CFLAGS} ${ALT_6800_CFLAGS} -o $@ -c $<
 
-m6800_alu.o: sim68xx/src/arch/m68xx/alu.c
-       ${CC} ${CFLAGS} ${ALT_6800_CFLAGS} -o $@ -c $<
-
 m6800_callstac.o: sim68xx/src/base/callstac.c
        ${CC} ${CFLAGS} ${ALT_6800_CFLAGS} -o $@ -c $<
 
@@ -100,6 +102,56 @@ m6800_opfunc.o: sim68xx/src/arch/m68xx/opfunc.c
 m6800_optab.o: sim68xx/src/arch/m6800/optab.c
        ${CC} ${CFLAGS} ${ALT_6800_CFLAGS} -o $@ -c $<
 
+# 6809
+emu_6809: emu_6809.o cpu_6809.o
+       ${CC} ${CFLAGS} -o $@ $^
+
+emu_6809.o: cpu_6809.h
+
+cpu_6809.o: cpu_6809.h
+
+emu_6809_alt: \
+emu_6809_alt.o \
+mc6809.o
+       ${CC} ${CFLAGS} -o $@ $^
+
+emu_6809_alt.o: \
+emu_6809.c \
+VCC/mc6809.h \
+VCC/tcc1014mmu.h
+       ${CC} ${CFLAGS} ${ALT_6809_CFLAGS} -o $@ -c $<
+
+mc6809.o: VCC/mc6809.c
+       ${CC} ${CFLAGS} ${ALT_6809_CFLAGS} -o $@ -c $<
+
+basic_6809.ihx: ExBasROM.hex
+       dos2unix <$< >$@
+
+ExBasROM.hex: ExBasRom.zip
+       rm -f $@
+       unzip $< $@
+
+ExBasRom.zip:
+       rm -f $@
+       wget http://searle.x10host.com/6809/$@
+
+# 8086
+emu_8086: emu_8086.o cpu_8086.o
+       ${CC} ${CFLAGS} -o $@ $^
+
+emu_8086.o: cpu_8086.h
+
+cpu_8086.o: cpu_8086.h
+
+emu_8086_alt: emu_8086_alt.o 8086.o
+       ${CC} ${CFLAGS} -o $@ $^
+
+emu_8086_alt.o: emu_8086.c 8086/8086.h
+       ${CC} ${CFLAGS} -DALT_BACKEND=1 -o $@ -c $<
+
+8086.o: 8086/8086.c 8086/8086.h
+       ${CC} ${CFLAGS} -c $<
+
 # Z80
 emu_z80: emu_z80.o cpu_z80.o
        ${CC} ${CFLAGS} -o $@ $^
diff --git a/VCC b/VCC
new file mode 160000 (submodule)
index 0000000..abe411b
--- /dev/null
+++ b/VCC
@@ -0,0 +1 @@
+Subproject commit abe411b45eefd525cd0607571d3e316daa963081
similarity index 100%
rename from basic_test.txt
rename to basic_6800_test.txt
diff --git a/basic_6809_test.txt b/basic_6809_test.txt
new file mode 100644 (file)
index 0000000..bc6c8c5
--- /dev/null
@@ -0,0 +1,58 @@
+10 PRINT "HELLO"
+20 REM P9=X9^Y9 === GOSUB 60030
+30 X9=.3:Y9=.7:GOSUB 60030:PRINT .3^.7,P9
+40 REM L9=LOG(X9) === GOSUB 60090
+50 X9=.4:GOSUB 60090:PRINT LOG(.4),L9
+60 REM E9=EXP(X9) === GOSUB 60160
+70 X9=.5:GOSUB 60160:PRINT EXP(.5),E9
+80 REM C9=COS(X9) === GOSUB 60240
+90 X9=.6:GOSUB 60240:PRINT COS(.6),C9
+100 REM T9=TAN(X9) === GOSUB 60280
+110 X9=.7:GOSUB 60280:PRINT TAN(.7),T9
+120 REM A9=ATN(X9) === GOSUB 60310
+130 X9=.8:GOSUB 60310:PRINT ATN(.8),A9
+140 END
+60000 REM EXPONENTIATION: P9=X9^Y9
+60010 REM NEED: EXP, LOG
+60020 REM VARIABLES USED: A9,B9,C9,E9,L9,P9,X9,Y9
+60030 P9=1 : E9=0 : IF Y9=0 THEN RETURN
+60040 IF X9<0 THEN IF INT(Y9)=Y9 THEN P9=1-2*Y9+4*INT(Y9/2) : X9=-X9
+60050 IF X9<>0 THEN GOSUB 60090 : X9=Y9*L9 : GOSUB 60160
+60060 P9=P9*E9 : RETURN
+60070 REM NATURAL LOGARITHM: L9=LOG(X9)
+60080 REM VARIABLES USED: A9,B9,C9,E9,L9,X9
+60090 E9=0 : IF X9<=0 THEN PRINT "LOG FC ERROR"; : STOP
+60095 A9=1 : B9=2 : C9=.5 : REM THIS WILL SPEED UP THE FOLLOWING
+60100 IF X9>=A9 THEN X9=C9*X9 : E9=E9+A9 : GOTO 60100
+60110 IF X9<C9 THEN X9=B9*X9 : E9=E9-A9 : GOTO 60110
+60120 X9=(X9-.707107)/(X9+.707107) : L9=X9*X9
+60130 L9=(((.598979*L9+.961471)*L9+2.88539)*X9+E9-.5)*.693147
+60135 RETURN
+60140 REM EXPONENTIAL: E9=EXP(X9)
+60150 REM VARIABLES USED: A9,E9,L9,X9
+60160 L9=INT(1.4427*X9)+1 : IF L9<1E7 THEN 60180
+60170 IF X9>0 THEN PRINT "EXP OV ERROR"; : STOP
+60175 E9=0 : RETURN
+60180 E9=.693147*L9-X9 : A9=1.32988E-3-1.41316E-4*E9
+60190 A9=((A9*E9-8.30136E-3)*E9+4.16574E-2)*E9
+60195 E9=(((A9-.166665)*E9+.5)*E9-1)*E9+1 : A9=2
+60197 IF L9<=0 THEN A9=.5 : L9=-L9 : IF L9=0 THEN RETURN
+60200 FOR X9=1 TO L9 : E9=A9*E9 : NEXT X9 : RETURN
+60210 REM COSINE: C9=COS(X9)
+60220 REM N.B. SIN MUST BE RETAINED AT LOAD-TIME
+60230 REM VARIABLES USED: C9,X9
+60240 C9=SIN(X9+1.5708) : RETURN
+60250 REM TANGENT: T9=TAN(X9)
+60260 REM NEEDS COS. (SIN NUST BE RETAINED AT LOAD-TIME)
+60270 REM VARIABLES USED: C9,T9,X9
+60280 GOSUB 60240 : T9=SIN(X9)/C9 : RETURN
+60290 REM ARCTANGENT: A9=ATN(X9)
+60300 REM VARIABLES USED: A9,B9,C9,T9,X9
+60310 T9=SGN(X9): X9=ABS(X9): C9=0 : IF X9>1 THEN C9=1 : X9=1/X9
+60320 A9=X9*X9 : B9=((2.86623E-3*A9-1.61657E-2)*A9+4.29096E-2)*A9
+60330 B9=((((B9-7.5289E-2)*A9+.106563)*A9-.142089)*A9+.199936)*A9
+60340 A9=((B9-.333332)*A9+1)*X9 : IF C9=1 THEN A9=1.5708-A9
+60350 A9=T9*A9 : RETURN
+RUN
+                                                                                                                                                                                                
+PRINT "DONE"
index 2b27a43..b9101aa 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _CPU_65C02_H
 #define _CPU_65C02_H
 
+#include <endian.h>
 #include <stdbool.h>
 #include <stdint.h>
 
@@ -214,8 +215,7 @@ static ALWAYS_INLINE int cpu_65c02_ea_absolute_indirect(struct cpu_65c02 *self)
 }
 
 static ALWAYS_INLINE int cpu_65c02_ea_relative(struct cpu_65c02 *self) {
-  int offset = cpu_65c02_fetch_byte(self);
-  return offset - ((offset << 1) & 0x100);
+  return (int8_t)cpu_65c02_fetch_byte(self);
 }
 
 static ALWAYS_INLINE int cpu_65c02_ea_zero_page(struct cpu_65c02 *self) {
index fc3296a..5f9b09b 100644 (file)
@@ -1,7 +1,7 @@
-#include <stdio.h>
 #ifndef _CPU_6800_H
 #define _CPU_6800_H
 
+#include <endian.h>
 #include <stdbool.h>
 #include <stdint.h>
 
@@ -27,8 +27,8 @@
 #define CPU_6800_EA_PC (-0xa)
 #define CPU_6800_EA_A (-8)
 #define CPU_6800_EA_B (-7)
-#define CPU_6800_EA_X (-6)
-#define CPU_6800_EA_S (-4)
+#define CPU_6800_EA_S (-6)
+#define CPU_6800_EA_X (-4)
 #define CPU_6800_EA_P (-2)
 #define CPU_6800_EA_IFLAGS (-1)
 
@@ -41,8 +41,8 @@ union cpu_6800_regs {
     uint16_t _fill_pc;
     uint8_t _fill_a;
     uint8_t _fill_b;
-    uint16_t _fill_x;
     uint16_t _fill_s;
+    uint16_t _fill_x;
     uint8_t _fill_p : 2;
     uint8_t hf : 1;
     uint8_t _if : 1;
@@ -59,8 +59,8 @@ union cpu_6800_regs {
     uint16_t _fill_pc;
     uint8_t a;
     uint8_t b;
-    uint16_t _fill_x;
     uint16_t _fill_s;
+    uint16_t _fill_x;
     uint8_t p;
     uint8_t iflags;
   } byte;
@@ -68,8 +68,8 @@ union cpu_6800_regs {
     uint16_t pc;
     uint8_t _fill_a;
     uint8_t _fill_b;
-    uint16_t x;
     uint16_t s;
+    uint16_t x;
     uint8_t _fill_p;
     uint8_t _fill_iflags;
   } word;
@@ -87,8 +87,8 @@ union cpu_6800_regs {
     uint8_t _if : 1;
     uint8_t hf : 1;
     uint8_t _fill_p : 2;
-    uint16_t _fill_s;
     uint16_t _fill_x;
+    uint16_t _fill_s;
     uint8_t _fill_b;
     uint8_t _fill_a;
     uint16_t _fill_pc;
@@ -96,8 +96,8 @@ union cpu_6800_regs {
   struct {
     uint8_t iflags;
     uint8_t p;
-    uint16_t _fill_s;
     uint16_t _fill_x;
+    uint16_t _fill_s;
     uint8_t b;
     uint8_t a;
     uint16_t _fill_pc;
@@ -105,8 +105,8 @@ union cpu_6800_regs {
   struct {
     uint8_t _fill_iflags;
     uint8_t _fill_p;
-    uint16_t s;
     uint16_t x;
+    uint16_t s;
     uint8_t _fill_b;
     uint8_t _fill_a;
     uint16_t pc;
@@ -198,8 +198,7 @@ static ALWAYS_INLINE int cpu_6800_ea_extended_indexed(struct cpu_6800 *self, int
 }
 
 static ALWAYS_INLINE int cpu_6800_ea_relative(struct cpu_6800 *self) {
-  int offset = cpu_6800_fetch_byte(self);
-  return offset - ((offset << 1) & 0x100);
+  return (int8_t)cpu_6800_fetch_byte(self);
 }
 
 static ALWAYS_INLINE int cpu_6800_ea_direct(struct cpu_6800 *self) {
@@ -432,16 +431,6 @@ static ALWAYS_INLINE void cpu_6800_inc_word_zf(struct cpu_6800 *self, int lvalue
   self->regs.bit.zf = result == 0;
 }
 
-static ALWAYS_INLINE void cpu_6800_swi(struct cpu_6800 *self) {
-  cpu_6800_push_word(self, self->regs.word.pc);
-  cpu_6800_push_word(self, self->regs.word.x);
-  cpu_6800_push_byte(self, self->regs.byte.a);
-  cpu_6800_push_byte(self, self->regs.byte.b);
-  cpu_6800_push_byte(self, self->regs.byte.p);
-  self->regs.word.pc = cpu_6800_read_word(self, CPU_6800_SWI_VECTOR);
-  self->regs.bit._if = true;
-}
-
 static ALWAYS_INLINE void cpu_6800_jmp(struct cpu_6800 *self, int lvalue) {
   self->regs.word.pc = lvalue;
 }
@@ -593,6 +582,16 @@ static ALWAYS_INLINE void cpu_6800_sub(struct cpu_6800 *self, int lvalue, int rv
   self->regs.bit.cf = (result1 >> 8) & 1;
 }
 
+static ALWAYS_INLINE void cpu_6800_swi(struct cpu_6800 *self) {
+  cpu_6800_push_word(self, self->regs.word.pc);
+  cpu_6800_push_word(self, self->regs.word.x);
+  cpu_6800_push_byte(self, self->regs.byte.a);
+  cpu_6800_push_byte(self, self->regs.byte.b);
+  cpu_6800_push_byte(self, self->regs.byte.p);
+  self->regs.word.pc = cpu_6800_read_word(self, CPU_6800_SWI_VECTOR);
+  self->regs.bit._if = true;
+}
+
 static ALWAYS_INLINE void cpu_6800_tap(struct cpu_6800 *self) {
   self->regs.byte.p = self->regs.byte.a | 0xc0;
 }
diff --git a/cpu_6809.c b/cpu_6809.c
new file mode 100644 (file)
index 0000000..b8f7a7f
--- /dev/null
@@ -0,0 +1,3124 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpu_6809.h"
+
+// initialization
+void cpu_6809_init(
+  struct cpu_6809 *self,
+  int (*read_byte)(void *context, int addr),
+  void *read_byte_context,
+  void (*write_byte)(void *context, int addr, int data),
+  void *write_byte_context
+) {
+  memset(self, 0, sizeof(struct cpu_6809));
+  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_6809_reset(struct cpu_6809 *self) {
+  self->regs.word.pc = cpu_6809_read_word(self, CPU_6809_RESET_VECTOR);
+  self->regs.byte.iflags = 0;
+  self->regs.bit._if = true;
+}
+
+// instruction decode
+int cpu_6809_addressing_mode(struct cpu_6809 *self) {
+  int ea;
+  switch (cpu_6809_fetch_byte(self)) {
+  case 0x00:
+    ea = (0 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x01:
+    ea = (1 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x02:
+    ea = (2 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x03:
+    ea = (3 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x04:
+    ea = (4 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x05:
+    ea = (5 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x06:
+    ea = (6 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x07:
+    ea = (7 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x08:
+    ea = (8 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x09:
+    ea = (9 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x0a:
+    ea = (10 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x0b:
+    ea = (11 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x0c:
+    ea = (12 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x0d:
+    ea = (13 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x0e:
+    ea = (14 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x0f:
+    ea = (15 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x10:
+    ea = (-16 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x11:
+    ea = (-15 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x12:
+    ea = (-14 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x13:
+    ea = (-13 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x14:
+    ea = (-12 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x15:
+    ea = (-11 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x16:
+    ea = (-10 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x17:
+    ea = (-9 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x18:
+    ea = (-8 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x19:
+    ea = (-7 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x1a:
+    ea = (-6 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x1b:
+    ea = (-5 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x1c:
+    ea = (-4 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x1d:
+    ea = (-3 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x1e:
+    ea = (-2 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x1f:
+    ea = (-1 + self->regs.word.x) & 0xffff;
+    break;
+  case 0x20:
+    ea = (0 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x21:
+    ea = (1 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x22:
+    ea = (2 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x23:
+    ea = (3 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x24:
+    ea = (4 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x25:
+    ea = (5 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x26:
+    ea = (6 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x27:
+    ea = (7 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x28:
+    ea = (8 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x29:
+    ea = (9 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x2a:
+    ea = (10 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x2b:
+    ea = (11 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x2c:
+    ea = (12 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x2d:
+    ea = (13 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x2e:
+    ea = (14 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x2f:
+    ea = (15 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x30:
+    ea = (-16 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x31:
+    ea = (-15 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x32:
+    ea = (-14 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x33:
+    ea = (-13 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x34:
+    ea = (-12 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x35:
+    ea = (-11 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x36:
+    ea = (-10 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x37:
+    ea = (-9 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x38:
+    ea = (-8 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x39:
+    ea = (-7 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x3a:
+    ea = (-6 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x3b:
+    ea = (-5 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x3c:
+    ea = (-4 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x3d:
+    ea = (-3 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x3e:
+    ea = (-2 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x3f:
+    ea = (-1 + self->regs.word.y) & 0xffff;
+    break;
+  case 0x40:
+    ea = (0 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x41:
+    ea = (1 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x42:
+    ea = (2 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x43:
+    ea = (3 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x44:
+    ea = (4 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x45:
+    ea = (5 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x46:
+    ea = (6 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x47:
+    ea = (7 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x48:
+    ea = (8 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x49:
+    ea = (9 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x4a:
+    ea = (10 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x4b:
+    ea = (11 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x4c:
+    ea = (12 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x4d:
+    ea = (13 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x4e:
+    ea = (14 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x4f:
+    ea = (15 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x50:
+    ea = (-16 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x51:
+    ea = (-15 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x52:
+    ea = (-14 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x53:
+    ea = (-13 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x54:
+    ea = (-12 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x55:
+    ea = (-11 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x56:
+    ea = (-10 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x57:
+    ea = (-9 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x58:
+    ea = (-8 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x59:
+    ea = (-7 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x5a:
+    ea = (-6 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x5b:
+    ea = (-5 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x5c:
+    ea = (-4 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x5d:
+    ea = (-3 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x5e:
+    ea = (-2 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x5f:
+    ea = (-1 + self->regs.word.u) & 0xffff;
+    break;
+  case 0x60:
+    ea = (0 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x61:
+    ea = (1 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x62:
+    ea = (2 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x63:
+    ea = (3 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x64:
+    ea = (4 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x65:
+    ea = (5 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x66:
+    ea = (6 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x67:
+    ea = (7 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x68:
+    ea = (8 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x69:
+    ea = (9 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x6a:
+    ea = (10 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x6b:
+    ea = (11 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x6c:
+    ea = (12 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x6d:
+    ea = (13 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x6e:
+    ea = (14 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x6f:
+    ea = (15 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x70:
+    ea = (-16 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x71:
+    ea = (-15 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x72:
+    ea = (-14 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x73:
+    ea = (-13 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x74:
+    ea = (-12 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x75:
+    ea = (-11 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x76:
+    ea = (-10 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x77:
+    ea = (-9 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x78:
+    ea = (-8 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x79:
+    ea = (-7 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x7a:
+    ea = (-6 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x7b:
+    ea = (-5 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x7c:
+    ea = (-4 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x7d:
+    ea = (-3 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x7e:
+    ea = (-2 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x7f:
+    ea = (-1 + self->regs.word.s) & 0xffff;
+    break;
+  case 0x80:
+    ea = self->regs.word.x++;
+    break;
+  case 0x81:
+    ea = self->regs.word.x;
+    self->regs.word.x += 2;
+    break;
+  case 0x82:
+    ea = --self->regs.word.x;
+    break;
+  case 0x83:
+    self->regs.word.x -= 2;
+    ea = self->regs.word.x;
+    break;
+  case 0x84:
+    ea = self->regs.word.x;
+    break;
+  case 0x85:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.x) & 0xffff;
+    break;
+  case 0x86:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.x) & 0xffff;
+    break;
+  case 0x87:
+    cpu_6809_illegal_opcode(self);
+  case 0x88:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.x) & 0xffff;
+    break;
+  case 0x89:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.x) & 0xffff;
+    break;
+  case 0x8a:
+    cpu_6809_illegal_opcode(self);
+  case 0x8b:
+    ea = (self->regs.word.d + self->regs.word.x) & 0xffff;
+    break;
+  case 0x8c:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0x8d:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0x8e:
+    cpu_6809_illegal_opcode(self);
+  case 0x8f:
+    cpu_6809_illegal_opcode(self);
+  case 0x90:
+    cpu_6809_illegal_opcode(self);
+  case 0x91:
+    ea = self->regs.word.x;
+    self->regs.word.x += 2;
+    goto indirect;
+  case 0x92:
+    cpu_6809_illegal_opcode(self);
+  case 0x93:
+    self->regs.word.x -= 2;
+    ea = self->regs.word.x;
+    goto indirect;
+  case 0x94:
+    ea = self->regs.word.x;
+    goto indirect;
+  case 0x95:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.x) & 0xffff;
+    goto indirect;
+  case 0x96:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.x) & 0xffff;
+    goto indirect;
+  case 0x97:
+    cpu_6809_illegal_opcode(self);
+  case 0x98:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.x) & 0xffff;
+    goto indirect;
+  case 0x99:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.x) & 0xffff;
+    goto indirect;
+  case 0x9a:
+    cpu_6809_illegal_opcode(self);
+  case 0x9b:
+    ea = (self->regs.word.d + self->regs.word.x) & 0xffff;
+    goto indirect;
+  case 0x9c:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0x9d:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0x9e:
+    cpu_6809_illegal_opcode(self);
+  case 0x9f:
+    ea = cpu_6809_fetch_word(self);
+    goto indirect;
+  case 0xa0:
+    ea = self->regs.word.y++;
+    break;
+  case 0xa1:
+    ea = self->regs.word.y;
+    self->regs.word.y += 2;
+    break;
+  case 0xa2:
+    ea = --self->regs.word.y;
+    break;
+  case 0xa3:
+    self->regs.word.y -= 2;
+    ea = self->regs.word.y;
+    break;
+  case 0xa4:
+    ea = self->regs.word.y;
+    break;
+  case 0xa5:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.y) & 0xffff;
+    break;
+  case 0xa6:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.y) & 0xffff;
+    break;
+  case 0xa7:
+    cpu_6809_illegal_opcode(self);
+  case 0xa8:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.y) & 0xffff;
+    break;
+  case 0xa9:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.y) & 0xffff;
+    break;
+  case 0xaa:
+    cpu_6809_illegal_opcode(self);
+  case 0xab:
+    ea = (self->regs.word.d + self->regs.word.y) & 0xffff;
+    break;
+  case 0xac:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0xad:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0xae:
+    cpu_6809_illegal_opcode(self);
+  case 0xaf:
+    cpu_6809_illegal_opcode(self);
+  case 0xb0:
+    cpu_6809_illegal_opcode(self);
+  case 0xb1:
+    ea = self->regs.word.y;
+    self->regs.word.y += 2;
+    goto indirect;
+  case 0xb2:
+    cpu_6809_illegal_opcode(self);
+  case 0xb3:
+    self->regs.word.y -= 2;
+    ea = self->regs.word.y;
+    goto indirect;
+  case 0xb4:
+    ea = self->regs.word.y;
+    goto indirect;
+  case 0xb5:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.y) & 0xffff;
+    goto indirect;
+  case 0xb6:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.y) & 0xffff;
+    goto indirect;
+  case 0xb7:
+    cpu_6809_illegal_opcode(self);
+  case 0xb8:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.y) & 0xffff;
+    goto indirect;
+  case 0xb9:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.y) & 0xffff;
+    goto indirect;
+  case 0xba:
+    cpu_6809_illegal_opcode(self);
+  case 0xbb:
+    ea = (self->regs.word.d + self->regs.word.y) & 0xffff;
+    goto indirect;
+  case 0xbc:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0xbd:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0xbe:
+    cpu_6809_illegal_opcode(self);
+  case 0xbf:
+    cpu_6809_illegal_opcode(self);
+  case 0xc0:
+    ea = self->regs.word.u++;
+    break;
+  case 0xc1:
+    ea = self->regs.word.u;
+    self->regs.word.u += 2;
+    break;
+  case 0xc2:
+    ea = --self->regs.word.u;
+    break;
+  case 0xc3:
+    self->regs.word.u -= 2;
+    ea = self->regs.word.u;
+    break;
+  case 0xc4:
+    ea = self->regs.word.u;
+    break;
+  case 0xc5:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.u) & 0xffff;
+    break;
+  case 0xc6:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.u) & 0xffff;
+    break;
+  case 0xc7:
+    cpu_6809_illegal_opcode(self);
+  case 0xc8:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.u) & 0xffff;
+    break;
+  case 0xc9:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.u) & 0xffff;
+    break;
+  case 0xca:
+    cpu_6809_illegal_opcode(self);
+  case 0xcb:
+    ea = (self->regs.word.d + self->regs.word.u) & 0xffff;
+    break;
+  case 0xcc:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0xcd:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0xce:
+    cpu_6809_illegal_opcode(self);
+  case 0xcf:
+    cpu_6809_illegal_opcode(self);
+  case 0xd0:
+    cpu_6809_illegal_opcode(self);
+  case 0xd1:
+    ea = self->regs.word.u;
+    self->regs.word.u += 2;
+    goto indirect;
+  case 0xd2:
+    cpu_6809_illegal_opcode(self);
+  case 0xd3:
+    self->regs.word.u -= 2;
+    ea = self->regs.word.u;
+    goto indirect;
+  case 0xd4:
+    ea = self->regs.word.u;
+    goto indirect;
+  case 0xd5:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.u) & 0xffff;
+    goto indirect;
+  case 0xd6:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.u) & 0xffff;
+    goto indirect;
+  case 0xd7:
+    cpu_6809_illegal_opcode(self);
+  case 0xd8:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.u) & 0xffff;
+    goto indirect;
+  case 0xd9:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.u) & 0xffff;
+    goto indirect;
+  case 0xda:
+    cpu_6809_illegal_opcode(self);
+  case 0xdb:
+    ea = (self->regs.word.d + self->regs.word.u) & 0xffff;
+    goto indirect;
+  case 0xdc:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0xdd:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0xde:
+    cpu_6809_illegal_opcode(self);
+  case 0xdf:
+    cpu_6809_illegal_opcode(self);
+  case 0xe0:
+    ea = self->regs.word.s++;
+    break;
+  case 0xe1:
+    ea = self->regs.word.s;
+    self->regs.word.s += 2;
+    break;
+  case 0xe2:
+    ea = --self->regs.word.s;
+    break;
+  case 0xe3:
+    self->regs.word.s -= 2;
+    ea = self->regs.word.s;
+    break;
+  case 0xe4:
+    ea = self->regs.word.s;
+    break;
+  case 0xe5:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.s) & 0xffff;
+    break;
+  case 0xe6:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.s) & 0xffff;
+    break;
+  case 0xe7:
+    cpu_6809_illegal_opcode(self);
+  case 0xe8:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.s) & 0xffff;
+    break;
+  case 0xe9:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.s) & 0xffff;
+    break;
+  case 0xea:
+    cpu_6809_illegal_opcode(self);
+  case 0xeb:
+    ea = (self->regs.word.d + self->regs.word.s) & 0xffff;
+    break;
+  case 0xec:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0xed:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+    break;
+  case 0xee:
+    cpu_6809_illegal_opcode(self);
+  case 0xef:
+    cpu_6809_illegal_opcode(self);
+  case 0xf0:
+    cpu_6809_illegal_opcode(self);
+  case 0xf1:
+    ea = self->regs.word.s;
+    self->regs.word.s += 2;
+    goto indirect;
+  case 0xf2:
+    cpu_6809_illegal_opcode(self);
+  case 0xf3:
+    self->regs.word.s -= 2;
+    ea = self->regs.word.s;
+    goto indirect;
+  case 0xf4:
+    ea = self->regs.word.s;
+    goto indirect;
+  case 0xf5:
+    ea = ((int8_t)self->regs.byte.b + self->regs.word.s) & 0xffff;
+    goto indirect;
+  case 0xf6:
+    ea = ((int8_t)self->regs.byte.a + self->regs.word.s) & 0xffff;
+    goto indirect;
+  case 0xf7:
+    cpu_6809_illegal_opcode(self);
+  case 0xf8:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.s) & 0xffff;
+    goto indirect;
+  case 0xf9:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.s) & 0xffff;
+    goto indirect;
+  case 0xfa:
+    cpu_6809_illegal_opcode(self);
+  case 0xfb:
+    ea = (self->regs.word.d + self->regs.word.s) & 0xffff;
+    goto indirect;
+  case 0xfc:
+    ea = ((int8_t)cpu_6809_fetch_byte(self) + self->regs.word.pc) & 0xffff;
+    goto indirect;
+  case 0xfd:
+    ea = (cpu_6809_fetch_word(self) + self->regs.word.pc) & 0xffff;
+  indirect:
+    ea = cpu_6809_read_word(self, ea);
+    break;
+  case 0xfe:
+    cpu_6809_illegal_opcode(self);
+  case 0xff:
+    cpu_6809_illegal_opcode(self);
+  }
+  return ea;
+}
+
+void cpu_6809_execute(struct cpu_6809 *self) {
+  if (self->regs.bit.nmi_pending) {
+    self->regs.bit.nmi_pending = false;
+    if (!self->regs.bit.wai_flag)
+      cpu_6809_cwai(self, 0);
+    self->regs.bit.wai_flag = false;
+    self->regs.word.pc = cpu_6809_read_word(self, CPU_6809_NMI_VECTOR);
+    self->regs.bit._if = true;
+    return;
+  }
+
+  if (self->regs.bit.irq_pending && !self->regs.bit._if) {
+    self->regs.bit.irq_pending = false;
+    if (!self->regs.bit.wai_flag)
+      cpu_6809_cwai(self, 0);
+    self->regs.bit.wai_flag = false;
+    self->regs.word.pc = cpu_6809_read_word(self, CPU_6809_IRQ_VECTOR);
+    self->regs.bit._if = true;
+    return;
+  }
+
+  if (self->regs.bit.wai_flag) {
+    ++self->cycles;
+    return;
+  }
+
+  switch (cpu_6809_fetch_byte(self)) {
+  case 0x00:
+    cpu_6809_neg(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x01:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x02:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x03:
+    cpu_6809_com(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x04:
+    cpu_6809_lsr(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x05:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x06:
+    cpu_6809_ror(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x07:
+    cpu_6809_asr(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x08:
+    cpu_6809_asl(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x09:
+    cpu_6809_rol(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x0a:
+    cpu_6809_dec_byte(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x0b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0c:
+    cpu_6809_inc_byte(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x0d:
+    cpu_6809_cmp_byte(self, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)), 0);
+    break;
+  case 0x0e:
+    cpu_6809_jmp(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x0f:
+    cpu_6809_clr(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x10:
+    cpu_6809_execute_10(self);
+    break;
+  case 0x11:
+    cpu_6809_execute_11(self);
+    break;
+  case 0x12:
+    cpu_6809_nop(self);
+    break;
+  case 0x13:
+    cpu_6809_sync(self);
+    break;
+  case 0x14:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x15:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x16:
+    cpu_6809_lbra(self, true, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x17:
+    cpu_6809_lbsr(self, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x18:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x19:
+    cpu_6809_daa(self);
+    break;
+  case 0x1a:
+    cpu_6809_orcc(self, cpu_6809_fetch_byte(self));
+    break;
+  case 0x1b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1c:
+    cpu_6809_andcc(self, cpu_6809_fetch_byte(self));
+    break;
+  case 0x1d:
+    cpu_6809_sex(self);
+    break;
+  case 0x1e:
+    cpu_6809_exg(self, cpu_6809_fetch_byte(self));
+    break;
+  case 0x1f:
+    cpu_6809_tfr(self, cpu_6809_fetch_byte(self));
+    break;
+  case 0x20:
+    cpu_6809_bra(self, true, cpu_6809_ea_relative(self));
+    break;
+  case 0x21:
+    cpu_6809_bra(self, false, cpu_6809_ea_relative(self));
+    break;
+  case 0x22:
+    cpu_6809_bra(self, !self->regs.bit.cf && !self->regs.bit.zf, cpu_6809_ea_relative(self));
+    break;
+  case 0x23:
+    cpu_6809_bra(self, self->regs.bit.cf || self->regs.bit.zf, cpu_6809_ea_relative(self));
+    break;
+  case 0x24:
+    cpu_6809_bra(self, !self->regs.bit.cf, cpu_6809_ea_relative(self));
+    break;
+  case 0x25:
+    cpu_6809_bra(self, self->regs.bit.cf, cpu_6809_ea_relative(self));
+    break;
+  case 0x26:
+    cpu_6809_bra(self, !self->regs.bit.zf, cpu_6809_ea_relative(self));
+    break;
+  case 0x27:
+    cpu_6809_bra(self, self->regs.bit.zf, cpu_6809_ea_relative(self));
+    break;
+  case 0x28:
+    cpu_6809_bra(self, !self->regs.bit.vf, cpu_6809_ea_relative(self));
+    break;
+  case 0x29:
+    cpu_6809_bra(self, self->regs.bit.vf, cpu_6809_ea_relative(self));
+    break;
+  case 0x2a:
+    cpu_6809_bra(self, !self->regs.bit.nf, cpu_6809_ea_relative(self));
+    break;
+  case 0x2b:
+    cpu_6809_bra(self, self->regs.bit.nf, cpu_6809_ea_relative(self));
+    break;
+  case 0x2c:
+    cpu_6809_bra(self, !self->regs.bit.nf && !self->regs.bit.vf, cpu_6809_ea_relative(self));
+    break;
+  case 0x2d:
+    cpu_6809_bra(self, self->regs.bit.nf || self->regs.bit.vf, cpu_6809_ea_relative(self));
+    break;
+  case 0x2e:
+    cpu_6809_bra(self, !self->regs.bit.nf && !self->regs.bit.vf && !self->regs.bit.zf, cpu_6809_ea_relative(self));
+    break;
+  case 0x2f:
+    cpu_6809_bra(self, self->regs.bit.nf || self->regs.bit.vf || self->regs.bit.zf, cpu_6809_ea_relative(self));
+    break;
+  case 0x30:
+    cpu_6809_lea(self, CPU_6809_EA_X, cpu_6809_addressing_mode(self));
+    break;
+  case 0x31:
+    cpu_6809_lea(self, CPU_6809_EA_Y, cpu_6809_addressing_mode(self));
+    break;
+  case 0x32:
+    cpu_6809_lea(self, CPU_6809_EA_S, cpu_6809_addressing_mode(self));
+    break;
+  case 0x33:
+    cpu_6809_lea(self, CPU_6809_EA_U, cpu_6809_addressing_mode(self));
+    break;
+  case 0x34:
+    cpu_6809_psh(self, CPU_6809_EA_S, cpu_6809_fetch_byte(self));
+    break;
+  case 0x35:
+    cpu_6809_pul(self, CPU_6809_EA_S, cpu_6809_fetch_byte(self));
+    break;
+  case 0x36:
+    cpu_6809_psh(self, CPU_6809_EA_U, cpu_6809_fetch_byte(self));
+    break;
+  case 0x37:
+    cpu_6809_pul(self, CPU_6809_EA_U, cpu_6809_fetch_byte(self));
+    break;
+  case 0x38:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x39:
+    cpu_6809_rts(self);
+    break;
+  case 0x3a:
+    cpu_6809_add_word(self, CPU_6809_EA_X, self->regs.byte.b);
+    break;
+  case 0x3b:
+    cpu_6809_rti(self);
+    break;
+  case 0x3c:
+    cpu_6809_cwai(self, cpu_6809_fetch_byte(self));
+    break;
+  case 0x3d:
+    cpu_6809_mul(self);
+    break;
+  case 0x3e:
+    cpu_6809_reset(self);
+    break;
+  case 0x3f:
+    cpu_6809_swi(self);
+    break;
+  case 0x40:
+    cpu_6809_neg(self, CPU_6809_EA_A);
+    break;
+  case 0x41:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x42:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x43:
+    cpu_6809_com(self, CPU_6809_EA_A);
+    break;
+  case 0x44:
+    cpu_6809_lsr(self, CPU_6809_EA_A);
+    break;
+  case 0x45:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x46:
+    cpu_6809_ror(self, CPU_6809_EA_A);
+    break;
+  case 0x47:
+    cpu_6809_asr(self, CPU_6809_EA_A);
+    break;
+  case 0x48:
+    cpu_6809_asl(self, CPU_6809_EA_A);
+    break;
+  case 0x49:
+    cpu_6809_rol(self, CPU_6809_EA_A);
+    break;
+  case 0x4a:
+    cpu_6809_dec_byte(self, CPU_6809_EA_A);
+    break;
+  case 0x4b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4c:
+    cpu_6809_inc_byte(self, CPU_6809_EA_A);
+    break;
+  case 0x4d:
+    cpu_6809_cmp_byte(self, self->regs.byte.a, 0);
+    break;
+  case 0x4e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4f:
+    cpu_6809_clr(self, CPU_6809_EA_A);
+    break;
+  case 0x50:
+    cpu_6809_neg(self, CPU_6809_EA_B);
+    break;
+  case 0x51:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x52:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x53:
+    cpu_6809_com(self, CPU_6809_EA_B);
+    break;
+  case 0x54:
+    cpu_6809_lsr(self, CPU_6809_EA_B);
+    break;
+  case 0x55:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x56:
+    cpu_6809_ror(self, CPU_6809_EA_B);
+    break;
+  case 0x57:
+    cpu_6809_asr(self, CPU_6809_EA_B);
+    break;
+  case 0x58:
+    cpu_6809_asl(self, CPU_6809_EA_B);
+    break;
+  case 0x59:
+    cpu_6809_rol(self, CPU_6809_EA_B);
+    break;
+  case 0x5a:
+    cpu_6809_dec_byte(self, CPU_6809_EA_B);
+    break;
+  case 0x5b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5c:
+    cpu_6809_inc_byte(self, CPU_6809_EA_B);
+    break;
+  case 0x5d:
+    cpu_6809_cmp_byte(self, self->regs.byte.b, 0);
+    break;
+  case 0x5e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5f:
+    cpu_6809_clr(self, CPU_6809_EA_B);
+    break;
+  case 0x60:
+    cpu_6809_neg(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x61:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x62:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x63:
+    cpu_6809_com(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x64:
+    cpu_6809_lsr(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x65:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x66:
+    cpu_6809_ror(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x67:
+    cpu_6809_asr(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x68:
+    cpu_6809_asl(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x69:
+    cpu_6809_rol(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x6a:
+    cpu_6809_dec_byte(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x6b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6c:
+    cpu_6809_inc_byte(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x6d:
+    cpu_6809_cmp_byte(self, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)), 0);
+    break;
+  case 0x6e:
+    cpu_6809_jmp(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x6f:
+    cpu_6809_clr(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0x70:
+    cpu_6809_neg(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x71:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x72:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x73:
+    cpu_6809_com(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x74:
+    cpu_6809_lsr(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x75:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x76:
+    cpu_6809_ror(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x77:
+    cpu_6809_asr(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x78:
+    cpu_6809_asl(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x79:
+    cpu_6809_rol(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x7a:
+    cpu_6809_dec_byte(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x7b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7c:
+    cpu_6809_inc_byte(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x7d:
+    cpu_6809_cmp_byte(self, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)), 0);
+    break;
+  case 0x7e:
+    cpu_6809_jmp(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x7f:
+    cpu_6809_clr(self, cpu_6809_ea_extended(self));
+    break;
+  case 0x80:
+    cpu_6809_sub_byte(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x81:
+    cpu_6809_cmp_byte(self, self->regs.byte.a, cpu_6809_fetch_byte(self));
+    break;
+  case 0x82:
+    cpu_6809_sbc(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x83:
+    cpu_6809_sub_word(self, CPU_6809_EA_D, cpu_6809_fetch_word(self));
+    break;
+  case 0x84:
+    cpu_6809_and(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x85:
+    cpu_6809_bit(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x86:
+    cpu_6809_ld_byte(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x87:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x88:
+    cpu_6809_eor(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x89:
+    cpu_6809_adc(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x8a:
+    cpu_6809_or(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x8b:
+    cpu_6809_add_byte(self, CPU_6809_EA_A, cpu_6809_fetch_byte(self));
+    break;
+  case 0x8c:
+    cpu_6809_cmp_word(self, self->regs.word.x, cpu_6809_fetch_word(self));
+    break;
+  case 0x8d:
+    cpu_6809_bsr(self, cpu_6809_ea_relative(self));
+    break;
+  case 0x8e:
+    cpu_6809_ld_word(self, CPU_6809_EA_X, cpu_6809_fetch_word(self));
+    break;
+  case 0x8f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x90:
+    cpu_6809_sub_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x91:
+    cpu_6809_cmp_byte(self, self->regs.byte.a, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x92:
+    cpu_6809_sbc(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x93:
+    cpu_6809_sub_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x94:
+    cpu_6809_and(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x95:
+    cpu_6809_bit(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x96:
+    cpu_6809_ld_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x97:
+    cpu_6809_st_byte(self, self->regs.byte.a, cpu_6809_ea_direct(self));
+    break;
+  case 0x98:
+    cpu_6809_eor(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x99:
+    cpu_6809_adc(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9a:
+    cpu_6809_or(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9b:
+    cpu_6809_add_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9c:
+    cpu_6809_cmp_word(self, self->regs.word.x, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9d:
+    cpu_6809_jsr(self, cpu_6809_ea_direct(self));
+    break;
+  case 0x9e:
+    cpu_6809_ld_word(self, CPU_6809_EA_X, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9f:
+    cpu_6809_st_word(self, self->regs.word.x, cpu_6809_ea_direct(self));
+    break;
+  case 0xa0:
+    cpu_6809_sub_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa1:
+    cpu_6809_cmp_byte(self, self->regs.byte.a, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa2:
+    cpu_6809_sbc(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa3:
+    cpu_6809_sub_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa4:
+    cpu_6809_and(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa5:
+    cpu_6809_bit(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa6:
+    cpu_6809_ld_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa7:
+    cpu_6809_st_byte(self, self->regs.byte.a, cpu_6809_addressing_mode(self));
+    break;
+  case 0xa8:
+    cpu_6809_eor(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa9:
+    cpu_6809_adc(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xaa:
+    cpu_6809_or(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xab:
+    cpu_6809_add_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xac:
+    cpu_6809_cmp_word(self, self->regs.word.x, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xad:
+    cpu_6809_jsr(self, cpu_6809_addressing_mode(self));
+    break;
+  case 0xae:
+    cpu_6809_ld_word(self, CPU_6809_EA_X, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xaf:
+    cpu_6809_st_word(self, self->regs.word.x, cpu_6809_addressing_mode(self));
+    break;
+  case 0xb0:
+    cpu_6809_sub_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb1:
+    cpu_6809_cmp_byte(self, self->regs.byte.a, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb2:
+    cpu_6809_sbc(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb3:
+    cpu_6809_sub_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb4:
+    cpu_6809_and(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb5:
+    cpu_6809_bit(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb6:
+    cpu_6809_ld_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb7:
+    cpu_6809_st_byte(self, self->regs.byte.a, cpu_6809_ea_extended(self));
+    break;
+  case 0xb8:
+    cpu_6809_eor(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb9:
+    cpu_6809_adc(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xba:
+    cpu_6809_or(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbb:
+    cpu_6809_add_byte(self, CPU_6809_EA_A, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbc:
+    cpu_6809_cmp_word(self, self->regs.word.x, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbd:
+    cpu_6809_jsr(self, cpu_6809_ea_extended(self));
+    break;
+  case 0xbe:
+    cpu_6809_ld_word(self, CPU_6809_EA_X, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbf:
+    cpu_6809_st_word(self, self->regs.word.x, cpu_6809_ea_extended(self));
+    break;
+  case 0xc0:
+    cpu_6809_sub_byte(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc1:
+    cpu_6809_cmp_byte(self, self->regs.byte.b, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc2:
+    cpu_6809_sbc(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc3:
+    cpu_6809_add_word(self, CPU_6809_EA_D, cpu_6809_fetch_word(self));
+    break;
+  case 0xc4:
+    cpu_6809_and(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc5:
+    cpu_6809_bit(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc6:
+    cpu_6809_ld_byte(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc8:
+    cpu_6809_eor(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xc9:
+    cpu_6809_adc(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xca:
+    cpu_6809_or(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xcb:
+    cpu_6809_add_byte(self, CPU_6809_EA_B, cpu_6809_fetch_byte(self));
+    break;
+  case 0xcc:
+    cpu_6809_ld_word(self, CPU_6809_EA_D, cpu_6809_fetch_word(self));
+    break;
+  case 0xcd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xce:
+    cpu_6809_ld_word(self, CPU_6809_EA_U, cpu_6809_fetch_word(self));
+    break;
+  case 0xcf:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd0:
+    cpu_6809_sub_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd1:
+    cpu_6809_cmp_byte(self, self->regs.byte.b, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd2:
+    cpu_6809_sbc(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd3:
+    cpu_6809_add_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd4:
+    cpu_6809_and(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd5:
+    cpu_6809_bit(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd6:
+    cpu_6809_ld_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd7:
+    cpu_6809_st_byte(self, self->regs.byte.b, cpu_6809_ea_direct(self));
+    break;
+  case 0xd8:
+    cpu_6809_eor(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xd9:
+    cpu_6809_adc(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xda:
+    cpu_6809_or(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xdb:
+    cpu_6809_add_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xdc:
+    cpu_6809_ld_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xdd:
+    cpu_6809_st_word(self, self->regs.word.d, cpu_6809_ea_direct(self));
+    break;
+  case 0xde:
+    cpu_6809_ld_word(self, CPU_6809_EA_U, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xdf:
+    cpu_6809_st_word(self, self->regs.word.u, cpu_6809_ea_direct(self));
+    break;
+  case 0xe0:
+    cpu_6809_sub_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe1:
+    cpu_6809_cmp_byte(self, self->regs.byte.b, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe2:
+    cpu_6809_sbc(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe3:
+    cpu_6809_add_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe4:
+    cpu_6809_and(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe5:
+    cpu_6809_bit(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe6:
+    cpu_6809_ld_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe7:
+    cpu_6809_st_byte(self, self->regs.byte.b, cpu_6809_addressing_mode(self));
+    break;
+  case 0xe8:
+    cpu_6809_eor(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xe9:
+    cpu_6809_adc(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xea:
+    cpu_6809_or(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xeb:
+    cpu_6809_add_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xec:
+    cpu_6809_ld_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xed:
+    cpu_6809_st_word(self, self->regs.word.d, cpu_6809_addressing_mode(self));
+    break;
+  case 0xee:
+    cpu_6809_ld_word(self, CPU_6809_EA_U, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xef:
+    cpu_6809_st_word(self, self->regs.word.u, cpu_6809_addressing_mode(self));
+    break;
+  case 0xf0:
+    cpu_6809_sub_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf1:
+    cpu_6809_cmp_byte(self, self->regs.byte.b, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf2:
+    cpu_6809_sbc(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf3:
+    cpu_6809_add_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf4:
+    cpu_6809_and(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf5:
+    cpu_6809_bit(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf6:
+    cpu_6809_ld_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf7:
+    cpu_6809_st_byte(self, self->regs.byte.b, cpu_6809_ea_extended(self));
+    break;
+  case 0xf8:
+    cpu_6809_eor(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xf9:
+    cpu_6809_adc(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xfa:
+    cpu_6809_or(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xfb:
+    cpu_6809_add_byte(self, CPU_6809_EA_B, cpu_6809_read_byte(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xfc:
+    cpu_6809_ld_word(self, CPU_6809_EA_D, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xfd:
+    cpu_6809_st_word(self, self->regs.word.d, cpu_6809_ea_extended(self));
+    break;
+  case 0xfe:
+    cpu_6809_ld_word(self, CPU_6809_EA_U, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xff:
+    cpu_6809_st_word(self, self->regs.word.u, cpu_6809_ea_extended(self));
+    break;
+  }
+}
+
+void cpu_6809_execute_10(struct cpu_6809 *self) {
+  switch (cpu_6809_fetch_byte(self)) {
+  case 0x00:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x01:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x02:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x03:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x04:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x05:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x06:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x07:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x08:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x09:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x10:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x11:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x12:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x13:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x14:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x15:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x16:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x17:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x18:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x19:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x20:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x21:
+    cpu_6809_lbra(self, false, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x22:
+    cpu_6809_lbra(self, !self->regs.bit.cf && !self->regs.bit.zf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x23:
+    cpu_6809_lbra(self, self->regs.bit.cf || self->regs.bit.zf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x24:
+    cpu_6809_lbra(self, !self->regs.bit.cf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x25:
+    cpu_6809_lbra(self, self->regs.bit.cf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x26:
+    cpu_6809_lbra(self, !self->regs.bit.zf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x27:
+    cpu_6809_lbra(self, self->regs.bit.zf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x28:
+    cpu_6809_lbra(self, !self->regs.bit.vf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x29:
+    cpu_6809_lbra(self, self->regs.bit.vf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x2a:
+    cpu_6809_lbra(self, !self->regs.bit.nf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x2b:
+    cpu_6809_lbra(self, self->regs.bit.nf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x2c:
+    cpu_6809_lbra(self, !self->regs.bit.nf && !self->regs.bit.vf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x2d:
+    cpu_6809_lbra(self, self->regs.bit.nf || self->regs.bit.vf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x2e:
+    cpu_6809_lbra(self, !self->regs.bit.nf && !self->regs.bit.vf && !self->regs.bit.zf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x2f:
+    cpu_6809_lbra(self, self->regs.bit.nf || self->regs.bit.vf || self->regs.bit.zf, cpu_6809_ea_long_relative(self));
+    break;
+  case 0x30:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x31:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x32:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x33:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x34:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x35:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x36:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x37:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x38:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x39:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3f:
+    cpu_6809_swi_n(self, 2);
+    break;
+  case 0x40:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x41:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x42:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x43:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x44:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x45:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x46:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x47:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x48:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x49:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x50:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x51:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x52:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x53:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x54:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x55:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x56:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x57:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x58:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x59:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x60:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x61:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x62:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x63:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x64:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x65:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x66:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x67:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x68:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x69:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x70:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x71:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x72:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x73:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x74:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x75:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x76:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x77:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x78:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x79:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x80:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x81:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x82:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x83:
+    cpu_6809_cmp_word(self, self->regs.word.d, cpu_6809_fetch_word(self));
+    break;
+  case 0x84:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x85:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x86:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x87:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x88:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x89:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8c:
+    cpu_6809_cmp_word(self, self->regs.word.y, cpu_6809_fetch_word(self));
+    break;
+  case 0x8d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8e:
+    cpu_6809_ld_word(self, CPU_6809_EA_Y, cpu_6809_fetch_word(self));
+    break;
+  case 0x8f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x90:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x91:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x92:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x93:
+    cpu_6809_cmp_word(self, self->regs.word.d, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x94:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x95:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x96:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x97:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x98:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x99:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9c:
+    cpu_6809_cmp_word(self, self->regs.word.y, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9e:
+    cpu_6809_ld_word(self, CPU_6809_EA_Y, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9f:
+    cpu_6809_st_word(self, self->regs.word.y, cpu_6809_ea_direct(self));
+    break;
+  case 0xa0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa3:
+    cpu_6809_cmp_word(self, self->regs.word.d, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xaa:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xab:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xac:
+    cpu_6809_cmp_word(self, self->regs.word.y, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xad:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xae:
+    cpu_6809_ld_word(self, CPU_6809_EA_Y, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xaf:
+    cpu_6809_st_word(self, self->regs.word.y, cpu_6809_addressing_mode(self));
+    break;
+  case 0xb0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb3:
+    cpu_6809_cmp_word(self, self->regs.word.d, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xba:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbc:
+    cpu_6809_cmp_word(self, self->regs.word.y, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbe:
+    cpu_6809_ld_word(self, CPU_6809_EA_Y, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbf:
+    cpu_6809_st_word(self, self->regs.word.y, cpu_6809_ea_extended(self));
+    break;
+  case 0xc0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xca:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcc:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xce:
+    cpu_6809_ld_word(self, CPU_6809_EA_S, cpu_6809_fetch_word(self));
+    break;
+  case 0xcf:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xda:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdc:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xde:
+    cpu_6809_ld_word(self, CPU_6809_EA_S, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0xdf:
+    cpu_6809_st_word(self, self->regs.word.s, cpu_6809_ea_direct(self));
+    break;
+  case 0xe0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xea:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xeb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xec:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xed:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xee:
+    cpu_6809_ld_word(self, CPU_6809_EA_S, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xef:
+    cpu_6809_st_word(self, self->regs.word.s, cpu_6809_addressing_mode(self));
+    break;
+  case 0xf0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfa:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfc:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfe:
+    cpu_6809_ld_word(self, CPU_6809_EA_S, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xff:
+    cpu_6809_st_word(self, self->regs.word.s, cpu_6809_ea_extended(self));
+    break;
+  }
+}
+
+void cpu_6809_execute_11(struct cpu_6809 *self) {
+  switch (cpu_6809_fetch_byte(self)) {
+  case 0x00:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x01:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x02:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x03:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x04:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x05:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x06:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x07:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x08:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x09:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x0f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x10:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x11:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x12:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x13:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x14:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x15:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x16:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x17:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x18:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x19:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x1f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x20:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x21:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x22:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x23:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x24:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x25:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x26:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x27:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x28:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x29:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x2a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x2b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x2c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x2d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x2e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x2f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x30:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x31:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x32:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x33:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x34:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x35:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x36:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x37:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x38:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x39:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x3f:
+    cpu_6809_swi_n(self, 3);
+    break;
+  case 0x40:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x41:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x42:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x43:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x44:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x45:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x46:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x47:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x48:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x49:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x4f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x50:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x51:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x52:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x53:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x54:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x55:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x56:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x57:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x58:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x59:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x5f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x60:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x61:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x62:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x63:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x64:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x65:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x66:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x67:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x68:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x69:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x6f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x70:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x71:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x72:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x73:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x74:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x75:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x76:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x77:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x78:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x79:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7c:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x7f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x80:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x81:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x82:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x83:
+    cpu_6809_cmp_word(self, self->regs.word.u, cpu_6809_fetch_word(self));
+    break;
+  case 0x84:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x85:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x86:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x87:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x88:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x89:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8c:
+    cpu_6809_cmp_word(self, self->regs.word.s, cpu_6809_fetch_word(self));
+    break;
+  case 0x8d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x8f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x90:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x91:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x92:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x93:
+    cpu_6809_cmp_word(self, self->regs.word.u, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x94:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x95:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x96:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x97:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x98:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x99:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9a:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9b:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9c:
+    cpu_6809_cmp_word(self, self->regs.word.s, cpu_6809_read_word(self, cpu_6809_ea_direct(self)));
+    break;
+  case 0x9d:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9e:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0x9f:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa3:
+    cpu_6809_cmp_word(self, self->regs.word.u, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xa4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xa9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xaa:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xab:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xac:
+    cpu_6809_cmp_word(self, self->regs.word.s, cpu_6809_read_word(self, cpu_6809_addressing_mode(self)));
+    break;
+  case 0xad:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xae:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xaf:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb3:
+    cpu_6809_cmp_word(self, self->regs.word.u, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xb4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xb9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xba:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbc:
+    cpu_6809_cmp_word(self, self->regs.word.s, cpu_6809_read_word(self, cpu_6809_ea_extended(self)));
+    break;
+  case 0xbd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbe:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xbf:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xc9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xca:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcc:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xce:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xcf:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xd9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xda:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdc:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xde:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xdf:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xe9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xea:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xeb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xec:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xed:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xee:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xef:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf0:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf1:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf2:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf3:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf4:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf5:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf6:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf7:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf8:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xf9:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfa:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfb:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfc:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfd:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xfe:
+    cpu_6809_illegal_opcode(self);
+    break;
+  case 0xff:
+    cpu_6809_illegal_opcode(self);
+    break;
+  }
+}
diff --git a/cpu_6809.h b/cpu_6809.h
new file mode 100644 (file)
index 0000000..e48fce8
--- /dev/null
@@ -0,0 +1,703 @@
+#ifndef _CPU_6809_H
+#define _CPU_6809_H
+
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+// gcc specific
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE __attribute__((always_inline))
+#endif
+
+#define CPU_6809_IRQ_VECTOR 0xfff8
+#define CPU_6809_SWI_VECTOR 0xfffa
+#define CPU_6809_NMI_VECTOR 0xfffc
+#define CPU_6809_RESET_VECTOR 0xfffe
+
+// bits within REG_CC
+#define CPU_6809_REG_CC_BIT_H 5
+#define CPU_6809_REG_CC_BIT_I 4
+#define CPU_6809_REG_CC_BIT_N 3
+#define CPU_6809_REG_CC_BIT_Z 2
+#define CPU_6809_REG_CC_BIT_V 1
+#define CPU_6809_REG_CC_BIT_C 0
+
+// special memory locations (negative address)
+#define CPU_6809_EA_PC (-0xe)
+#define CPU_6809_EA_D (-0xc)
+#define CPU_6809_EA_A (-0xc)
+#define CPU_6809_EA_B (-0xb)
+#define CPU_6809_EA_U (-0xa)
+#define CPU_6809_EA_S (-8)
+#define CPU_6809_EA_X (-6)
+#define CPU_6809_EA_Y (-4)
+#define CPU_6809_EA_P (-2)
+#define CPU_6809_EA_IFLAGS (-1)
+
+// registers, in same order as special memory locations, but reversed on
+// little endian hardware where special memory address will be complemented
+// (this allows special memory to always look like it is big endian)
+union cpu_6809_regs {
+#if __BYTE_ORDER == __BIG_ENDIAN
+  struct {
+    uint16_t _fill_pc;
+    uint16_t _fill_d;
+    uint16_t _fill_u;
+    uint16_t _fill_s;
+    uint16_t _fill_x;
+    uint16_t _fill_y;
+    uint8_t ef : 1;
+    uint8_t ff : 1;
+    uint8_t hf : 1;
+    uint8_t _if : 1;
+    uint8_t nf : 1;
+    uint8_t zf : 1;
+    uint8_t vf : 1;
+    uint8_t cf : 1;
+    uint8_t _fill_iflags : 5;
+    uint8_t wai_flag : 1;
+    uint8_t irq_pending : 1;
+    uint8_t nmi_pending : 1;
+  } bit;
+  struct {
+    uint16_t _fill_pc;
+    uint8_t a;
+    uint8_t b;
+    uint16_t _fill_u;
+    uint16_t _fill_s;
+    uint16_t _fill_x;
+    uint16_t _fill_y;
+    uint8_t cc;
+    uint8_t iflags;
+  } byte;
+  struct {
+    uint16_t pc;
+    uint16_t d;
+    uint16_t u;
+    uint16_t s;
+    uint16_t x;
+    uint16_t y;
+    uint8_t _fill_cc;
+    uint8_t _fill_iflags;
+  } word;
+  uint8_t mem_be[0xe];
+#else
+  struct {
+    uint8_t nmi_pending : 1;
+    uint8_t irq_pending : 1;
+    uint8_t wai_flag : 1;
+    uint8_t _fill_iflags : 5;
+    uint8_t cf : 1;
+    uint8_t vf : 1;
+    uint8_t zf : 1;
+    uint8_t nf : 1;
+    uint8_t _if : 1;
+    uint8_t hf : 1;
+    uint8_t ff : 1;
+    uint8_t ef : 1;
+    uint16_t _fill_y;
+    uint16_t _fill_x;
+    uint16_t _fill_s;
+    uint16_t _fill_u;
+    uint16_t _fill_d;
+    uint16_t _fill_pc;
+  } bit;
+  struct {
+    uint8_t iflags;
+    uint8_t cc;
+    uint16_t _fill_y;
+    uint16_t _fill_x;
+    uint16_t _fill_s;
+    uint16_t _fill_u;
+    uint8_t b;
+    uint8_t a;
+    uint16_t _fill_pc;
+  } byte;
+  struct {
+    uint8_t _fill_iflags;
+    uint8_t _fill_cc;
+    uint16_t y;
+    uint16_t x;
+    uint16_t s;
+    uint16_t u;
+    uint16_t d;
+    uint16_t pc;
+  } word;
+  uint8_t mem_le[0xe];
+#endif
+};
+
+struct cpu_6809 {
+  int cycles;
+  int (*read_byte)(void *context, int addr);
+  void *read_byte_context;
+  void (*write_byte)(void *context, int addr, int data);
+  void *write_byte_context;
+  union cpu_6809_regs regs;
+};
+
+// memory or special memory access
+static ALWAYS_INLINE int cpu_6809_read_byte(struct cpu_6809 *self, int addr) {
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    return self->regs.mem_be[sizeof(union cpu_6809_regs) + addr];
+#else
+    return self->regs.mem_le[~addr];
+#endif
+  self->cycles += 1;
+  return self->read_byte(self->read_byte_context, addr & 0xffff);
+}
+
+static ALWAYS_INLINE int cpu_6809_read_word(struct cpu_6809 *self, int addr) {
+  int data = cpu_6809_read_byte(self, addr) << 8;
+  return data | cpu_6809_read_byte(self, addr + 1);
+}
+
+static ALWAYS_INLINE void cpu_6809_write_byte(struct cpu_6809 *self, int addr, int data) {
+  self->cycles += 1;
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    self->regs.mem_be[sizeof(union cpu_6809_regs) + addr] = data;
+#else
+    self->regs.mem_le[~addr] = data;
+#endif
+  else
+    self->write_byte(self->write_byte_context, addr, data);
+}
+
+static ALWAYS_INLINE void cpu_6809_write_word(struct cpu_6809 *self, int addr, int data) {
+  cpu_6809_write_byte(self, addr, data >> 8);
+  cpu_6809_write_byte(self, addr + 1, data & 0xff);
+}
+
+static ALWAYS_INLINE int cpu_6809_fetch_byte(struct cpu_6809 *self) {
+  int data = cpu_6809_read_byte(self, self->regs.word.pc++);
+  return data;
+}
+
+static ALWAYS_INLINE int cpu_6809_fetch_word(struct cpu_6809 *self) {
+  int data = cpu_6809_fetch_byte(self) << 8;
+  return data | cpu_6809_fetch_byte(self);
+}
+
+static ALWAYS_INLINE void cpu_6809_push_byte(struct cpu_6809 *self, int data) {
+  cpu_6809_write_byte(self, self->regs.word.s--, data);
+}
+
+static ALWAYS_INLINE void cpu_6809_push_word(struct cpu_6809 *self, int data) {
+  cpu_6809_push_byte(self, data & 0xff);
+  cpu_6809_push_byte(self, data >> 8);
+}
+
+static ALWAYS_INLINE int cpu_6809_pop_byte(struct cpu_6809 *self) {
+  return cpu_6809_read_byte(self, ++self->regs.word.s);
+}
+
+static ALWAYS_INLINE int cpu_6809_pop_word(struct cpu_6809 *self) {
+  int data = cpu_6809_pop_byte(self) << 8;
+  return data | cpu_6809_pop_byte(self);
+}
+
+// effective address calculation
+static ALWAYS_INLINE int cpu_6809_ea_extended(struct cpu_6809 *self) {
+  return cpu_6809_fetch_word(self);
+}
+
+static ALWAYS_INLINE int cpu_6809_ea_relative(struct cpu_6809 *self) {
+  return (int8_t)cpu_6809_fetch_byte(self);
+}
+
+static ALWAYS_INLINE int cpu_6809_ea_long_relative(struct cpu_6809 *self) {
+  return cpu_6809_fetch_word(self);
+}
+
+static ALWAYS_INLINE int cpu_6809_ea_direct(struct cpu_6809 *self) {
+  return cpu_6809_fetch_byte(self);
+}
+
+// instruction execute
+static ALWAYS_INLINE void cpu_6809_adc(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = (data & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+  int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
+  int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
+
+  cpu_6809_write_byte(self, lvalue, result2 & 0xff);
+  self->regs.bit.hf = result0 >> 4;
+  self->regs.bit.nf = (result2 >> 7) & 1;
+  self->regs.bit.zf = (result2 & 0xff) == 0;
+  self->regs.bit.vf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+  self->regs.bit.cf = result2 >> 8;
+}
+
+static ALWAYS_INLINE void cpu_6809_add_byte(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = (data & 0xf) + (rvalue & 0xf);
+  int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
+  int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
+
+  cpu_6809_write_byte(self, lvalue, result2 & 0xff);
+  self->regs.bit.hf = result0 >> 4;
+  self->regs.bit.nf = (result2 >> 7) & 1;
+  self->regs.bit.zf = (result2 & 0xff) == 0;
+  self->regs.bit.vf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+  self->regs.bit.cf = result2 >> 8;
+}
+
+static ALWAYS_INLINE void cpu_6809_add_word(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int data = cpu_6809_read_word(self, lvalue);
+
+  int result0 = (data & 0xfff) + (rvalue & 0xfff);
+  int result1 = result0 + (data & 0x7000) + (rvalue & 0x7000);
+  int result2 = result1 + (data & 0x8000) + (rvalue & 0x8000);
+
+  cpu_6809_write_word(self, lvalue, result2 & 0xffff);
+  self->regs.bit.hf = result0 >> 12;
+  self->regs.bit.nf = (result2 >> 15) & 1;
+  self->regs.bit.zf = (result2 & 0xffff) == 0;
+  self->regs.bit.vf = ((result1 >> 15) ^ (result2 >> 16)) & 1;
+  self->regs.bit.cf = result2 >> 16;
+}
+
+static ALWAYS_INLINE void cpu_6809_and(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int result = cpu_6809_read_byte(self, lvalue) & rvalue;
+
+  cpu_6809_write_byte(self, lvalue, result);
+  self->regs.bit.nf = result >> 7;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_andcc(struct cpu_6809 *self, int rvalue) {
+  self->regs.byte.cc &= rvalue;
+}
+
+static ALWAYS_INLINE void cpu_6809_asl(struct cpu_6809 *self, int lvalue) {
+  int result = cpu_6809_read_byte(self, lvalue) << 1;
+  ++self->cycles;
+
+  cpu_6809_write_byte(self, lvalue, result & 0xff);
+  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.vf = ((result >> 7) ^ (result >> 8)) & 1;
+  self->regs.bit.cf = result >> 8;
+}
+
+static ALWAYS_INLINE void cpu_6809_asr(struct cpu_6809 *self, int lvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result = data | ((data << 1) & 0x100);
+  ++self->cycles;
+
+  cpu_6809_write_byte(self, lvalue, result >> 1);
+  self->regs.bit.nf = result >> 8;
+  self->regs.bit.zf = (result & 0xfe) == 0;
+  self->regs.bit.vf = (result ^ (result >> 8)) & 1;
+  self->regs.bit.cf = result & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_bit(struct cpu_6809 *self, int rvalue0, int rvalue1) {
+  int result = rvalue0 & rvalue1;
+
+  self->regs.bit.nf = result >> 7;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_bra(struct cpu_6809 *self, bool pred, int lvalue) {
+  if (pred) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+    self->regs.word.pc += lvalue;
+  }
+}
+
+static ALWAYS_INLINE void cpu_6809_bsr(struct cpu_6809 *self, int lvalue) {
+  cpu_6809_push_word(self, self->regs.word.pc);
+  self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+  self->regs.word.pc += lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6809_clr(struct cpu_6809 *self, int lvalue) {
+  //cpu_6809_read_byte(self, lvalue); // clr is implemented as RMW like inc/dec
+  cpu_6809_write_byte(self, lvalue, 0);
+
+  self->regs.bit.nf = false;
+  self->regs.bit.zf = true;
+  self->regs.bit.vf = false;
+  self->regs.bit.cf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_cmp_byte(struct cpu_6809 *self, int rvalue0, int rvalue1) {
+  int result0 = (rvalue0 & 0x7f) - (rvalue1 & 0x7f);
+  int result1 = result0 + (rvalue0 & 0x80) - (rvalue1 & 0x80);
+
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.cf = (result1 >> 8) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_com(struct cpu_6809 *self, int lvalue) {
+  int result = cpu_6809_read_byte(self, lvalue) ^ 0xff;
+
+  cpu_6809_write_byte(self, lvalue, result);
+  self->regs.bit.nf = result >> 7;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = false;
+  self->regs.bit.cf = true;
+}
+
+static ALWAYS_INLINE void cpu_6809_cmp_word(struct cpu_6809 *self, int rvalue0, int rvalue1) {
+  int result0 = (rvalue0 & 0x7fff) - (rvalue1 & 0x7fff);
+  int result1 = result0 + (rvalue0 & 0x8000) - (rvalue1 & 0x8000);
+
+  self->regs.bit.nf = (result1 >> 15) & 1;
+  self->regs.bit.zf = (result1 & 0xffff) == 0;
+  self->regs.bit.vf = ((result0 >> 15) ^ (result1 >> 16)) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_cwai(struct cpu_6809 *self, int rvalue) {
+  cpu_6809_push_word(self, self->regs.word.pc);
+  cpu_6809_push_word(self, self->regs.word.x);
+  cpu_6809_push_byte(self, self->regs.byte.a);
+  cpu_6809_push_byte(self, self->regs.byte.b);
+  cpu_6809_push_byte(self, self->regs.byte.cc);
+  self->regs.bit.wai_flag = true;
+}
+
+static ALWAYS_INLINE void cpu_6809_daa(struct cpu_6809 *self) {
+  int correction = 0;
+  if (self->regs.bit.hf || (self->regs.byte.a & 0xf) >= 0xa)
+    correction = 6;
+  if (self->regs.bit.cf || self->regs.byte.a >= 0x9a) {
+    correction |= 0x60;
+    self->regs.bit.cf = true;
+  }
+
+  int result0 = (self->regs.byte.a & 0x7f) + correction;
+  int result1 = result0 + (self->regs.byte.a & 0x80);
+
+  self->regs.byte.a = result1 & 0xff;
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  //self->regs.bit.cf |= result1 >> 8;
+}
+
+static ALWAYS_INLINE void cpu_6809_dec_byte(struct cpu_6809 *self, int lvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = (data & 0x7f) - 1;
+  int result1 = result0 + (data & 0x80);
+  ++self->cycles;
+
+  cpu_6809_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_dec_word(struct cpu_6809 *self, int lvalue) {
+  cpu_6809_write_word(
+    self,
+    lvalue,
+    (cpu_6809_read_word(self, lvalue) - 1) & 0xffff
+  );
+  ++self->cycles;
+}
+
+static ALWAYS_INLINE void cpu_6809_dec_word_zf(struct cpu_6809 *self, int lvalue) {
+  int result = (cpu_6809_read_word(self, lvalue) - 1) & 0xffff;
+  ++self->cycles;
+
+  self->regs.word.x = result;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_6809_eor(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int result = cpu_6809_read_byte(self, lvalue) ^ rvalue;
+
+  cpu_6809_write_byte(self, lvalue, result);
+  self->regs.bit.nf = result >> 7;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_exg(struct cpu_6809 *self, int postbyte) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_illegal_opcode(struct cpu_6809 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_inc_byte(struct cpu_6809 *self, int lvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = (data & 0x7f) + 1;
+  int result1 = result0 + (data & 0x80);
+  ++self->cycles;
+
+  cpu_6809_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_inc_word(struct cpu_6809 *self, int lvalue) {
+  cpu_6809_write_word(
+    self,
+    lvalue,
+    (cpu_6809_read_word(self, lvalue) + 1) & 0xffff
+  );
+  ++self->cycles;
+}
+
+static ALWAYS_INLINE void cpu_6809_inc_word_zf(struct cpu_6809 *self, int lvalue) {
+  int result = (cpu_6809_read_word(self, lvalue) + 1) & 0xffff;
+  ++self->cycles;
+
+  self->regs.word.x = result;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_6809_jmp(struct cpu_6809 *self, int lvalue) {
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6809_jsr(struct cpu_6809 *self, int lvalue) {
+  cpu_6809_push_word(self, self->regs.word.pc);
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6809_lbra(struct cpu_6809 *self, bool pred, int lvalue) {
+  if (pred) {
+    self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+    self->regs.word.pc += lvalue;
+  }
+}
+
+static ALWAYS_INLINE void cpu_6809_lbsr(struct cpu_6809 *self, int lvalue) {
+  cpu_6809_push_word(self, self->regs.word.pc);
+  self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+  self->regs.word.pc += lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6809_ld_word(struct cpu_6809 *self, int lvalue, int rvalue) {
+  cpu_6809_write_word(self, lvalue, rvalue);
+
+  self->regs.bit.nf = (rvalue >> 15) & 1;
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_ld_byte(struct cpu_6809 *self, int lvalue, int rvalue) {
+  cpu_6809_write_byte(self, lvalue, rvalue);
+
+  self->regs.bit.nf = (rvalue >> 7) & 1;
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_lea(struct cpu_6809 *self, int lvalue0, int lvalue1) {
+  cpu_6809_write_word(self, lvalue0, lvalue1);
+
+  self->regs.bit.nf = (lvalue1 >> 15) & 1;
+  self->regs.bit.zf = lvalue1 == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_lsr(struct cpu_6809 *self, int lvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result = data;
+  ++self->cycles;
+
+  cpu_6809_write_byte(self, lvalue, result >> 1);
+  self->regs.bit.nf = result >> 8;
+  self->regs.bit.zf = (result & 0xfe) == 0;
+  self->regs.bit.vf = (result ^ (result >> 8)) & 1;
+  self->regs.bit.cf = result & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_mul(struct cpu_6809 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_neg(struct cpu_6809 *self, int lvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = -(data & 0x7f);
+  int result1 = result0 - (data & 0x80);
+
+  cpu_6809_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.cf = (result1 >> 8) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_nop(struct cpu_6809 *self) {
+}
+
+static ALWAYS_INLINE void cpu_6809_or(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int result = cpu_6809_read_byte(self, lvalue) | rvalue;
+
+  cpu_6809_write_byte(self, lvalue, result);
+  self->regs.bit.nf = result >> 7;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_orcc(struct cpu_6809 *self, int rvalue) {
+  self->regs.byte.cc |= rvalue;
+}
+
+static ALWAYS_INLINE void cpu_6809_psh(struct cpu_6809 *self, int lvalue, int postbyte) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_pul(struct cpu_6809 *self, int lvalue, int postbyte) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_rol(struct cpu_6809 *self, int lvalue) {
+  int result = self->regs.bit.cf | (cpu_6809_read_byte(self, lvalue) << 1);
+  ++self->cycles;
+
+  cpu_6809_write_byte(self, lvalue, result & 0xff);
+  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.vf = ((result >> 7) ^ (result >> 8)) & 1;
+  self->regs.bit.cf = result >> 8;
+}
+
+static ALWAYS_INLINE void cpu_6809_ror(struct cpu_6809 *self, int lvalue) {
+  int result = cpu_6809_read_byte(self, lvalue) | (self->regs.bit.cf << 8);
+  ++self->cycles;
+  cpu_6809_write_byte(self, lvalue, result >> 1);
+
+  self->regs.bit.nf = result >> 8;
+  self->regs.bit.zf = (result & 0x1fe) == 0;
+  self->regs.bit.vf = (result ^ (result >> 8)) & 1;
+  self->regs.bit.cf = result & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_rti(struct cpu_6809 *self) {
+  self->regs.byte.cc = cpu_6809_pop_byte(self);
+  self->regs.byte.b = cpu_6809_pop_byte(self);
+  self->regs.byte.a = cpu_6809_pop_byte(self);
+  self->regs.word.x = cpu_6809_pop_word(self);
+  self->regs.word.pc = cpu_6809_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_6809_rts(struct cpu_6809 *self) {
+  self->regs.word.pc = cpu_6809_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_6809_sbc(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = (data & 0x7f) - (rvalue & 0x7f) - self->regs.bit.cf;
+  int result1 = result0 + (data & 0x80) - (rvalue & 0x80);
+
+  cpu_6809_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.cf = (result1 >> 8) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_sex(struct cpu_6809 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_st_word(struct cpu_6809 *self, int rvalue, int lvalue) {
+  cpu_6809_write_word(self, lvalue, rvalue);
+
+  self->regs.bit.nf = (rvalue >> 15) & 1;
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_st_byte(struct cpu_6809 *self, int rvalue, int lvalue) {
+  cpu_6809_write_byte(self, lvalue, rvalue);
+
+  self->regs.bit.nf = (rvalue >> 7) & 1;
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.vf = false;
+}
+
+static ALWAYS_INLINE void cpu_6809_sub_byte(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int data = cpu_6809_read_byte(self, lvalue);
+
+  int result0 = (data & 0x7f) - (rvalue & 0x7f);
+  int result1 = result0 + (data & 0x80) - (rvalue & 0x80);
+
+  cpu_6809_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.nf = (result1 >> 7) & 1;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.cf = (result1 >> 8) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_sub_word(struct cpu_6809 *self, int lvalue, int rvalue) {
+  int data = cpu_6809_read_word(self, lvalue);
+
+  int result0 = (data & 0x7fff) - (rvalue & 0x7fff);
+  int result1 = result0 + (data & 0x8000) - (rvalue & 0x8000);
+
+  cpu_6809_write_word(self, lvalue, result1 & 0xffff);
+  self->regs.bit.nf = (result1 >> 15) & 1;
+  self->regs.bit.zf = (result1 & 0xffff) == 0;
+  self->regs.bit.vf = ((result0 >> 15) ^ (result1 >> 16)) & 1;
+  self->regs.bit.cf = (result1 >> 16) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6809_swi(struct cpu_6809 *self) {
+  cpu_6809_push_word(self, self->regs.word.pc);
+  cpu_6809_push_word(self, self->regs.word.x);
+  cpu_6809_push_byte(self, self->regs.byte.a);
+  cpu_6809_push_byte(self, self->regs.byte.b);
+  cpu_6809_push_byte(self, self->regs.byte.cc);
+  self->regs.word.pc = cpu_6809_read_word(self, CPU_6809_SWI_VECTOR);
+  self->regs.bit._if = true;
+}
+
+static ALWAYS_INLINE void cpu_6809_swi_n(struct cpu_6809 *self, int n) {
+  cpu_6809_push_word(self, self->regs.word.pc);
+  cpu_6809_push_word(self, self->regs.word.x);
+  cpu_6809_push_byte(self, self->regs.byte.a);
+  cpu_6809_push_byte(self, self->regs.byte.b);
+  cpu_6809_push_byte(self, self->regs.byte.cc);
+  self->regs.word.pc = cpu_6809_read_word(self, CPU_6809_SWI_VECTOR);
+  self->regs.bit._if = true;
+}
+
+static ALWAYS_INLINE void cpu_6809_sync(struct cpu_6809 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6809_tfr(struct cpu_6809 *self, int postbyte) {
+  abort();
+}
+
+
+// prototypes
+void cpu_6809_init(
+  struct cpu_6809 *self,
+  int (*read_byte)(void *context, int addr),
+  void *read_byte_context,
+  void (*write_byte)(void *context, int addr, int data),
+  void *write_byte_context
+);
+void cpu_6809_reset(struct cpu_6809 *self);
+int cpu_6809_addressing_mode(struct cpu_6809 *self);
+void cpu_6809_execute(struct cpu_6809 *self);
+void cpu_6809_execute_10(struct cpu_6809 *self);
+void cpu_6809_execute_11(struct cpu_6809 *self);
+#endif
index 66fcf6f..d77f9b3 100644 (file)
--- a/cpu_z80.h
+++ b/cpu_z80.h
@@ -1,6 +1,7 @@
 #ifndef _CPU_Z80_H
 #define _CPU_Z80_H
 
+#include <endian.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -311,12 +312,11 @@ static ALWAYS_INLINE void cpu_z80_out_byte(struct cpu_z80 *self, int addr, int d
 
 // effective address calculation
 static ALWAYS_INLINE int cpu_z80_relative(struct cpu_z80 *self) {
-  int offset = cpu_z80_fetch_byte(self);
-  return offset - ((offset << 1) & 0x100);
+  return (int8_t)cpu_z80_fetch_byte(self);
 }
 
 static ALWAYS_INLINE int cpu_z80_displacement(struct cpu_z80 *self, int base) {
-  return (base + cpu_z80_relative(self)) & 0xffff;
+  return (base + (int8_t)cpu_z80_fetch_byte(self)) & 0xffff;
 }
 
 // byte-addressed ports are extended to word using a as high 8 bits
diff --git a/decode_6809.py b/decode_6809.py
new file mode 100755 (executable)
index 0000000..7d4d42d
--- /dev/null
@@ -0,0 +1,298 @@
+#!/usr/bin/env python3
+
+import sys
+
+# those which allow pre/post increment have to be lvalues
+addressing_values = {
+  '$12': '(int8_t)cpu_6809_fetch_byte(self)',
+  '$1234': 'cpu_6809_fetch_word(self)',
+  'a': '(int8_t)self->regs.byte.a',
+  'b': '(int8_t)self->regs.byte.b',
+  'd': 'self->regs.word.d',
+  '--u': 'self->regs.word.u',
+  '-u': '--self->regs.word.u',
+  'u': 'self->regs.word.u',
+  'u+': 'self->regs.word.u++',
+  'u++': 'self->regs.word.u',
+  '--s': 'self->regs.word.s',
+  '-s': '--self->regs.word.s',
+  's': 'self->regs.word.s',
+  's+': 'self->regs.word.s++',
+  's++': 'self->regs.word.s',
+  '--x': 'self->regs.word.x',
+  '-x': '--self->regs.word.x',
+  'x': 'self->regs.word.x',
+  'x+': 'self->regs.word.x++',
+  'x++': 'self->regs.word.x',
+  '--y': 'self->regs.word.y',
+  '-y': '--self->regs.word.y',
+  'y': 'self->regs.word.y',
+  'y+': 'self->regs.word.y++',
+  'y++': 'self->regs.word.y',
+  'pc': 'self->regs.word.pc',
+}
+
+# end-relative range of operands that are rvalues
+rvalue_opcodes = {
+  'add': (-1, 0),
+  'adc': (-1, 0),
+  'and': (-1, 0),
+  'andcc': (-1, 0),
+  'bit': (-1, 0),
+  'cmp': (-2, 0),
+  'cmp_byte': (-2, 0),
+  'cwai': (-1, 0),
+  'eor': (-1, 0),
+  'ld': (-1, 0),
+  'or': (-1, 0),
+  'orcc': (-1, 0),
+  'sub': (-1, 0),
+  'sbc': (-1, 0),
+  'st': (-2, -1),
+}
+
+# if it is in byte_opcodes it is treated as byte and has no suffix
+byte_opcodes = {
+  'adc',
+  'and',
+  'andcc',
+  'asl',
+  'asr',
+  'bit',
+  'cl',
+  'clr',
+  'cmp_byte',
+  'com',
+  'cwai',
+  'dec_byte',
+  'eor',
+  'inc_byte',
+  'lsr',
+  'neg',
+  'or',
+  'orcc',
+  'rol',
+  'ror',
+  'sbc',
+  'se',
+}
+# if any operand is in byte_operands it is treated as byte and has suffix
+# in this case another operand which is word can upgrade the size to word
+byte_operands = {
+  '#$12',
+  'a',
+  'b',
+}
+byte_rvalue_modes = {
+  '#$12': 'cpu_6809_fetch_byte(self)',
+  'a': 'self->regs.byte.a',
+  'b': 'self->regs.byte.b',
+}
+byte_lvalue_modes = {
+  '<$12': 'cpu_6809_ea_direct(self)',
+  '$1234': 'cpu_6809_ea_extended(self)',
+  '-14,x': 'cpu_6809_addressing_mode(self)',
+  'a': 'CPU_6809_EA_A',
+  'b': 'CPU_6809_EA_B',
+}
+
+# if it is in word_opcodes it is treated as word and has no suffix
+word_opcodes = {
+  'bra',
+  'bsr',
+  'dec_word_zf',
+  'inc_word_zf',
+  'exg',
+  'jmp',
+  'jsr',
+  'lbra',
+  'lbsr',
+  'lea',
+  'psh',
+  'pul',
+  'tfr',
+}
+# if any operand is in word_operands it is treated as word and has suffix
+# in this case it is mandatory that no operand also be in byte_operands
+word_operands = {
+  '#$1234',
+  'd',
+  'u',
+  's',
+  'x',
+  'y',
+}
+word_rvalue_modes = {
+  '#$1234': 'cpu_6809_fetch_word(self)',
+  'a': 'self->regs.byte.a',
+  'b': 'self->regs.byte.b',
+  'd': 'self->regs.word.d',
+  'u': 'self->regs.word.u',
+  's': 'self->regs.word.s',
+  'x': 'self->regs.word.x',
+  'y': 'self->regs.word.y',
+}
+word_lvalue_modes = {
+  'ne': '!self->regs.bit.zf',
+  'eq': 'self->regs.bit.zf',
+  'cc': '!self->regs.bit.cf',
+  'cs': 'self->regs.bit.cf',
+  'vc': '!self->regs.bit.vf',
+  'vs': 'self->regs.bit.vf',
+  'pl': '!self->regs.bit.nf',
+  'mi': 'self->regs.bit.nf',
+  'ge': '!self->regs.bit.nf && !self->regs.bit.vf',
+  'gt': '!self->regs.bit.nf && !self->regs.bit.vf && !self->regs.bit.zf',
+  'hi': '!self->regs.bit.cf && !self->regs.bit.zf',
+  'le': 'self->regs.bit.nf || self->regs.bit.vf || self->regs.bit.zf',
+  'ls': 'self->regs.bit.cf || self->regs.bit.zf',
+  'lt': 'self->regs.bit.nf || self->regs.bit.vf',
+  '$0014': 'cpu_6809_ea_relative(self)',
+  '$1237': 'cpu_6809_ea_long_relative(self)',
+  '$1238': 'cpu_6809_ea_long_relative(self)',
+  '<$12': 'cpu_6809_ea_direct(self)',
+  '$1234': 'cpu_6809_ea_extended(self)',
+  '-14,x': 'cpu_6809_addressing_mode(self)',
+  'x,a': 'cpu_6809_fetch_byte(self)',
+  'x,y': 'cpu_6809_fetch_byte(self)',
+  'd': 'CPU_6809_EA_D',
+  'u': 'CPU_6809_EA_U',
+  's': 'CPU_6809_EA_S',
+  'x': 'CPU_6809_EA_X',
+  'y': 'CPU_6809_EA_Y',
+}
+
+line = sys.stdin.readline().strip()
+assert line == 'addressing modes'
+
+print('int cpu_6809_addressing_mode(struct cpu_6809 *self) {')
+print('  int ea;')
+print('  switch (cpu_6809_fetch_byte(self)) {')
+
+for i in range(0x100):
+  line = sys.stdin.readline().strip()
+
+  print(f'  case 0x{i:02x}:')
+  instr = line.split()
+  assert instr[:2] == ['lea', 'x']
+  mode = instr[2]
+
+  if mode == '???':
+    print('    cpu_6809_illegal_opcode(self);')
+    continue
+
+  indirect = False
+  if mode[:1] == '[' and mode[-1:] == ']':
+    indirect = True
+    mode = mode[1:-1]
+  mode = [j for j in mode.split(',') if len(j)]
+
+  mode_str = ' + '.join([addressing_values.get(j, j) for j in mode])
+  if len(mode) >= 2:
+    mode_str = '({0:s}) & 0xffff'.format(mode_str)
+
+  for j in mode:
+    if j[:2] == '--':
+      print('    {0:s} -= 2;'.format(addressing_values[j[2:]]))
+  print('    ea = {0:s};'.format(mode_str))
+  for j in mode:
+    if j[-2:] == '++':
+      print('    {0:s} += 2;'.format(addressing_values[j[:-2]]))
+  if indirect:
+    if i == 0xfd:
+      print('  indirect:') 
+      print('    ea = cpu_6809_read_word(self, ea);')
+      print('    break;')
+    else:
+      print('    goto indirect;')
+  else:
+    print('    break;')
+
+line = sys.stdin.readline().strip()
+assert len(line) == 0
+
+print('  }')
+print('  return ea;')
+print('}')
+print()
+
+prefixes = [[], [0x10], [0x11]]
+for i in prefixes:
+  line = sys.stdin.readline().strip()
+  assert line == 'opcodes{0:s}'.format(''.join([f' 0x{j:02x}' for j in i]))
+
+  print(
+    'void cpu_6809_execute{0:s}(struct cpu_6809 *self) {{'.format(
+      ''.join([f'_{j:02x}' for j in i])
+    )
+  )
+  print('  switch (cpu_6809_fetch_byte(self)) {')
+
+  for j in range(0x100):
+    line = sys.stdin.readline().strip()
+
+    print(f'  case 0x{j:02x}:')
+    k = i + [j]
+    if k in prefixes:
+      print(
+        '    cpu_6809_execute{0:s}(self);'.format(
+          ''.join([f'_{k:02x}' for k in k])
+        )
+      )
+    else:
+      instr = line.split()
+      #print('xxx', instr)
+
+      # detect operation size (byte or word)
+      suffix = ''
+      if instr[0] not in byte_opcodes and instr[0] not in word_opcodes:
+        for k in instr[1:]:
+          if k in byte_operands and suffix != '_word':
+            suffix = '_byte'
+          elif k in word_operands:
+            suffix = '_word'
+
+      # work out which operands are rvalue
+      k0, k1 = rvalue_opcodes.get(instr[0], (0, 0))
+      k0 += len(instr)
+      k1 += len(instr)
+
+      # translate operands
+      if suffix == '_byte' or instr[0] in byte_opcodes:
+        for l in range(1, len(instr)):
+          if l >= k0 and l < k1:
+            if instr[l] in byte_rvalue_modes:
+              instr[l] = byte_rvalue_modes[instr[l]]
+            elif instr[l] in byte_lvalue_modes:
+              instr[l] = 'cpu_6809_read_byte(self, {0:s})'.format(
+                byte_lvalue_modes[instr[l]]
+              )
+          elif instr[l] in byte_lvalue_modes:
+            instr[l] = byte_lvalue_modes[instr[l]]
+      elif suffix == '_word' or instr[0] in word_opcodes:
+        for l in range(1, len(instr)):
+          if l >= k0 and l < k1:
+            if instr[l] in word_rvalue_modes:
+              instr[l] = word_rvalue_modes[instr[l]]
+            elif instr[l] in word_lvalue_modes:
+              instr[l] = 'cpu_6809_read_word(self, {0:s})'.format(
+                word_lvalue_modes[instr[l]]
+              )
+          elif instr[l] in word_lvalue_modes:
+            instr[l] = word_lvalue_modes[instr[l]]
+
+      print(
+        '    cpu_6809_{0:s}{1:s}(self{2:s});'.format(
+          instr[0],
+          suffix,
+          ''.join([', ' + k for k in instr[1:]])
+        )
+      )
+    print('    break;')
+
+  line = sys.stdin.readline().strip()
+  assert len(line) == 0
+
+  print('  }')
+  print('}')
+  print()
diff --git a/decode_6809.sh b/decode_6809.sh
new file mode 100755 (executable)
index 0000000..18b0f4b
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+sed -f decode_6809_pre.sed <instr_6809.txt |\
+./decode_6809.py |\
+sed -f decode_6809_post.sed >decode_6809.txt
diff --git a/decode_6809_post.sed b/decode_6809_post.sed
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/decode_6809_pre.sed b/decode_6809_pre.sed
new file mode 100644 (file)
index 0000000..fa29ba4
--- /dev/null
@@ -0,0 +1,24 @@
+y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+s/^invalid/illegal_opcode/
+s/^\(bra\|bhi\|bls\|bcc\|bcs\|bne\|beq\|bvc\|bvs\|bpl\|bmi\|bge\|blt\|bgt\|ble\|bsr\) 12/\1 0014/
+s/^bra/bra true/
+s/^brn/bra false/
+s/^b\(hi\|ls\|cc\|cs\|ne\|eq\|vc\|vs\|pl\|mi\|ge\|lt\|gt\|le\)/bra \1/
+s/^lbra/lbra true/
+s/^lbrn/lbra false/
+s/^lb\(hi\|ls\|cc\|cs\|ne\|eq\|vc\|vs\|pl\|mi\|ge\|lt\|gt\|le\)/lbra \1/
+s/^\(or\)\([ab]\)/\1 \2/
+s/^\([a-z][a-z][a-z]\)\([abdusxy]\)/\1 \2/
+s/^lbr a/lbra/
+s/^\(inc\|dec\)/\1_byte/
+s/^de\([us]\)/dec \1/
+s/^de\([xy]\)/dec_word_zf \1/
+s/^in\([us]\)/inc \1/
+s/^in\([xy]\)/inc_word_zf \1/
+s/^\(ld\)\([abdusxy]\)/\1 \2/
+s/^\(st\)\([abdusxy]\)/\1 \2/
+s/^ab\([ax]\)/add \1 b/
+s/^sba/sub a b/
+s/^cba/cmp a b/
+s/^tst \(.*\)/cmp_byte \1 0/
+s/^\(swi\)\([23]\)/\1_n \2/
index ee31ebb..09bb150 100644 (file)
@@ -1,4 +1,3 @@
-#include <assert.h> // temp
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -124,7 +123,6 @@ int read_byte(void *context, int addr) {
 }
 
 void write_byte(void *context, int addr, int data) {
- assert((data & ~0xff) == 0);
 #if MEM_TRACE
   fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
 #endif
@@ -189,12 +187,12 @@ int main(int argc, char **argv) {
 #if REG_TRACE
     fprintf(
       stderr,
-      "pc=%04x a=%02x b=%02x x=%04x s=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
+      "pc=%04x a=%02x b=%02x s=%04x x=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
       regs.pc,
       regs.accd.a,
       regs.accd.b,
-      regs.ix,
       regs.sp,
+      regs.ix,
       regs.ccr | 0xc0,
       (regs.ccr >> 5) & 1,
       (regs.ccr >> 4) & 1,
@@ -216,12 +214,12 @@ int main(int argc, char **argv) {
 #if REG_TRACE
     fprintf(
       stderr,
-      "pc=%04x a=%02x b=%02x x=%04x s=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
+      "pc=%04x a=%02x b=%02x s=%04x x=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
       cpu.regs.word.pc,
       cpu.regs.byte.a,
       cpu.regs.byte.b,
-      cpu.regs.word.x,
       cpu.regs.word.s,
+      cpu.regs.word.x,
       cpu.regs.byte.p,
       cpu.regs.bit.hf,
       cpu.regs.bit._if,
diff --git a/emu_6809.c b/emu_6809.c
new file mode 100644 (file)
index 0000000..9ff627f
--- /dev/null
@@ -0,0 +1,291 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if ALT_BACKEND
+#include "VCC/mc6809.h"
+#include "VCC/tcc1014mmu.h"
+#else
+#include "cpu_6809.h"
+#endif
+
+#define REG_TRACE 1
+#define MEM_TRACE 1
+
+#define MEM_SIZE 0x10000
+uint8_t mem[MEM_SIZE];
+
+int load_ihx(char *name) {
+  FILE *fp = fopen(name, "r");
+  if (fp == NULL) {
+    perror(name);
+    exit(EXIT_FAILURE);
+  }
+
+  int base = 0, entry_point = 0;
+  bool had_eof = false;
+  char line[0x100];
+  while (fgets(line, 0x100, fp)) {
+    for (char *p = line; *p; ++p)
+      if (*p == '\n') {
+        *p = 0;
+        break;
+      }
+
+    if (had_eof) {
+      fprintf(stderr, "garbage after EOF record: %s\n", line);
+      exit(EXIT_FAILURE);
+    }
+
+    if (line[0] != ':') {
+      fprintf(stderr, "require colon: %s\n", line);
+      exit(EXIT_FAILURE);
+    }
+
+    uint8_t buf[0x7f];
+    int len;
+    for (len = 0; len < 0x7f; ++len) {
+      char *p = line + 1 + len * 2;
+      if (*p == 0)
+        break;
+      if (*p == '\n') {
+        *p = 0;
+        break;
+      }
+      uint8_t c = p[2];
+      p[2] = 0;
+
+      char *q;
+      buf[len] = (uint8_t)strtol(p, &q, 16);
+      p[2] = c;
+      if (q != p + 2) {
+        fprintf(stderr, "not hex byte: %s\n", p);
+        exit(EXIT_FAILURE);
+      }
+    }
+
+    if (len == 0) {
+      fprintf(stderr, "empty line: %s\n", line);
+      exit(EXIT_FAILURE);
+    }
+
+    uint8_t checksum = 0;
+    for (int i = 0; i < len; ++i)
+      checksum += buf[i];
+    if (checksum) {
+      checksum -= buf[len - 1];
+      fprintf(
+        stderr,
+        "checksum %02x, should be %02x\n",
+        checksum,
+        buf[len - 1]
+      );
+      exit(EXIT_FAILURE);
+    }
+
+    len -= 5;
+    if (len != buf[0]) {
+      fprintf(stderr, "incorrect length: %s\n", line);
+      exit(EXIT_FAILURE);
+    }
+
+    int addr = (buf[1] << 8) | buf[2], end_addr;
+    switch (buf[3]) {
+    case 0:
+      addr += base;
+      end_addr = addr + len;
+      if (end_addr < addr || end_addr > MEM_SIZE) {
+        fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
+        exit(EXIT_FAILURE);
+      }
+      memcpy(mem + addr, buf + 4, len);
+      break;
+    case 1:
+      had_eof = true;
+      break;
+    case 4:
+      if (len < 2) {
+        fprintf(stderr, "invalid extended linear address record: %s\n", line);
+        exit(EXIT_FAILURE);
+      }
+      base = (buf[4] << 24) | (buf[5] << 16);
+      break;
+    case 5:
+      if (len < 4) {
+        fprintf(stderr, "invalid start linear address record: %s\n", line);
+        exit(EXIT_FAILURE);
+      }
+      entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
+      break;
+    default:
+      fprintf(stderr, "unknown record type: 0x%x\n", buf[3]);
+      exit(EXIT_FAILURE);
+    }
+  }
+  if (!had_eof) {
+    fprintf(stderr, "no EOF record\n");
+    exit(EXIT_FAILURE);
+  }
+
+  fclose(fp);
+  return entry_point;
+}
+
+int read_byte(void *context, int addr) {
+  int data;
+  switch (addr) {
+  case 0xa001:
+    data = getchar();
+    switch (data) {
+    case '\n':
+      data = '\r';
+      break;
+    case 0x7f:
+      data = '\b';
+      break;
+    case EOF:
+      exit(EXIT_SUCCESS);
+      break;
+    }
+    break;
+  default:
+    data = mem[addr];
+    break;
+  }
+#if MEM_TRACE
+  fprintf(stderr, "addr=%04x rd=%02x\n", addr, data);
+#endif
+  return data;
+}
+
+void write_byte(void *context, int addr, int data) {
+#if MEM_TRACE
+  fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
+#endif
+  switch (addr) {
+  case 0xa000:
+    break;
+  case 0xa001:
+    data &= 0x7f;
+    switch (data) {
+    case '\r':
+      putchar('\n');
+      break;
+    case '\n':
+      break;
+    default:
+      putchar(data);
+      break;
+    }
+    break;
+  default:
+    mem[addr] = data;
+  }
+}
+
+#if ALT_BACKEND
+int JS_Ramp_Clock;
+
+void SetMapType(unsigned char type) {
+}
+
+unsigned char MemRead8(short unsigned int addr) {
+  return read_byte(NULL, addr);
+}
+
+unsigned short MemRead16(unsigned short addr) {
+  int result = MemRead8(addr) << 8;
+  return result | MemRead8(addr + 1);
+}
+
+void MemWrite8(unsigned char value, unsigned short addr) {
+  write_byte(NULL, addr, value);
+}
+
+void MemWrite16(unsigned short data,unsigned short addr) {
+  MemWrite8(data >> 8, addr);
+  MemWrite8(data & 0xFF, addr + 1);
+  return;
+}
+#endif
+
+int main(int argc, char **argv) {
+  if (argc < 2) {
+    printf("usage: %s image.ihx\n", argv[0]);
+    exit(EXIT_FAILURE);
+  }
+  load_ihx(argv[1]);
+
+  mem[0xa000] = 3; // bit 0 = rdrf, bit 1 = tdre
+
+#if ALT_BACKEND
+  MC6809Init();
+  MC6809Reset();
+
+  while (true) {
+#if REG_TRACE
+    fprintf(
+      stderr,
+      "pc=%04x d=%04x u=%04x s=%04x x=%04x y=%04x cc=%02x ef=%d ff=%d hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
+      pc.Reg,
+      d.Reg,
+      u.Reg,
+      s.Reg,
+      x.Reg,
+      y.Reg,
+      cc[0] |
+      (cc[1] << 1) |
+      (cc[2] << 2) |
+      (cc[3] << 3) |
+      (cc[4] << 4) |
+      (cc[5] << 5) |
+      (cc[6] << 6) |
+      (cc[7] << 7),
+      cc[7],
+      cc[6],
+      cc[5],
+      cc[4],
+      cc[3],
+      cc[2],
+      cc[1],
+      cc[0]
+    );
+#endif
+
+    MC6809Exec(1);
+  }
+#else
+  struct cpu_6809 cpu;
+  cpu_6809_init(&cpu, read_byte, NULL, write_byte, NULL);
+  cpu_6809_reset(&cpu);
+
+  while (true) {
+#if REG_TRACE
+    fprintf(
+      stderr,
+      "pc=%04x d=%04x u=%04x s=%04x x=%04x y=%04x cc=%02x ef=%d ff=%d hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
+      cpu.regs.word.pc,
+      cpu.regs.word.d,
+      cpu.regs.word.u,
+      cpu.regs.word.s,
+      cpu.regs.word.x,
+      cpu.regs.word.y,
+      cpu.regs.byte.cc,
+      cpu.regs.bit.ef,
+      cpu.regs.bit.ff,
+      cpu.regs.bit.hf,
+      cpu.regs.bit._if,
+      cpu.regs.bit.nf,
+      cpu.regs.bit.zf,
+      cpu.regs.bit.vf,
+      cpu.regs.bit.cf
+    );
+#endif
+
+    cpu_6809_execute(&cpu);
+  }
+#endif
+
+  return 0;
+}