Pristine copy of src/devices/cpu/m6502 from MAME commit 7a3eb11, but only the m6502...
authorNick Downing <nick.downing@lifx.co>
Sun, 30 Jun 2019 00:08:04 +0000 (10:08 +1000)
committerNick Downing <nick.downing@lifx.co>
Sun, 30 Jun 2019 00:27:41 +0000 (10:27 +1000)
14 files changed:
m6502/dm6502.lst [new file with mode: 0644]
m6502/dm65c02.lst [new file with mode: 0644]
m6502/m6502.cpp [new file with mode: 0644]
m6502/m6502.h [new file with mode: 0644]
m6502/m6502.txt [new file with mode: 0644]
m6502/m6502d.cpp [new file with mode: 0644]
m6502/m6502d.h [new file with mode: 0644]
m6502/m6502make.py [new file with mode: 0755]
m6502/m65c02.cpp [new file with mode: 0644]
m6502/m65c02.h [new file with mode: 0644]
m6502/m65c02d.cpp [new file with mode: 0644]
m6502/m65c02d.h [new file with mode: 0644]
m6502/om6502.lst [new file with mode: 0644]
m6502/om65c02.lst [new file with mode: 0644]

diff --git a/m6502/dm6502.lst b/m6502/dm6502.lst
new file mode 100644 (file)
index 0000000..654a2f1
--- /dev/null
@@ -0,0 +1,20 @@
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+# m6502_family_device - 6502, 6504
+brk_imp     ora_idx     kil_non     slo_idx     nop_zpg     ora_zpg     asl_zpg     slo_zpg     php_imp     ora_imm     asl_acc     anc_imm     nop_aba     ora_aba     asl_aba     slo_aba
+bpl_rel     ora_idy     kil_non     slo_idy     nop_zpx     ora_zpx     asl_zpx     slo_zpx     clc_imp     ora_aby     nop_imp     slo_aby     nop_abx     ora_abx     asl_abx     slo_abx
+jsr_adr     and_idx     kil_non     rla_idx     bit_zpg     and_zpg     rol_zpg     rla_zpg     plp_imp     and_imm     rol_acc     anc_imm     bit_aba     and_aba     rol_aba     rla_aba
+bmi_rel     and_idy     kil_non     rla_idy     nop_zpx     and_zpx     rol_zpx     rla_zpx     sec_imp     and_aby     nop_imp     rla_aby     nop_abx     and_abx     rol_abx     rla_abx
+rti_imp     eor_idx     kil_non     sre_idx     nop_zpg     eor_zpg     lsr_zpg     sre_zpg     pha_imp     eor_imm     lsr_acc     asr_imm     jmp_adr     eor_aba     lsr_aba     sre_aba
+bvc_rel     eor_idy     kil_non     sre_idy     nop_zpx     eor_zpx     lsr_zpx     sre_zpx     cli_imp     eor_aby     nop_imp     sre_aby     nop_abx     eor_abx     lsr_abx     sre_abx
+rts_imp     adc_idx     kil_non     rra_idx     nop_zpg     adc_zpg     ror_zpg     rra_zpg     pla_imp     adc_imm     ror_acc     arr_imm     jmp_ind     adc_aba     ror_aba     rra_aba
+bvs_rel     adc_idy     kil_non     rra_idy     nop_zpx     adc_zpx     ror_zpx     rra_zpx     sei_imp     adc_aby     nop_imp     rra_aby     nop_abx     adc_abx     ror_abx     rra_abx
+nop_imm     sta_idx     nop_imm     sax_idx     sty_zpg     sta_zpg     stx_zpg     sax_zpg     dey_imp     nop_imm     txa_imp     ane_imm     sty_aba     sta_aba     stx_aba     sax_aba
+bcc_rel     sta_idy     kil_non     sha_idy     sty_zpx     sta_zpx     stx_zpy     sax_zpy     tya_imp     sta_aby     txs_imp     shs_aby     shy_abx     sta_abx     shx_aby     sha_aby
+ldy_imm     lda_idx     ldx_imm     lax_idx     ldy_zpg     lda_zpg     ldx_zpg     lax_zpg     tay_imp     lda_imm     tax_imp     lxa_imm     ldy_aba     lda_aba     ldx_aba     lax_aba
+bcs_rel     lda_idy     kil_non     lax_idy     ldy_zpx     lda_zpx     ldx_zpy     lax_zpy     clv_imp     lda_aby     tsx_imp     las_aby     ldy_abx     lda_abx     ldx_aby     lax_aby
+cpy_imm     cmp_idx     nop_imm     dcp_idx     cpy_zpg     cmp_zpg     dec_zpg     dcp_zpg     iny_imp     cmp_imm     dex_imp     sbx_imm     cpy_aba     cmp_aba     dec_aba     dcp_aba
+bne_rel     cmp_idy     kil_non     dcp_idy     nop_zpx     cmp_zpx     dec_zpx     dcp_zpx     cld_imp     cmp_aby     nop_imp     dcp_aby     nop_abx     cmp_abx     dec_abx     dcp_abx
+cpx_imm     sbc_idx     nop_imm     isb_idx     cpx_zpg     sbc_zpg     inc_zpg     isb_zpg     inx_imp     sbc_imm     nop_imp     sbc_imm     cpx_aba     sbc_aba     inc_aba     isb_aba
+beq_rel     sbc_idy     kil_non     isb_idy     nop_zpx     sbc_zpx     inc_zpx     isb_zpx     sed_imp     sbc_aby     nop_imp     isb_aby     nop_abx     sbc_abx     inc_abx     isb_abx
+reset
diff --git a/m6502/dm65c02.lst b/m6502/dm65c02.lst
new file mode 100644 (file)
index 0000000..a174a15
--- /dev/null
@@ -0,0 +1,20 @@
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+# m65c02
+brk_c_imp   ora_idx     nop_imm     nop_c_imp   tsb_zpg     ora_zpg     asl_zpg     nop_c_imp   php_imp     ora_imm     asl_acc     nop_c_imp   tsb_aba     ora_aba     asl_aba     nop_c_imp
+bpl_rel     ora_idy     ora_zpi     nop_c_imp   trb_zpg     ora_zpx     asl_zpx     nop_c_imp   clc_imp     ora_aby     inc_acc     nop_c_imp   trb_aba     ora_abx     asl_c_abx   nop_c_imp
+jsr_adr     and_idx     nop_imm     nop_c_imp   bit_zpg     and_zpg     rol_zpg     nop_c_imp   plp_imp     and_imm     rol_acc     nop_c_imp   bit_aba     and_aba     rol_aba     nop_c_imp
+bmi_rel     and_idy     and_zpi     nop_c_imp   bit_zpx     and_zpx     rol_zpx     nop_c_imp   sec_imp     and_aby     dec_acc     nop_c_imp   bit_abx     and_abx     rol_c_abx   nop_c_imp
+rti_imp     eor_idx     nop_imm     nop_c_imp   nop_zpg     eor_zpg     lsr_zpg     nop_c_imp   pha_imp     eor_imm     lsr_acc     nop_c_imp   jmp_adr     eor_aba     lsr_aba     nop_c_imp
+bvc_rel     eor_idy     eor_zpi     nop_c_imp   nop_zpx     eor_zpx     lsr_zpx     nop_c_imp   cli_imp     eor_aby     phy_imp     nop_c_imp   nop_c_aba   eor_abx     lsr_c_abx   nop_c_imp
+rts_imp     adc_c_idx   nop_imm     nop_c_imp   stz_zpg     adc_c_zpg   ror_zpg     nop_c_imp   pla_imp     adc_c_imm   ror_acc     nop_c_imp   jmp_c_ind   adc_c_aba   ror_aba     nop_c_imp
+bvs_rel     adc_c_idy   adc_c_zpi   nop_c_imp   stz_zpx     adc_c_zpx   ror_zpx     nop_c_imp   sei_imp     adc_c_aby   ply_imp     nop_c_imp   jmp_iax     adc_c_abx   ror_c_abx   nop_c_imp
+bra_rel     sta_idx     nop_imm     nop_c_imp   sty_zpg     sta_zpg     stx_zpg     nop_c_imp   dey_imp     bit_imm     txa_imp     nop_c_imp   sty_aba     sta_aba     stx_aba     nop_c_imp
+bcc_rel     sta_idy     sta_zpi     nop_c_imp   sty_zpx     sta_zpx     stx_zpy     nop_c_imp   tya_imp     sta_aby     txs_imp     nop_c_imp   stz_aba     sta_abx     stz_abx     nop_c_imp
+ldy_imm     lda_idx     ldx_imm     nop_c_imp   ldy_zpg     lda_zpg     ldx_zpg     nop_c_imp   tay_imp     lda_imm     tax_imp     nop_c_imp   ldy_aba     lda_aba     ldx_aba     nop_c_imp
+bcs_rel     lda_idy     lda_zpi     nop_c_imp   ldy_zpx     lda_zpx     ldx_zpy     nop_c_imp   clv_imp     lda_aby     tsx_imp     nop_c_imp   ldy_abx     lda_abx     ldx_aby     nop_c_imp
+cpy_imm     cmp_idx     nop_imm     nop_c_imp   cpy_zpg     cmp_zpg     dec_zpg     nop_c_imp   iny_imp     cmp_imm     dex_imp     nop_c_imp   cpy_aba     cmp_aba     dec_aba     nop_c_imp
+bne_rel     cmp_idy     cmp_zpi     nop_c_imp   nop_zpx     cmp_zpx     dec_zpx     nop_c_imp   cld_imp     cmp_aby     phx_imp     nop_c_imp   nop_c_abx   cmp_abx     dec_abx     nop_c_imp
+cpx_imm     sbc_c_idx   nop_imm     nop_c_imp   cpx_zpg     sbc_c_zpg   inc_zpg     nop_c_imp   inx_imp     sbc_c_imm   nop_imp     nop_c_imp   cpx_aba     sbc_c_aba   inc_aba     nop_c_imp
+beq_rel     sbc_c_idy   sbc_c_zpi   nop_c_imp   nop_zpx     sbc_c_zpx   inc_zpx     nop_c_imp   sed_imp     sbc_c_aby   plx_imp     nop_c_imp   nop_c_abx   sbc_c_abx   inc_abx     nop_c_imp
+reset
diff --git a/m6502/m6502.cpp b/m6502/m6502.cpp
new file mode 100644 (file)
index 0000000..2249ee5
--- /dev/null
@@ -0,0 +1,621 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m6502.c
+
+    MOS Technology 6502, original NMOS variant
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "m6502.h"
+#include "m6502d.h"
+
+DEFINE_DEVICE_TYPE(M6502, m6502_device, "m6502", "MOS Technology M6502")
+
+m6502_device::m6502_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+       m6502_device(mconfig, M6502, tag, owner, clock)
+{
+}
+
+m6502_device::m6502_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+       cpu_device(mconfig, type, tag, owner, clock),
+       sync_w(*this),
+       program_config("program", ENDIANNESS_LITTLE, 8, 16),
+       sprogram_config("decrypted_opcodes", ENDIANNESS_LITTLE, 8, 16), PPC(0), NPC(0), PC(0), SP(0), TMP(0), TMP2(0), A(0), X(0), Y(0), P(0), IR(0), inst_state_base(0), mintf(nullptr),
+       inst_state(0), inst_substate(0), icount(0), nmi_state(false), irq_state(false), apu_irq_state(false), v_state(false), irq_taken(false), sync(false), inhibit_interrupts(false)
+{
+       cache_disabled = false;
+}
+
+void m6502_device::device_start()
+{
+       if(cache_disabled)
+               mintf = std::make_unique<mi_default_nd>();
+       else
+               mintf = std::make_unique<mi_default_normal>();
+
+       init();
+}
+
+void m6502_device::init()
+{
+       mintf->program  = &space(AS_PROGRAM);
+       mintf->sprogram = has_space(AS_OPCODES) ? &space(AS_OPCODES) : mintf->program;
+
+       mintf->cache  = mintf->program->cache<0, 0, ENDIANNESS_LITTLE>();
+       mintf->scache = mintf->sprogram->cache<0, 0, ENDIANNESS_LITTLE>();
+
+       sync_w.resolve_safe();
+
+       XPC = 0;
+
+       state_add(STATE_GENPC,     "GENPC",     XPC).callexport().noshow();
+       state_add(STATE_GENPCBASE, "CURPC",     XPC).callexport().noshow();
+       state_add(STATE_GENSP,     "GENSP",     SP).noshow();
+       state_add(STATE_GENFLAGS,  "GENFLAGS",  P).callimport().formatstr("%6s").noshow();
+       state_add(M6502_PC,        "PC",        NPC).callimport();
+       state_add(M6502_A,         "A",         A);
+       state_add(M6502_X,         "X",         X);
+       state_add(M6502_Y,         "Y",         Y);
+       state_add(M6502_P,         "P",         P).callimport();
+       state_add(M6502_S,         "SP",        SP);
+       state_add(M6502_IR,        "IR",        IR);
+
+       save_item(NAME(PC));
+       save_item(NAME(NPC));
+       save_item(NAME(PPC));
+       save_item(NAME(A));
+       save_item(NAME(X));
+       save_item(NAME(Y));
+       save_item(NAME(P));
+       save_item(NAME(SP));
+       save_item(NAME(TMP));
+       save_item(NAME(TMP2));
+       save_item(NAME(IR));
+       save_item(NAME(nmi_state));
+       save_item(NAME(irq_state));
+       save_item(NAME(apu_irq_state));
+       save_item(NAME(v_state));
+       save_item(NAME(inst_state));
+       save_item(NAME(inst_substate));
+       save_item(NAME(inst_state_base));
+       save_item(NAME(irq_taken));
+       save_item(NAME(inhibit_interrupts));
+
+       set_icountptr(icount);
+
+       PC = 0x0000;
+       NPC = 0x0000;
+       A = 0x00;
+       X = 0x80;
+       Y = 0x00;
+       P = 0x36;
+       SP = 0x01bd;
+       TMP = 0x0000;
+       TMP2 = 0x00;
+       IR = 0x00;
+       nmi_state = false;
+       irq_state = false;
+       apu_irq_state = false;
+       irq_taken = false;
+       v_state = false;
+       inst_state = STATE_RESET;
+       inst_substate = 0;
+       inst_state_base = 0;
+       sync = false;
+       inhibit_interrupts = false;
+       count_before_instruction_step = 0;
+}
+
+void m6502_device::device_reset()
+{
+       inst_state = STATE_RESET;
+       inst_substate = 0;
+       inst_state_base = 0;
+       nmi_state = false;
+       irq_state = false;
+       apu_irq_state = false;
+       irq_taken = false;
+       v_state = false;
+       sync = false;
+       sync_w(CLEAR_LINE);
+       inhibit_interrupts = false;
+}
+
+
+uint32_t m6502_device::execute_min_cycles() const
+{
+       return 1;
+}
+
+uint32_t m6502_device::execute_max_cycles() const
+{
+       return 10;
+}
+
+uint32_t m6502_device::execute_input_lines() const
+{
+       return NMI_LINE+1;
+}
+
+bool m6502_device::execute_input_edge_triggered(int inputnum) const
+{
+       return inputnum == NMI_LINE;
+}
+
+void m6502_device::do_adc_d(uint8_t val)
+{
+       uint8_t c = P & F_C ? 1 : 0;
+       P &= ~(F_N|F_V|F_Z|F_C);
+       uint8_t al = (A & 15) + (val & 15) + c;
+       if(al > 9)
+               al += 6;
+       uint8_t ah = (A >> 4) + (val >> 4) + (al > 15);
+       if(!uint8_t(A + val + c))
+               P |= F_Z;
+       else if(ah & 8)
+               P |= F_N;
+       if(~(A^val) & (A^(ah << 4)) & 0x80)
+               P |= F_V;
+       if(ah > 9)
+               ah += 6;
+       if(ah > 15)
+               P |= F_C;
+       A = (ah << 4) | (al & 15);
+}
+
+void m6502_device::do_adc_nd(uint8_t val)
+{
+       uint16_t sum;
+       sum = A + val + (P & F_C ? 1 : 0);
+       P &= ~(F_N|F_V|F_Z|F_C);
+       if(!uint8_t(sum))
+               P |= F_Z;
+       else if(int8_t(sum) < 0)
+               P |= F_N;
+       if(~(A^val) & (A^sum) & 0x80)
+               P |= F_V;
+       if(sum & 0xff00)
+               P |= F_C;
+       A = sum;
+}
+
+void m6502_device::do_adc(uint8_t val)
+{
+       if(P & F_D)
+               do_adc_d(val);
+       else
+               do_adc_nd(val);
+}
+
+void m6502_device::do_arr_nd()
+{
+       bool c = P & F_C;
+       P &= ~(F_N|F_Z|F_C|F_V);
+       A >>= 1;
+       if(c)
+               A |= 0x80;
+       if(!A)
+               P |= F_Z;
+       else if(int8_t(A)<0)
+               P |= F_N;
+       if(A & 0x40)
+               P |= F_V|F_C;
+       if(A & 0x20)
+               P ^= F_V;
+}
+
+void m6502_device::do_arr_d()
+{
+       // The adc/ror interaction gives an extremely weird result
+       bool c = P & F_C;
+       P &= ~(F_N|F_Z|F_C|F_V);
+       uint8_t a = A >> 1;
+       if(c)
+               a |= 0x80;
+       if(!a)
+               P |= F_Z;
+       else if(int8_t(a) < 0)
+               P |= F_N;
+       if((a ^ A) & 0x40)
+               P |= F_V;
+
+       if((A & 0x0f) >= 0x05)
+               a = ((a + 6) & 0x0f) | (a & 0xf0);
+
+       if((A & 0xf0) >= 0x50) {
+               a += 0x60;
+               P |= F_C;
+       }
+       A = a;
+}
+
+void m6502_device::do_arr()
+{
+       if(P & F_D)
+               do_arr_d();
+       else
+               do_arr_nd();
+}
+
+void m6502_device::do_cmp(uint8_t val1, uint8_t val2)
+{
+       P &= ~(F_N|F_Z|F_C);
+       uint16_t r = val1-val2;
+       if(!r)
+               P |= F_Z;
+       else if(int8_t(r) < 0)
+               P |= F_N;
+       if(!(r & 0xff00))
+               P |= F_C;
+}
+
+void m6502_device::do_sbc_d(uint8_t val)
+{
+       uint8_t c = P & F_C ? 0 : 1;
+       P &= ~(F_N|F_V|F_Z|F_C);
+       uint16_t diff = A - val - c;
+       uint8_t al = (A & 15) - (val & 15) - c;
+       if(int8_t(al) < 0)
+               al -= 6;
+       uint8_t ah = (A >> 4) - (val >> 4) - (int8_t(al) < 0);
+       if(!uint8_t(diff))
+               P |= F_Z;
+       else if(diff & 0x80)
+               P |= F_N;
+       if((A^val) & (A^diff) & 0x80)
+               P |= F_V;
+       if(!(diff & 0xff00))
+               P |= F_C;
+       if(int8_t(ah) < 0)
+               ah -= 6;
+       A = (ah << 4) | (al & 15);
+}
+
+void m6502_device::do_sbc_nd(uint8_t val)
+{
+       uint16_t diff = A - val - (P & F_C ? 0 : 1);
+       P &= ~(F_N|F_V|F_Z|F_C);
+       if(!uint8_t(diff))
+               P |= F_Z;
+       else if(int8_t(diff) < 0)
+               P |= F_N;
+       if((A^val) & (A^diff) & 0x80)
+               P |= F_V;
+       if(!(diff & 0xff00))
+               P |= F_C;
+       A = diff;
+}
+
+void m6502_device::do_sbc(uint8_t val)
+{
+       if(P & F_D)
+               do_sbc_d(val);
+       else
+               do_sbc_nd(val);
+}
+
+void m6502_device::do_bit(uint8_t val)
+{
+       P &= ~(F_N|F_Z|F_V);
+       uint8_t r = A & val;
+       if(!r)
+               P |= F_Z;
+       if(val & 0x80)
+               P |= F_N;
+       if(val & 0x40)
+               P |= F_V;
+}
+
+uint8_t m6502_device::do_asl(uint8_t v)
+{
+       P &= ~(F_N|F_Z|F_C);
+       uint8_t r = v<<1;
+       if(!r)
+               P |= F_Z;
+       else if(int8_t(r) < 0)
+               P |= F_N;
+       if(v & 0x80)
+               P |= F_C;
+       return r;
+}
+
+uint8_t m6502_device::do_lsr(uint8_t v)
+{
+       P &= ~(F_N|F_Z|F_C);
+       if(v & 1)
+               P |= F_C;
+       v >>= 1;
+       if(!v)
+               P |= F_Z;
+       return v;
+}
+
+uint8_t m6502_device::do_ror(uint8_t v)
+{
+       bool c = P & F_C;
+       P &= ~(F_N|F_Z|F_C);
+       if(v & 1)
+               P |= F_C;
+       v >>= 1;
+       if(c)
+               v |= 0x80;
+       if(!v)
+               P |= F_Z;
+       else if(int8_t(v)<0)
+               P |= F_N;
+       return v;
+}
+
+uint8_t m6502_device::do_rol(uint8_t v)
+{
+       bool c = P & F_C;
+       P &= ~(F_N|F_Z|F_C);
+       if(v & 0x80)
+               P |= F_C;
+       v <<= 1;
+       if(c)
+               v |= 0x01;
+       if(!v)
+               P |= F_Z;
+       else if(int8_t(v)<0)
+               P |= F_N;
+       return v;
+}
+
+uint8_t m6502_device::do_asr(uint8_t v)
+{
+       P &= ~(F_N|F_Z|F_C);
+       if(v & 1)
+               P |= F_C;
+       v >>= 1;
+       if(!v)
+               P |= F_Z;
+       else if(v & 0x40) {
+               P |= F_N;
+               v |= 0x80;
+       }
+       return v;
+}
+
+offs_t m6502_device::pc_to_external(u16 pc)
+{
+       return pc;
+}
+
+void m6502_device::execute_run()
+{
+       if(inst_substate)
+               do_exec_partial();
+
+       while(icount > 0) {
+               if(inst_state < 0xff00) {
+                       PPC = NPC;
+                       inst_state = IR | inst_state_base;
+                       if(machine().debug_flags & DEBUG_FLAG_ENABLED)
+                               debugger_instruction_hook(pc_to_external(NPC));
+               }
+               do_exec_full();
+       }
+}
+
+void m6502_device::execute_set_input(int inputnum, int state)
+{
+       switch(inputnum) {
+       case IRQ_LINE: irq_state = state == ASSERT_LINE; break;
+       case APU_IRQ_LINE: apu_irq_state = state == ASSERT_LINE; break;
+       case NMI_LINE: nmi_state = nmi_state || (state == ASSERT_LINE); break;
+       case V_LINE:
+               if(!v_state && state == ASSERT_LINE)
+                       P |= F_V;
+               v_state = state == ASSERT_LINE;
+               break;
+       }
+}
+
+
+device_memory_interface::space_config_vector m6502_device::memory_space_config() const
+{
+       if(has_configured_map(AS_OPCODES))
+               return space_config_vector {
+                       std::make_pair(AS_PROGRAM, &program_config),
+                       std::make_pair(AS_OPCODES, &sprogram_config)
+               };
+       else
+               return space_config_vector {
+                       std::make_pair(AS_PROGRAM, &program_config)
+               };
+}
+
+
+void m6502_device::state_import(const device_state_entry &entry)
+{
+       switch(entry.index()) {
+       case STATE_GENFLAGS:
+       case M6502_P:
+               P = P | (F_B|F_E);
+               break;
+       case M6502_PC:
+               PC = NPC;
+               irq_taken = false;
+               prefetch();
+               PPC = NPC;
+               inst_state = IR | inst_state_base;
+               break;
+       }
+}
+
+void m6502_device::state_export(const device_state_entry &entry)
+{
+       switch(entry.index()) {
+       case STATE_GENPC:     XPC = pc_to_external(PPC); break;
+       case STATE_GENPCBASE: XPC = pc_to_external(NPC); break;
+       }
+}
+
+void m6502_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+       switch(entry.index()) {
+       case STATE_GENFLAGS:
+       case M6502_P:
+               str = string_format("%c%c%c%c%c%c",
+                                               P & F_N ? 'N' : '.',
+                                               P & F_V ? 'V' : '.',
+                                               P & F_D ? 'D' : '.',
+                                               P & F_I ? 'I' : '.',
+                                               P & F_Z ? 'Z' : '.',
+                                               P & F_C ? 'C' : '.');
+               break;
+       }
+}
+
+void m6502_device::prefetch()
+{
+       sync = true;
+       sync_w(ASSERT_LINE);
+       NPC = PC;
+       IR = mintf->read_sync(PC);
+       sync = false;
+       sync_w(CLEAR_LINE);
+
+       if((nmi_state || ((irq_state || apu_irq_state) && !(P & F_I))) && !inhibit_interrupts) {
+               irq_taken = true;
+               IR = 0x00;
+       } else
+               PC++;
+}
+
+void m6502_device::prefetch_noirq()
+{
+       sync = true;
+       sync_w(ASSERT_LINE);
+       NPC = PC;
+       IR = mintf->read_sync(PC);
+       sync = false;
+       sync_w(CLEAR_LINE);
+       PC++;
+}
+
+void m6502_device::set_nz(uint8_t v)
+{
+       P &= ~(F_Z|F_N);
+       if(v & 0x80)
+               P |= F_N;
+       if(!v)
+               P |= F_Z;
+}
+
+std::unique_ptr<util::disasm_interface> m6502_device::create_disassembler()
+{
+       return std::make_unique<m6502_disassembler>();
+}
+
+uint8_t m6502_device::memory_interface::read_9(uint16_t adr)
+{
+       return read(adr);
+}
+
+void m6502_device::memory_interface::write_9(uint16_t adr, uint8_t val)
+{
+       write(adr, val);
+}
+
+
+uint8_t m6502_device::mi_default_normal::read(uint16_t adr)
+{
+       return program->read_byte(adr);
+}
+
+uint8_t m6502_device::mi_default_normal::read_sync(uint16_t adr)
+{
+       return scache->read_byte(adr);
+}
+
+uint8_t m6502_device::mi_default_normal::read_arg(uint16_t adr)
+{
+       return cache->read_byte(adr);
+}
+
+
+void m6502_device::mi_default_normal::write(uint16_t adr, uint8_t val)
+{
+       program->write_byte(adr, val);
+}
+
+uint8_t m6502_device::mi_default_nd::read_sync(uint16_t adr)
+{
+       return sprogram->read_byte(adr);
+}
+
+uint8_t m6502_device::mi_default_nd::read_arg(uint16_t adr)
+{
+       return program->read_byte(adr);
+}
+
+m6502_mcu_device::m6502_mcu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+       m6502_device(mconfig, type, tag, owner, clock)
+{
+}
+
+
+void m6502_mcu_device::recompute_bcount(uint64_t event_time)
+{
+       if(!event_time || event_time >= total_cycles() + icount) {
+               bcount = 0;
+               return;
+       }
+       bcount = total_cycles() + icount - event_time;
+}
+
+void m6502_mcu_device::execute_run()
+{
+       internal_update(total_cycles());
+
+       icount -= count_before_instruction_step;
+       if(icount < 0) {
+               count_before_instruction_step = -icount;
+               icount = 0;
+       } else
+               count_before_instruction_step = 0;
+
+       while(bcount && icount <= bcount)
+               internal_update(total_cycles() + icount - bcount);
+
+       if(icount > 0 && inst_substate)
+               do_exec_partial();
+
+       while(icount > 0) {
+               while(icount > bcount) {
+                       if(inst_state < 0xff00) {
+                               PPC = NPC;
+                               inst_state = IR | inst_state_base;
+                               if(machine().debug_flags & DEBUG_FLAG_ENABLED)
+                                       debugger_instruction_hook(NPC);
+                       }
+                       do_exec_full();
+               }
+               if(icount > 0)
+                       while(bcount && icount <= bcount)
+                               internal_update(total_cycles() + icount - bcount);
+               if(icount > 0 && inst_substate)
+                       do_exec_partial();
+       }
+       if(icount < 0) {
+               count_before_instruction_step = -icount;
+               icount = 0;
+       }
+}
+
+void m6502_mcu_device::add_event(uint64_t &event_time, uint64_t new_event)
+{
+       if(!new_event)
+               return;
+       if(!event_time || event_time > new_event)
+               event_time = new_event;
+}
+
+
+#include "cpu/m6502/m6502.hxx"
diff --git a/m6502/m6502.h b/m6502/m6502.h
new file mode 100644 (file)
index 0000000..b6034d9
--- /dev/null
@@ -0,0 +1,298 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m6502.h
+
+    MOS Technology 6502, original NMOS variant
+
+***************************************************************************/
+
+#ifndef MAME_CPU_M6502_M6502_H
+#define MAME_CPU_M6502_M6502_H
+
+class m6502_device : public cpu_device {
+public:
+       enum {
+               IRQ_LINE = INPUT_LINE_IRQ0,
+               APU_IRQ_LINE = INPUT_LINE_IRQ1,
+               NMI_LINE = INPUT_LINE_NMI,
+               V_LINE   = INPUT_LINE_IRQ0 + 16
+       };
+
+       m6502_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+       bool get_sync() const { return sync; }
+       void disable_cache() { cache_disabled = true; }
+
+       auto sync_cb() { return sync_w.bind(); }
+
+       devcb_write_line sync_w;
+
+protected:
+       m6502_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+       class memory_interface {
+       public:
+               address_space *program, *sprogram;
+               memory_access_cache<0, 0, ENDIANNESS_LITTLE> *cache, *scache;
+
+               virtual ~memory_interface() {}
+               virtual uint8_t read(uint16_t adr) = 0;
+               virtual uint8_t read_9(uint16_t adr);
+               virtual uint8_t read_sync(uint16_t adr) = 0;
+               virtual uint8_t read_arg(uint16_t adr) = 0;
+               virtual void write(uint16_t adr, uint8_t val) = 0;
+               virtual void write_9(uint16_t adr, uint8_t val);
+       };
+
+       class mi_default_normal : public memory_interface {
+       public:
+               virtual ~mi_default_normal() {}
+               virtual uint8_t read(uint16_t adr) override;
+               virtual uint8_t read_sync(uint16_t adr) override;
+               virtual uint8_t read_arg(uint16_t adr) override;
+               virtual void write(uint16_t adr, uint8_t val) override;
+       };
+
+       class mi_default_nd : public mi_default_normal {
+       public:
+               virtual ~mi_default_nd() {}
+               virtual uint8_t read_sync(uint16_t adr) override;
+               virtual uint8_t read_arg(uint16_t adr) override;
+       };
+
+       enum {
+               STATE_RESET = 0xff00
+       };
+
+       enum {
+               F_N = 0x80,
+               F_V = 0x40,
+               F_E = 0x20, // 65ce02
+               F_T = 0x20, // M740: replaces A with $00,X in some opcodes when set
+               F_B = 0x10,
+               F_D = 0x08,
+               F_I = 0x04,
+               F_Z = 0x02,
+               F_C = 0x01
+       };
+
+       virtual void init();
+
+       // device-level overrides
+       virtual void device_start() override;
+       virtual void device_reset() override;
+
+       // device_execute_interface overrides
+       virtual uint32_t execute_min_cycles() const override;
+       virtual uint32_t execute_max_cycles() const override;
+       virtual uint32_t execute_input_lines() const override;
+       virtual void execute_run() override;
+       virtual void execute_set_input(int inputnum, int state) override;
+       virtual bool execute_input_edge_triggered(int inputnum) const override;
+
+       // device_memory_interface overrides
+       virtual space_config_vector memory_space_config() const override;
+
+       // device_state_interface overrides
+       virtual void state_import(const device_state_entry &entry) override;
+       virtual void state_export(const device_state_entry &entry) override;
+       virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+       // device_disasm_interface overrides
+       virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+       address_space_config program_config, sprogram_config;
+
+       uint16_t  PPC;                    /* previous program counter */
+       uint16_t  NPC;                    /* next start-of-instruction program counter */
+       uint16_t  PC;                     /* program counter */
+       uint16_t  SP;                     /* stack pointer (always 100 - 1FF) */
+       uint16_t  TMP;                    /* temporary internal values */
+       uint8_t   TMP2;                   /* another temporary internal value, 8 bits this time */
+       uint8_t   A;                      /* Accumulator */
+       uint8_t   X;                      /* X index register */
+       uint8_t   Y;                      /* Y index register */
+       uint8_t   P;                      /* Processor status */
+       uint8_t   IR;                     /* Prefetched instruction register */
+       int     inst_state_base;        /* Current instruction bank */
+
+       std::unique_ptr<memory_interface> mintf;
+       int inst_state, inst_substate;
+       int icount, bcount, count_before_instruction_step;
+       bool nmi_state, irq_state, apu_irq_state, v_state;
+       bool irq_taken, sync, cache_disabled, inhibit_interrupts;
+
+       uint8_t read(uint16_t adr) { return mintf->read(adr); }
+       uint8_t read_9(uint16_t adr) { return mintf->read_9(adr); }
+       void write(uint16_t adr, uint8_t val) { mintf->write(adr, val); }
+       void write_9(uint16_t adr, uint8_t val) { mintf->write_9(adr, val); }
+       uint8_t read_arg(uint16_t adr) { return mintf->read_arg(adr); }
+       uint8_t read_pc() { return mintf->read_arg(PC++); }
+       uint8_t read_pc_noinc() { return mintf->read_arg(PC); }
+       void prefetch();
+       void prefetch_noirq();
+       void set_nz(uint8_t v);
+
+       u32 XPC;
+       virtual offs_t pc_to_external(u16 pc); // For paged PCs
+       virtual void do_exec_full();
+       virtual void do_exec_partial();
+
+       // inline helpers
+       static inline bool page_changing(uint16_t base, int delta) { return ((base + delta) ^ base) & 0xff00; }
+       static inline uint16_t set_l(uint16_t base, uint8_t val) { return (base & 0xff00) | val; }
+       static inline uint16_t set_h(uint16_t base, uint8_t val) { return (base & 0x00ff) | (val << 8); }
+
+       inline void dec_SP() { SP = set_l(SP, SP-1); }
+       inline void inc_SP() { SP = set_l(SP, SP+1); }
+
+       void do_adc_d(uint8_t val);
+       void do_adc_nd(uint8_t val);
+       void do_sbc_d(uint8_t val);
+       void do_sbc_nd(uint8_t val);
+       void do_arr_d();
+       void do_arr_nd();
+
+       void do_adc(uint8_t val);
+       void do_cmp(uint8_t val1, uint8_t val2);
+       void do_sbc(uint8_t val);
+       void do_bit(uint8_t val);
+       void do_arr();
+       uint8_t do_asl(uint8_t v);
+       uint8_t do_lsr(uint8_t v);
+       uint8_t do_ror(uint8_t v);
+       uint8_t do_rol(uint8_t v);
+       uint8_t do_asr(uint8_t v);
+
+#define O(o) void o ## _full(); void o ## _partial()
+
+       // NMOS 6502 opcodes
+       //   documented opcodes
+       O(adc_aba); O(adc_abx); O(adc_aby); O(adc_idx); O(adc_idy); O(adc_imm); O(adc_zpg); O(adc_zpx);
+       O(and_aba); O(and_abx); O(and_aby); O(and_imm); O(and_idx); O(and_idy); O(and_zpg); O(and_zpx);
+       O(asl_aba); O(asl_abx); O(asl_acc); O(asl_zpg); O(asl_zpx);
+       O(bcc_rel);
+       O(bcs_rel);
+       O(beq_rel);
+       O(bit_aba); O(bit_zpg);
+       O(bmi_rel);
+       O(bne_rel);
+       O(bpl_rel);
+       O(brk_imp);
+       O(bvc_rel);
+       O(bvs_rel);
+       O(clc_imp);
+       O(cld_imp);
+       O(cli_imp);
+       O(clv_imp);
+       O(cmp_aba); O(cmp_abx); O(cmp_aby); O(cmp_idx); O(cmp_idy); O(cmp_imm); O(cmp_zpg); O(cmp_zpx);
+       O(cpx_aba); O(cpx_imm); O(cpx_zpg);
+       O(cpy_aba); O(cpy_imm); O(cpy_zpg);
+       O(dec_aba); O(dec_abx); O(dec_zpg); O(dec_zpx);
+       O(dex_imp);
+       O(dey_imp);
+       O(eor_aba); O(eor_abx); O(eor_aby); O(eor_idx); O(eor_idy); O(eor_imm); O(eor_zpg); O(eor_zpx);
+       O(inc_aba); O(inc_abx); O(inc_zpg); O(inc_zpx);
+       O(inx_imp);
+       O(iny_imp);
+       O(jmp_adr); O(jmp_ind);
+       O(jsr_adr);
+       O(lda_aba); O(lda_abx); O(lda_aby); O(lda_idx); O(lda_idy); O(lda_imm); O(lda_zpg); O(lda_zpx);
+       O(ldx_aba); O(ldx_aby); O(ldx_imm); O(ldx_zpg); O(ldx_zpy);
+       O(ldy_aba); O(ldy_abx); O(ldy_imm); O(ldy_zpg); O(ldy_zpx);
+       O(lsr_aba); O(lsr_abx); O(lsr_acc); O(lsr_zpg); O(lsr_zpx);
+       O(nop_imp);
+       O(ora_aba); O(ora_abx); O(ora_aby); O(ora_imm); O(ora_idx); O(ora_idy); O(ora_zpg); O(ora_zpx);
+       O(pha_imp);
+       O(php_imp);
+       O(pla_imp);
+       O(plp_imp);
+       O(rol_aba); O(rol_abx); O(rol_acc); O(rol_zpg); O(rol_zpx);
+       O(ror_aba); O(ror_abx); O(ror_acc); O(ror_zpg); O(ror_zpx);
+       O(rti_imp);
+       O(rts_imp);
+       O(sbc_aba); O(sbc_abx); O(sbc_aby); O(sbc_idx); O(sbc_idy); O(sbc_imm); O(sbc_zpg); O(sbc_zpx);
+       O(sec_imp);
+       O(sed_imp);
+       O(sei_imp);
+       O(sta_aba); O(sta_abx); O(sta_aby); O(sta_idx); O(sta_idy); O(sta_zpg); O(sta_zpx);
+       O(stx_aba); O(stx_zpg); O(stx_zpy);
+       O(sty_aba); O(sty_zpg); O(sty_zpx);
+       O(tax_imp);
+       O(tay_imp);
+       O(tsx_imp);
+       O(txa_imp);
+       O(txs_imp);
+       O(tya_imp);
+
+       //   exceptions
+       O(reset);
+
+       //   undocumented reliable instructions
+       O(dcp_aba); O(dcp_abx); O(dcp_aby); O(dcp_idx); O(dcp_idy); O(dcp_zpg); O(dcp_zpx);
+       O(isb_aba); O(isb_abx); O(isb_aby); O(isb_idx); O(isb_idy); O(isb_zpg); O(isb_zpx);
+       O(lax_aba); O(lax_aby); O(lax_idx); O(lax_idy); O(lax_zpg); O(lax_zpy);
+       O(rla_aba); O(rla_abx); O(rla_aby); O(rla_idx); O(rla_idy); O(rla_zpg); O(rla_zpx);
+       O(rra_aba); O(rra_abx); O(rra_aby); O(rra_idx); O(rra_idy); O(rra_zpg); O(rra_zpx);
+       O(sax_aba); O(sax_idx); O(sax_zpg); O(sax_zpy);
+       O(sbx_imm);
+       O(sha_aby); O(sha_idy);
+       O(shs_aby);
+       O(shx_aby);
+       O(shy_abx);
+       O(slo_aba); O(slo_abx); O(slo_aby); O(slo_idx); O(slo_idy); O(slo_zpg); O(slo_zpx);
+       O(sre_aba); O(sre_abx); O(sre_aby); O(sre_idx); O(sre_idy); O(sre_zpg); O(sre_zpx);
+
+       //   undocumented unreliable instructions
+       //     behaviour differs between visual6502 and online docs, which
+       //     is a clear sign reliability is not to be expected
+       //     implemented version follows visual6502
+       O(anc_imm);
+       O(ane_imm);
+       O(arr_imm);
+       O(asr_imm);
+       O(las_aby);
+       O(lxa_imm);
+
+       //   nop variants
+       O(nop_imm); O(nop_aba); O(nop_abx); O(nop_zpg); O(nop_zpx);
+
+       //   system killers
+       O(kil_non);
+
+#undef O
+};
+
+class m6502_mcu_device : public m6502_device {
+protected:
+       m6502_mcu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+       void internal_update() { internal_update(total_cycles()); }
+       virtual void internal_update(uint64_t current_time) = 0;
+       void recompute_bcount(uint64_t event_time);
+       static void add_event(uint64_t &event_time, uint64_t new_event);
+
+       virtual void execute_run() override;
+};
+
+enum {
+       M6502_PC = 1,
+       M6502_A,
+       M6502_X,
+       M6502_Y,
+       M6502_P,
+       M6502_S,
+       M6502_IR
+};
+
+enum {
+       M6502_IRQ_LINE = m6502_device::IRQ_LINE,
+       M6502_NMI_LINE = m6502_device::NMI_LINE,
+       M6502_SET_OVERFLOW = m6502_device::V_LINE
+};
+
+DECLARE_DEVICE_TYPE(M6502, m6502_device)
+
+#endif // MAME_CPU_M6502_M6502_H
diff --git a/m6502/m6502.txt b/m6502/m6502.txt
new file mode 100644 (file)
index 0000000..d92af7e
--- /dev/null
@@ -0,0 +1,163 @@
+mos metal oxid semiconductor
+bought by cbm
+
+license to produce chips
+ rockwell
+
+transistor, logic gate designs:
+NMOS (M65xx)
+CMOS (M65Cxx)
+HMOS (M75xx) hyper? MOS, used in early c16/plus4 series
+H2MOS (M85xx) hyper2 MOS, used in C128, later c16/plus4, late C64
+?SCMOS (M65SCxx) Super? CMOS
+?CE (M65CExx, M45xx) CMOS Enhanced?, used in not released C65
+
+HMOS, H2MOS CPUs have the same core as the NMOS series
+
+6500 / 6501
+mask programable microcontroller
+32 io ports (2 interruptable)
+timer
+64 byte ram
+8 kbyte rom
+
+6502 (used in many designs)
+b-flag always 1! (only pushed as 0 when break executed!)
+memory changing opcodes accesses memory: read, write data, write modified data
+
+6504
+only 12 address pins a11..a0
+
+6508
+8 io pins (p0 bis p7)
+
+6509
+1 megabyte memory management
+(lda,sta (zeropage),y modified, uses 2nd address extension register)
+
+6510/8500 (used in some designs)
+6 io pins (p0 bis p5)
+
+6510T/8503? (used in commodore C1551 floppy)
+8 io pins
+integrated clock generation?
+
+7501/8501 (c16, c116, c232, c264, plus4, c364)
+7 io pins (no p5)
+no nmi
+
+8502 (c128)
+7 io pins (no p7)
+
+the above series is opcode compatible (including illegal opcodes)
+
+
+n2a03 (some arcades, NES)
+-------------------------
+(nintendo variant)
+NMOS based!
+illegal opcodes
+$6c jump indirect low byte overrun problem as in 6502
+no decimal mode
+integrated sound hardware
+
+
+65c02 (used in some designs)
+----------------------------
+fixed jmp ind opcode
+memory changing opcodes accesses memory: read, read, write
+no illegal opcodes from the above series
+so not full compatible to 6502 series
+b flag always 1 as in NMOS Series is not known?
+additional commands
+
+several other CMOS variants
+
+
+65sc02 (where used?)
+--------------------
+65c02 compatible
+additional commands
+
+atari lynx bastian schicks bll
+integrated m65sc02 cpu core
+no bbr bbs instructions, else m65c02 compatible
+
+watara supervision
+integrated m65c02 cpu core (or m65sc02 or m65ce02?)
+
+
+gte65816 (nintendo snes)
+------------------------
+65802 upgrade cpu (c64 and c128 upgrade cpu)
+16 bit wide registers
+24 bit address space
+65c02? compatible mode
+additional commands
+
+
+spc700
+------
+(snes sound processor)
+same register layout?
+same addressing modes?
+heavily modified opcodes
+YA could be combined for 16 bit operations?
+
+
+huc6280 (nec pcengine)
+----------------------
+65sc02 compatible?
+8 memory registers
+(highest 3 bits select memory register, these build a22..a13)
+(so 2 Megabyte address room!)
+additional commands?
+several additional integrated features
+
+
+65ce02 (c65 prototype)
+----------------------
+(scan of documentation available, also use
+c65 m4510 documentation)
+(cpu core to be used in asics)
+65sc02 compatible
+z register
+(65c02 zeropage indexed addressing is now (zeropage),z)
+b bank register, highbyte of all zerozape addressing
+register for stack high byte
+additional command (some from the 65816)
+
+
+m4510 (Commodore C65 CPU)
+-------------------------
+(scan of documentation (in c65 documentation) available)
+65ce02 compatible
+integrated 20 bit memory management (map)
+(aug opcode changed to map opcode)
+2 cia6526 integrated
+1 uart integrated
+
+
+mitsubishi 740 series
+---------------------
+(data book in electronic form available)
+(M507xx, M509xx, M374xx, M38xxx, M375xx)
+NMOS based
+additional operation mode
+(arithmetic instruction not performing on akku (a=a operation addressing mode)
+but on zeropage ([x]=[x] operation addressing mode))
+additional instructions LDM, MUL, DIV, TST, COM, RRF, CLT, SET, WIT, STP, CLP
+BRK 1 byte only?
+BRA CMOS compatible
+BBC, BBR different opcode as CMOS, and also akku addressing
+different TRB, TSB
+no CMOS STZ, JMP ind,x
+STP not in all variants
+MUL, DIV not in all variants
+
+
+Set Overflow Pin
+----------------
+in 6502 and pin compatibles (65C02 65SC02 65SC802 65CE02), M6509
+no SO pin 6510/7501/8500/8501/8502/65sc816
+6510T ?
diff --git a/m6502/m6502d.cpp b/m6502/m6502d.cpp
new file mode 100644 (file)
index 0000000..589aafd
--- /dev/null
@@ -0,0 +1,198 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m6502d.cpp
+
+    MOS Technology 6502, original NMOS variant, disassembler
+
+***************************************************************************/
+
+#include "emu.h"
+#include "m6502d.h"
+#include "cpu/m6502/m6502d.hxx"
+
+m6502_base_disassembler::m6502_base_disassembler(const disasm_entry *_table) : table(_table)
+{
+}
+
+u32 m6502_base_disassembler::get_instruction_bank() const
+{
+       return 0;
+}
+
+u32 m6502_base_disassembler::opcode_alignment() const
+{
+       return 1;
+}
+
+offs_t m6502_base_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+       const disasm_entry &e = table[opcodes.r8(pc) | get_instruction_bank()];
+       uint32_t flags = e.flags | SUPPORTED;
+       util::stream_format(stream, "%s", e.opcode);
+
+       switch(e.mode) {
+       case DASM_non:
+               flags |= 1;
+               break;
+
+       case DASM_aba:
+               util::stream_format(stream, " $%02x%02x", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_abx:
+               util::stream_format(stream, " $%02x%02x, x", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_aby:
+               util::stream_format(stream, " $%02x%02x, y", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_acc:
+               util::stream_format(stream, " a");
+               flags |= 1;
+               break;
+
+       case DASM_adr:
+               util::stream_format(stream, " $%02x%02x", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_bzp:
+               util::stream_format(stream, "%d $%02x", (opcodes.r8(pc) >> 4) & 7, params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_iax:
+               util::stream_format(stream, " ($%02x%02x, x)", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_idx:
+               util::stream_format(stream, " ($%02x, x)", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_idy:
+               util::stream_format(stream, " ($%02x), y", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_idz:
+               util::stream_format(stream, " ($%02x), z", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_imm:
+               util::stream_format(stream, " #$%02x", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_imp:
+               flags |= 1;
+               break;
+
+       case DASM_ind:
+               util::stream_format(stream, " ($%02x%02x)", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_isy:
+               util::stream_format(stream, " ($%02x, s), y", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_iw2:
+               util::stream_format(stream, " #$%02x%02x", params.r8(pc+2), params.r8(pc+1));
+               flags |= 3;
+               break;
+
+       case DASM_iw3:
+               util::stream_format(stream, " #$%02x%02x%02x", params.r8(pc+3), params.r8(pc+2), params.r8(pc+1));
+               flags |= 4;
+               break;
+
+       case DASM_rel:
+               util::stream_format(stream, " $%04x", (pc & 0xf0000) | uint16_t(pc + 2 + int8_t(params.r8(pc+1))));
+               flags |= 2;
+               break;
+
+       case DASM_rw2:
+               util::stream_format(stream, " $%04x", (pc & 0xf0000) | uint16_t(pc + 2 + int16_t((params.r8(pc+2) << 8) | params.r8(pc+1))));
+               flags |= 3;
+               break;
+
+       case DASM_zpb:
+               util::stream_format(stream, "%d $%02x, $%04x", (opcodes.r8(pc) >> 4) & 7, params.r8(pc+1), (pc & 0xf0000) | uint16_t(pc + 3 + int8_t(params.r8(pc+2))));
+               flags |= 3;
+               break;
+
+       case DASM_zpg:
+               util::stream_format(stream, " $%02x", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_zpi:
+               util::stream_format(stream, " ($%02x)", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_zpx:
+               util::stream_format(stream, " $%02x, x", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_zpy:
+               util::stream_format(stream, " $%02x, y", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_imz:
+               util::stream_format(stream, " #$%02x, $%02x", params.r8(pc+1), params.r8(pc+2));
+               flags |= 3;
+               break;
+
+       case DASM_spg:
+               util::stream_format(stream, " \\$%02x", params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_biz:
+               util::stream_format(stream, " %d, $%02x", (opcodes.r8(pc) >> 5) & 7, params.r8(pc+1));
+               flags |= 2;
+               break;
+
+       case DASM_bzr:
+               util::stream_format(stream, " %d, $%02x, $%04x", (opcodes.r8(pc) >> 5) & 7, params.r8(pc+1), (pc & 0xf0000) | uint16_t(pc + 3 + int8_t(params.r8(pc+2))));
+               flags |= 3;
+               break;
+
+       case DASM_bar:
+               util::stream_format(stream, " %d, a, $%04x", (opcodes.r8(pc) >> 5) & 7, (pc & 0xf0000) | uint16_t(pc + 3 + int8_t(params.r8(pc+1))));
+               flags |= 2;
+               break;
+
+       case DASM_bac:
+               util::stream_format(stream, " %d, a", (opcodes.r8(pc) >> 5) & 7);
+               flags |= 1;
+               break;
+
+       case DASM_xa3:
+               util::stream_format(stream, " #$%02x%02x%02x", params.r8(pc+1), params.r8(pc+3), params.r8(pc+2));
+               flags |= 4;
+               break;
+
+       default:
+               fprintf(stderr, "Unhandled dasm mode %d\n", e.mode);
+               abort();
+       }
+       return flags;
+}
+
+m6502_disassembler::m6502_disassembler() : m6502_base_disassembler(disasm_entries)
+{
+}
diff --git a/m6502/m6502d.h b/m6502/m6502d.h
new file mode 100644 (file)
index 0000000..5a02ddd
--- /dev/null
@@ -0,0 +1,82 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m6502d.h
+
+    MOS Technology 6502, original NMOS variant, disassembler
+
+***************************************************************************/
+
+#ifndef MAME_CPU_M6502_M6502D_H
+#define MAME_CPU_M6502_M6502D_H
+
+#pragma once
+
+class m6502_base_disassembler : public util::disasm_interface
+{
+public:
+       struct disasm_entry {
+               const char *opcode;
+               int mode;
+               offs_t flags;
+       };
+
+       m6502_base_disassembler(const disasm_entry *table);
+       virtual ~m6502_base_disassembler() = default;
+
+       virtual u32 opcode_alignment() const override;
+       virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+
+protected:
+       enum {
+               DASM_non,    /* no additional arguments */
+               DASM_aba,    /* absolute */
+               DASM_abx,    /* absolute + X */
+               DASM_aby,    /* absolute + Y */
+               DASM_acc,    /* accumulator */
+               DASM_adr,    /* absolute address (jmp,jsr) */
+               DASM_bzp,    /* zero page with bit selection */
+               DASM_iax,    /* indirect + X (65c02 jmp) */
+               DASM_idx,    /* zero page pre indexed */
+               DASM_idy,    /* zero page post indexed */
+               DASM_idz,    /* zero page post indexed (65ce02) */
+               DASM_imm,    /* immediate */
+               DASM_imp,    /* implicit */
+               DASM_ind,    /* indirect (jmp) */
+               DASM_isy,    /* zero page pre indexed sp and post indexed Y (65ce02) */
+               DASM_iw2,    /* immediate word (65ce02) */
+               DASM_iw3,    /* augment (65ce02) */
+               DASM_rel,    /* relative */
+               DASM_rw2,    /* relative word (65cs02, 65ce02) */
+               DASM_zpb,    /* zero page and branch (65c02 bbr, bbs) */
+               DASM_zpg,    /* zero page */
+               DASM_zpi,    /* zero page indirect (65c02) */
+               DASM_zpx,    /* zero page + X */
+               DASM_zpy,    /* zero page + Y */
+               DASM_imz,    /* load immediate byte, store to zero page address (M740) */
+               DASM_spg,    /* "special page": implied FF00 OR immediate value (M740)*/
+               DASM_biz,    /* bit, zero page (M740) */
+               DASM_bzr,    /* bit, zero page, relative offset (M740) */
+               DASM_bar,    /* bit, accumulator, relative offset (M740) */
+               DASM_bac,    /* bit, accumulator (M740) */
+               DASM_xa3     /* unknown XaviX opcode, 24-bit ROM pointer? */
+       };
+
+       virtual u32 get_instruction_bank() const;
+
+private:
+       const disasm_entry *table;
+};
+
+class m6502_disassembler : public m6502_base_disassembler
+{
+public:
+       m6502_disassembler();
+       virtual ~m6502_disassembler() = default;
+
+private:
+       static const disasm_entry disasm_entries[0x100];
+};
+
+#endif
diff --git a/m6502/m6502make.py b/m6502/m6502make.py
new file mode 100755 (executable)
index 0000000..ea51fe4
--- /dev/null
@@ -0,0 +1,304 @@
+#!/usr/bin/python
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+
+from __future__ import print_function
+
+USAGE = """
+Usage:
+%s prefix {opc.lst|-} disp.lst device.inc deviced.inc
+"""
+import sys
+import logging
+
+MAX_STATES = 0
+
+def load_opcodes(fname):
+    """Load opcodes from .lst file"""
+    opcodes = []
+    logging.info("load_opcodes: %s", fname)
+    try:
+        f = open(fname, "rU")
+    except Exception:
+        err = sys.exc_info()[1]
+        logging.error("cannot read opcodes file %s [%s]", fname, err)
+        sys.exit(1)
+
+    for line in f:
+        if line.startswith("#"): continue
+        line = line.rstrip()
+        if not line: continue
+        if line.startswith(" ") or line.startswith("\t"):
+            # append instruction to last opcode
+            opcodes[-1][1].append(line)
+        else:
+            # add new opcode
+            opcodes.append((line, []))
+    return opcodes
+
+
+def load_disp(fname):
+    logging.info("load_disp: %s", fname)
+    states = []
+    try:
+        f = open(fname, "rU")
+    except Exception:
+        err = sys.exc_info()[1]
+        logging.error("cannot read display file %s [%s]", fname, err)
+        sys.exit(1)
+    for line in f:
+        if line.startswith("#"): continue
+        line = line.strip()
+        if not line: continue
+        tokens = line.split()
+        states += tokens
+    return states
+
+def emit(f, text):
+    """write string to file"""
+    print(text, file=f)
+
+FULL_PROLOG="""\
+void %(device)s_device::%(opcode)s_full()
+{
+"""
+
+FULL_EPILOG="""\
+}
+"""
+
+FULL_EAT_ALL="""\
+\ticount=0; inst_substate = %(substate)s; return;
+"""
+
+FULL_MEMORY="""\
+\tif(icount == 0) { inst_substate = %(substate)s; return; }
+%(ins)s
+\ticount--;
+"""
+
+FULL_NONE="""\
+%(ins)s
+"""
+
+PARTIAL_PROLOG="""\
+void %(device)s_device::%(opcode)s_partial()
+{
+switch(inst_substate) {
+case 0:
+"""
+
+PARTIAL_EPILOG="""\
+}
+\tinst_substate = 0;
+}
+
+"""
+
+PARTIAL_EAT_ALL="""\
+\ticount=0; inst_substate = %(substate)s; return;
+case %(substate)s:;
+"""
+
+PARTIAL_MEMORY="""\
+\tif(icount == 0) { inst_substate = %(substate)s; return; }
+case %(substate)s:
+%(ins)s
+\ticount--;
+"""
+
+PARTIAL_NONE="""\
+%(ins)s
+"""
+def identify_line_type(ins):
+    if "eat-all-cycles" in ins: return "EAT"
+    for s in ["read", "write", "prefetch(", "prefetch_noirq("]:
+        if s in ins:
+            return "MEMORY"
+    return "NONE"
+
+
+def save_opcodes(f, device, opcodes):
+    for name, instructions in opcodes:
+        d = { "device": device,
+              "opcode": name,
+              }
+
+        emit(f, FULL_PROLOG % d)
+        substate = 1
+        for ins in instructions:
+            d["substate"] = str(substate)
+            d["ins"] =  ins
+            line_type = identify_line_type(ins)
+            if line_type == "EAT":
+                emit(f, FULL_EAT_ALL % d)
+                substate += 1
+            elif line_type == "MEMORY":
+                emit(f, FULL_MEMORY % d)
+                substate += 1
+            else:
+                emit(f, FULL_NONE %d)
+        emit(f, FULL_EPILOG % d)
+
+        emit(f, PARTIAL_PROLOG % d)
+        substate = 1
+        for ins in instructions:
+            d["substate"] = str(substate)
+            d["ins"] =  ins
+            line_type = identify_line_type(ins)
+            if line_type == "EAT":
+                emit(f, PARTIAL_EAT_ALL % d)
+                substate += 1
+            elif line_type == "MEMORY":
+                emit(f, PARTIAL_MEMORY % d)
+                substate += 1
+            else:
+                emit(f, PARTIAL_NONE %d)
+        emit(f, PARTIAL_EPILOG % d)
+
+
+DO_EXEC_FULL_PROLOG="""\
+void %(device)s_device::do_exec_full()
+{
+\tswitch(inst_state) {
+"""
+
+DO_EXEC_FULL_EPILOG="""\
+\t}
+}
+"""
+
+DO_EXEC_PARTIAL_PROLOG="""\
+void %(device)s_device::do_exec_partial()
+{
+\tswitch(inst_state) {
+"""
+
+DO_EXEC_PARTIAL_EPILOG="""\
+\t}
+}
+"""
+
+DISASM_PROLOG="""\
+const %(device)s_disassembler::disasm_entry %(device)s_disassembler::disasm_entries[0x%(disasm_count)x] = {
+"""
+
+DISASM_EPILOG="""\
+};
+"""
+
+def save_tables(f, device, states):
+    total_states = len(states)
+
+    d = { "device": device,
+          "disasm_count": total_states-1
+          }
+    
+    emit(f, DO_EXEC_FULL_PROLOG % d)
+    for n, state in enumerate(states):
+        if state == ".": continue
+        if n < total_states - 1:
+            emit(f, "\tcase 0x%02x: %s_full(); break;" % (n, state))
+        else:
+            emit(f, "\tcase %s: %s_full(); break;" % ("STATE_RESET", state))
+    emit(f, DO_EXEC_FULL_EPILOG % d)
+
+    emit(f, DO_EXEC_PARTIAL_PROLOG % d)
+    for n, state in enumerate(states):
+        if state == ".": continue
+        if n < total_states - 1:
+            emit(f, "\tcase 0x%02x: %s_partial(); break;" % (n, state))
+        else:
+            emit(f, "\tcase %s: %s_partial(); break;" % ("STATE_RESET", state))
+    emit(f, DO_EXEC_PARTIAL_EPILOG % d)
+
+def save_dasm(f, device, states):
+    total_states = len(states)
+
+    d = { "device": device,
+          "disasm_count": total_states-1
+          }
+    
+    emit(f, DISASM_PROLOG % d )
+    for n, state in enumerate(states):
+        if state == ".": continue
+        if n == total_states - 1: break
+        tokens = state.split("_")
+        opc = tokens[0]
+        mode = tokens[-1]
+        extra = "0"
+        if opc in ["jsr", "bsr", "callf"]:
+            extra = "STEP_OVER"
+        elif opc in ["rts", "rti", "rtn", "retf"]:
+            extra = "STEP_OUT"
+        emit(f, '\t{ "%s", DASM_%s, %s },' % (opc, mode, extra))
+    emit(f, DISASM_EPILOG % d)
+
+def saves(fname, device, opcodes, states):
+    logging.info("saving: %s", fname)
+    try:
+        f = open(fname, "w")
+    except Exception:
+        err = sys.exc_info()[1]
+        logging.error("cannot write file %s [%s]", fname, err)
+        sys.exit(1)
+    save_opcodes(f, device, opcodes)
+    emit(f, "\n")
+    save_tables(f, device, states)
+    f.close()
+
+
+def saved(fname, device, opcodes, states):
+    logging.info("saving: %s", fname)
+    try:
+        f = open(fname, "w")
+    except Exception:
+        err = sys.exc_info()[1]
+        logging.error("cannot write file %s [%s]", fname, err)
+        sys.exit(1)
+    save_dasm(f, device, states)
+    f.close()
+
+
+def main(argv):
+    debug = False
+    logformat=("%(levelname)s:"
+               "%(module)s:"
+               "%(lineno)d:"
+               "%(threadName)s:"
+               "%(message)s")
+    if debug:
+        logging.basicConfig(level=logging.INFO, format=logformat)
+    else:
+        logging.basicConfig(level=logging.WARNING, format=logformat)
+
+
+    if len(argv) != 6:
+        print(USAGE % argv[0])
+        return 1
+
+    mode = argv[1]
+    device_name = argv[2]
+
+    opcodes = []
+    if argv[3] !=  "-":
+        opcodes = load_opcodes(argv[3])
+        logging.info("found %d opcodes", len(opcodes))
+    else:
+        logging.info("skipping opcode reading")
+
+
+    states = load_disp(argv[4])
+    logging.info("loaded %s states", len(states))
+
+    assert (len(states) & 0xff) == 1
+    if mode == 's':
+        saves(argv[5], device_name, opcodes, states)
+    else:
+        saved(argv[5], device_name, opcodes, states)
+
+
+# ======================================================================
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))
+
diff --git a/m6502/m65c02.cpp b/m6502/m65c02.cpp
new file mode 100644 (file)
index 0000000..80df7c7
--- /dev/null
@@ -0,0 +1,33 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m65c02.c
+
+    MOS Technology 6502, CMOS variant with some additional instructions
+    (but not the bitwise ones)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "m65c02.h"
+#include "m65c02d.h"
+
+DEFINE_DEVICE_TYPE(M65C02, m65c02_device, "m65c02", "MOS Technology M65C02")
+
+m65c02_device::m65c02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+       m6502_device(mconfig, M65C02, tag, owner, clock)
+{
+}
+
+m65c02_device::m65c02_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+       m6502_device(mconfig, type, tag, owner, clock)
+{
+}
+
+std::unique_ptr<util::disasm_interface> m65c02_device::create_disassembler()
+{
+       return std::make_unique<m65c02_disassembler>();
+}
+
+#include "cpu/m6502/m65c02.hxx"
diff --git a/m6502/m65c02.h b/m6502/m65c02.h
new file mode 100644 (file)
index 0000000..b267075
--- /dev/null
@@ -0,0 +1,76 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m65c02.h
+
+    MOS Technology 6502, CMOS variant with some additional instructions
+    (but not the bitwise ones)
+
+***************************************************************************/
+#ifndef MAME_CPU_M6502_M65C02_H
+#define MAME_CPU_M6502_M65C02_H
+
+#pragma once
+
+#include "m6502.h"
+
+class m65c02_device : public m6502_device {
+public:
+       m65c02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+       virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+       virtual void do_exec_full() override;
+       virtual void do_exec_partial() override;
+
+protected:
+       m65c02_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+#define O(o) void o ## _full(); void o ## _partial()
+
+       // 65c02 opcodes
+       O(adc_c_aba); O(adc_c_abx); O(adc_c_aby); O(adc_c_idx); O(adc_c_idy); O(adc_c_imm); O(adc_c_zpg); O(adc_c_zpi); O(adc_c_zpx);
+       O(and_zpi);
+       O(asl_c_abx);
+       O(bbr_zpb);
+       O(bbs_zpb);
+       O(bit_abx); O(bit_imm); O(bit_zpx);
+       O(bra_rel);
+       O(brk_c_imp);
+       O(cmp_zpi);
+       O(dec_acc);
+       O(eor_zpi);
+       O(inc_acc);
+       O(jmp_c_ind); O(jmp_iax);
+       O(lda_zpi);
+       O(lsr_c_abx);
+       O(nop_c_aba); O(nop_c_abx); O(nop_c_imp);
+       O(ora_zpi);
+       O(phx_imp);
+       O(phy_imp);
+       O(plx_imp);
+       O(ply_imp);
+       O(rmb_bzp);
+       O(rol_c_abx);
+       O(ror_c_abx);
+       O(sbc_c_aba); O(sbc_c_abx); O(sbc_c_aby); O(sbc_c_idx); O(sbc_c_idy); O(sbc_c_imm); O(sbc_c_zpg); O(sbc_c_zpi); O(sbc_c_zpx);
+       O(smb_bzp);
+       O(stp_imp);
+       O(sta_zpi);
+       O(stz_aba); O(stz_abx); O(stz_zpg); O(stz_zpx);
+       O(trb_aba); O(trb_zpg);
+       O(tsb_aba); O(tsb_zpg);
+       O(wai_imp);
+
+#undef O
+};
+
+enum {
+       M65C02_IRQ_LINE = m6502_device::IRQ_LINE,
+       M65C02_NMI_LINE = m6502_device::NMI_LINE,
+       M65C02_SET_OVERFLOW = m6502_device::V_LINE
+};
+
+DECLARE_DEVICE_TYPE(M65C02, m65c02_device)
+
+#endif // MAME_CPU_M6502_M65C02_H
diff --git a/m6502/m65c02d.cpp b/m6502/m65c02d.cpp
new file mode 100644 (file)
index 0000000..2c7b3b8
--- /dev/null
@@ -0,0 +1,18 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m65c02d.cpp
+
+    MOS Technology 6502, CMOS variant with some additional instructions
+    (but not the bitwise ones), disassembler
+
+***************************************************************************/
+
+#include "emu.h"
+#include "m65c02d.h"
+#include "cpu/m6502/m65c02d.hxx"
+
+m65c02_disassembler::m65c02_disassembler() : m6502_base_disassembler(disasm_entries)
+{
+}
diff --git a/m6502/m65c02d.h b/m6502/m65c02d.h
new file mode 100644 (file)
index 0000000..77b134c
--- /dev/null
@@ -0,0 +1,29 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+    m65c02d.h
+
+    MOS Technology 6502, CMOS variant with some additional instructions
+    (but not the bitwise ones), disassembler
+
+***************************************************************************/
+
+#ifndef MAME_CPU_M6502_M65C02D_H
+#define MAME_CPU_M6502_M65C02D_H
+
+#pragma once
+
+#include "m6502d.h"
+
+class m65c02_disassembler : public m6502_base_disassembler
+{
+public:
+       m65c02_disassembler();
+       virtual ~m65c02_disassembler() = default;
+
+private:
+       static const disasm_entry disasm_entries[0x100];
+};
+
+#endif
diff --git a/m6502/om6502.lst b/m6502/om6502.lst
new file mode 100644 (file)
index 0000000..bd0f3cb
--- /dev/null
@@ -0,0 +1,1967 @@
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+# NMOS 6502 opcodes
+# Verified with visual6502
+#   documented opcodes
+
+adc_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_adc(TMP);
+       prefetch();
+
+adc_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP = read(TMP);
+       do_adc(TMP);
+       prefetch();
+
+adc_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       TMP = read(TMP);
+       do_adc(TMP);
+       prefetch();
+
+adc_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_adc(read(TMP));
+       prefetch();
+
+adc_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       do_adc(read(TMP+Y));
+       prefetch();
+
+adc_imm
+       TMP = read_pc();
+       do_adc(TMP);
+       prefetch();
+
+adc_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_adc(TMP);
+       prefetch();
+
+adc_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = read(uint8_t(TMP+X));
+       do_adc(TMP);
+       prefetch();
+
+and_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       A &= read(TMP);
+       set_nz(A);
+       prefetch();
+
+and_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       A &= read(TMP);
+       set_nz(A);
+       prefetch();
+
+and_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       A &= read(TMP);
+       set_nz(A);
+       prefetch();
+
+and_imm
+       A &= read_pc();
+       set_nz(A);
+       prefetch();
+
+and_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A &= read(TMP);
+       set_nz(A);
+       prefetch();
+
+and_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A &= read(TMP+Y);
+       set_nz(A);
+       prefetch();
+
+and_zpg
+       TMP = read_pc();
+       A &= read(TMP);
+       set_nz(A);
+       prefetch();
+
+and_zpx
+       TMP = read_pc();
+       read(TMP);
+       A &= read(uint8_t(TMP+X));
+       set_nz(A);
+       prefetch();
+
+asl_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+asl_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+asl_acc
+       read_pc_noinc();
+       A = do_asl(A);
+       prefetch();
+
+asl_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+asl_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+bcc_rel
+       TMP = read_pc();
+       if(!(P & F_C)) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bcs_rel
+       TMP = read_pc();
+       if(P & F_C) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+beq_rel
+       TMP = read_pc();
+       if(P & F_Z) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bit_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       do_bit(read(TMP));
+       prefetch();
+
+bit_zpg
+       TMP = read_pc();
+       do_bit(read(TMP));
+       prefetch();
+
+bmi_rel
+       TMP = read_pc();
+       if(P & F_N) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bne_rel
+       TMP = read_pc();
+       if(!(P & F_Z)) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bpl_rel
+       TMP = read_pc();
+       if(!(P & F_N)) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+brk_imp
+       // The 6502 bug when a nmi occurs in a brk is reproduced (case !irq_taken && nmi_state)
+       if(irq_taken) {
+               read_pc_noinc();
+       } else {
+               read_pc();
+       }
+       write(SP, PC >> 8);
+       dec_SP();
+       write(SP, PC);
+       dec_SP();
+       write(SP, irq_taken ? P & ~F_B : P);
+       dec_SP();
+       if(nmi_state) {
+               PC = read_arg(0xfffa);
+               PC = set_h(PC, read_arg(0xfffb));
+               nmi_state = false;
+               standard_irq_callback(NMI_LINE);
+       } else {
+               PC = read_arg(0xfffe);
+               PC = set_h(PC, read_arg(0xffff));
+               if(irq_taken)
+                       standard_irq_callback(IRQ_LINE);
+       }
+       irq_taken = false;
+       P |= F_I; // Do *not* move after the prefetch
+       prefetch();
+       inst_state = -1;
+
+bvc_rel
+       TMP = read_pc();
+       if(!(P & F_V)) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bvs_rel
+       TMP = read_pc();
+       if(P & F_V) {
+               read_pc_noinc();
+               if(page_changing(PC, int8_t(TMP))) {
+                       read_arg(set_l(PC, PC+int8_t(TMP)));
+               }
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+clc_imp
+       read_pc_noinc();
+       P &= ~F_C;
+       prefetch();
+
+cld_imp
+       read_pc_noinc();
+       P &= ~F_D;
+       prefetch();
+
+cli_imp
+       read_pc_noinc();
+       prefetch();
+       P &= ~F_I; // Do *not* move it before the prefetch
+
+clv_imp
+       read_pc_noinc();
+       P &= ~F_V;
+       prefetch();
+
+cmp_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_cmp(A, TMP);
+       prefetch();
+
+cmp_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP = read(TMP);
+       do_cmp(A, TMP);
+       prefetch();
+
+cmp_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       TMP = read(TMP);
+       do_cmp(A, TMP);
+       prefetch();
+
+cmp_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_cmp(A, read(TMP));
+       prefetch();
+
+cmp_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       do_cmp(A, read(TMP+Y));
+       prefetch();
+
+cmp_imm
+       TMP = read_pc();
+       do_cmp(A, TMP);
+       prefetch();
+
+cmp_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_cmp(A, TMP);
+       prefetch();
+
+cmp_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = read(uint8_t(TMP+X));
+       do_cmp(A, TMP);
+       prefetch();
+
+cpx_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_cmp(X, TMP);
+       prefetch();
+
+cpx_imm
+       TMP = read_pc();
+       do_cmp(X, TMP);
+       prefetch();
+
+cpx_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_cmp(X, TMP);
+       prefetch();
+
+cpy_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_cmp(Y, TMP);
+       prefetch();
+
+cpy_imm
+       TMP = read_pc();
+       do_cmp(Y, TMP);
+       prefetch();
+
+cpy_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_cmp(Y, TMP);
+       prefetch();
+
+dec_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+dec_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+dec_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+dec_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+dex_imp
+       read_pc_noinc();
+       X--;
+       set_nz(X);
+       prefetch();
+
+dey_imp
+       read_pc_noinc();
+       Y--;
+       set_nz(Y);
+       prefetch();
+
+eor_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       A ^= read(TMP);
+       set_nz(A);
+       prefetch();
+
+eor_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       A ^= read(TMP);
+       set_nz(A);
+       prefetch();
+
+eor_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       A ^= read(TMP);
+       set_nz(A);
+       prefetch();
+
+eor_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A ^= read(TMP);
+       set_nz(A);
+       prefetch();
+
+eor_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A ^= read(TMP+Y);
+       set_nz(A);
+       prefetch();
+
+eor_imm
+       A ^= read_pc();
+       set_nz(A);
+       prefetch();
+
+eor_zpg
+       TMP = read_pc();
+       A ^= read(TMP);
+       set_nz(A);
+       prefetch();
+
+eor_zpx
+       TMP = read_pc();
+       read(TMP);
+       A ^= read(uint8_t(TMP+X));
+       set_nz(A);
+       prefetch();
+
+inc_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+inc_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+inc_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+inc_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       set_nz(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+inx_imp
+       read_pc_noinc();
+       X++;
+       set_nz(X);
+       prefetch();
+
+iny_imp
+       read_pc_noinc();
+       Y++;
+       set_nz(Y);
+       prefetch();
+
+jmp_adr
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       PC = TMP;
+       prefetch();
+
+jmp_ind
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       PC = read(TMP);
+       PC = set_h(PC, read(set_l(TMP, TMP+1)));
+       prefetch();
+
+jsr_adr
+       TMP = read_pc();
+       read(SP);
+       write(SP, PC>>8);
+       dec_SP();
+       write(SP, PC);
+       dec_SP();
+       TMP = set_h(TMP, read_pc());
+       PC = TMP;
+       prefetch();
+
+lda_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       A = read(TMP);
+       set_nz(A);
+       prefetch();
+
+lda_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       A = read(TMP + X);
+       set_nz(A);
+       prefetch();
+
+lda_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A = read(TMP + Y);
+       set_nz(A);
+       prefetch();
+
+lda_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A = read(TMP);
+       set_nz(A);
+       prefetch();
+
+lda_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A = read(TMP+Y);
+       set_nz(A);
+       prefetch();
+
+lda_imm
+       A = read_pc();
+       set_nz(A);
+       prefetch();
+
+lda_zpg
+       TMP = read_pc();
+       A = read(TMP);
+       set_nz(A);
+       prefetch();
+
+lda_zpx
+       TMP = read_pc();
+       read(TMP);
+       A = read(uint8_t(TMP+X));
+       set_nz(A);
+       prefetch();
+
+ldx_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       X = read(TMP);
+       set_nz(X);
+       prefetch();
+
+ldx_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       X = read(TMP + Y);
+       set_nz(X);
+       prefetch();
+
+ldx_imm
+       X = read_pc();
+       set_nz(X);
+       prefetch();
+
+ldx_zpg
+       TMP = read_pc();
+       X = read(TMP);
+       set_nz(X);
+       prefetch();
+
+ldx_zpy
+       TMP = read_pc();
+       read(TMP);
+       X = read(uint8_t(TMP+Y));
+       set_nz(X);
+       prefetch();
+
+ldy_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       Y = read(TMP);
+       set_nz(Y);
+       prefetch();
+
+ldy_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       Y = read(TMP);
+       set_nz(Y);
+       prefetch();
+
+ldy_imm
+       Y = read_pc();
+       set_nz(Y);
+       prefetch();
+
+ldy_zpg
+       TMP = read_pc();
+       Y = read(TMP);
+       set_nz(Y);
+       prefetch();
+
+ldy_zpx
+       TMP = read_pc();
+       read(TMP);
+       Y = read(uint8_t(TMP+X));
+       set_nz(Y);
+       prefetch();
+
+lsr_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+lsr_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+lsr_acc
+       read_pc_noinc();
+       A = do_lsr(A);
+       prefetch();
+
+lsr_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+lsr_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+nop_imp
+       read_pc_noinc();
+       prefetch();
+
+ora_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       A |= read(TMP);
+       set_nz(A);
+       prefetch();
+
+ora_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       A |= read(TMP);
+       set_nz(A);
+       prefetch();
+
+ora_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       A |= read(TMP);
+       set_nz(A);
+       prefetch();
+
+ora_imm
+       A |= read_pc();
+       set_nz(A);
+       prefetch();
+
+ora_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A |= read(TMP);
+       set_nz(A);
+       prefetch();
+
+ora_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A |= read(TMP+Y);
+       set_nz(A);
+       prefetch();
+
+ora_zpg
+       TMP = read_pc();
+       A |= read(TMP);
+       set_nz(A);
+       prefetch();
+
+ora_zpx
+       TMP = read_pc();
+       read(TMP);
+       A |= read(uint8_t(TMP+X));
+       set_nz(A);
+       prefetch();
+
+pha_imp
+       read_pc_noinc();
+       write(SP, A);
+       dec_SP();
+       prefetch();
+
+php_imp
+       read_pc_noinc();
+       write(SP, P);
+       dec_SP();
+       prefetch();
+
+pla_imp
+       read_pc_noinc();
+       read(SP);
+       inc_SP();
+       A = read(SP);
+       set_nz(A);
+       prefetch();
+
+plp_imp
+       read_pc_noinc();
+       read(SP);
+       inc_SP();
+       TMP = read(SP) | (F_B|F_E);
+       prefetch();
+       P = TMP; // Do *not* move it before the prefetch
+
+rol_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+rol_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+rol_acc
+       read_pc_noinc();
+       A = do_rol(A);
+       prefetch();
+
+rol_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+rol_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+ror_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+ror_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+ror_acc
+       read_pc_noinc();
+       A = do_ror(A);
+       prefetch();
+
+ror_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+ror_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+rti_imp
+       read_pc_noinc();
+       read(SP);
+       inc_SP();
+       P = read(SP) | (F_B|F_E);
+       inc_SP();
+       PC = read(SP);
+       inc_SP();
+       PC = set_h(PC, read(SP));
+       prefetch();
+
+rts_imp
+       read_pc_noinc();
+       read(SP);
+       inc_SP();
+       PC = read(SP);
+       inc_SP();
+       PC = set_h(PC, read(SP));
+       read_pc();
+       prefetch();
+
+sbc_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_sbc(TMP);
+       prefetch();
+
+sbc_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP = read(TMP);
+       do_sbc(TMP);
+       prefetch();
+
+sbc_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       TMP = read(TMP);
+       do_sbc(TMP);
+       prefetch();
+
+sbc_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_sbc(read(TMP));
+       prefetch();
+
+sbc_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       do_sbc(read(TMP+Y));
+       prefetch();
+
+sbc_imm
+       TMP = read_pc();
+       do_sbc(TMP);
+       prefetch();
+
+sbc_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_sbc(TMP);
+       prefetch();
+
+sbc_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = read(uint8_t(TMP+X));
+       do_sbc(TMP);
+       prefetch();
+
+sec_imp
+       read_pc_noinc();
+       P |= F_C;
+       prefetch();
+
+sed_imp
+       read_pc_noinc();
+       P |= F_D;
+       prefetch();
+
+sei_imp
+       read_pc_noinc();
+       prefetch();
+       P |= F_I; // Do *not* move it before the prefetch
+
+sta_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       write(TMP, A);
+       prefetch();
+
+sta_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       write(TMP+X, A);
+       prefetch();
+
+sta_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       write(TMP+Y, A);
+       prefetch();
+
+sta_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       write(TMP, A);
+       prefetch();
+
+sta_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       write(TMP+Y, A);
+       prefetch();
+
+sta_zpg
+       TMP = read_pc();
+       write(TMP, A);
+       prefetch();
+
+sta_zpx
+       TMP = read_pc();
+       read(TMP);
+       write(uint8_t(TMP+X), A);
+       prefetch();
+
+stx_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       write(TMP, X);
+       prefetch();
+
+stx_zpg
+       TMP = read_pc();
+       write(TMP, X);
+       prefetch();
+
+stx_zpy
+       TMP = read_pc();
+       read(TMP);
+       write(uint8_t(TMP+Y), X);
+       prefetch();
+
+sty_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       write(TMP, Y);
+       prefetch();
+
+sty_zpg
+       TMP = read_pc();
+       write(TMP, Y);
+       prefetch();
+
+sty_zpx
+       TMP = read_pc();
+       read(TMP);
+       write(uint8_t(TMP+X), Y);
+       prefetch();
+
+tax_imp
+       read_pc_noinc();
+       X = A;
+       set_nz(X);
+       prefetch();
+
+tay_imp
+       read_pc_noinc();
+       Y = A;
+       set_nz(Y);
+       prefetch();
+
+tsx_imp
+       read_pc_noinc();
+       X = SP;
+       set_nz(X);
+       prefetch();
+
+txa_imp
+       read_pc_noinc();
+       A = X;
+       set_nz(A);
+       prefetch();
+
+txs_imp
+       read_pc_noinc();
+       SP = set_l(SP, X);
+       prefetch();
+
+tya_imp
+       read_pc_noinc();
+       A = Y;
+       set_nz(A);
+       prefetch();
+
+#   exceptions
+reset
+       PC = read_arg(0xfffc);
+       PC = set_h(PC, read_arg(0xfffd));
+       prefetch();
+       inst_state = -1;
+
+
+#   undocumented reliable instructions
+dcp_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+dcp_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+dcp_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+dcp_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+dcp_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+dcp_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+dcp_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2--;
+       write(TMP, TMP2);
+       do_cmp(A, TMP2);
+       prefetch();
+
+isb_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+isb_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+isb_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+isb_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+isb_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+isb_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+isb_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2++;
+       write(TMP, TMP2);
+       do_sbc(TMP2);
+       prefetch();
+
+lax_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       A = X = read(TMP);
+       set_nz(A);
+       prefetch();
+
+lax_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A = X = read(TMP+Y);
+       set_nz(A);
+       prefetch();
+
+lax_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A = X = read(TMP);
+       set_nz(A);
+       prefetch();
+
+lax_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       A = X = read(TMP+Y);
+       set_nz(A);
+       prefetch();
+
+lax_zpg
+       TMP = read_pc();
+       A = X = read(TMP);
+       set_nz(A);
+       prefetch();
+
+lax_zpy
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+Y);
+       A = X = read(TMP);
+       set_nz(A);
+       prefetch();
+
+rla_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rla_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rla_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rla_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rla_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rla_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rla_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       A &= TMP2;
+       set_nz(A);
+       prefetch();
+
+rra_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+rra_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+rra_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+rra_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+rra_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+rra_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+rra_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       do_adc(TMP2);
+       prefetch();
+
+sax_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = A & X;
+       write(TMP, TMP2);
+       prefetch();
+
+sax_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = A & X;
+       write(TMP, TMP2);
+       prefetch();
+
+sax_zpg
+       TMP = read_pc();
+       TMP2 = A & X;
+       write(TMP, TMP2);
+       prefetch();
+
+sax_zpy
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+Y);
+       TMP2 = A & X;
+       write(TMP, TMP2);
+       prefetch();
+
+sbx_imm
+       TMP2 = read_pc();
+       X &= A;
+       if(X < TMP2)
+               P &= ~F_C;
+       else
+               P |= F_C;
+       X -= TMP2;
+       set_nz(X);
+       prefetch();
+
+sha_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP2 = A & X & ((TMP >> 8)+1);
+       if(page_changing(TMP, Y))
+               TMP = set_h(TMP+Y, TMP2);
+       else
+               TMP += Y;
+       write(TMP, TMP2);
+       prefetch();
+
+sha_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP2 = A & X & ((TMP >> 8)+1);
+       if(page_changing(TMP, Y))
+               TMP = set_h(TMP+Y, TMP2);
+       else
+               TMP += Y;
+       write(TMP, TMP2);
+       prefetch();
+
+shs_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       SP = set_l(SP, A & X);
+       TMP2 = A & X & ((TMP >> 8)+1);
+       if(page_changing(TMP, Y))
+               TMP = set_h(TMP+Y, TMP2);
+       else
+               TMP += Y;
+       write(TMP, TMP2);
+       prefetch();
+
+shx_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP2 = X & ((TMP >> 8)+1);
+       if(page_changing(TMP, Y))
+               TMP = set_h(TMP+Y, TMP2);
+       else
+               TMP += Y;
+       write(TMP, TMP2);
+       prefetch();
+
+shy_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP2 = Y & ((TMP >> 8)+1);
+       if(page_changing(TMP, X))
+               TMP = set_h(TMP+X, TMP2);
+       else
+               TMP += X;
+       write(TMP, TMP2);
+       prefetch();
+
+slo_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+slo_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+slo_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+slo_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+slo_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+slo_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+slo_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       A |= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       read(set_l(TMP, TMP+Y));
+       TMP += Y;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+sre_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = uint8_t(TMP+X);
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       A ^= TMP2;
+       set_nz(A);
+       prefetch();
+
+# undocumented unreliable instructions
+anc_imm
+       A &= read_pc();
+       set_nz(A);
+       if(A & 0x80)
+               P |= F_C;
+       else
+               P &= ~F_C;
+       prefetch();
+
+ane_imm
+       TMP2 = read_pc();
+       A &= TMP2 & X;
+       set_nz(A);
+       prefetch();
+
+asr_imm
+       A &= read_pc();
+       A = do_lsr(A);
+       prefetch();
+
+arr_imm
+       A &= read_pc();
+       do_arr();
+       prefetch();
+
+las_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP2 = read(TMP+Y);
+       A = TMP2 | 0x51;
+       X = 0xff;
+       set_nz(TMP2);
+       prefetch();
+
+lxa_imm
+       A = X = read_pc();
+       set_nz(A);
+       prefetch();
+
+# nop variants
+nop_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(TMP);
+       prefetch();
+
+nop_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       read(TMP + X);
+       prefetch();
+
+nop_imm
+       read_pc();
+       prefetch();
+
+nop_zpg
+       TMP = read_pc();
+       read(TMP);
+       prefetch();
+
+nop_zpx
+       TMP = read_pc();
+       read(TMP);
+       read(uint8_t(TMP+X));
+       prefetch();
+
+# system killers
+kil_non
+       read_pc();
+       read(0xffff);
+       read(0xfffe);
+       read(0xfffe);
+       for(;;) {
+               read(0xffff);
+       }
diff --git a/m6502/om65c02.lst b/m6502/om65c02.lst
new file mode 100644 (file)
index 0000000..6f72fe7
--- /dev/null
@@ -0,0 +1,586 @@
+# license:BSD-3-Clause
+# copyright-holders:Olivier Galibert
+# m65c02 opcodes
+
+adc_c_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_adc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP = read(TMP);
+       do_adc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       TMP = read(TMP);
+       do_adc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_adc(read(TMP));
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       do_adc(read(TMP+Y));
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_imm
+       TMP = read_pc();
+       do_adc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_adc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_adc(read(TMP));
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+adc_c_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = read(uint8_t(TMP+X));
+       do_adc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+and_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A &= read(TMP);
+       set_nz(A);
+       prefetch();
+
+asl_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_asl(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+bbr_zpb
+       // Access pattern uncertain
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       TMP = read_pc();
+       read_pc_noinc();
+       if(!(TMP2 & (1 << ((inst_state >> 4) & 7)))) {
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bbs_zpb
+       // Access pattern uncertain
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       TMP = read_pc();
+       read_pc_noinc();
+       if(TMP2 & (1 << ((inst_state >> 4) & 7))) {
+               PC += int8_t(TMP);
+       }
+       prefetch();
+
+bit_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       do_bit(read(TMP));
+       prefetch();
+
+bit_imm
+       TMP = read_pc();
+       if(A & TMP)
+               P &= ~F_Z;
+       else
+               P |= F_Z;
+       prefetch();
+
+bit_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = read(uint8_t(TMP+X));
+       do_bit(TMP);
+       prefetch();
+
+bra_rel
+       TMP = read_pc();
+       read_pc_noinc();
+       if(page_changing(PC, int8_t(TMP))) {
+               read_arg(set_l(PC, PC+int8_t(TMP)));
+       }
+       PC += int8_t(TMP);
+       prefetch();
+
+brk_c_imp
+       if(irq_taken || nmi_state) {
+               read_pc_noinc();
+       } else {
+               read_pc();
+       }
+       write(SP, PC >> 8);
+       dec_SP();
+       write(SP, PC);
+       dec_SP();
+       write(SP, irq_taken || nmi_state ? P & ~F_B : P);
+       dec_SP();
+       if(irq_taken && nmi_state) {
+               PC = read_arg(0xfffa);
+               PC = set_h(PC, read_arg(0xfffb));
+               nmi_state = false;
+               standard_irq_callback(NMI_LINE);
+       } else {
+               PC = read_arg(0xfffe);
+               PC = set_h(PC, read_arg(0xffff));
+               if(irq_taken)
+                       standard_irq_callback(IRQ_LINE);
+       }
+       irq_taken = false;
+       P = (P | F_I) & ~F_D; // Do *not* move after the prefetch
+       prefetch();
+       inst_state = -1;
+
+cmp_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_cmp(A, read(TMP));
+       prefetch();
+
+dec_acc
+       read_pc_noinc();
+       A--;
+       set_nz(A);
+       prefetch();
+
+eor_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A ^= read(TMP);
+       set_nz(A);
+       prefetch();
+
+inc_acc
+       read_pc_noinc();
+       A++;
+       set_nz(A);
+       prefetch();
+
+jmp_iax
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       TMP += X;
+       PC = read(TMP);
+       PC = set_h(PC, read(TMP+1));
+       prefetch();
+
+jmp_c_ind
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       PC = read(TMP);
+       read(set_l(TMP, TMP+1));
+       PC = set_h(PC, read(TMP+1));
+       prefetch();
+
+lda_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A = read(TMP);
+       set_nz(A);
+       prefetch();
+
+
+lsr_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_lsr(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+nop_c_imp
+       prefetch();
+
+nop_c_aba
+       read_pc();
+       read_pc();
+       read_pc_noinc();
+       read_pc_noinc();
+       read_pc_noinc();
+       read_pc_noinc();
+       read_pc_noinc();
+       prefetch();
+
+nop_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       prefetch();
+
+ora_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       A |= read(TMP);
+       set_nz(A);
+       prefetch();
+
+phx_imp
+       read_pc_noinc();
+       write(SP, X);
+       dec_SP();
+       prefetch();
+
+phy_imp
+       read_pc_noinc();
+       write(SP, Y);
+       dec_SP();
+       prefetch();
+
+plx_imp
+       read_pc_noinc();
+       read(SP);
+       inc_SP();
+       X = read(SP);
+       set_nz(X);
+       prefetch();
+
+ply_imp
+       read_pc_noinc();
+       read(SP);
+       inc_SP();
+       Y = read(SP);
+       set_nz(Y);
+       prefetch();
+
+rmb_bzp
+       // Access pattern unknown but probable (built upon inc_zpg)
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 &= ~(1 << ((inst_state >> 4) & 7));
+       write(TMP, TMP2);
+       prefetch();
+
+rol_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_rol(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+
+ror_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 = do_ror(TMP2);
+       write(TMP, TMP2);
+       prefetch();
+
+sbc_c_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP = read(TMP);
+       do_sbc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, X)) {
+               read(set_l(TMP, TMP+X));
+       }
+       TMP += X;
+       TMP = read(TMP);
+       do_sbc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_aby
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       TMP += Y;
+       TMP = read(TMP);
+       do_sbc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_idx
+       TMP2 = read_pc();
+       read(TMP2);
+       TMP2 += X;
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_sbc(read(TMP));
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_idy
+       TMP2 = read_pc();
+       TMP = read(TMP2);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       if(page_changing(TMP, Y)) {
+               read(set_l(TMP, TMP+Y));
+       }
+       do_sbc(read(TMP+Y));
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_imm
+       TMP = read_pc();
+       do_sbc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_zpg
+       TMP = read_pc();
+       TMP = read(TMP);
+       do_sbc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       do_sbc(read(TMP));
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+sbc_c_zpx
+       TMP = read_pc();
+       read(TMP);
+       TMP = read(uint8_t(TMP+X));
+       do_sbc(TMP);
+       if(P & F_D) {
+               read_pc_noinc();
+               set_nz(A);
+       }
+       prefetch();
+
+smb_bzp
+       // Access pattern unknown but probable (built upon inc_zpg)
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       TMP2 |= 1 << ((inst_state >> 4) & 7);
+       write(TMP, TMP2);
+       prefetch();
+
+sta_zpi
+       TMP2 = read_pc();
+       TMP = read(TMP2 & 0xff);
+       TMP = set_h(TMP, read((TMP2+1) & 0xff));
+       write(TMP, A);
+       prefetch();
+
+stp_imp
+       for(;;) {
+               eat-all-cycles;
+       }
+
+stz_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       write(TMP, 0x00);
+       prefetch();
+
+stz_abx
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       read(set_l(TMP, TMP+X));
+       write(TMP+X, 0x00);
+       prefetch();
+
+stz_zpg
+       TMP = read_pc();
+       write(TMP, 0x00);
+       prefetch();
+
+stz_zpx
+       TMP = read_pc();
+       read(TMP);
+       write(uint8_t(TMP+X), 0x00);
+       prefetch();
+
+trb_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       if(A & TMP2)
+               P &= ~F_Z;
+       else
+               P |= F_Z;
+       TMP2 &= ~A;
+       write(TMP, TMP2);
+       prefetch();
+
+trb_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       if(A & TMP2)
+               P &= ~F_Z;
+       else
+               P |= F_Z;
+       TMP2 &= ~A;
+       write(TMP, TMP2);
+       prefetch();
+
+tsb_aba
+       TMP = read_pc();
+       TMP = set_h(TMP, read_pc());
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       if(A & TMP2)
+               P &= ~F_Z;
+       else
+               P |= F_Z;
+       TMP2 |= A;
+       write(TMP, TMP2);
+       prefetch();
+
+tsb_zpg
+       TMP = read_pc();
+       TMP2 = read(TMP);
+       write(TMP, TMP2);
+       if(A & TMP2)
+               P &= ~F_Z;
+       else
+               P |= F_Z;
+       TMP2 |= A;
+       write(TMP, TMP2);
+       prefetch();
+
+wai_imp
+       read_pc_noinc();
+       read_pc_noinc();
+       while(!nmi_state && !irq_state) {
+               eat-all-cycles;
+       }
+       prefetch();