using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using mame;

namespace cpu.m6800
{
    public partial class M6800 : cpuexec_data
    {
        public static M6800 m1;
        public static Action action_rx, action_tx;
        public Action[] insn, m6800_insn, hd63701_insn, m6803_insn;
        public Register PPC, PC;
        public Register S, X, D, EA;
        public byte[] cycles;
        public byte cc, wai_state, ic_eddge;
        public byte[] irq_state = new byte[2];
        public byte nmi_state;
        public int extra_cycles;
        public delegate int irq_delegate(int i);
        public irq_delegate irq_callback;
        public byte port1_ddr, port2_ddr, port3_ddr, port4_ddr, port1_data, port2_data, port3_data, port4_data;
        public byte tcsr, pending_tcsr, irq2, ram_ctrl;
        public Register counter, output_compare, timer_over;
        public ushort input_capture;
        public int clock;
        public byte trcsr, rmcr, rdr, tdr, rsr, tsr;
        public int rxbits, txbits, trcsr_read, tx;
        public M6800_TX_STATE txstate;
        public Timer.emu_timer m6800_rx_timer, m6800_tx_timer;
        private byte TCSR_OLVL = 0x01, TCSR_IEDG = 0x02, TCSR_ETOI = 0x04, TCSR_EOCI = 0x08, TCSR_EICI = 0x10, TCSR_TOF = 0x20, TCSR_OCF = 0x40, TCSR_ICF = 0x80;
        protected byte M6800_WAI = 8, M6800_SLP = 0x10;
        private const byte M6800_IRQ_LINE = 0, M6800_TIN_LINE = 1;
        private ushort M6803_DDR1 = 0x00, M6803_DDR2 = 0x01, M6803_DDR3 = 0x04, M6803_DDR4 = 0x05, M6803_PORT1 = 0x100, M6803_PORT2 = 0x101, M6803_PORT3 = 0x102, M6803_PORT4 = 0x103;
        private byte M6800_RMCR_SS_MASK = 0x03, M6800_RMCR_SS_4096 = 0x03, M6800_RMCR_SS_1024 = 0x02, M6800_RMCR_SS_128 = 0x01, M6800_RMCR_SS_16 = 0x00, M6800_RMCR_CC_MASK = 0x0c;
        private byte M6800_TRCSR_RDRF = 0x80, M6800_TRCSR_ORFE = 0x40, M6800_TRCSR_TDRE = 0x20, M6800_TRCSR_RIE = 0x10, M6800_TRCSR_RE = 0x08, M6800_TRCSR_TIE = 0x04, M6800_TRCSR_TE = 0x02, M6800_TRCSR_WU = 0x01, M6800_PORT2_IO4 = 0x10, M6800_PORT2_IO3 = 0x08;
        private int[] M6800_RMCR_SS = new int[] { 16, 128, 1024, 4096 };
        public enum M6800_TX_STATE
        {
            INIT = 0,
            READY
        }
        private byte CLEAR_LINE = 0, INPUT_LINE_NMI = 32;
        protected ulong totalExecutedCycles;
        protected int pendingCycles;
        public override ulong TotalExecutedCycles
        {
            get
            {
                return totalExecutedCycles;
            }
            set
            {
                totalExecutedCycles = value;
            }
        }
        public override int PendingCycles
        {
            get
            {
                return pendingCycles;
            }
            set
            {
                pendingCycles = value;
            }
        }
        public uint timer_next;
        public byte[] flags8i = new byte[256]	 /* increment */
{
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0a,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
};
        private byte[] flags8d = new byte[256] /* decrement */
{
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
};
        private byte[] cycles_6800 = new byte[]
{
		/* 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
	/*0*/ 99, 2,99,99,99,99, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
	/*1*/  2, 2,99,99,99,99, 2, 2,99, 2,99, 2,99,99,99,99,
	/*2*/  4,99, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	/*3*/  4, 4, 4, 4, 4, 4, 4, 4,99, 5,99,10,99,99, 9,12,
	/*4*/  2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
	/*5*/  2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
	/*6*/  7,99,99, 7, 7,99, 7, 7, 7, 7, 7,99, 7, 7, 4, 7,
	/*7*/  6,99,99, 6, 6,99, 6, 6, 6, 6, 6,99, 6, 6, 3, 6,
	/*8*/  2, 2, 2,99, 2, 2, 2,99, 2, 2, 2, 2, 3, 8, 3,99,
	/*9*/  3, 3, 3,99, 3, 3, 3, 4, 3, 3, 3, 3, 4,99, 4, 5,
	/*A*/  5, 5, 5,99, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
	/*B*/  4, 4, 4,99, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
	/*C*/  2, 2, 2,99, 2, 2, 2,99, 2, 2, 2, 2,99,99, 3,99,
	/*D*/  3, 3, 3,99, 3, 3, 3, 4, 3, 3, 3, 3,99,99, 4, 5,
	/*E*/  5, 5, 5,99, 5, 5, 5, 6, 5, 5, 5, 5,99,99, 6, 7,
	/*F*/  4, 4, 4,99, 4, 4, 4, 5, 4, 4, 4, 4,99,99, 5, 6
};
        protected byte[] cycles_6803 =
{
		/* 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
	/*0*/ 99, 2,99,99, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
	/*1*/  2, 2,99,99,99,99, 2, 2,99, 2,99, 2,99,99,99,99,
	/*2*/  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	/*3*/  3, 3, 4, 4, 3, 3, 3, 3, 5, 5, 3,10, 4,10, 9,12,
	/*4*/  2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
	/*5*/  2,99,99, 2, 2,99, 2, 2, 2, 2, 2,99, 2, 2,99, 2,
	/*6*/  6,99,99, 6, 6,99, 6, 6, 6, 6, 6,99, 6, 6, 3, 6,
	/*7*/  6,99,99, 6, 6,99, 6, 6, 6, 6, 6,99, 6, 6, 3, 6,
	/*8*/  2, 2, 2, 4, 2, 2, 2,99, 2, 2, 2, 2, 4, 6, 3,99,
	/*9*/  3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 4, 4,
	/*A*/  4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 5, 5,
	/*B*/  4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 5, 5,
	/*C*/  2, 2, 2, 4, 2, 2, 2,99, 2, 2, 2, 2, 3,99, 3,99,
	/*D*/  3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
	/*E*/  4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
	/*F*/  4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
};
        private byte[] cycles_63701 =
{
		/* 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
	/*0*/ 99, 1,99,99, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
	/*1*/  1, 1,99,99,99,99, 1, 1, 2, 2, 4, 1,99,99,99,99,
	/*2*/  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	/*3*/  1, 1, 3, 3, 1, 1, 4, 4, 4, 5, 1,10, 5, 7, 9,12,
	/*4*/  1,99,99, 1, 1,99, 1, 1, 1, 1, 1,99, 1, 1,99, 1,
	/*5*/  1,99,99, 1, 1,99, 1, 1, 1, 1, 1,99, 1, 1,99, 1,
	/*6*/  6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 5, 6, 4, 3, 5,
	/*7*/  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 3, 5,
	/*8*/  2, 2, 2, 3, 2, 2, 2,99, 2, 2, 2, 2, 3, 5, 3,99,
	/*9*/  3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4,
	/*A*/  4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
	/*B*/  4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5,
	/*C*/  2, 2, 2, 3, 2, 2, 2,99, 2, 2, 2, 2, 3,99, 3,99,
	/*D*/  3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
	/*E*/  4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
	/*F*/  4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5
};

        public Func<ushort, byte> ReadOp, ReadOpArg;
        public Func<ushort, byte> ReadMemory;
        public Action<ushort, byte> WriteMemory;
        public Func<ushort, byte> ReadIO;
        public Action<ushort, byte> WriteIO;

        public M6800()
        {
            m6800_insn = new Action[256]
            {
                illegal,nop,	illegal,illegal,illegal,illegal,tap,	tpa,
                inx,	dex,	clv,	sev,	clc,	sec,	cli,	sei,
                sba,	cba,	illegal,illegal,illegal,illegal,tab,	tba,
                illegal,daa,	illegal,aba,	illegal,illegal,illegal,illegal,
                bra,	brn,	bhi,	bls,	bcc,	bcs,	bne,	beq,
                bvc,	bvs,	bpl,	bmi,	bge,	blt,	bgt,	ble,
                tsx,	ins,	pula,	pulb,	des,	txs,	psha,	pshb,
                illegal,rts,	illegal,rti,	illegal,illegal,wai,	swi,
                nega,	illegal,illegal,coma,	lsra,	illegal,rora,	asra,
                asla,	rola,	deca,	illegal,inca,	tsta,	illegal,clra,
                negb,	illegal,illegal,comb,	lsrb,	illegal,rorb,	asrb,
                aslb,	rolb,	decb,	illegal,incb,	tstb,	illegal,clrb,
                neg_ix, illegal,illegal,com_ix, lsr_ix, illegal,ror_ix, asr_ix,
                asl_ix, rol_ix, dec_ix, illegal,inc_ix, tst_ix, jmp_ix, clr_ix,
                neg_ex, illegal,illegal,com_ex, lsr_ex, illegal,ror_ex, asr_ex,
                asl_ex, rol_ex, dec_ex, illegal,inc_ex, tst_ex, jmp_ex, clr_ex,
                suba_im,cmpa_im,sbca_im,illegal,anda_im,bita_im,lda_im, sta_im,
                eora_im,adca_im,ora_im, adda_im,cmpx_im,bsr,	lds_im, sts_im,
                suba_di,cmpa_di,sbca_di,illegal,anda_di,bita_di,lda_di, sta_di,
                eora_di,adca_di,ora_di, adda_di,cmpx_di,jsr_di, lds_di, sts_di,
                suba_ix,cmpa_ix,sbca_ix,illegal,anda_ix,bita_ix,lda_ix, sta_ix,
                eora_ix,adca_ix,ora_ix, adda_ix,cmpx_ix,jsr_ix, lds_ix, sts_ix,
                suba_ex,cmpa_ex,sbca_ex,illegal,anda_ex,bita_ex,lda_ex, sta_ex,
                eora_ex,adca_ex,ora_ex, adda_ex,cmpx_ex,jsr_ex, lds_ex, sts_ex,
                subb_im,cmpb_im,sbcb_im,illegal,andb_im,bitb_im,ldb_im, stb_im,
                eorb_im,adcb_im,orb_im, addb_im,illegal,illegal,ldx_im, stx_im,
                subb_di,cmpb_di,sbcb_di,illegal,andb_di,bitb_di,ldb_di, stb_di,
                eorb_di,adcb_di,orb_di, addb_di,illegal,illegal,ldx_di, stx_di,
                subb_ix,cmpb_ix,sbcb_ix,illegal,andb_ix,bitb_ix,ldb_ix, stb_ix,
                eorb_ix,adcb_ix,orb_ix, addb_ix,illegal,illegal,ldx_ix, stx_ix,
                subb_ex,cmpb_ex,sbcb_ex,illegal,andb_ex,bitb_ex,ldb_ex, stb_ex,
                eorb_ex,adcb_ex,orb_ex, addb_ex,illegal,illegal,ldx_ex, stx_ex
            };
            hd63701_insn=new Action[]
            {
                trap,   nop,	trap	,trap	,lsrd,	asld,	tap,	tpa,
                inx,	dex,	clv,	sev,	clc,	sec,	cli,	sei,
                sba,	cba,	undoc1, undoc2, trap	,trap	,tab,	tba,
                xgdx,	daa,	slp		,aba,	trap	,trap	,trap	,trap	,
                bra,	brn,	bhi,	bls,	bcc,	bcs,	bne,	beq,
                bvc,	bvs,	bpl,	bmi,	bge,	blt,	bgt,	ble,
                tsx,	ins,	pula,	pulb,	des,	txs,	psha,	pshb,
                pulx,	rts,	abx,	rti,	pshx,	mul,	wai,	swi,
                nega,	trap	,trap	,coma,	lsra,	trap	,rora,	asra,
                asla,	rola,	deca,	trap	,inca,	tsta,	trap	,clra,
                negb,	trap	,trap	,comb,	lsrb,	trap	,rorb,	asrb,
                aslb,	rolb,	decb,	trap	,incb,	tstb,	trap	,clrb,
                neg_ix, aim_ix, oim_ix, com_ix, lsr_ix, eim_ix, ror_ix, asr_ix,
                asl_ix, rol_ix, dec_ix, tim_ix, inc_ix, tst_ix, jmp_ix, clr_ix,
                neg_ex, aim_di, oim_di, com_ex, lsr_ex, eim_di, ror_ex, asr_ex,
                asl_ex, rol_ex, dec_ex, tim_di, inc_ex, tst_ex, jmp_ex, clr_ex,
                suba_im,cmpa_im,sbca_im,subd_im,anda_im,bita_im,lda_im, sta_im,
                eora_im,adca_im,ora_im, adda_im,cpx_im ,bsr,	lds_im, sts_im,
                suba_di,cmpa_di,sbca_di,subd_di,anda_di,bita_di,lda_di, sta_di,
                eora_di,adca_di,ora_di, adda_di,cpx_di ,jsr_di, lds_di, sts_di,
                suba_ix,cmpa_ix,sbca_ix,subd_ix,anda_ix,bita_ix,lda_ix, sta_ix,
                eora_ix,adca_ix,ora_ix, adda_ix,cpx_ix ,jsr_ix, lds_ix, sts_ix,
                suba_ex,cmpa_ex,sbca_ex,subd_ex,anda_ex,bita_ex,lda_ex, sta_ex,
                eora_ex,adca_ex,ora_ex, adda_ex,cpx_ex ,jsr_ex, lds_ex, sts_ex,
                subb_im,cmpb_im,sbcb_im,addd_im,andb_im,bitb_im,ldb_im, stb_im,
                eorb_im,adcb_im,orb_im, addb_im,ldd_im, std_im, ldx_im, stx_im,
                subb_di,cmpb_di,sbcb_di,addd_di,andb_di,bitb_di,ldb_di, stb_di,
                eorb_di,adcb_di,orb_di, addb_di,ldd_di, std_di, ldx_di, stx_di,
                subb_ix,cmpb_ix,sbcb_ix,addd_ix,andb_ix,bitb_ix,ldb_ix, stb_ix,
                eorb_ix,adcb_ix,orb_ix, addb_ix,ldd_ix, std_ix, ldx_ix, stx_ix,
                subb_ex,cmpb_ex,sbcb_ex,addd_ex,andb_ex,bitb_ex,ldb_ex, stb_ex,
                eorb_ex,adcb_ex,orb_ex, addb_ex,ldd_ex, std_ex, ldx_ex, stx_ex
            };
            insn = hd63701_insn;
            cycles = cycles_63701;
            clock = 1536000;
            irq_callback = null;
            m6800_rx_timer = Timer.timer_alloc_common(m6800_rx_tick, "m6800_rx_tick", false);
            m6800_tx_timer = Timer.timer_alloc_common(m6800_tx_tick, "m6800_tx_tick", false);
        }
        public override void Reset()
        {
            m6800_reset();
        }
        private byte IMMBYTE()
        {
            byte b = ReadOpArg(PC.LowWord);
            PC.LowWord++;
            return b;
        }
        private Register IMMWORD()
        {
            Register w = new Register();
            w.d = (uint)((ReadOpArg(PC.LowWord) << 8) | ReadOpArg((ushort)((PC.LowWord + 1) & 0xffff)));
            PC.LowWord += 2;
            return w;
        }
        private void PUSHBYTE(byte b)
        {
            WriteMemory(S.LowWord, b);
            --S.LowWord;
        }
        private void PUSHWORD(Register w)
        {
            WriteMemory(S.LowWord, w.LowByte);
            --S.LowWord;
            WriteMemory(S.LowWord, w.HighByte);
            --S.LowWord;
        }
        private byte PULLBYTE()
        {
            S.LowWord++;
            return ReadMemory(S.LowWord);
        }
        private Register PULLWORD()
        {
            Register w = new Register();
            S.LowWord++;
            w.d = (uint)(ReadMemory(S.LowWord) << 8);
            S.LowWord++;
            w.d |= ReadMemory(S.LowWord);
            return w;
        }
        private void MODIFIED_tcsr()
        {
            irq2 = (byte)((tcsr & (tcsr << 3)) & (TCSR_ICF | TCSR_OCF | TCSR_TOF));
        }
        private void SET_TIMER_EVENT()
        {
            timer_next = (output_compare.d - counter.d < timer_over.d - counter.d) ? output_compare.d : timer_over.d;
        }
        protected void CLEANUP_conters()
        {
            output_compare.HighWord -= counter.HighWord;
            timer_over.LowWord -= counter.HighWord;
            counter.HighWord = 0;
            SET_TIMER_EVENT();
        }
        private void MODIFIED_counters()
        {
            output_compare.HighWord = (output_compare.LowWord >= counter.LowWord) ? counter.HighWord : (ushort)(counter.HighWord + 1);
            SET_TIMER_EVENT();
        }
        private void TAKE_ICI()
        {
            ENTER_INTERRUPT(0xfff6);
        }
        private void TAKE_OCI()
        {
            ENTER_INTERRUPT(0xfff4);
        }
        private void TAKE_TOI()
        {
            ENTER_INTERRUPT(0xfff2);
        }
        private void TAKE_SCI()
        {
            ENTER_INTERRUPT(0xfff0);
        }
        private void TAKE_TRAP()
        {
            ENTER_INTERRUPT(0xffee);
        }
        private void ONE_MORE_INSN()
        {
            byte ireg;
            PPC = PC;
            //debugger_instruction_hook(Machine, PCD);
            ireg = ReadOp(PC.LowWord);
            PC.LowWord++;
            insn[ireg]();
            INCREMENT_COUNTER(cycles[ireg]);
        }
        private void CHECK_IRQ_LINES()
        {
            if ((cc & 0x10) == 0)
            {
                if (irq_state[0] != (byte)LineState.CLEAR_LINE)
                {
                    ENTER_INTERRUPT(0xfff8);
                    if( irq_callback!=null )
                    {
				        irq_callback(0);
                    }
                }
                else
                {
                    m6800_check_irq2();
                }
            }
        }
        private void CLR_HNZVC()
        {
            cc &= 0xd0;
        }
        private void CLR_NZV()
        {
            cc &= 0xf1;
        }
        private void CLR_HNZC()
        {
            cc &= 0xd2;
        }
        private void CLR_NZVC()
        {
            cc &= 0xf0;
        }
        private void CLR_Z()
        {
            cc &= 0xfb;
        }
        private void CLR_NZC()
        {
            cc &= 0xf2;
        }
        private void CLR_ZC()
        {
            cc &= 0xfa;
        }
        private void CLR_C()
        {
            cc &= 0xfe;
        }
        private void SET_Z(byte a)
        {
            if (a == 0)
            {
                SEZ();
            }
        }
        private void SET_Z(ushort a)
        {
            if (a == 0)
            {
                SEZ();
            }
        }
        private void SET_Z8(byte a)
        {
            SET_Z(a);
        }
        private void SET_Z16(ushort a)
        {
            SET_Z(a);
        }
        private void SET_N8(byte a)
        {
            cc |= (byte)(((a) & 0x80) >> 4);
        }
        private void SET_N16(ushort a)
        {
            cc |= (byte)(((a) & 0x8000) >> 12);
        }
        private void SET_H(ushort a, ushort b, ushort r)
        {
            cc |= (byte)((((a) ^ (b) ^ (r)) & 0x10) << 1);
        }
        private void SET_C8(ushort a)
        {
            cc |= (byte)(((a) & 0x100) >> 8);
        }
        private void SET_C16(uint a)
        {
            cc |= (byte)(((a) & 0x10000) >> 16);
        }
        private void SET_V8(ushort a, ushort b, ushort r)
        {
            cc |= (byte)((((a) ^ (b) ^ (r) ^ ((r) >> 1)) & 0x80) >> 6);
        }
        private void SET_V16(uint a, uint b, uint r)
        {
            cc |= (byte)((((a) ^ (b) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 14);
        }
        private void SET_FLAGS8I(byte a)
        {
            cc |= flags8i[(a) & 0xff];
        }
        private void SET_FLAGS8D(byte a)
        {
            cc |= flags8d[(a) & 0xff];
        }
        private void SET_NZ8(byte a)
        {
            SET_N8(a);
            SET_Z8(a);
        }
        private void SET_NZ16(ushort a)
        {
            SET_N16(a);
            SET_Z16(a);
        }
        private void SET_FLAGS8(ushort a, ushort b, ushort r)
        {
            SET_N8((byte)r);
            SET_Z8((byte)r);
            SET_V8(a, b, r);
            SET_C8(r);
        }
        private void SET_FLAGS16(uint a, uint b, uint r)
        {
            SET_N16((ushort)r);
            SET_Z16((ushort)r);
            SET_V16(a, b, r);
            SET_C16(r);
        }
        private short SIGNED(byte b)
        {
            return (short)((b & 0x80) != 0 ? b | 0xff00 : b);
        }
        private void DIRECT()
        {
            EA.d = IMMBYTE();
        }
        private void IMM8()
        {
            EA.LowWord = PC.LowWord++;
        }
        private void IMM16()
        {
            EA.LowWord = PC.LowWord;
            PC.LowWord += 2;
        }
        private void EXTENDED()
        {
            EA = IMMWORD();
        }
        private void INDEXED()
        {
            EA.LowWord = (ushort)(X.LowWord + ReadOpArg(PC.LowWord));
            PC.LowWord++;
        }
        protected void SEC()
        {
            cc |= 0x01;
        }
        protected void CLC()
        {
            cc &= 0xfe;
        }
        protected void SEZ()
        {
            cc |= 0x04;
        }
        protected void CLZ()
        {
            cc &= 0xfb;
        }
        protected void SEN()
        {
            cc |= 0x08;
        }
        protected void CLN()
        {
            cc &= 0xf7;
        }
        protected void SEV()
        {
            cc |= 0x02;
        }
        protected void CLV()
        {
            cc &= 0xfd;
        }
        protected void SEH()
        {
            cc |= 0x20;
        }
        protected void CLH()
        {
            cc &= 0xdf;
        }
        protected void SEI()
        {
            cc |= 0x10;
        }
        protected void CLI()
        {
            cc &= unchecked((byte)(~0x10));
        }
        protected void INCREMENT_COUNTER(int amount)
        {
            pendingCycles -= amount;
            counter.d += (uint)amount;
            if (counter.d >= timer_next)
                check_timer_event();
        }
        protected void EAT_CYCLES()
        {
            int cycles_to_eat;
            cycles_to_eat = (int)(timer_next - counter.d);
            if (cycles_to_eat > pendingCycles)
                cycles_to_eat = pendingCycles;
            if (cycles_to_eat > 0)
            {
                INCREMENT_COUNTER(cycles_to_eat);
            }
        }
        private byte DIRBYTE()
        {
            DIRECT();
            return ReadMemory(EA.LowWord);
        }
        private Register DIRWORD()
        {
            Register w = new Register();
            DIRECT();
            w.LowWord = RM16(EA.LowWord);
            return w;
        }
        private byte EXTBYTE()
        {
            EXTENDED();
            return ReadMemory(EA.LowWord);
        }
        private Register EXTWORD()
        {
            Register w = new Register();
            EXTENDED();
            w.LowWord = RM16(EA.LowWord);
            return w;
        }
        private byte IDXBYTE()
        {
            INDEXED();
            return ReadMemory(EA.LowWord);
        }
        private Register IDXWORD()
        {
            Register w = new Register();
            INDEXED();
            w.LowWord = RM16(EA.LowWord);
            return w;
        }
        private void BRANCH(bool f)
        {
            byte t = IMMBYTE();
            if (f)
            {
                PC.LowWord += (ushort)SIGNED(t);
            }
        }
        private byte NXORV()
        {
            return (byte)((cc & 0x08) ^ ((cc & 0x02) << 2));
        }
        private ushort RM16(ushort Addr)
        {
            ushort result = (ushort)(ReadMemory(Addr) << 8);
            return (ushort)(result | ReadMemory((ushort)(Addr + 1)));
        }
        private void WM16(ushort Addr, Register p)
        {
            WriteMemory(Addr, p.HighByte);
            WriteMemory((ushort)(Addr + 1), p.LowByte);
        }
        private void ENTER_INTERRUPT(ushort irq_vector)
        {
            if ((wai_state & (M6800_WAI | M6800_SLP)) != 0)
            {
                if ((wai_state & M6800_WAI) != 0)
                    extra_cycles += 4;
                wai_state &= (byte)(~(M6800_WAI | M6800_SLP));
            }
            else
            {
                PUSHWORD(PC);
                PUSHWORD(X);
                PUSHBYTE(D.HighByte);
                PUSHBYTE(D.LowByte);
                PUSHBYTE(cc);
                extra_cycles += 12;
            }
            SEI();
            PC.d = RM16(irq_vector);
        }
        private void m6800_check_irq2()
        {
            if ((tcsr & (TCSR_EICI | TCSR_ICF)) == (TCSR_EICI | TCSR_ICF))
            {
                TAKE_ICI();
                //if( m6800.irq_callback )
                //	(void)(*m6800.irq_callback)(M6800_TIN_LINE);
            }
            else if ((tcsr & (TCSR_EOCI | TCSR_OCF)) == (TCSR_EOCI | TCSR_OCF))
            {
                TAKE_OCI();
            }
            else if ((tcsr & (TCSR_ETOI | TCSR_TOF)) == (TCSR_ETOI | TCSR_TOF))
            {
                TAKE_TOI();
            }
            else if (((trcsr & (M6800_TRCSR_RIE | M6800_TRCSR_RDRF)) == (M6800_TRCSR_RIE | M6800_TRCSR_RDRF)) ||
                     ((trcsr & (M6800_TRCSR_RIE | M6800_TRCSR_ORFE)) == (M6800_TRCSR_RIE | M6800_TRCSR_ORFE)) ||
                     ((trcsr & (M6800_TRCSR_TIE | M6800_TRCSR_TDRE)) == (M6800_TRCSR_TIE | M6800_TRCSR_TDRE)))
            {
                TAKE_SCI();
            }
        }
        private void check_timer_event()
        {
            if (counter.d >= output_compare.d)
            {
                output_compare.HighWord++;
                tcsr |= TCSR_OCF;
                pending_tcsr |= TCSR_OCF;
                MODIFIED_tcsr();
                if (((cc & 0x10) == 0) && ((tcsr & TCSR_EOCI) != 0))
                    TAKE_OCI();
            }
            if (counter.d >= timer_over.d)
            {
                timer_over.LowWord++;
                tcsr |= TCSR_TOF;
                pending_tcsr |= TCSR_TOF;
                MODIFIED_tcsr();
                if (((cc & 0x10) == 0) && (tcsr & TCSR_ETOI) != 0)
                    TAKE_TOI();
            }
            SET_TIMER_EVENT();
        }
        private void m6800_tx(int value)
        {
            port2_data = (byte)((port2_data & 0xef) | (value << 4));
            if (port2_ddr == 0xff)
                WriteIO(M6803_PORT2, port2_data);
            else
                WriteIO(M6803_PORT2, (byte)((port2_data & port2_ddr) | (ReadIO(M6803_PORT2) & (port2_ddr ^ 0xff))));
        }
        private int m6800_rx()
        {
            return (ReadIO(M6803_PORT2) & M6800_PORT2_IO3) >> 3;
        }
        public void m6800_tx_tick()
        {
            if ((trcsr & M6800_TRCSR_TE) != 0)
            {
                port2_ddr |= M6800_PORT2_IO4;
                switch (txstate)
                {
                    case M6800_TX_STATE.INIT:
                        tx = 1;
                        txbits++;

                        if (txbits == 10)
                        {
                            txstate = M6800_TX_STATE.READY;
                            txbits = 0;
                        }
                        break;

                    case M6800_TX_STATE.READY:
                        switch (txbits)
                        {
                            case 0:
                                if ((trcsr & M6800_TRCSR_TDRE) != 0)
                                {
                                    tx = 1;
                                }
                                else
                                {
                                    tsr = tdr;
                                    trcsr |= M6800_TRCSR_TDRE;
                                    tx = 0;
                                    txbits++;
                                }
                                break;

                            case 9:
                                // send stop bit '1'
                                tx = 1;
                                CHECK_IRQ_LINES();
                                txbits = 0;
                                break;

                            default:
                                tx = tsr & 0x01;
                                tsr >>= 1;
                                txbits++;
                                break;
                        }
                        break;
                }
            }
            m6800_tx(tx);
        }
        public void m6800_rx_tick()
        {
            if ((trcsr & M6800_TRCSR_RE) != 0)
            {
                if ((trcsr & M6800_TRCSR_WU) != 0)
                {
                    if (m6800_rx() == 1)
                    {
                        rxbits++;
                        if (rxbits == 10)
                        {
                            trcsr &= (byte)(~M6800_TRCSR_WU);
                            rxbits = 0;
                        }
                    }
                    else
                    {
                        rxbits = 0;
                    }
                }
                else
                {
                    switch (rxbits)
                    {
                        case 0:
                            if (m6800_rx() == 0)
                            {
                                rxbits++;
                            }
                            break;
                        case 9:
                            if (m6800_rx() == 1)
                            {
                                if ((trcsr & M6800_TRCSR_RDRF) != 0)
                                {
                                    trcsr |= M6800_TRCSR_ORFE;
                                    CHECK_IRQ_LINES();
                                }
                                else
                                {
                                    if ((trcsr & M6800_TRCSR_ORFE) == 0)
                                    {
                                        rdr = rsr;
                                        trcsr |= M6800_TRCSR_RDRF;
                                        CHECK_IRQ_LINES();
                                    }
                                }
                            }
                            else
                            {
                                if ((trcsr & M6800_TRCSR_ORFE) == 0)
                                {
                                    // transfer unframed data into receive register
                                    rdr = rsr;
                                }
                                trcsr |= (byte)M6800_TRCSR_ORFE;
                                trcsr &= (byte)(~M6800_TRCSR_RDRF);
                                CHECK_IRQ_LINES();
                            }
                            rxbits = 0;
                            break;
                        default:
                            rsr >>= 1;
                            rsr |= (byte)(m6800_rx() << 7);
                            rxbits++;
                            break;
                    }
                }
            }
        }
        private void m6800_reset()
        {
            SEI();				/* IRQ disabled */
            PC.LowWord = RM16(0xfffe);
            wai_state = 0;
            nmi_state = 0;
            irq_state[0] = 0;
            irq_state[1] = 0;
            ic_eddge = 0;
            port1_ddr = 0x00;
            port2_ddr = 0x00;
            tcsr = 0x00;
            pending_tcsr = 0x00;
            irq2 = 0;
            counter.d = 0x0000;
            output_compare.d = 0xffff;
            timer_over.d = 0xffff;
            ram_ctrl |= 0x40;
            trcsr = M6800_TRCSR_TDRE;
            rmcr = 0;
            Timer.timer_enable(m6800_rx_timer, false);
            Timer.timer_enable(m6800_tx_timer, false);
            txstate = M6800_TX_STATE.INIT;
            txbits = rxbits = 0;
            trcsr_read = 0;
        }
        public override void set_irq_line(int irqline, LineState state)
        {
            if (irqline == INPUT_LINE_NMI)
            {
                if (nmi_state == (byte)state)
                {
                    return;
                }
                nmi_state = (byte)state;
                if (state == LineState.CLEAR_LINE)
                {
                    return;
                }
                ENTER_INTERRUPT(0xfffc);
            }
            else
            {
                int eddge;
                if (irq_state[irqline] == (byte)state)
                {
                    return;
                }
                irq_state[irqline] = (byte)state;
                switch (irqline)
                {
                    case M6800_IRQ_LINE:
                        if (state == LineState.CLEAR_LINE)
                        {
                            return;
                        }
                        break;
                    case M6800_TIN_LINE:
                        eddge = (state == LineState.CLEAR_LINE) ? 2 : 0;
                        if (((tcsr & TCSR_IEDG) ^ (state == LineState.CLEAR_LINE ? TCSR_IEDG : 0)) == 0)
                        {
                            return;
                        }
                        /* active edge in */
                        tcsr |= TCSR_ICF;
                        pending_tcsr |= TCSR_ICF;
                        input_capture = counter.LowWord;
                        MODIFIED_tcsr();
                        if ((cc & 0x10) == 0)
                        {
                            m6800_check_irq2();
                        }
                        break;
                    default:
                        return;
                }
                CHECK_IRQ_LINES(); /* HJB 990417 */
            }
        }
        public override void cpunum_set_input_line_and_vector(int cpunum, int line, LineState state, int vector)
        {
            Timer.timer_set_internal(Cpuint.cpunum_empty_event_queue, "cpunum_empty_event_queue");
        }
        public override int ExecuteCycles(int cycles)
        {
            byte ireg;
            pendingCycles = cycles;
            CLEANUP_conters();
            INCREMENT_COUNTER(extra_cycles);
            extra_cycles = 0;
            do
            {
                int prevCycles = pendingCycles;
                if ((wai_state & (M6800_WAI | M6800_SLP))!=0)
                {
                    EAT_CYCLES();
                }
                else
                {
                    PPC = PC;
                    //debugger_instruction_hook(Machine, PCD);                    
                    ireg = ReadOp(PC.LowWord);
                    PC.LowWord++;
                    insn[ireg]();                    
                    INCREMENT_COUNTER(this.cycles[ireg]);
                    int delta = prevCycles - pendingCycles;
                    totalExecutedCycles += (ulong)delta;
                }
            } while (pendingCycles > 0);
            INCREMENT_COUNTER(extra_cycles);
            extra_cycles = 0;
            return cycles - pendingCycles;
        }
        public byte hd63701_internal_registers_r(int offset)
        {
            return m6803_internal_registers_r(offset);
        }
        public void hd63701_internal_registers_w(int offset, byte data)
        {
            m6803_internal_registers_w(offset, data);
        }
        private byte m6803_internal_registers_r(int offset)
        {
            switch (offset)
            {
                case 0x00:
                    return port1_ddr;
                case 0x01:
                    return port2_ddr;
                case 0x02:
                    return (byte)((ReadIO(0x100) & (port1_ddr ^ 0xff)) | (port1_data & port1_ddr));
                case 0x03:
                    return (byte)((ReadIO(0x101) & (port2_ddr ^ 0xff)) | (port2_data & port2_ddr));
                case 0x04:
                    return port3_ddr;
                case 0x05:
                    return port4_ddr;
                case 0x06:
                    return (byte)((ReadIO(0x102) & (port3_ddr ^ 0xff)) | (port3_data & port3_ddr));
                case 0x07:
                    return (byte)((ReadIO(0x103) & (port4_ddr ^ 0xff)) | (port4_data & port4_ddr));
                case 0x08:
                    pending_tcsr = 0;
                    return tcsr;
                case 0x09:
                    if ((pending_tcsr & TCSR_TOF) == 0)
                    {
                        tcsr &= (byte)(~TCSR_TOF);
                        MODIFIED_tcsr();
                    }
                    return counter.HighByte;
                case 0x0a:
                    return counter.LowByte;
                case 0x0b:
                    if ((pending_tcsr & TCSR_OCF) == 0)
                    {
                        tcsr &= (byte)(~TCSR_OCF);
                        MODIFIED_tcsr();
                    }
                    return output_compare.HighByte;
                case 0x0c:
                    if ((pending_tcsr & TCSR_OCF) == 0)
                    {
                        tcsr &= (byte)(~TCSR_OCF);
                        MODIFIED_tcsr();
                    }
                    return output_compare.LowByte;
                case 0x0d:
                    if ((pending_tcsr & TCSR_ICF) == 0)
                    {
                        tcsr &= (byte)(~TCSR_ICF);
                        MODIFIED_tcsr();
                    }
                    return (byte)((input_capture >> 0) & 0xff);
                case 0x0e:
                    return (byte)((input_capture >> 8) & 0xff);
                case 0x0f:
                    //logerror("CPU #%d PC %04x: warning - read from unsupported register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),offset);
                    return 0;
                case 0x10:
                    return rmcr;
                case 0x11:
                    trcsr_read = 1;
                    return trcsr;
                case 0x12:
                    if (trcsr_read != 0)
                    {
                        trcsr_read = 0;
                        trcsr = (byte)(trcsr & 0x3f);
                    }
                    return rdr;
                case 0x13:
                    return tdr;
                case 0x14:
                    //logerror("CPU #%d PC %04x: read RAM control register\n",cpu_getactivecpu(),activecpu_get_pc());
                    return ram_ctrl;
                case 0x15:
                case 0x16:
                case 0x17:
                case 0x18:
                case 0x19:
                case 0x1a:
                case 0x1b:
                case 0x1c:
                case 0x1d:
                case 0x1e:
                case 0x1f:
                default:
                    //logerror("CPU #%d PC %04x: warning - read from reserved internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),offset);
                    return 0;
            }
        }
        private void m6803_internal_registers_w(int offset, byte data)
        {
            int latch09=0;
            switch (offset)
            {
                case 0x00:
                    if (port1_ddr != data)
                    {
                        port1_ddr = data;
                        if (port1_ddr == 0xff)
                            WriteIO(0x100, port1_data);
                        else
                            WriteIO(0x100, (byte)((port1_data & port1_ddr) | (ReadIO(0x100) & (port1_ddr ^ 0xff))));
                    }
                    break;
                case 0x01:
                    if (port2_ddr != data)
                    {
                        port2_ddr = data;
                        if (port2_ddr == 0xff)
                            WriteIO(0x101, port2_data);
                        else
                            WriteIO(0x101, (byte)((port2_data & port2_ddr) | (ReadIO(0x101) & (port2_ddr ^ 0xff))));

                        if ((port2_ddr & 2) != 0)
                        {
                            //logerror("CPU #%d PC %04x: warning - port 2 bit 1 set as output (OLVL) - not supported\n", cpu_getactivecpu(), activecpu_get_pc());
                        }
                    }
                    break;
                case 0x02:
                    port1_data = data;
                    if (port1_ddr == 0xff)
                        WriteIO(0x100, port1_data);
                    else
                        WriteIO(0x100, (byte)((port1_data & port1_ddr) | (ReadIO(0x100) & (port1_ddr ^ 0xff))));
                    break;
                case 0x03:
                    if ((trcsr & M6800_TRCSR_TE) != 0)
                    {
                        port2_data = (byte)((data & 0xef) | (tx << 4));
                    }
                    else
                    {
                        port2_data = data;
                    }
                    if (port2_ddr == 0xff)
                        WriteIO(0x101, port2_data);
                    else
                        WriteIO(0x101, (byte)((port2_data & port2_ddr) | (ReadIO(0x101) & (port2_ddr ^ 0xff))));
                    break;
                case 0x04:
                    if (port3_ddr != data)
                    {
                        port3_ddr = data;
                        if (port3_ddr == 0xff)
                            WriteIO(0x102, port3_data);
                        else
                            WriteIO(0x102, (byte)((port3_data & port3_ddr) | (ReadIO(0x102) & (port3_ddr ^ 0xff))));
                    }
                    break;
                case 0x05:
                    if (port4_ddr != data)
                    {
                        port4_ddr = data;
                        if (port4_ddr == 0xff)
                            WriteIO(0x103, port4_data);
                        else
                            WriteIO(0x103, (byte)((port4_data & port4_ddr) | (ReadIO(0x103) & (port4_ddr ^ 0xff))));
                    }
                    break;
                case 0x06:
                    port3_data = data;
                    if (port3_ddr == 0xff)
                        WriteIO(0x102, port3_data);
                    else
                        WriteIO(0x102, (byte)((port3_data & port3_ddr) | (ReadIO(0x102) & (port3_ddr ^ 0xff))));
                    break;
                case 0x07:
                    port4_data = data;
                    if (port4_ddr == 0xff)
                        WriteIO(0x103, port4_data);
                    else
                        WriteIO(0x103, (byte)((port4_data & port4_ddr) | (ReadIO(0x103) & (port4_ddr ^ 0xff))));
                    break;
                case 0x08:
                    tcsr = data;
                    pending_tcsr &= tcsr;
                    MODIFIED_tcsr();
                    if ((cc & 0x10) == 0)
                        m6800_check_irq2();
                    break;
                case 0x09:
                    latch09 = data & 0xff;	/* 6301 only */
                    counter.LowWord = 0xfff8;
                    timer_over.LowWord = counter.HighWord;
                    MODIFIED_counters();
                    break;
                case 0x0a:	/* 6301 only */
                    counter.LowWord = (ushort)((latch09 << 8) | (data & 0xff));
                    timer_over.LowWord = counter.HighWord;
                    MODIFIED_counters();
                    break;
                case 0x0b:
                    if (output_compare.HighByte != data)
                    {
                        output_compare.HighByte = data;
                        MODIFIED_counters();
                    }
                    break;
                case 0x0c:
                    if (output_compare.LowByte != data)
                    {
                        output_compare.LowByte = data;
                        MODIFIED_counters();
                    }
                    break;
                case 0x0d:
                case 0x0e:
                case 0x12:
                    //logerror("CPU #%d PC %04x: warning - write %02x to read only internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),data,offset);
                    break;
                case 0x0f:
                    //logerror("CPU #%d PC %04x: warning - write %02x to unsupported internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),data,offset);
                    break;
                case 0x10:
                    rmcr = (byte)(data & 0x0f);
                    switch ((rmcr & M6800_RMCR_CC_MASK) >> 2)
                    {
                        case 0:
                        case 3: // not implemented
                            Timer.timer_enable(m6800_rx_timer, false);
                            Timer.timer_enable(m6800_tx_timer, false);
                            break;

                        case 1:
                        case 2:
                            {
                                int divisor = M6800_RMCR_SS[rmcr & M6800_RMCR_SS_MASK];
                                Timer.timer_adjust_periodic(m6800_rx_timer, Attotime.ATTOTIME_ZERO, new Atime(0, (long)(1e18 / (clock / divisor))));
                                Timer.timer_adjust_periodic(m6800_tx_timer, Attotime.ATTOTIME_ZERO, new Atime(0, (long)(1e18 / (clock / divisor))));
                            }
                            break;
                    }
                    break;
                case 0x11:
                    if ((data & M6800_TRCSR_TE) != 0 && (trcsr & M6800_TRCSR_TE) == 0)
                    {
                        txstate = 0;
                    }
                    trcsr = (byte)((trcsr & 0xe0) | (data & 0x1f));
                    break;
                case 0x13:
                    if (trcsr_read != 0)
                    {
                        trcsr_read = (int)M6800_TX_STATE.INIT;
                        trcsr &= (byte)(~M6800_TRCSR_TDRE);
                    }
                    tdr = data;
                    break;
                case 0x14:
                    //logerror("CPU #%d PC %04x: write %02x to RAM control register\n",cpu_getactivecpu(),activecpu_get_pc(),data);
                    ram_ctrl = data;
                    break;
                case 0x15:
                case 0x16:
                case 0x17:
                case 0x18:
                case 0x19:
                case 0x1a:
                case 0x1b:
                case 0x1c:
                case 0x1d:
                case 0x1e:
                case 0x1f:
                default:
                    //logerror("CPU #%d PC %04x: warning - write %02x to reserved internal register %02x\n",cpu_getactivecpu(),activecpu_get_pc(),data,offset);
                    break;
            }
        }
        public void SaveStateBinary(BinaryWriter writer)
        {
            writer.Write(PPC.LowWord);
            writer.Write(PC.LowWord);
            writer.Write(S.LowWord);
            writer.Write(X.LowWord);
            writer.Write(D.LowWord);
            writer.Write(cc);
            writer.Write(wai_state);
            writer.Write(nmi_state);
            writer.Write(irq_state[0]);
            writer.Write(irq_state[1]);
            writer.Write(ic_eddge);
            writer.Write(port1_ddr);
            writer.Write(port2_ddr);
            writer.Write(port3_ddr);
            writer.Write(port4_ddr);
            writer.Write(port1_data);
            writer.Write(port2_data);
            writer.Write(port3_data);
            writer.Write(port4_data);
            writer.Write(tcsr);
            writer.Write(pending_tcsr);
            writer.Write(irq2);
            writer.Write(ram_ctrl);
            writer.Write(counter.d);
            writer.Write(output_compare.d);
            writer.Write(input_capture);
            writer.Write(timer_over.d);
            writer.Write(clock);
            writer.Write(trcsr);
            writer.Write(rmcr);
            writer.Write(rdr);
            writer.Write(tdr);
            writer.Write(rsr);
            writer.Write(tsr);
            writer.Write(rxbits);
            writer.Write(txbits);
            writer.Write((int)txstate);
            writer.Write(trcsr_read);
            writer.Write(tx);
            writer.Write(TotalExecutedCycles);
            writer.Write(PendingCycles);
        }
        public void LoadStateBinary(BinaryReader reader)
        {
            PPC.LowWord = reader.ReadUInt16();
            PC.LowWord = reader.ReadUInt16();
            S.LowWord = reader.ReadUInt16();
            X.LowWord = reader.ReadUInt16();
            D.LowWord = reader.ReadUInt16();
            cc = reader.ReadByte();
            wai_state = reader.ReadByte();
            nmi_state = reader.ReadByte();
            irq_state[0] = reader.ReadByte();
            irq_state[1] = reader.ReadByte();
            ic_eddge = reader.ReadByte();
            port1_ddr = reader.ReadByte();
            port2_ddr = reader.ReadByte();
            port3_ddr = reader.ReadByte();
            port4_ddr = reader.ReadByte();
            port1_data = reader.ReadByte();
            port2_data = reader.ReadByte();
            port3_data = reader.ReadByte();
            port4_data = reader.ReadByte();
            tcsr = reader.ReadByte();
            pending_tcsr = reader.ReadByte();
            irq2 = reader.ReadByte();
            ram_ctrl = reader.ReadByte();
            counter.d = reader.ReadUInt32();
            output_compare.d = reader.ReadUInt32();
            input_capture = reader.ReadUInt16();
            timer_over.d = reader.ReadUInt32();
            clock = reader.ReadInt32();
            trcsr = reader.ReadByte();
            rmcr = reader.ReadByte();
            rdr = reader.ReadByte();
            tdr = reader.ReadByte();
            rsr = reader.ReadByte();
            tsr = reader.ReadByte();
            rxbits = reader.ReadInt32();
            txbits = reader.ReadInt32();
            txstate = (M6800.M6800_TX_STATE)reader.ReadInt32();
            trcsr_read = reader.ReadInt32();
            tx = reader.ReadInt32();
            TotalExecutedCycles = reader.ReadUInt64();
            PendingCycles = reader.ReadInt32();
        }
    }
    public class M6801 : M6800
    {
        public M6801()
        {
            m6803_insn = new Action[256]{
                illegal,nop,    illegal,illegal,lsrd,   asld,   tap,    tpa,
                inx,    dex,    CLV,    SEV,    CLC,    SEC,    cli,    sei,
                sba,    cba,    illegal,illegal,illegal,illegal,tab,    tba,
                illegal,daa,    illegal,aba,    illegal,illegal,illegal,illegal,
                bra,    brn,    bhi,    bls,    bcc,    bcs,    bne,    beq,
                bvc,    bvs,    bpl,    bmi,    bge,    blt,    bgt,    ble,
                tsx,    ins,    pula,   pulb,   des,    txs,    psha,   pshb,
                pulx,   rts,    abx,    rti,    pshx,   mul,    wai,    swi,
                nega,   illegal,illegal,coma,   lsra,   illegal,rora,   asra,
                asla,   rola,   deca,   illegal,inca,   tsta,   illegal,clra,
                negb,   illegal,illegal,comb,   lsrb,   illegal,rorb,   asrb,
                aslb,   rolb,   decb,   illegal,incb,   tstb,   illegal,clrb,
                neg_ix, illegal,illegal,com_ix, lsr_ix, illegal,ror_ix, asr_ix,
                asl_ix, rol_ix, dec_ix, illegal,inc_ix, tst_ix, jmp_ix, clr_ix,
                neg_ex, illegal,illegal,com_ex, lsr_ex, illegal,ror_ex, asr_ex,
                asl_ex, rol_ex, dec_ex, illegal,inc_ex, tst_ex, jmp_ex, clr_ex,
                suba_im,cmpa_im,sbca_im,subd_im,anda_im,bita_im,lda_im, sta_im,
                eora_im,adca_im,ora_im, adda_im,cpx_im, bsr,    lds_im, sts_im,
                suba_di,cmpa_di,sbca_di,subd_di,anda_di,bita_di,lda_di, sta_di,
                eora_di,adca_di,ora_di, adda_di,cpx_di, jsr_di, lds_di, sts_di,
                suba_ix,cmpa_ix,sbca_ix,subd_ix,anda_ix,bita_ix,lda_ix, sta_ix,
                eora_ix,adca_ix,ora_ix, adda_ix,cpx_ix, jsr_ix, lds_ix, sts_ix,
                suba_ex,cmpa_ex,sbca_ex,subd_ex,anda_ex,bita_ex,lda_ex, sta_ex,
                eora_ex,adca_ex,ora_ex, adda_ex,cpx_ex, jsr_ex, lds_ex, sts_ex,
                subb_im,cmpb_im,sbcb_im,addd_im,andb_im,bitb_im,ldb_im, stb_im,
                eorb_im,adcb_im,orb_im, addb_im,ldd_im, std_im, ldx_im, stx_im,
                subb_di,cmpb_di,sbcb_di,addd_di,andb_di,bitb_di,ldb_di, stb_di,
                eorb_di,adcb_di,orb_di, addb_di,ldd_di, std_di, ldx_di, stx_di,
                subb_ix,cmpb_ix,sbcb_ix,addd_ix,andb_ix,bitb_ix,ldb_ix, stb_ix,
                eorb_ix,adcb_ix,orb_ix, addb_ix,ldd_ix, std_ix, ldx_ix, stx_ix,
                subb_ex,cmpb_ex,sbcb_ex,addd_ex,andb_ex,bitb_ex,ldb_ex, stb_ex,
                eorb_ex,adcb_ex,orb_ex, addb_ex,ldd_ex, std_ex, ldx_ex, stx_ex
            };
            clock = 1000000;
            irq_callback = Cpuint.cpu_3_irq_callback;
            m6800_rx_timer = Timer.timer_alloc_common(m6800_rx_tick, "m6800_rx_tick", false);
            m6800_tx_timer = Timer.timer_alloc_common(m6800_tx_tick, "m6800_tx_tick", false);
        }
        public override int ExecuteCycles(int cycles)
        {
            return m6801_execute(cycles);
        }
        public int m6801_execute(int cycles)
        {
            byte ireg;
            pendingCycles = cycles;
            CLEANUP_conters();
            INCREMENT_COUNTER(extra_cycles);
            extra_cycles = 0;
            do
            {
                int prevCycles = pendingCycles;
                if ((wai_state & M6800_WAI) != 0)
                {
                    EAT_CYCLES();
                }
                else
                {
                    PPC = PC;
                    //debugger_instruction_hook(Machine, PCD);
                    ireg = ReadOp(PC.LowWord);
                    PC.LowWord++;
                    m6803_insn[ireg]();
                    INCREMENT_COUNTER(cycles_6803[ireg]);
                    int delta = prevCycles - pendingCycles;
                    totalExecutedCycles += (ulong)delta;
                }
            } while (pendingCycles > 0);
            INCREMENT_COUNTER(extra_cycles);
            extra_cycles = 0;
            return cycles - pendingCycles;
        }        
    }
}
