Preliminary 6800 CPU emulation, can compile but is not accurate yet
authorNick Downing <nick@ndcode.org>
Mon, 25 Jul 2022 06:02:12 +0000 (16:02 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 25 Jul 2022 06:02:12 +0000 (16:02 +1000)
Makefile
cpu_65c02.h
cpu_6800.c [new file with mode: 0644]
cpu_6800.h [new file with mode: 0644]
cpu_z80.h
decode_6800.py [new file with mode: 0755]
decode_6800.sed [new file with mode: 0644]
emu_6800.c
instr_6800.txt
sim68xx

index 7f2316d..7dafed7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -10,12 +10,12 @@ emu_65c02 \
 emu_65c02_alt \
 6502_functional_test.ihx \
 65C02_extended_opcodes_test.ihx \
+emu_6800 \
 emu_6800_alt \
 emu_z80 \
 emu_z80_alt \
 zexall.ihx \
 zexdoc.ihx
-#emu_6800
 
 # 65C02
 emu_65c02: emu_65c02.o cpu_65c02.o
index e8d4e05..559ed85 100644 (file)
@@ -133,7 +133,7 @@ static ALWAYS_INLINE int cpu_65c02_read_byte(struct cpu_65c02 *self, int addr) {
 #if __BYTE_ORDER == __BIG_ENDIAN
     return self->regs.mem_be[~addr];
 #else
-    return self->regs.mem_le[addr - CPU_65C02_EA_A];
+    return self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr];
 #endif
   self->cycles += 1;
   return self->read_byte(self->read_byte_context, addr & 0xffff);
@@ -155,7 +155,7 @@ static ALWAYS_INLINE void cpu_65c02_write_byte(struct cpu_65c02 *self, int addr,
 #if __BYTE_ORDER == __BIG_ENDIAN
     self->regs.mem_be[~addr] = data;
 #else
-    self->regs.mem_le[addr - CPU_65C02_EA_A] = data;
+    self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr] = data;
 #endif
   else
     self->write_byte(self->write_byte_context, addr, data);
@@ -177,8 +177,7 @@ static ALWAYS_INLINE int cpu_65c02_fetch_word(struct cpu_65c02 *self) {
 }
 
 static ALWAYS_INLINE void cpu_65c02_push_byte(struct cpu_65c02 *self, int data) {
-  cpu_65c02_write_byte(self, self->regs.byte.s | 0x100, data);
-  --self->regs.byte.s;
+  cpu_65c02_write_byte(self, self->regs.byte.s-- | 0x100, data);
 }
 
 static ALWAYS_INLINE void cpu_65c02_push_word(struct cpu_65c02 *self, int data) {
@@ -187,8 +186,7 @@ static ALWAYS_INLINE void cpu_65c02_push_word(struct cpu_65c02 *self, int data)
 }
 
 static ALWAYS_INLINE int cpu_65c02_pop_byte(struct cpu_65c02 *self) {
-  ++self->regs.byte.s;
-  return cpu_65c02_read_byte(self, self->regs.byte.s | 0x100);
+  return cpu_65c02_read_byte(self, ++self->regs.byte.s | 0x100);
 }
 
 static ALWAYS_INLINE int cpu_65c02_pop_word(struct cpu_65c02 *self) {
diff --git a/cpu_6800.c b/cpu_6800.c
new file mode 100644 (file)
index 0000000..b131109
--- /dev/null
@@ -0,0 +1,824 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpu_6800.h"
+
+// initialization
+void cpu_6800_init(
+  struct cpu_6800 *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_6800));
+  self->regs.byte.p = 0xc0; // unused bits are hard coded to 1
+  self->read_byte = read_byte;
+  self->read_byte_context = read_byte_context;
+  self->write_byte = write_byte;
+  self->write_byte_context = write_byte_context;
+}
+
+void cpu_6800_reset(struct cpu_6800 *self) {
+  self->regs.word.pc = cpu_6800_read_word(self, CPU_6800_RESET_VECTOR);
+  self->regs.byte.iflags = 0;
+  self->regs.bit._if = true;
+}
+
+// instruction decode
+void cpu_6800_execute(struct cpu_6800 *self) {
+  if (self->regs.bit.nmi_pending) {
+    self->regs.bit.nmi_pending = false;
+    self->regs.bit.wai_flag = false;
+    cpu_6800_swi(self, CPU_6800_NMI_VECTOR);
+    return;
+  }
+
+  if (self->regs.bit.irq_pending) {
+    if (self->regs.bit._if == 0) {
+      self->regs.bit.irq_pending = false;
+      self->regs.bit.wai_flag = false;
+      cpu_6800_swi(self, CPU_6800_IRQ_VECTOR);
+      return;
+    }
+    if (self->regs.bit.wai_flag) {
+      self->regs.bit.irq_pending = false;
+      self->regs.bit.wai_flag = false;
+    }
+  }
+  else if (self->regs.bit.wai_flag) {
+    ++self->cycles;
+    return;
+  }
+
+  switch (cpu_6800_fetch_byte(self)) {
+  case 0x00:
+    cpu_6800_ill(self);
+    break;
+  case 0x01:
+    cpu_6800_nop(self);
+    break;
+  case 0x02:
+    cpu_6800_ill(self);
+    break;
+  case 0x03:
+    cpu_6800_ill(self);
+    break;
+  case 0x04:
+    cpu_6800_ill(self);
+    break;
+  case 0x05:
+    cpu_6800_ill(self);
+    break;
+  case 0x06:
+    cpu_6800_sta(self, self->regs.byte.a | 0xc0, CPU_6800_EA_P);
+    break;
+  case 0x07:
+    cpu_6800_sta(self, self->regs.byte.p, CPU_6800_EA_A);
+    break;
+  case 0x08:
+    cpu_6800_in(self, CPU_6800_EA_X);
+    break;
+  case 0x09:
+    cpu_6800_de(self, CPU_6800_EA_X);
+    break;
+  case 0x0a:
+    cpu_6800_cl(self, CPU_6800_REG_P_BIT_V);
+    break;
+  case 0x0b:
+    cpu_6800_se(self, CPU_6800_REG_P_BIT_V);
+    break;
+  case 0x0c:
+    cpu_6800_cl(self, CPU_6800_REG_P_BIT_C);
+    break;
+  case 0x0d:
+    cpu_6800_se(self, CPU_6800_REG_P_BIT_C);
+    break;
+  case 0x0e:
+    cpu_6800_cl(self, CPU_6800_REG_P_BIT_I);
+    break;
+  case 0x0f:
+    cpu_6800_se(self, CPU_6800_REG_P_BIT_I);
+    break;
+  case 0x10:
+    cpu_6800_sub(self, CPU_6800_EA_A, self->regs.byte.b);
+    break;
+  case 0x11:
+    cpu_6800_cmp(self, CPU_6800_EA_A, self->regs.byte.b);
+    break;
+  case 0x12:
+    cpu_6800_ill(self);
+    break;
+  case 0x13:
+    cpu_6800_ill(self);
+    break;
+  case 0x14:
+    cpu_6800_ill(self);
+    break;
+  case 0x15:
+    cpu_6800_ill(self);
+    break;
+  case 0x16:
+    cpu_6800_lda(self, CPU_6800_EA_A, self->regs.byte.a);
+    break;
+  case 0x17:
+    cpu_6800_lda(self, CPU_6800_EA_A, self->regs.byte.b);
+    break;
+  case 0x18:
+    cpu_6800_ill(self);
+    break;
+  case 0x19:
+    cpu_6800_daa(self);
+    break;
+  case 0x1a:
+    cpu_6800_ill(self);
+    break;
+  case 0x1b:
+    cpu_6800_add(self, CPU_6800_EA_A, self->regs.byte.b);
+    break;
+  case 0x1c:
+    cpu_6800_ill(self);
+    break;
+  case 0x1d:
+    cpu_6800_ill(self);
+    break;
+  case 0x1e:
+    cpu_6800_ill(self);
+    break;
+  case 0x1f:
+    cpu_6800_ill(self);
+    break;
+  case 0x20:
+    cpu_6800_bra(self, true, cpu_6800_ea_direct(self));
+    break;
+  case 0x21:
+    cpu_6800_ill(self);
+    break;
+  case 0x22:
+    cpu_6800_bra(self, !self->regs.bit.cf && !self->regs.bit.zf, cpu_6800_ea_direct(self));
+    break;
+  case 0x23:
+    cpu_6800_bra(self, self->regs.bit.cf || self->regs.bit.zf, cpu_6800_ea_direct(self));
+    break;
+  case 0x24:
+    cpu_6800_bra(self, !self->regs.bit.cf, cpu_6800_ea_direct(self));
+    break;
+  case 0x25:
+    cpu_6800_bra(self, self->regs.bit.cf, cpu_6800_ea_direct(self));
+    break;
+  case 0x26:
+    cpu_6800_bra(self, !self->regs.bit.zf, cpu_6800_ea_direct(self));
+    break;
+  case 0x27:
+    cpu_6800_bra(self, self->regs.bit.zf, cpu_6800_ea_direct(self));
+    break;
+  case 0x28:
+    cpu_6800_bra(self, !self->regs.bit.vf, cpu_6800_ea_direct(self));
+    break;
+  case 0x29:
+    cpu_6800_bra(self, self->regs.bit.vf, cpu_6800_ea_direct(self));
+    break;
+  case 0x2a:
+    cpu_6800_bra(self, !self->regs.bit.nf, cpu_6800_ea_direct(self));
+    break;
+  case 0x2b:
+    cpu_6800_bra(self, self->regs.bit.nf, cpu_6800_ea_direct(self));
+    break;
+  case 0x2c:
+    cpu_6800_bra(self, !self->regs.bit.nf && !self->regs.bit.vf, cpu_6800_ea_direct(self));
+    break;
+  case 0x2d:
+    cpu_6800_bra(self, self->regs.bit.nf || self->regs.bit.vf, cpu_6800_ea_direct(self));
+    break;
+  case 0x2e:
+    cpu_6800_bra(self, !self->regs.bit.nf && !self->regs.bit.vf && !self->regs.bit.zf, cpu_6800_ea_direct(self));
+    break;
+  case 0x2f:
+    cpu_6800_bra(self, self->regs.bit.nf || self->regs.bit.vf || self->regs.bit.zf, cpu_6800_ea_direct(self));
+    break;
+  case 0x30:
+    cpu_6800_st(self, self->regs.word.s, CPU_6800_EA_X);
+    break;
+  case 0x31:
+    cpu_6800_in(self, CPU_6800_EA_S);
+    break;
+  case 0x32:
+    cpu_6800_pul(self, CPU_6800_EA_A);
+    break;
+  case 0x33:
+    cpu_6800_pul(self, CPU_6800_EA_B);
+    break;
+  case 0x34:
+    cpu_6800_de(self, CPU_6800_EA_S);
+    break;
+  case 0x35:
+    cpu_6800_st(self, self->regs.word.x, CPU_6800_EA_S);
+    break;
+  case 0x36:
+    cpu_6800_psh(self, self->regs.byte.a);
+    break;
+  case 0x37:
+    cpu_6800_psh(self, self->regs.byte.b);
+    break;
+  case 0x38:
+    cpu_6800_ill(self);
+    break;
+  case 0x39:
+    cpu_6800_rts(self);
+    break;
+  case 0x3a:
+    cpu_6800_ill(self);
+    break;
+  case 0x3b:
+    cpu_6800_rti(self);
+    break;
+  case 0x3c:
+    cpu_6800_ill(self);
+    break;
+  case 0x3d:
+    cpu_6800_ill(self);
+    break;
+  case 0x3e:
+    cpu_6800_wai(self);
+    break;
+  case 0x3f:
+    cpu_6800_swi(self, CPU_6800_SWI_VECTOR);
+    break;
+  case 0x40:
+    cpu_6800_neg(self, CPU_6800_EA_A);
+    break;
+  case 0x41:
+    cpu_6800_ill(self);
+    break;
+  case 0x42:
+    cpu_6800_ill(self);
+    break;
+  case 0x43:
+    cpu_6800_com(self, CPU_6800_EA_A);
+    break;
+  case 0x44:
+    cpu_6800_lsr(self, CPU_6800_EA_A);
+    break;
+  case 0x45:
+    cpu_6800_ill(self);
+    break;
+  case 0x46:
+    cpu_6800_ror(self, CPU_6800_EA_A);
+    break;
+  case 0x47:
+    cpu_6800_asr(self, CPU_6800_EA_A);
+    break;
+  case 0x48:
+    cpu_6800_lsl(self, CPU_6800_EA_A);
+    break;
+  case 0x49:
+    cpu_6800_rol(self, CPU_6800_EA_A);
+    break;
+  case 0x4a:
+    cpu_6800_dec(self, CPU_6800_EA_A);
+    break;
+  case 0x4b:
+    cpu_6800_ill(self);
+    break;
+  case 0x4c:
+    cpu_6800_inc(self, CPU_6800_EA_A);
+    break;
+  case 0x4d:
+    cpu_6800_tst(self, self->regs.byte.a);
+    break;
+  case 0x4e:
+    cpu_6800_ill(self);
+    break;
+  case 0x4f:
+    cpu_6800_clr(self, CPU_6800_EA_A);
+    break;
+  case 0x50:
+    cpu_6800_neg(self, CPU_6800_EA_B);
+    break;
+  case 0x51:
+    cpu_6800_ill(self);
+    break;
+  case 0x52:
+    cpu_6800_ill(self);
+    break;
+  case 0x53:
+    cpu_6800_com(self, CPU_6800_EA_B);
+    break;
+  case 0x54:
+    cpu_6800_lsr(self, CPU_6800_EA_B);
+    break;
+  case 0x55:
+    cpu_6800_ill(self);
+    break;
+  case 0x56:
+    cpu_6800_ror(self, CPU_6800_EA_B);
+    break;
+  case 0x57:
+    cpu_6800_asr(self, CPU_6800_EA_B);
+    break;
+  case 0x58:
+    cpu_6800_lsl(self, CPU_6800_EA_B);
+    break;
+  case 0x59:
+    cpu_6800_rol(self, CPU_6800_EA_B);
+    break;
+  case 0x5a:
+    cpu_6800_dec(self, CPU_6800_EA_B);
+    break;
+  case 0x5b:
+    cpu_6800_ill(self);
+    break;
+  case 0x5c:
+    cpu_6800_inc(self, CPU_6800_EA_B);
+    break;
+  case 0x5d:
+    cpu_6800_tst(self, self->regs.byte.b);
+    break;
+  case 0x5e:
+    cpu_6800_ill(self);
+    break;
+  case 0x5f:
+    cpu_6800_clr(self, CPU_6800_EA_B);
+    break;
+  case 0x60:
+    cpu_6800_neg(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x61:
+    cpu_6800_ill(self);
+    break;
+  case 0x62:
+    cpu_6800_ill(self);
+    break;
+  case 0x63:
+    cpu_6800_com(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x64:
+    cpu_6800_lsr(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x65:
+    cpu_6800_ill(self);
+    break;
+  case 0x66:
+    cpu_6800_ror(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x67:
+    cpu_6800_asr(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x68:
+    cpu_6800_lsl(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x69:
+    cpu_6800_rol(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x6a:
+    cpu_6800_dec(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x6b:
+    cpu_6800_ill(self);
+    break;
+  case 0x6c:
+    cpu_6800_inc(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x6d:
+    cpu_6800_tst(self, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0x6e:
+    cpu_6800_jmp(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x6f:
+    cpu_6800_clr(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0x70:
+    cpu_6800_neg(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x71:
+    cpu_6800_ill(self);
+    break;
+  case 0x72:
+    cpu_6800_ill(self);
+    break;
+  case 0x73:
+    cpu_6800_com(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x74:
+    cpu_6800_lsr(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x75:
+    cpu_6800_ill(self);
+    break;
+  case 0x76:
+    cpu_6800_ror(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x77:
+    cpu_6800_asr(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x78:
+    cpu_6800_lsl(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x79:
+    cpu_6800_rol(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x7a:
+    cpu_6800_dec(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x7b:
+    cpu_6800_ill(self);
+    break;
+  case 0x7c:
+    cpu_6800_inc(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x7d:
+    cpu_6800_tst(self, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0x7e:
+    cpu_6800_jmp(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x7f:
+    cpu_6800_clr(self, cpu_6800_ea_extended(self));
+    break;
+  case 0x80:
+    cpu_6800_sub(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x81:
+    cpu_6800_cmp(self, self->regs.byte.a, cpu_6800_fetch_byte(self));
+    break;
+  case 0x82:
+    cpu_6800_sbc(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x83:
+    cpu_6800_ill(self);
+    break;
+  case 0x84:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x85:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x86:
+    cpu_6800_lda(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x87:
+    cpu_6800_ill(self);
+    break;
+  case 0x88:
+    cpu_6800_eor(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x89:
+    cpu_6800_adc(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x8a:
+    cpu_6800_ora(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x8b:
+    cpu_6800_add(self, CPU_6800_EA_A, cpu_6800_fetch_byte(self));
+    break;
+  case 0x8c:
+    cpu_6800_cp(self, self->regs.word.x, cpu_6800_fetch_word(self));
+    break;
+  case 0x8d:
+    cpu_6800_bsr(self, cpu_6800_ea_direct(self));
+    break;
+  case 0x8e:
+    cpu_6800_ld(self, CPU_6800_EA_S, cpu_6800_fetch_word(self));
+    break;
+  case 0x8f:
+    cpu_6800_ill(self);
+    break;
+  case 0x90:
+    cpu_6800_sub(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x91:
+    cpu_6800_cmp(self, self->regs.byte.a, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x92:
+    cpu_6800_sbc(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x93:
+    cpu_6800_ill(self);
+    break;
+  case 0x94:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x95:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x96:
+    cpu_6800_lda(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x97:
+    cpu_6800_sta(self, CPU_6800_EA_A, cpu_6800_ea_direct(self));
+    break;
+  case 0x98:
+    cpu_6800_eor(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x99:
+    cpu_6800_adc(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x9a:
+    cpu_6800_ora(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x9b:
+    cpu_6800_add(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x9c:
+    cpu_6800_cp(self, self->regs.word.x, cpu_6800_read_word(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x9d:
+    cpu_6800_ill(self);
+    break;
+  case 0x9e:
+    cpu_6800_ld(self, CPU_6800_EA_S, cpu_6800_read_word(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0x9f:
+    cpu_6800_st(self, self->regs.word.s, cpu_6800_ea_direct(self));
+    break;
+  case 0xa0:
+    cpu_6800_sub(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa1:
+    cpu_6800_cmp(self, self->regs.byte.a, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa2:
+    cpu_6800_sbc(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa3:
+    cpu_6800_ill(self);
+    break;
+  case 0xa4:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa5:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa6:
+    cpu_6800_lda(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa7:
+    cpu_6800_sta(self, CPU_6800_EA_A, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0xa8:
+    cpu_6800_eor(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xa9:
+    cpu_6800_adc(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xaa:
+    cpu_6800_ora(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xab:
+    cpu_6800_add(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xac:
+    cpu_6800_cp(self, self->regs.word.x, cpu_6800_read_word(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xad:
+    cpu_6800_jsr(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0xae:
+    cpu_6800_ld(self, CPU_6800_EA_S, cpu_6800_read_word(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xaf:
+    cpu_6800_st(self, self->regs.word.s, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0xb0:
+    cpu_6800_sub(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb1:
+    cpu_6800_cmp(self, self->regs.byte.a, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb2:
+    cpu_6800_sbc(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb3:
+    cpu_6800_ill(self);
+    break;
+  case 0xb4:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb5:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb6:
+    cpu_6800_lda(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb7:
+    cpu_6800_sta(self, CPU_6800_EA_A, cpu_6800_ea_extended(self));
+    break;
+  case 0xb8:
+    cpu_6800_eor(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xb9:
+    cpu_6800_adc(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xba:
+    cpu_6800_ora(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xbb:
+    cpu_6800_add(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xbc:
+    cpu_6800_cp(self, self->regs.word.x, cpu_6800_read_word(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xbd:
+    cpu_6800_jsr(self, cpu_6800_ea_extended(self));
+    break;
+  case 0xbe:
+    cpu_6800_ld(self, CPU_6800_EA_S, cpu_6800_read_word(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xbf:
+    cpu_6800_st(self, self->regs.word.s, cpu_6800_ea_extended(self));
+    break;
+  case 0xc0:
+    cpu_6800_sub(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc1:
+    cpu_6800_cmp(self, self->regs.byte.b, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc2:
+    cpu_6800_sbc(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc3:
+    cpu_6800_ill(self);
+    break;
+  case 0xc4:
+    cpu_6800_and(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc5:
+    cpu_6800_bit(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc6:
+    cpu_6800_lda(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc7:
+    cpu_6800_ill(self);
+    break;
+  case 0xc8:
+    cpu_6800_eor(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xc9:
+    cpu_6800_adc(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xca:
+    cpu_6800_ora(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xcb:
+    cpu_6800_add(self, CPU_6800_EA_B, cpu_6800_fetch_byte(self));
+    break;
+  case 0xcc:
+    cpu_6800_ill(self);
+    break;
+  case 0xcd:
+    cpu_6800_ill(self);
+    break;
+  case 0xce:
+    cpu_6800_ld(self, CPU_6800_EA_X, cpu_6800_fetch_word(self));
+    break;
+  case 0xcf:
+    cpu_6800_ill(self);
+    break;
+  case 0xd0:
+    cpu_6800_sub(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd1:
+    cpu_6800_cmp(self, self->regs.byte.b, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd2:
+    cpu_6800_sbc(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd3:
+    cpu_6800_ill(self);
+    break;
+  case 0xd4:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd5:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd6:
+    cpu_6800_lda(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd7:
+    cpu_6800_sta(self, CPU_6800_EA_B, cpu_6800_ea_direct(self));
+    break;
+  case 0xd8:
+    cpu_6800_eor(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xd9:
+    cpu_6800_adc(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xda:
+    cpu_6800_ora(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xdb:
+    cpu_6800_add(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xdc:
+    cpu_6800_ill(self);
+    break;
+  case 0xdd:
+    cpu_6800_ill(self);
+    break;
+  case 0xde:
+    cpu_6800_ld(self, CPU_6800_EA_X, cpu_6800_read_word(self, cpu_6800_ea_direct(self)));
+    break;
+  case 0xdf:
+    cpu_6800_st(self, self->regs.word.x, cpu_6800_ea_direct(self));
+    break;
+  case 0xe0:
+    cpu_6800_sub(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe1:
+    cpu_6800_cmp(self, self->regs.byte.b, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe2:
+    cpu_6800_sbc(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe3:
+    cpu_6800_ill(self);
+    break;
+  case 0xe4:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe5:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe6:
+    cpu_6800_lda(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe7:
+    cpu_6800_sta(self, CPU_6800_EA_B, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0xe8:
+    cpu_6800_eor(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xe9:
+    cpu_6800_adc(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xea:
+    cpu_6800_ora(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xeb:
+    cpu_6800_add(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xec:
+    cpu_6800_ill(self);
+    break;
+  case 0xed:
+    cpu_6800_ill(self);
+    break;
+  case 0xee:
+    cpu_6800_ld(self, CPU_6800_EA_X, cpu_6800_read_word(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x)));
+    break;
+  case 0xef:
+    cpu_6800_st(self, self->regs.word.x, cpu_6800_ea_direct_indexed(self, self->regs.word.x));
+    break;
+  case 0xf0:
+    cpu_6800_sub(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf1:
+    cpu_6800_cmp(self, self->regs.byte.b, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf2:
+    cpu_6800_sbc(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf3:
+    cpu_6800_ill(self);
+    break;
+  case 0xf4:
+    cpu_6800_and(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf5:
+    cpu_6800_bit(self, CPU_6800_EA_A, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf6:
+    cpu_6800_lda(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf7:
+    cpu_6800_sta(self, CPU_6800_EA_B, cpu_6800_ea_extended(self));
+    break;
+  case 0xf8:
+    cpu_6800_eor(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xf9:
+    cpu_6800_adc(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xfa:
+    cpu_6800_ora(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xfb:
+    cpu_6800_add(self, CPU_6800_EA_B, cpu_6800_read_byte(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xfc:
+    cpu_6800_ill(self);
+    break;
+  case 0xfd:
+    cpu_6800_ill(self);
+    break;
+  case 0xfe:
+    cpu_6800_ld(self, CPU_6800_EA_X, cpu_6800_read_word(self, cpu_6800_ea_extended(self)));
+    break;
+  case 0xff:
+    cpu_6800_st(self, self->regs.word.x, cpu_6800_ea_extended(self));
+    break;
+  }
+}
diff --git a/cpu_6800.h b/cpu_6800.h
new file mode 100644 (file)
index 0000000..2bd2c57
--- /dev/null
@@ -0,0 +1,573 @@
+#ifndef _CPU_6800_H
+#define _CPU_6800_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// gcc specific
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE __attribute__((always_inline))
+#endif
+
+#define CPU_6800_IRQ_VECTOR 0xfff8
+#define CPU_6800_SWI_VECTOR 0xfffa
+#define CPU_6800_NMI_VECTOR 0xfffc
+#define CPU_6800_RESET_VECTOR 0xfffe
+
+// bits within REG_P
+#define CPU_6800_REG_P_BIT_H 5
+#define CPU_6800_REG_P_BIT_I 4
+#define CPU_6800_REG_P_BIT_N 3
+#define CPU_6800_REG_P_BIT_Z 2
+#define CPU_6800_REG_P_BIT_V 1
+#define CPU_6800_REG_P_BIT_C 0
+
+// special memory locations (negative address)
+#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_P (-2)
+#define CPU_6800_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_6800_regs {
+#if __BYTE_ORDER == __BIG_ENDIAN
+  struct {
+    uint16_t _fill_pc;
+    uint8_t _fill_a;
+    uint8_t _fill_b;
+    uint16_t _fill_x;
+    uint16_t _fill_s;
+    uint8_t _fill_p : 2;
+    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_x;
+    uint16_t _fill_s;
+    uint8_t p;
+    uint8_t iflags;
+  } byte;
+  struct {
+    uint16_t pc;
+    uint8_t _fill_a;
+    uint8_t _fill_b;
+    uint16_t x;
+    uint16_t s;
+    uint8_t _fill_p;
+    uint8_t _fill_iflags;
+  } word;
+  uint8_t mem_be[0xa];
+#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 _fill_p : 2;
+    uint16_t _fill_s;
+    uint16_t _fill_x;
+    uint8_t _fill_b;
+    uint8_t _fill_a;
+    uint16_t _fill_pc;
+  } bit;
+  struct {
+    uint8_t iflags;
+    uint8_t p;
+    uint16_t _fill_s;
+    uint16_t _fill_x;
+    uint8_t b;
+    uint8_t a;
+    uint16_t _fill_pc;
+  } byte;
+  struct {
+    uint8_t _fill_iflags;
+    uint8_t _fill_p;
+    uint16_t s;
+    uint16_t x;
+    uint8_t _fill_b;
+    uint8_t _fill_a;
+    uint16_t pc;
+  } word;
+  uint8_t mem_le[0xa];
+#endif
+};
+
+struct cpu_6800 {
+  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_6800_regs regs;
+};
+
+// memory or special memory access
+static ALWAYS_INLINE int cpu_6800_read_byte(struct cpu_6800 *self, int addr) {
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    return self->regs.mem_be[sizeof(union cpu_6800_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_6800_read_word(struct cpu_6800 *self, int addr) {
+  int data = cpu_6800_read_byte(self, addr) << 8;
+  return data | cpu_6800_read_byte(self, addr + 1);
+}
+
+static ALWAYS_INLINE void cpu_6800_write_byte(struct cpu_6800 *self, int addr, int data) {
+  self->cycles += 1;
+  if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    self->regs.mem_be[sizeof(union cpu_6800_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_6800_write_word(struct cpu_6800 *self, int addr, int data) {
+  cpu_6800_write_byte(self, addr, data >> 8);
+  cpu_6800_write_byte(self, addr + 1, data & 0xff);
+}
+
+static ALWAYS_INLINE int cpu_6800_fetch_byte(struct cpu_6800 *self) {
+  int data = cpu_6800_read_byte(self, self->regs.word.pc++);
+  return data;
+}
+
+static ALWAYS_INLINE int cpu_6800_fetch_word(struct cpu_6800 *self) {
+  int data = cpu_6800_fetch_byte(self) << 8;
+  return data | cpu_6800_fetch_byte(self);
+}
+
+static ALWAYS_INLINE void cpu_6800_push_byte(struct cpu_6800 *self, int data) {
+  cpu_6800_write_byte(self, self->regs.word.s--, data);
+}
+
+static ALWAYS_INLINE void cpu_6800_push_word(struct cpu_6800 *self, int data) {
+  cpu_6800_push_byte(self, data & 0xff);
+  cpu_6800_push_byte(self, data >> 8);
+}
+
+static ALWAYS_INLINE int cpu_6800_pop_byte(struct cpu_6800 *self) {
+  return cpu_6800_read_byte(self, ++self->regs.word.s);
+}
+
+static ALWAYS_INLINE int cpu_6800_pop_word(struct cpu_6800 *self) {
+  int data = cpu_6800_pop_byte(self) << 8;
+  return data | cpu_6800_pop_byte(self);
+}
+
+// effective address calculation
+static ALWAYS_INLINE int cpu_6800_ea_extended(struct cpu_6800 *self) {
+  return cpu_6800_fetch_word(self);
+}
+
+static ALWAYS_INLINE int cpu_6800_ea_extended_indexed(struct cpu_6800 *self, int rvalue) {
+  int addr = cpu_6800_ea_extended(self);
+  self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8;
+  return addr + rvalue;
+}
+
+static ALWAYS_INLINE int cpu_6800_ea_relative(struct cpu_6800 *self) {
+  int offset = cpu_6800_fetch_byte(self);
+  return offset - ((offset << 1) & 0x100);
+}
+
+static ALWAYS_INLINE int cpu_6800_ea_direct(struct cpu_6800 *self) {
+  return cpu_6800_fetch_byte(self);
+}
+
+static ALWAYS_INLINE int cpu_6800_ea_direct_indexed(struct cpu_6800 *self, int rvalue) {
+  return (cpu_6800_ea_direct(self) + rvalue) & 0xff;
+}
+
+// instruction execute
+static ALWAYS_INLINE void cpu_6800_adc(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int data = cpu_6800_read_byte(self, lvalue);
+
+  int result0 = self->regs.bit.cf + (data & 0x7f) + (rvalue & 0x7f);
+  int result1 = result0 + (data & 0x80) + (rvalue & 0x80);
+
+  cpu_6800_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.cf = result1 >> 8;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.nf = (result1 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_add(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int data = cpu_6800_read_byte(self, lvalue);
+
+  int result0 = (data & 0x7f) + (rvalue & 0x7f);
+  int result1 = result0 + (data & 0x80) + (rvalue & 0x80);
+
+  cpu_6800_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.cf = result1 >> 8;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.nf = (result1 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_and(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) & rvalue;
+
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.byte.a = result;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_asr(struct cpu_6800 *self, int lvalue) {
+  int data = cpu_6800_read_byte(self, lvalue);
+
+  int result = data | ((data << 1) & 0x100);
+  ++self->cycles;
+
+  cpu_6800_write_byte(self, lvalue, result >> 1);
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0xfe) == 0;
+  self->regs.bit.nf = false;
+}
+
+
+static ALWAYS_INLINE void cpu_6800_bit(struct cpu_6800 *self, int rvalue0, int rvalue1) {
+  int result = rvalue0 & rvalue1;
+
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_bit_imm(struct cpu_6800 *self, int rvalue) {
+  int result = self->regs.byte.a & rvalue;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_6800_bra(struct cpu_6800 *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_6800_bsr(struct cpu_6800 *self, int lvalue) {
+  cpu_6800_push_word(self, (self->regs.word.pc - 1) & 0xffff);
+  self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
+  self->regs.word.pc += lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6800_cl(struct cpu_6800 *self, int n) {
+  self->regs.byte.p &= ~(1 << n);
+}
+
+static ALWAYS_INLINE void cpu_6800_clr(struct cpu_6800 *self, int lvalue) {
+  cpu_6800_write_byte(self, lvalue, 0);
+}
+
+static ALWAYS_INLINE void cpu_6800_cmp(struct cpu_6800 *self, int rvalue0, int rvalue1) {
+  rvalue1 ^= 0xff;
+  int result = 1 + rvalue0 + rvalue1;
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_com(struct cpu_6800 *self, int lvalue) {
+  int result = ~cpu_6800_read_byte(self, lvalue);
+
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.bit.nf = true;
+  self->regs.bit.hf = true;
+}
+
+static ALWAYS_INLINE void cpu_6800_cp(struct cpu_6800 *self, int rvalue0, int rvalue1) {
+  rvalue1 ^= 0xffff;
+  int result = 1 + rvalue0 + rvalue1;
+  self->regs.bit.cf = result >> 16;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 15) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_daa(struct cpu_6800 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6800_de(struct cpu_6800 *self, int lvalue) {
+  int result = (cpu_6800_read_word(self, lvalue) - 1) & 0xffff;
+  ++self->cycles;
+  cpu_6800_write_word(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 15;
+}
+
+static ALWAYS_INLINE void cpu_6800_dec(struct cpu_6800 *self, int lvalue) {
+  int result = (cpu_6800_read_byte(self, lvalue) - 1) & 0xff;
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_eor(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) ^ rvalue;
+
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.byte.a = result;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_ill(struct cpu_6800 *self) {
+  abort();
+}
+
+static ALWAYS_INLINE void cpu_6800_in(struct cpu_6800 *self, int lvalue) {
+  int result = (cpu_6800_read_word(self, lvalue) + 1) & 0xffff;
+  ++self->cycles;
+  cpu_6800_write_word(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 15;
+}
+
+static ALWAYS_INLINE void cpu_6800_inc(struct cpu_6800 *self, int lvalue) {
+  int result = (cpu_6800_read_byte(self, lvalue) + 1) & 0xff;
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_swi(struct cpu_6800 *self, int lvalue) {
+  ++self->cycles;
+  cpu_6800_push_word(self, self->regs.word.pc);
+  cpu_6800_push_byte(self, self->regs.byte.p);
+  self->regs.word.pc = cpu_6800_read_word(self, lvalue);
+  self->regs.bit._if = true;
+}
+
+static ALWAYS_INLINE void cpu_6800_jmp(struct cpu_6800 *self, int lvalue) {
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6800_jsr(struct cpu_6800 *self, int lvalue) {
+  cpu_6800_push_word(self, (self->regs.word.pc - 1) & 0xffff);
+  self->regs.word.pc = lvalue;
+}
+
+static ALWAYS_INLINE void cpu_6800_ld(struct cpu_6800 *self, int lvalue, int rvalue) {
+  cpu_6800_write_word(self, lvalue, rvalue);
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.nf = (rvalue >> 15) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_lda(struct cpu_6800 *self, int lvalue, int rvalue) {
+  cpu_6800_write_byte(self, lvalue, rvalue);
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.nf = (rvalue >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_lsl(struct cpu_6800 *self, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) << 1;
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result & 0xff);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_lsr(struct cpu_6800 *self, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result >> 1);
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0xfe) == 0;
+  self->regs.bit.nf = false;
+}
+
+static ALWAYS_INLINE void cpu_6800_neg(struct cpu_6800 *self, int lvalue) {
+  int data = cpu_6800_read_byte(self, lvalue);
+
+  int result0 = -(data & 0xf);
+  int result1 = result0 - (data & 0x70);
+  int result2 = result1 - (data & 0x80);
+
+  cpu_6800_write_byte(self, lvalue, result2 & 0xff);
+  self->regs.bit.cf = (result2 >> 8) & 1;
+  self->regs.bit.nf = true;
+  self->regs.bit.vf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+  self->regs.bit.hf = (result0 >> 4) & 1;
+  self->regs.bit.zf = (result2 & 0xff) == 0;
+  self->regs.bit.nf = (result2 >> 7) & 1;
+}
+
+
+static ALWAYS_INLINE void cpu_6800_nop(struct cpu_6800 *self) {
+}
+
+static ALWAYS_INLINE void cpu_6800_ora(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) | rvalue;
+
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.byte.a = result;
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_plp(struct cpu_6800 *self) {
+  self->regs.byte.p = cpu_6800_pop_byte(self) | 0xc0;
+}
+
+static ALWAYS_INLINE void cpu_6800_psh(struct cpu_6800 *self, int rvalue) {
+  cpu_6800_push_byte(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_6800_pul(struct cpu_6800 *self, int lvalue) {
+  int result = cpu_6800_pop_byte(self);
+  cpu_6800_write_byte(self, lvalue, result);
+  self->regs.bit.zf = result == 0;
+  self->regs.bit.nf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_rmb(struct cpu_6800 *self, int n, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) & ~(1 << n);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_6800_rol(struct cpu_6800 *self, int lvalue) {
+  int result = self->regs.bit.cf | (cpu_6800_read_byte(self, lvalue) << 1);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result & 0xff);
+  self->regs.bit.cf = result >> 8;
+  self->regs.bit.zf = (result & 0xff) == 0;
+  self->regs.bit.nf = (result >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_ror(struct cpu_6800 *self, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) | (self->regs.bit.cf << 8);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result >> 1);
+  self->regs.bit.cf = result & 1;
+  self->regs.bit.zf = (result & 0x1fe) == 0;
+  self->regs.bit.nf = (result >> 8) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_rti(struct cpu_6800 *self) {
+  self->regs.byte.p = cpu_6800_pop_byte(self) | 0xc0;
+  self->regs.word.pc = cpu_6800_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_6800_rts(struct cpu_6800 *self) {
+  self->regs.word.pc = (cpu_6800_pop_word(self) + 1) & 0xffff;
+}
+
+static ALWAYS_INLINE void cpu_6800_sbc(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int data = cpu_6800_read_byte(self, lvalue);
+  rvalue ^= 0xff;
+
+  int result0 = self->regs.bit.cf + (data & 0x7f) + (rvalue & 0x7f);
+  int result1 = result0 + (data & 0x80) + (rvalue & 0x80);
+
+  cpu_6800_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.cf = result1 >> 8;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.nf = (result1 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_se(struct cpu_6800 *self, int n) {
+  self->regs.byte.p |= 1 << n;
+}
+
+static ALWAYS_INLINE void cpu_6800_smb(struct cpu_6800 *self, int n, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue) | (1 << n);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_6800_st(struct cpu_6800 *self, int rvalue, int lvalue) {
+  cpu_6800_write_word(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_6800_sta(struct cpu_6800 *self, int rvalue, int lvalue) {
+  cpu_6800_write_byte(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_6800_sub(struct cpu_6800 *self, int lvalue, int rvalue) {
+  int data = cpu_6800_read_byte(self, lvalue);
+  rvalue ^= 0xff;
+
+  int result0 = (data & 0x7f) + (rvalue & 0x7f);
+  int result1 = result0 + (data & 0x80) + (rvalue & 0x80);
+
+  cpu_6800_write_byte(self, lvalue, result1 & 0xff);
+  self->regs.bit.cf = result1 >> 8;
+  self->regs.bit.zf = (result1 & 0xff) == 0;
+  self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1;
+  self->regs.bit.nf = (result1 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_6800_trb(struct cpu_6800 *self, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result & ~self->regs.byte.a);
+  result &= self->regs.byte.a;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_6800_tsb(struct cpu_6800 *self, int lvalue) {
+  int result = cpu_6800_read_byte(self, lvalue);
+  ++self->cycles;
+  cpu_6800_write_byte(self, lvalue, result | self->regs.byte.a);
+  result &= self->regs.byte.a;
+  self->regs.bit.zf = result == 0;
+}
+
+static ALWAYS_INLINE void cpu_6800_tst(struct cpu_6800 *self, int rvalue) {
+  self->regs.bit.zf = rvalue == 0;
+  self->regs.bit.nf = rvalue >> 7;
+}
+
+static ALWAYS_INLINE void cpu_6800_wai(struct cpu_6800 *self) {
+  self->regs.bit.wai_flag = true;
+}
+
+// prototypes
+void cpu_6800_init(
+  struct cpu_6800 *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_6800_reset(struct cpu_6800 *self);
+void cpu_6800_execute(struct cpu_6800 *self);
+#endif
index a2e5853..28c3eea 100644 (file)
--- a/cpu_z80.h
+++ b/cpu_z80.h
@@ -250,7 +250,7 @@ static ALWAYS_INLINE int cpu_z80_read_byte(struct cpu_z80 *self, int addr) {
 #if __BYTE_ORDER == __BIG_ENDIAN
     return self->regs.mem_be[~addr];
 #else
-    return self->regs.mem_le[addr - CPU_Z80_EA_F];
+    return self->regs.mem_le[sizeof(union cpu_z80_regs) + addr];
 #endif
   self->cycles += 1;
   return self->read_byte(self->read_byte_context, addr & 0xffff);
@@ -267,7 +267,7 @@ static ALWAYS_INLINE void cpu_z80_write_byte(struct cpu_z80 *self, int addr, int
 #if __BYTE_ORDER == __BIG_ENDIAN
     self->regs.mem_be[~addr] = data;
 #else
-    self->regs.mem_le[addr - CPU_Z80_EA_F] = data;
+    self->regs.mem_le[sizeof(union cpu_z80_regs) + addr] = data;
 #endif
   else
     self->write_byte(self->write_byte_context, addr, data);
diff --git a/decode_6800.py b/decode_6800.py
new file mode 100755 (executable)
index 0000000..8f649e1
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+
+import sys
+
+# if first argument is embedded in opcode, it is rvalue for these
+acc_rvalue_opcodes = {
+  'cmp',
+  'psh',
+  'tst',
+}
+
+rvalue_opcodes = {
+  'add',
+  'adc',
+  'and',
+  'bit',
+  'cmp',
+  'cpx',
+  'eor',
+  'lda',
+  'ldx',
+  'lds',
+  'ora',
+  'sub',
+  'sbc',
+  'tst',
+}
+rvalue_modes = {
+  '#12': 'cpu_6800_fetch_byte(self)',
+  '#1234': 'cpu_6800_fetch_word(self)',
+  '12': 'cpu_6800_read_byte(self, cpu_6800_ea_direct(self))',
+  '12,x': 'cpu_6800_read_byte(self, cpu_6800_ea_direct_indexed(self, self->regs.word.x))',
+  '1234': 'cpu_6800_read_byte(self, cpu_6800_ea_extended(self))',
+  '1234,x': 'cpu_6800_read_byte(self, cpu_6800_ea_extended_indexed(self, self->regs.word.x))',
+  'a': 'self->regs.byte.a',
+  'b': 'self->regs.byte.b',
+}
+lvalue_modes = {
+  '0014': 'cpu_6800_ea_relative(self)',
+  '12': 'cpu_6800_ea_direct(self)',
+  '12,x': 'cpu_6800_ea_direct_indexed(self, self->regs.word.x)',
+  '1234': 'cpu_6800_ea_extended(self)',
+  '1234,x': 'cpu_6800_ea_extended_indexed(self, self->regs.word.x)',
+  'a': 'CPU_6800_EA_A',
+  'b': 'CPU_6800_EA_B',
+}
+
+print('void cpu_6800_execute(struct cpu_6800 *self) {')
+print('  switch (cpu_6800_fetch_byte(self)) {')
+for i in range(0x100):
+  print(f'  case 0x{i:02x}:')
+  instr = sys.stdin.readline().strip().split('\t')[-1].split()
+  if instr[0] == '---':
+    instr[0] = 'ill' # illegal opcode
+  #print('xxx', instr)
+  if len(instr) >= 2:
+    if instr[0][:3] in rvalue_opcodes:
+      instr[1] = rvalue_modes[instr[1]]
+    else:
+      instr[1] = lvalue_modes[instr[1]]
+  if len(instr[0]) >= 4:
+    # move accumulator a/b from opcode to first argument
+    if instr[0][:3] in acc_rvalue_opcodes:
+      instr[:1] = [instr[0][:3], rvalue_modes[instr[0][3:]]]
+    else:
+      instr[:1] = [instr[0][:3], lvalue_modes[instr[0][3:]]]
+  print(
+    '    cpu_6800_{0:s}(self{1:s});'.format(
+      instr[0],
+      ''.join([', ' + j for j in instr[1:]])
+    )
+  )
+  print('    break;')
+print('  }')
+print('}')
diff --git a/decode_6800.sed b/decode_6800.sed
new file mode 100644 (file)
index 0000000..6974f4d
--- /dev/null
@@ -0,0 +1,39 @@
+s/cpu_6800_bpl(self/cpu_6800_bnc(self/
+s/cpu_6800_bmi(self/cpu_6800_bns(self/
+s/cpu_6800_bne(self/cpu_6800_bzc(self/
+s/cpu_6800_beq(self/cpu_6800_bzs(self/
+s/cpu_6800_bra(self/cpu_6800_bra(self, true/
+s/cpu_6800_b\([czvn]\)c(self/cpu_6800_bra(self, !self->regs.bit.\1f/
+s/cpu_6800_b\([czvn]\)s(self/cpu_6800_bra(self, self->regs.bit.\1f/
+s/cpu_6800_bge(self/cpu_6800_bra(self, !self->regs.bit.nf \&\& !self->regs.bit.vf/
+s/cpu_6800_bgt(self/cpu_6800_bra(self, !self->regs.bit.nf \&\& !self->regs.bit.vf \&\& !self->regs.bit.zf/
+s/cpu_6800_bhi(self/cpu_6800_bra(self, !self->regs.bit.cf \&\& !self->regs.bit.zf/
+s/cpu_6800_ble(self/cpu_6800_bra(self, self->regs.bit.nf || self->regs.bit.vf || self->regs.bit.zf/
+s/cpu_6800_bls(self/cpu_6800_bra(self, self->regs.bit.cf || self->regs.bit.zf/
+s/cpu_6800_blt(self/cpu_6800_bra(self, self->regs.bit.nf || self->regs.bit.vf/
+s/cpu_6800_st\([xs]\)(self/cpu_6800_st(self, self->regs.word.\1/
+s/cpu_6800_ld\([xs]\)(self\(.*\)byte/cpu_6800_ld(self, CPU_6800_EA_\1\2word/
+s/cpu_6800_ld\([xs]\)(self/cpu_6800_ld(self, CPU_6800_EA_\1/
+s/cpu_6800_txs(self/cpu_6800_st(self, self->regs.word.x, CPU_6800_EA_S/
+s/cpu_6800_tsx(self/cpu_6800_st(self, self->regs.word.s, CPU_6800_EA_X/
+s/cpu_6800_a\([ab]\)\([ab]\)(self/cpu_6800_add(self, CPU_6800_EA_\2, self->regs.byte.\1/
+s/cpu_6800_c\([ab]\)\([ab]\)(self/cpu_6800_cmp(self, CPU_6800_EA_\2, self->regs.byte.\1/
+s/cpu_6800_s\([ab]\)\([ab]\)(self/cpu_6800_sub(self, CPU_6800_EA_\2, self->regs.byte.\1/
+s/cpu_6800_t\([ab]\)\([ab]\)(self/cpu_6800_lda(self, CPU_6800_EA_\2, self->regs.byte.\1/
+s/cpu_6800_tap(self/cpu_6800_sta(self, self->regs.byte.a | 0xc0, CPU_6800_EA_P/
+s/cpu_6800_tpa(self/cpu_6800_sta(self, self->regs.byte.p, CPU_6800_EA_A/
+s/cpu_6800_cl\([cidv]\)(self/cpu_6800_cl(self, CPU_6800_REG_P_BIT_\1/
+s/cpu_6800_se\([cidv]\)(self/cpu_6800_se(self, CPU_6800_REG_P_BIT_\1/
+s/cpu_6800_in\([xs]\)(self/cpu_6800_in(self, CPU_6800_EA_\1/
+s/cpu_6800_de\([xs]\)(self/cpu_6800_de(self, CPU_6800_EA_\1/
+s/cpu_6800_cp\([xs]\)(self\(.*\)byte/cpu_6800_cp(self, self->regs.word.\1\2word/
+s/cpu_6800_cp\([xs]\)(self/cpu_6800_cp(self, self->regs.word.\1/
+s/cpu_6800_swi(self/cpu_6800_swi(self, CPU_6800_SWI_VECTOR/
+s/CPU_6800_EA_a/CPU_6800_EA_A/g
+s/CPU_6800_EA_b/CPU_6800_EA_A/g
+s/CPU_6800_EA_x/CPU_6800_EA_X/g
+s/CPU_6800_EA_s/CPU_6800_EA_S/g
+s/CPU_6800_REG_P_BIT_c/CPU_6800_REG_P_BIT_C/g
+s/CPU_6800_REG_P_BIT_i/CPU_6800_REG_P_BIT_I/g
+s/CPU_6800_REG_P_BIT_d/CPU_6800_REG_P_BIT_D/g
+s/CPU_6800_REG_P_BIT_v/CPU_6800_REG_P_BIT_V/g
index 02b40b7..754d807 100644 (file)
@@ -187,9 +187,10 @@ int main(int argc, char **argv) {
 #if REG_TRACE
     fprintf(
       stderr,
-      "pc=%04x d=%04x ix=%02x sp=%04x ccr=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
+      "pc=%04x a=%02x b=%02x x=%04x s=%04x ccr=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
       regs.pc,
-      (regs.accd.a << 8) | regs.accd.b,
+      regs.accd.a,
+      regs.accd.b,
       regs.ix,
       regs.sp,
       regs.ccr | 0xc0,
@@ -208,35 +209,28 @@ int main(int argc, char **argv) {
   struct cpu_6800 cpu;
   cpu_6800_init(&cpu, read_byte, NULL, write_byte, NULL);
   cpu_6800_reset(&cpu);
-  cpu.regs.word.pc = entry_point;
-  cpu.regs.byte.s = 0xff;
 
   while (true) {
 #if REG_TRACE
     fprintf(
       stderr,
-      "pc=%04x a=%02x x=%02x y=%02x s=%02x p=%02x cf=%d zf=%d if=%d df=%d vf=%d nf=%d\n",
+      "pc=%04x a=%02x b=%02x x=%04x s=%04x ccr=%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.x,
-      cpu.regs.byte.y,
-      cpu.regs.byte.s,
-      cpu.regs.byte.p,
-      cpu.regs.bit.cf,
-      cpu.regs.bit.zf,
+      cpu.regs.byte.b,
+      cpu.regs.word.x,
+      cpu.regs.word.s,
+      cpu.regs.byte.ccr,
+      cpu.regs.bit.hf,
       cpu.regs.bit._if,
-      cpu.regs.bit.df,
+      cpu.regs.bit.nf,
+      cpu.regs.bit.zf,
       cpu.regs.bit.vf,
-      cpu.regs.bit.nf
+      cpu.regs.bit.cf
     );
 #endif
 
-    int pc = cpu.regs.word.pc;
     cpu_6800_execute(&cpu);
-    if (pc == cpu.regs.word.pc) {
-      printf("hung at %04x\n", pc);
-      break;
-    }
   }
 #endif
 
index 384fae2..0f2af54 100644 (file)
 0100   80 12           suba #12
 0100   81 12           cmpa #12
 0100   82 12           sbca #12
-0100   83 12 34        subd #1234
+0100   83              ---
 0100   84 12           anda #12
 0100   85 12           bita #12
 0100   86 12           ldaa #12
diff --git a/sim68xx b/sim68xx
index ac4242a..64cb8ed 160000 (submodule)
--- a/sim68xx
+++ b/sim68xx
@@ -1 +1 @@
-Subproject commit ac4242a2c330a365d589b6c186a7f6129c408b5e
+Subproject commit 64cb8ed44c43dbefa00555677290340728057f40