summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/m6800/m6800.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/m6800/m6800.c')
-rw-r--r--trunk/src/emu/cpu/m6800/m6800.c2130
1 files changed, 2130 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/m6800/m6800.c b/trunk/src/emu/cpu/m6800/m6800.c
new file mode 100644
index 00000000000..747c2f6850a
--- /dev/null
+++ b/trunk/src/emu/cpu/m6800/m6800.c
@@ -0,0 +1,2130 @@
+/*** m6800: Portable 6800 class emulator *************************************
+
+ m68xx.c
+
+ References:
+
+ 6809 Simulator V09, By L.C. Benschop, Eidnhoven The Netherlands.
+
+ m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from
+ the 6809 Simulator V09)
+
+ 6809 Microcomputer Programming & Interfacing with Experiments"
+ by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc.
+
+ System dependencies: UINT16 must be 16 bit unsigned int
+ UINT8 must be 8 bit unsigned int
+ UINT32 must be more than 16 bits
+ arrays up to 65536 bytes must be supported
+ machine must be twos complement
+
+History
+991031 ZV
+ Added NSC-8105 support
+
+990319 HJB
+ Fixed wrong LSB/MSB order for push/pull word.
+ Subtract .extra_cycles at the beginning/end of the exectuion loops.
+
+990316 HJB
+ Renamed to 6800, since that's the basic CPU.
+ Added different cycle count tables for M6800/2/8, M6801/3 and m68xx.
+
+990314 HJB
+ Also added the M6800 subtype.
+
+990311 HJB
+ Added _info functions. Now uses static m6808_Regs struct instead
+ of single statics. Changed the 16 bit registers to use the generic
+ PAIR union. Registers defined using macros. Split the core into
+ four execution loops for M6802, M6803, M6808 and HD63701.
+ TST, TSTA and TSTB opcodes reset carry flag.
+TODO:
+ Verify invalid opcodes for the different CPU types.
+ Add proper credits to _info functions.
+ Integrate m6808_Flags into the registers (multiple m6808 type CPUs?)
+
+990301 HJB
+ Modified the interrupt handling. No more pending interrupt checks.
+ WAI opcode saves state, when an interrupt is taken (IRQ or OCI),
+ the state is only saved if not already done by WAI.
+
+*****************************************************************************/
+
+/*
+
+ Chip RAM NVRAM ROM SCI r15-f ports
+ -----------------------------------------------------------------
+ MC6800 - - - no no 4
+ MC6802 128 32 - no no 4
+ MC6802NS 128 - - no no 4
+ MC6808 - - - no no 4
+
+ MC6801 128 64 2K yes no 4
+ MC68701 128 64 - yes no 4
+ MC6803 128 64 - yes no 4
+
+ MC6801U4 192 32 4K yes yes 4
+ MC6803U4 192 32 - yes yes 4
+
+ HD6801 128 64 2K yes no 4
+ HD6301V 128 - 4K yes no 4
+ HD63701V 192 - 4K yes no 4
+ HD6303R 128 - - yes no 4
+
+ HD6301X 192 - 4K yes yes 6
+ HD6301Y 256 - 16K yes yes 6
+ HD6303X 192 - - yes yes 6
+ HD6303Y 256 - - yes yes 6
+
+ NSC8105
+ MS2010-A
+
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "m6800.h"
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#if 0
+/* CPU subtypes, needed for extra insn after TAP/CLI/SEI */
+enum
+{
+ SUBTYPE_M6800,
+ SUBTYPE_M6801,
+ SUBTYPE_M6802,
+ SUBTYPE_M6803,
+ SUBTYPE_M6808,
+ SUBTYPE_HD6301,
+ SUBTYPE_HD63701,
+ SUBTYPE_NSC8105
+};
+#endif
+
+/* 6800 Registers */
+typedef struct _m6800_state m6800_state;
+struct _m6800_state
+{
+// int subtype; /* CPU subtype */
+ PAIR ppc; /* Previous program counter */
+ PAIR pc; /* Program counter */
+ PAIR s; /* Stack pointer */
+ PAIR x; /* Index register */
+ PAIR d; /* Accumulators */
+ UINT8 cc; /* Condition codes */
+ UINT8 wai_state; /* WAI opcode state ,(or sleep opcode state) */
+ UINT8 nmi_state; /* NMI line state */
+ UINT8 nmi_pending; /* NMI pending */
+ UINT8 irq_state[3]; /* IRQ line state [IRQ1,TIN,SC1] */
+ UINT8 ic_eddge; /* InputCapture eddge , b.0=fall,b.1=raise */
+ int sc1_state;
+
+ device_irq_acknowledge_callback irq_callback;
+ legacy_cpu_device *device;
+
+ /* Memory spaces */
+ address_space *program;
+ direct_read_data *direct;
+ address_space *data;
+ address_space *io;
+
+ void (* const * insn)(m6800_state *); /* instruction table */
+ const UINT8 *cycles; /* clock cycle of instruction table */
+ /* internal registers */
+ UINT8 port1_ddr;
+ UINT8 port2_ddr;
+ UINT8 port3_ddr;
+ UINT8 port4_ddr;
+ UINT8 port1_data;
+ UINT8 port2_data;
+ UINT8 port3_data;
+ UINT8 port4_data;
+ UINT8 p3csr; // Port 3 Control/Status Register
+ UINT8 tcsr; /* Timer Control and Status Register */
+ UINT8 pending_tcsr; /* pending IRQ flag for clear IRQflag process */
+ UINT8 irq2; /* IRQ2 flags */
+ UINT8 ram_ctrl;
+ PAIR counter; /* free running counter */
+ PAIR output_compare; /* output compare */
+ UINT16 input_capture; /* input capture */
+ int p3csr_is3_flag_read;
+ int port3_latched;
+
+ int clock;
+ UINT8 trcsr, rmcr, rdr, tdr, rsr, tsr;
+ int rxbits, txbits, txstate, trcsr_read_tdre, trcsr_read_orfe, trcsr_read_rdrf, tx;
+ int port2_written;
+
+ int icount;
+ int latch09;
+
+ PAIR timer_over;
+ emu_timer *sci_timer;
+ PAIR ea; /* effective address */
+
+ devcb_resolved_write_line out_sc2_func;
+};
+
+INLINE m6800_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == M6800 ||
+ device->type() == M6801 ||
+ device->type() == M6802 ||
+ device->type() == M6803 ||
+ device->type() == M6808 ||
+ device->type() == HD6301 ||
+ device->type() == HD63701 ||
+ device->type() == NSC8105);
+ return (m6800_state *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+#if 0
+static void hd63701_trap_pc(m6800_state *cpustate);
+#endif
+
+#define pPPC cpustate->ppc
+#define pPC cpustate->pc
+#define pS cpustate->s
+#define pX cpustate->x
+#define pD cpustate->d
+
+#define PC cpustate->pc.w.l
+#define PCD cpustate->pc.d
+#define S cpustate->s.w.l
+#define SD cpustate->s.d
+#define X cpustate->x.w.l
+#define D cpustate->d.w.l
+#define A cpustate->d.b.h
+#define B cpustate->d.b.l
+#define CC cpustate->cc
+
+#define CT cpustate->counter.w.l
+#define CTH cpustate->counter.w.h
+#define CTD cpustate->counter.d
+#define OC cpustate->output_compare.w.l
+#define OCH cpustate->output_compare.w.h
+#define OCD cpustate->output_compare.d
+#define TOH cpustate->timer_over.w.l
+#define TOD cpustate->timer_over.d
+
+#define EAD cpustate->ea.d
+#define EA cpustate->ea.w.l
+
+/* point of next timer event */
+static UINT32 timer_next;
+
+/* memory interface */
+
+/****************************************************************************/
+/* Read a byte from given memory location */
+/****************************************************************************/
+#define RM(Addr) ((unsigned)cpustate->program->read_byte(Addr))
+
+/****************************************************************************/
+/* Write a byte to given memory location */
+/****************************************************************************/
+#define WM(Addr,Value) (cpustate->program->write_byte(Addr,Value))
+
+/****************************************************************************/
+/* M6800_RDOP() is identical to M6800_RDMEM() except it is used for reading */
+/* opcodes. In case of system with memory mapped I/O, this function can be */
+/* used to greatly speed up emulation */
+/****************************************************************************/
+#define M_RDOP(Addr) ((unsigned)cpustate->direct->read_decrypted_byte(Addr))
+
+/****************************************************************************/
+/* M6800_RDOP_ARG() is identical to M6800_RDOP() but it's used for reading */
+/* opcode arguments. This difference can be used to support systems that */
+/* use different encoding mechanisms for opcodes and opcode arguments */
+/****************************************************************************/
+#define M_RDOP_ARG(Addr) ((unsigned)cpustate->direct->read_raw_byte(Addr))
+
+/* macros to access memory */
+#define IMMBYTE(b) b = M_RDOP_ARG(PCD); PC++
+#define IMMWORD(w) w.d = (M_RDOP_ARG(PCD)<<8) | M_RDOP_ARG((PCD+1)&0xffff); PC+=2
+
+#define PUSHBYTE(b) WM(SD,b); --S
+#define PUSHWORD(w) WM(SD,w.b.l); --S; WM(SD,w.b.h); --S
+#define PULLBYTE(b) S++; b = RM(SD)
+#define PULLWORD(w) S++; w.d = RM(SD)<<8; S++; w.d |= RM(SD)
+
+#define MODIFIED_tcsr { \
+ cpustate->irq2 = (cpustate->tcsr&(cpustate->tcsr<<3))&(TCSR_ICF|TCSR_OCF|TCSR_TOF); \
+}
+
+#define SET_TIMER_EVENT { \
+ timer_next = (OCD - CTD < TOD - CTD) ? OCD : TOD; \
+}
+
+/* cleanup high-word of counters */
+#define CLEANUP_COUNTERS() { \
+ OCH -= CTH; \
+ TOH -= CTH; \
+ CTH = 0; \
+ SET_TIMER_EVENT; \
+}
+
+/* when change freerunningcounter or outputcapture */
+#define MODIFIED_counters { \
+ OCH = (OC >= CT) ? CTH : CTH+1; \
+ SET_TIMER_EVENT; \
+}
+
+// I/O registers
+
+enum
+{
+ IO_P1DDR = 0,
+ IO_P2DDR,
+ IO_P1DATA,
+ IO_P2DATA,
+ IO_P3DDR,
+ IO_P4DDR,
+ IO_P3DATA,
+ IO_P4DATA,
+ IO_TCSR,
+ IO_CH,
+ IO_CL,
+ IO_OCRH,
+ IO_OCRL,
+ IO_ICRH,
+ IO_ICRL,
+ IO_P3CSR,
+ IO_RMCR,
+ IO_TRCSR,
+ IO_RDR,
+ IO_TDR,
+ IO_RCR,
+ IO_CAAH,
+ IO_CAAL,
+ IO_TCR1,
+ IO_TCR2,
+ IO_TSR,
+ IO_OCR2H,
+ IO_OCR2L,
+ IO_OCR3H,
+ IO_OCR3L,
+ IO_ICR2H,
+ IO_ICR2L
+};
+
+// serial I/O
+
+#define M6800_RMCR_SS_MASK 0x03 // Speed Select
+#define M6800_RMCR_SS_4096 0x03 // E / 4096
+#define M6800_RMCR_SS_1024 0x02 // E / 1024
+#define M6800_RMCR_SS_128 0x01 // E / 128
+#define M6800_RMCR_SS_16 0x00 // E / 16
+#define M6800_RMCR_CC_MASK 0x0c // Clock Control/Format Select
+
+#define M6800_TRCSR_RDRF 0x80 // Receive Data Register Full
+#define M6800_TRCSR_ORFE 0x40 // Over Run Framing Error
+#define M6800_TRCSR_TDRE 0x20 // Transmit Data Register Empty
+#define M6800_TRCSR_RIE 0x10 // Receive Interrupt Enable
+#define M6800_TRCSR_RE 0x08 // Receive Enable
+#define M6800_TRCSR_TIE 0x04 // Transmit Interrupt Enable
+#define M6800_TRCSR_TE 0x02 // Transmit Enable
+#define M6800_TRCSR_WU 0x01 // Wake Up
+
+#define M6800_PORT2_IO4 0x10
+#define M6800_PORT2_IO3 0x08
+
+#define M6801_P3CSR_LE 0x08
+#define M6801_P3CSR_OSS 0x10
+#define M6801_P3CSR_IS3_ENABLE 0x40
+#define M6801_P3CSR_IS3_FLAG 0x80
+
+static const int M6800_RMCR_SS[] = { 16, 128, 1024, 4096 };
+
+#define M6800_SERIAL_START 0
+#define M6800_SERIAL_STOP 9
+
+enum
+{
+ M6800_TX_STATE_INIT = 0,
+ M6800_TX_STATE_READY
+};
+
+/* take interrupt */
+#define TAKE_ICI enter_interrupt(cpustate, "M6800 '%s' take ICI\n",0xfff6)
+#define TAKE_OCI enter_interrupt(cpustate, "M6800 '%s' take OCI\n",0xfff4)
+#define TAKE_TOI enter_interrupt(cpustate, "M6800 '%s' take TOI\n",0xfff2)
+#define TAKE_SCI enter_interrupt(cpustate, "M6800 '%s' take SCI\n",0xfff0)
+#define TAKE_TRAP enter_interrupt(cpustate, "M6800 '%s' take TRAP\n",0xffee)
+
+/* operate one instruction for */
+#define ONE_MORE_INSN() { \
+ UINT8 ireg; \
+ pPPC = pPC; \
+ debugger_instruction_hook(cpustate->device, PCD); \
+ ireg=M_RDOP(PCD); \
+ PC++; \
+ (*cpustate->insn[ireg])(cpustate); \
+ increment_counter(cpustate, cpustate->cycles[ireg]); \
+}
+
+/* CC masks HI NZVC
+ 7654 3210 */
+#define CLR_HNZVC CC&=0xd0
+#define CLR_NZV CC&=0xf1
+#define CLR_HNZC CC&=0xd2
+#define CLR_NZVC CC&=0xf0
+#define CLR_Z CC&=0xfb
+#define CLR_NZC CC&=0xf2
+#define CLR_ZC CC&=0xfa
+#define CLR_C CC&=0xfe
+
+/* macros for CC -- CC bits affected should be reset before calling */
+#define SET_Z(a) if(!(a))SEZ
+#define SET_Z8(a) SET_Z((UINT8)(a))
+#define SET_Z16(a) SET_Z((UINT16)(a))
+#define SET_N8(a) CC|=(((a)&0x80)>>4)
+#define SET_N16(a) CC|=(((a)&0x8000)>>12)
+#define SET_H(a,b,r) CC|=((((a)^(b)^(r))&0x10)<<1)
+#define SET_C8(a) CC|=(((a)&0x100)>>8)
+#define SET_C16(a) CC|=(((a)&0x10000)>>16)
+#define SET_V8(a,b,r) CC|=((((a)^(b)^(r)^((r)>>1))&0x80)>>6)
+#define SET_V16(a,b,r) CC|=((((a)^(b)^(r)^((r)>>1))&0x8000)>>14)
+
+static const UINT8 flags8i[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
+};
+static const UINT8 flags8d[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
+};
+#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];}
+#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];}
+
+/* combos */
+#define SET_NZ8(a) {SET_N8(a);SET_Z8(a);}
+#define SET_NZ16(a) {SET_N16(a);SET_Z16(a);}
+#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
+#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);}
+
+/* for treating an UINT8 as a signed INT16 */
+#define SIGNED(b) ((INT16)(b&0x80?b|0xff00:b))
+
+/* Macros for addressing modes */
+#define DIRECT IMMBYTE(EAD)
+#define IMM8 EA=PC++
+#define IMM16 {EA=PC;PC+=2;}
+#define EXTENDED IMMWORD(cpustate->ea)
+#define INDEXED {EA=X+(UINT8)M_RDOP_ARG(PCD);PC++;}
+
+/* macros to set status flags */
+#if defined(SEC)
+#undef SEC
+#endif
+#define SEC CC|=0x01
+#define CLC CC&=0xfe
+#define SEZ CC|=0x04
+#define CLZ CC&=0xfb
+#define SEN CC|=0x08
+#define CLN CC&=0xf7
+#define SEV CC|=0x02
+#define CLV CC&=0xfd
+#define SEH CC|=0x20
+#define CLH CC&=0xdf
+#define SEI CC|=0x10
+#define CLI CC&=~0x10
+
+/* mnemonicos for the Timer Control and Status Register bits */
+#define TCSR_OLVL 0x01
+#define TCSR_IEDG 0x02
+#define TCSR_ETOI 0x04
+#define TCSR_EOCI 0x08
+#define TCSR_EICI 0x10
+#define TCSR_TOF 0x20
+#define TCSR_OCF 0x40
+#define TCSR_ICF 0x80
+
+/* macros for convenience */
+#define DIRBYTE(b) {DIRECT;b=RM(EAD);}
+#define DIRWORD(w) {DIRECT;w.d=RM16(cpustate, EAD);}
+#define EXTBYTE(b) {EXTENDED;b=RM(EAD);}
+#define EXTWORD(w) {EXTENDED;w.d=RM16(cpustate, EAD);}
+
+#define IDXBYTE(b) {INDEXED;b=RM(EAD);}
+#define IDXWORD(w) {INDEXED;w.d=RM16(cpustate, EAD);}
+
+/* Macros for branch instructions */
+#define BRANCH(f) {IMMBYTE(t);if(f){PC+=SIGNED(t);}}
+#define NXORV ((CC&0x08)^((CC&0x02)<<2))
+
+#define M6800_WAI 8 /* set when WAI is waiting for an interrupt */
+#define M6800_SLP 0x10 /* HD63701 only */
+
+/* Note: don't use 0 cycles here for invalid opcodes so that we don't */
+/* hang in an infinite loop if we hit one */
+#define XX 5 // invalid opcode unknown cc
+static const UINT8 cycles_6800[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ XX, 2,XX,XX,XX,XX, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
+ /*1*/ 2, 2,XX,XX,XX,XX, 2, 2,XX, 2,XX, 2,XX,XX,XX,XX,
+ /*2*/ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /*3*/ 4, 4, 4, 4, 4, 4, 4, 4,XX, 5,XX,10,XX,XX, 9,12,
+ /*4*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2,
+ /*5*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2,
+ /*6*/ 7,XX,XX, 7, 7,XX, 7, 7, 7, 7, 7,XX, 7, 7, 4, 7,
+ /*7*/ 6,XX,XX, 6, 6,XX, 6, 6, 6, 6, 6,XX, 6, 6, 3, 6,
+ /*8*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2, 3, 8, 3, 4,
+ /*9*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3, 4, 6, 4, 5,
+ /*A*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7,
+ /*B*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6,
+ /*C*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2,XX,XX, 3, 4,
+ /*D*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3,XX,XX, 4, 5,
+ /*E*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5,XX,XX, 6, 7,
+ /*F*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4,XX,XX, 5, 6
+};
+
+static const UINT8 cycles_6803[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ XX, 2,XX,XX, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
+ /*1*/ 2, 2,XX,XX,XX,XX, 2, 2,XX, 2,XX, 2,XX,XX,XX,XX,
+ /*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,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2,
+ /*5*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2,
+ /*6*/ 6,XX,XX, 6, 6,XX, 6, 6, 6, 6, 6,XX, 6, 6, 3, 6,
+ /*7*/ 6,XX,XX, 6, 6,XX, 6, 6, 6, 6, 6,XX, 6, 6, 3, 6,
+ /*8*/ 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 4, 6, 3, 3,
+ /*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, 2, 2, 2, 2, 2, 3,XX, 3, 3,
+ /*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
+};
+
+static const UINT8 cycles_63701[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ XX, 1,XX,XX, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /*1*/ 1, 1,XX,XX,XX,XX, 1, 1, 2, 2, 4, 1,XX,XX,XX,XX,
+ /*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,XX,XX, 1, 1,XX, 1, 1, 1, 1, 1,XX, 1, 1,XX, 1,
+ /*5*/ 1,XX,XX, 1, 1,XX, 1, 1, 1, 1, 1,XX, 1, 1,XX, 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, 2, 2, 2, 2, 2, 3, 5, 3, 3,
+ /*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, 2, 2, 2, 2, 2, 3,XX, 3, 3,
+ /*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
+};
+
+static const UINT8 cycles_nsc8105[] =
+{
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ /*0*/ XX,XX, 2,XX,XX, 2,XX, 2, 4, 2, 4, 2, 2, 2, 2, 2,
+ /*1*/ 2,XX, 2,XX,XX, 2,XX, 2,XX,XX, 2, 2,XX,XX,XX,XX,
+ /*2*/ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /*3*/ 4, 4, 4, 4, 4, 4, 4, 4,XX,XX, 5,10,XX, 9,XX,12,
+ /*4*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 8, 4,
+ /*5*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3, 4, 4, 6, 5,
+ /*6*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5, 6, 6, 8, 7,
+ /*7*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4, 5, 5, 9, 6,
+ /*8*/ 2,XX,XX, 2, 2, 2,XX, 2, 2, 2, 2,XX, 2,XX, 2, 2,
+ /*9*/ 2,XX,XX, 2, 2, 2,XX, 2, 2, 2, 2,XX, 2,XX, 2, 2,
+ /*A*/ 7,XX,XX, 7, 7, 7,XX, 7, 7, 7, 7,XX, 7, 4, 7, 7,
+ /*B*/ 6,XX,XX, 6, 6, 6,XX, 6, 6, 6, 6,XX, 6, 3, 6, 6,
+ /*C*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2,XX, 3,XX, 4,
+ /*D*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3,XX, 4,XX, 5,
+ /*E*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6,XX, 7,
+ /*F*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5,XX, 6
+};
+#undef XX // /invalid opcode unknown cc
+
+#define EAT_CYCLES \
+{ \
+ int cycles_to_eat; \
+ \
+ cycles_to_eat = timer_next - CTD; \
+ if( cycles_to_eat > cpustate->icount) cycles_to_eat = cpustate->icount; \
+ if (cycles_to_eat > 0) \
+ { \
+ increment_counter(cpustate, cycles_to_eat); \
+ } \
+}
+
+INLINE UINT32 RM16(m6800_state *cpustate, UINT32 Addr )
+{
+ UINT32 result = RM(Addr) << 8;
+ return result | RM((Addr+1)&0xffff);
+}
+
+INLINE void WM16(m6800_state *cpustate, UINT32 Addr, PAIR *p )
+{
+ WM( Addr, p->b.h );
+ WM( (Addr+1)&0xffff, p->b.l );
+}
+
+/* IRQ enter */
+static void enter_interrupt(m6800_state *cpustate, const char *message,UINT16 irq_vector)
+{
+ LOG((message, cpustate->device->tag()));
+ if( cpustate->wai_state & (M6800_WAI|M6800_SLP) )
+ {
+ if( cpustate->wai_state & M6800_WAI )
+ cpustate->icount -= 4;
+ cpustate->wai_state &= ~(M6800_WAI|M6800_SLP);
+ }
+ else
+ {
+ PUSHWORD(pPC);
+ PUSHWORD(pX);
+ PUSHBYTE(A);
+ PUSHBYTE(B);
+ PUSHBYTE(CC);
+ cpustate->icount -= 12;
+ }
+ SEI;
+ PCD = RM16(cpustate, irq_vector );
+}
+
+
+
+static void m6800_check_irq2(m6800_state *cpustate)
+{
+ if ((cpustate->tcsr & (TCSR_EICI|TCSR_ICF)) == (TCSR_EICI|TCSR_ICF))
+ {
+ TAKE_ICI;
+ if( cpustate->irq_callback )
+ (void)(*cpustate->irq_callback)(cpustate->device, M6801_TIN_LINE);
+ }
+ else if ((cpustate->tcsr & (TCSR_EOCI|TCSR_OCF)) == (TCSR_EOCI|TCSR_OCF))
+ {
+ TAKE_OCI;
+ }
+ else if ((cpustate->tcsr & (TCSR_ETOI|TCSR_TOF)) == (TCSR_ETOI|TCSR_TOF))
+ {
+ TAKE_TOI;
+ }
+ else if (((cpustate->trcsr & (M6800_TRCSR_RIE|M6800_TRCSR_RDRF)) == (M6800_TRCSR_RIE|M6800_TRCSR_RDRF)) ||
+ ((cpustate->trcsr & (M6800_TRCSR_RIE|M6800_TRCSR_ORFE)) == (M6800_TRCSR_RIE|M6800_TRCSR_ORFE)) ||
+ ((cpustate->trcsr & (M6800_TRCSR_TIE|M6800_TRCSR_TDRE)) == (M6800_TRCSR_TIE|M6800_TRCSR_TDRE)))
+ {
+ //logerror("M6800 '%s' SCI interrupt\n", cpustate->device->tag());
+ TAKE_SCI;
+ }
+}
+
+
+/* check the IRQ lines for pending interrupts */
+INLINE void CHECK_IRQ_LINES(m6800_state *cpustate)
+{
+ // TODO: IS3 interrupt
+
+ if (cpustate->nmi_pending)
+ {
+ if(cpustate->wai_state & M6800_SLP)
+ cpustate->wai_state &= ~M6800_SLP;
+
+ cpustate->nmi_pending = FALSE;
+ enter_interrupt(cpustate, "M6800 '%s' take NMI\n",0xfffc);
+ }
+ else
+ {
+ if( cpustate->irq_state[M6800_IRQ_LINE] != CLEAR_LINE )
+ { /* standard IRQ */
+ if(cpustate->wai_state & M6800_SLP)
+ cpustate->wai_state &= ~M6800_SLP;
+
+ if( !(CC & 0x10) )
+ {
+ enter_interrupt(cpustate, "M6800 '%s' take IRQ1\n",0xfff8);
+ if( cpustate->irq_callback )
+ (void)(*cpustate->irq_callback)(cpustate->device, M6800_IRQ_LINE);
+ }
+ }
+ else
+ if( !(CC & 0x10) )
+ m6800_check_irq2(cpustate);
+ }
+}
+
+/* check OCI or TOI */
+static void check_timer_event(m6800_state *cpustate)
+{
+ /* OCI */
+ if( CTD >= OCD)
+ {
+ OCH++; // next IRQ point
+ cpustate->tcsr |= TCSR_OCF;
+ cpustate->pending_tcsr |= TCSR_OCF;
+ MODIFIED_tcsr;
+ if((cpustate->tcsr & TCSR_EOCI) && cpustate->wai_state & M6800_SLP)
+ cpustate->wai_state &= ~M6800_SLP;
+ if ( !(CC & 0x10) && (cpustate->tcsr & TCSR_EOCI))
+ TAKE_OCI;
+ }
+ /* TOI */
+ if( CTD >= TOD)
+ {
+ TOH++; // next IRQ point
+#if 0
+ CLEANUP_COUNTERS();
+#endif
+ cpustate->tcsr |= TCSR_TOF;
+ cpustate->pending_tcsr |= TCSR_TOF;
+ MODIFIED_tcsr;
+ if((cpustate->tcsr & TCSR_ETOI) && cpustate->wai_state & M6800_SLP)
+ cpustate->wai_state &= ~M6800_SLP;
+ if ( !(CC & 0x10) && (cpustate->tcsr & TCSR_ETOI))
+ TAKE_TOI;
+ }
+ /* set next event */
+ SET_TIMER_EVENT;
+}
+
+INLINE void increment_counter(m6800_state *cpustate, int amount)
+{
+ cpustate->icount -= amount;
+ CTD += amount;
+ if( CTD >= timer_next)
+ check_timer_event(cpustate);
+}
+
+INLINE void set_rmcr(m6800_state *cpustate, UINT8 data)
+{
+ if (cpustate->rmcr == data) return;
+
+ cpustate->rmcr = data;
+
+ switch ((cpustate->rmcr & M6800_RMCR_CC_MASK) >> 2)
+ {
+ case 0:
+ case 3: // not implemented
+ cpustate->sci_timer->enable(false);
+ break;
+
+ case 1:
+ case 2:
+ {
+ int divisor = M6800_RMCR_SS[cpustate->rmcr & M6800_RMCR_SS_MASK];
+
+ cpustate->sci_timer->adjust(attotime::from_hz(cpustate->clock / divisor), 0, attotime::from_hz(cpustate->clock / divisor));
+ }
+ break;
+ }
+}
+
+INLINE void write_port2(m6800_state *cpustate)
+{
+ if (!cpustate->port2_written) return;
+
+ UINT8 data = cpustate->port2_data;
+ UINT8 ddr = cpustate->port2_ddr & 0x1f;
+
+ if ((ddr != 0x1f) && ddr)
+ {
+ data = (cpustate->port2_data & ddr) | (ddr ^ 0xff);
+ }
+
+ if (cpustate->trcsr & M6800_TRCSR_TE)
+ {
+ data = (data & 0xef) | (cpustate->tx << 4);
+ }
+
+ data &= 0x1f;
+
+ cpustate->io->write_byte(M6801_PORT2, data);
+}
+
+/* include the opcode prototypes and function pointer tables */
+#include "6800tbl.c"
+
+/* include the opcode functions */
+#include "6800ops.c"
+
+static int m6800_rx(m6800_state *cpustate)
+{
+ return (cpustate->io->read_byte(M6801_PORT2) & M6800_PORT2_IO3) >> 3;
+}
+
+static void serial_transmit(m6800_state *cpustate)
+{
+ //logerror("M6800 '%s' Tx Tick\n", cpustate->device->tag());
+
+ if (cpustate->trcsr & M6800_TRCSR_TE)
+ {
+ // force Port 2 bit 4 as output
+ cpustate->port2_ddr |= M6800_PORT2_IO4;
+
+ switch (cpustate->txstate)
+ {
+ case M6800_TX_STATE_INIT:
+ cpustate->tx = 1;
+ cpustate->txbits++;
+
+ if (cpustate->txbits == 10)
+ {
+ cpustate->txstate = M6800_TX_STATE_READY;
+ cpustate->txbits = M6800_SERIAL_START;
+ }
+ break;
+
+ case M6800_TX_STATE_READY:
+ switch (cpustate->txbits)
+ {
+ case M6800_SERIAL_START:
+ if (cpustate->trcsr & M6800_TRCSR_TDRE)
+ {
+ // transmit buffer is empty, send consecutive '1's
+ cpustate->tx = 1;
+ }
+ else
+ {
+ // transmit buffer is full, send data
+
+ // load TDR to shift register
+ cpustate->tsr = cpustate->tdr;
+
+ // transmit buffer is empty, set TDRE flag
+ cpustate->trcsr |= M6800_TRCSR_TDRE;
+
+ // send start bit '0'
+ cpustate->tx = 0;
+
+ cpustate->txbits++;
+
+ //logerror("M6800 '%s' Transmit START Data %02x\n", cpustate->device->tag(), cpustate->tsr);
+ }
+ break;
+
+ case M6800_SERIAL_STOP:
+ // send stop bit '1'
+ cpustate->tx = 1;
+
+ CHECK_IRQ_LINES(cpustate);
+
+ cpustate->txbits = M6800_SERIAL_START;
+
+ //logerror("M6800 '%s' Transmit STOP\n", cpustate->device->tag());
+ break;
+
+ default:
+ // send data bit '0' or '1'
+ cpustate->tx = cpustate->tsr & 0x01;
+
+ // shift transmit register
+ cpustate->tsr >>= 1;
+
+ //logerror("M6800 '%s' Transmit Bit %u: %u\n", cpustate->device->tag(), cpustate->txbits, cpustate->tx);
+
+ cpustate->txbits++;
+ break;
+ }
+ break;
+ }
+
+ cpustate->port2_written = 1;
+ write_port2(cpustate);
+ }
+}
+
+static void serial_receive(m6800_state *cpustate)
+{
+ //logerror("M6800 '%s' Rx Tick TRCSR %02x bits %u check %02x\n", cpustate->device->tag(), cpustate->trcsr, cpustate->rxbits, cpustate->trcsr & M6800_TRCSR_RE);
+
+ if (cpustate->trcsr & M6800_TRCSR_RE)
+ {
+ if (cpustate->trcsr & M6800_TRCSR_WU)
+ {
+ // wait for 10 bits of '1'
+ if (m6800_rx(cpustate) == 1)
+ {
+ cpustate->rxbits++;
+
+ //logerror("M6800 '%s' Received WAKE UP bit %u\n", cpustate->device->tag(), cpustate->rxbits);
+
+ if (cpustate->rxbits == 10)
+ {
+ //logerror("M6800 '%s' Receiver Wake Up\n", cpustate->device->tag());
+
+ cpustate->trcsr &= ~M6800_TRCSR_WU;
+ cpustate->rxbits = M6800_SERIAL_START;
+ }
+ }
+ else
+ {
+ //logerror("M6800 '%s' Receiver Wake Up interrupted\n", cpustate->device->tag());
+
+ cpustate->rxbits = M6800_SERIAL_START;
+ }
+ }
+ else
+ {
+ // receive data
+ switch (cpustate->rxbits)
+ {
+ case M6800_SERIAL_START:
+ if (m6800_rx(cpustate) == 0)
+ {
+ // start bit found
+ cpustate->rxbits++;
+
+ //logerror("M6800 '%s' Received START bit\n", cpustate->device->tag());
+ }
+ break;
+
+ case M6800_SERIAL_STOP:
+ if (m6800_rx(cpustate) == 1)
+ {
+ //logerror("M6800 '%s' Received STOP bit\n", cpustate->device->tag());
+
+ if (cpustate->trcsr & M6800_TRCSR_RDRF)
+ {
+ // overrun error
+ cpustate->trcsr |= M6800_TRCSR_ORFE;
+
+ //logerror("M6800 '%s' Receive Overrun Error\n", cpustate->device->tag());
+
+ CHECK_IRQ_LINES(cpustate);
+ }
+ else
+ {
+ if (!(cpustate->trcsr & M6800_TRCSR_ORFE))
+ {
+ // transfer data into receive register
+ cpustate->rdr = cpustate->rsr;
+
+ //logerror("M6800 '%s' Receive Data Register: %02x\n", cpustate->device->tag(), cpustate->rdr);
+
+ // set RDRF flag
+ cpustate->trcsr |= M6800_TRCSR_RDRF;
+
+ CHECK_IRQ_LINES(cpustate);
+ }
+ }
+ }
+ else
+ {
+ // framing error
+ if (!(cpustate->trcsr & M6800_TRCSR_ORFE))
+ {
+ // transfer unframed data into receive register
+ cpustate->rdr = cpustate->rsr;
+ }
+
+ cpustate->trcsr |= M6800_TRCSR_ORFE;
+ cpustate->trcsr &= ~M6800_TRCSR_RDRF;
+
+ //logerror("M6800 '%s' Receive Framing Error\n", cpustate->device->tag());
+
+ CHECK_IRQ_LINES(cpustate);
+ }
+
+ cpustate->rxbits = M6800_SERIAL_START;
+ break;
+
+ default:
+ // shift receive register
+ cpustate->rsr >>= 1;
+
+ // receive bit into register
+ cpustate->rsr |= (m6800_rx(cpustate) << 7);
+
+ //logerror("M6800 '%s' Received DATA bit %u: %u\n", cpustate->device->tag(), cpustate->rxbits, BIT(cpustate->rsr, 7));
+
+ cpustate->rxbits++;
+ break;
+ }
+ }
+ }
+}
+
+static TIMER_CALLBACK( sci_tick )
+{
+ m6800_state *cpustate = (m6800_state *)ptr;
+
+ serial_transmit(cpustate);
+ serial_receive(cpustate);
+}
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+static void state_register(m6800_state *cpustate, const char *type)
+{
+ cpustate->device->save_item(NAME(cpustate->ppc.w.l));
+ cpustate->device->save_item(NAME(cpustate->pc.w.l));
+ cpustate->device->save_item(NAME(cpustate->s.w.l));
+ cpustate->device->save_item(NAME(cpustate->x.w.l));
+ cpustate->device->save_item(NAME(cpustate->d.w.l));
+ cpustate->device->save_item(NAME(cpustate->cc));
+ cpustate->device->save_item(NAME(cpustate->wai_state));
+ cpustate->device->save_item(NAME(cpustate->nmi_state));
+ cpustate->device->save_item(NAME(cpustate->nmi_pending));
+ cpustate->device->save_item(NAME(cpustate->irq_state));
+ cpustate->device->save_item(NAME(cpustate->ic_eddge));
+
+ cpustate->device->save_item(NAME(cpustate->port1_ddr));
+ cpustate->device->save_item(NAME(cpustate->port2_ddr));
+ cpustate->device->save_item(NAME(cpustate->port3_ddr));
+ cpustate->device->save_item(NAME(cpustate->port4_ddr));
+ cpustate->device->save_item(NAME(cpustate->port1_data));
+ cpustate->device->save_item(NAME(cpustate->port2_data));
+ cpustate->device->save_item(NAME(cpustate->port3_data));
+ cpustate->device->save_item(NAME(cpustate->port4_data));
+ cpustate->device->save_item(NAME(cpustate->port2_written));
+ cpustate->device->save_item(NAME(cpustate->port3_latched));
+ cpustate->device->save_item(NAME(cpustate->p3csr));
+ cpustate->device->save_item(NAME(cpustate->p3csr_is3_flag_read));
+ cpustate->device->save_item(NAME(cpustate->tcsr));
+ cpustate->device->save_item(NAME(cpustate->pending_tcsr));
+ cpustate->device->save_item(NAME(cpustate->irq2));
+ cpustate->device->save_item(NAME(cpustate->ram_ctrl));
+
+ cpustate->device->save_item(NAME(cpustate->counter.d));
+ cpustate->device->save_item(NAME(cpustate->output_compare.d));
+ cpustate->device->save_item(NAME(cpustate->input_capture));
+ cpustate->device->save_item(NAME(cpustate->timer_over.d));
+
+ cpustate->device->save_item(NAME(cpustate->clock));
+ cpustate->device->save_item(NAME(cpustate->trcsr));
+ cpustate->device->save_item(NAME(cpustate->rmcr));
+ cpustate->device->save_item(NAME(cpustate->rdr));
+ cpustate->device->save_item(NAME(cpustate->tdr));
+ cpustate->device->save_item(NAME(cpustate->rsr));
+ cpustate->device->save_item(NAME(cpustate->tsr));
+ cpustate->device->save_item(NAME(cpustate->rxbits));
+ cpustate->device->save_item(NAME(cpustate->txbits));
+ cpustate->device->save_item(NAME(cpustate->txstate));
+ cpustate->device->save_item(NAME(cpustate->trcsr_read_tdre));
+ cpustate->device->save_item(NAME(cpustate->trcsr_read_orfe));
+ cpustate->device->save_item(NAME(cpustate->trcsr_read_rdrf));
+ cpustate->device->save_item(NAME(cpustate->tx));
+}
+
+static CPU_INIT( m6800 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ // cpustate->subtype = SUBTYPE_M6800;
+ cpustate->insn = m6800_insn;
+ cpustate->cycles = cycles_6800;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+ state_register(cpustate, "m6800");
+}
+
+static CPU_RESET( m6800 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+
+ cpustate->cc = 0xc0;
+ SEI; /* IRQ disabled */
+ PCD = RM16(cpustate, 0xfffe );
+
+ cpustate->wai_state = 0;
+ cpustate->nmi_state = 0;
+ cpustate->nmi_pending = 0;
+ cpustate->sc1_state = 0;
+ cpustate->irq_state[M6800_IRQ_LINE] = 0;
+ cpustate->irq_state[M6801_TIN_LINE] = 0;
+ cpustate->ic_eddge = 0;
+
+ cpustate->port1_ddr = 0x00;
+ cpustate->port2_ddr = 0x00;
+ cpustate->port3_ddr = 0x00;
+ cpustate->p3csr = 0x00;
+ cpustate->p3csr_is3_flag_read = 0;
+ cpustate->port2_written = 0;
+ cpustate->port3_latched = 0;
+ /* TODO: on reset port 2 should be read to determine the operating mode (bits 0-2) */
+ cpustate->tcsr = 0x00;
+ cpustate->pending_tcsr = 0x00;
+ cpustate->irq2 = 0;
+ CTD = 0x0000;
+ OCD = 0xffff;
+ TOD = 0xffff;
+ cpustate->ram_ctrl |= 0x40;
+
+ cpustate->trcsr = M6800_TRCSR_TDRE;
+
+ cpustate->txstate = M6800_TX_STATE_INIT;
+ cpustate->txbits = cpustate->rxbits = 0;
+ cpustate->tx = 1;
+ cpustate->trcsr_read_tdre = 0;
+ cpustate->trcsr_read_orfe = 0;
+ cpustate->trcsr_read_rdrf = 0;
+
+ set_rmcr(cpustate, 0);
+}
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+static CPU_EXIT( m6800 )
+{
+ /* nothing to do */
+}
+
+
+static void set_irq_line(m6800_state *cpustate, int irqline, int state)
+{
+ switch (irqline)
+ {
+ case INPUT_LINE_NMI:
+ if (!cpustate->nmi_state && state != CLEAR_LINE)
+ cpustate->nmi_pending = TRUE;
+ cpustate->nmi_state = state;
+ break;
+
+ case M6801_SC1_LINE:
+ if (!cpustate->port3_latched && (cpustate->p3csr & M6801_P3CSR_LE))
+ {
+ if (!cpustate->sc1_state && state)
+ {
+ // latch input data to port 3
+ cpustate->port3_data = (cpustate->io->read_byte(M6801_PORT3) & (cpustate->port3_ddr ^ 0xff)) | (cpustate->port3_data & cpustate->port3_ddr);
+ cpustate->port3_latched = 1;
+ //logerror("M6801 '%s' Latched Port 3 Data: %02x\n", cpustate->device->tag(), cpustate->port3_data);
+
+ // set IS3 flag bit
+ cpustate->p3csr |= M6801_P3CSR_IS3_FLAG;
+ }
+ }
+ cpustate->sc1_state = state;
+ break;
+
+ default:
+ LOG(("M6800 '%s' set_irq_line %d,%d\n", cpustate->device->tag(), irqline, state));
+ cpustate->irq_state[irqline] = state;
+
+ if (irqline == M6801_TIN_LINE && state != cpustate->irq_state[irqline])
+ {
+ //eddge = (state == CLEAR_LINE ) ? 2 : 0;
+ if( ((cpustate->tcsr&TCSR_IEDG) ^ (state==CLEAR_LINE ? TCSR_IEDG : 0))==0 )
+ return;
+ /* active edge in */
+ cpustate->tcsr |= TCSR_ICF;
+ cpustate->pending_tcsr |= TCSR_ICF;
+ cpustate->input_capture = CT;
+ MODIFIED_tcsr;
+ }
+ }
+}
+
+/****************************************************************************
+ * Execute cycles CPU cycles. Return number of cycles really executed
+ ****************************************************************************/
+static CPU_EXECUTE( m6800 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ UINT8 ireg;
+
+ CHECK_IRQ_LINES(cpustate); /* HJB 990417 */
+
+ CLEANUP_COUNTERS();
+
+ do
+ {
+ if( cpustate->wai_state & (M6800_WAI|M6800_SLP) )
+ {
+ EAT_CYCLES;
+ }
+ else
+ {
+ pPPC = pPC;
+ debugger_instruction_hook(device, PCD);
+ ireg=M_RDOP(PCD);
+ PC++;
+ (*cpustate->insn[ireg])(cpustate);
+ increment_counter(cpustate, cpustate->cycles[ireg]);
+ }
+ } while( cpustate->icount>0 );
+}
+
+/****************************************************************************
+ * M6801 almost (fully?) equal to the M6803
+ ****************************************************************************/
+static CPU_INIT( m6801 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+// cpustate->subtype = SUBTYPE_M6801;
+ cpustate->insn = m6803_insn;
+ cpustate->cycles = cycles_6803;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ cpustate->clock = device->clock() / 4;
+ cpustate->sci_timer = device->machine().scheduler().timer_alloc(FUNC(sci_tick), cpustate);
+
+ state_register(cpustate, "m6801");
+
+ if (device->static_config() != NULL)
+ {
+ m6801_interface *intf = (m6801_interface *) device->static_config();
+
+ cpustate->out_sc2_func.resolve(intf->out_sc2_func, *device);
+ }
+ else
+ {
+ devcb_write_line nullcb = DEVCB_NULL;
+ cpustate->out_sc2_func.resolve(nullcb, *device);
+ }
+}
+
+/****************************************************************************
+ * M6802 almost (fully?) equal to the M6800
+ ****************************************************************************/
+static CPU_INIT( m6802 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ // cpustate->subtype = SUBTYPE_M6802;
+ cpustate->insn = m6800_insn;
+ cpustate->cycles = cycles_6800;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ state_register(cpustate, "m6802");
+}
+
+/****************************************************************************
+ * M6803 almost (fully?) equal to the M6801
+ ****************************************************************************/
+static CPU_INIT( m6803 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ // cpustate->subtype = SUBTYPE_M6803;
+ cpustate->insn = m6803_insn;
+ cpustate->cycles = cycles_6803;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ cpustate->clock = device->clock() / 4;
+ cpustate->sci_timer = device->machine().scheduler().timer_alloc(FUNC(sci_tick), cpustate);
+
+ state_register(cpustate, "m6803");
+
+ if (device->static_config() != NULL)
+ {
+ m6801_interface *intf = (m6801_interface *) device->static_config();
+
+ cpustate->out_sc2_func.resolve(intf->out_sc2_func, *device);
+ }
+ else
+ {
+ devcb_write_line nullcb = DEVCB_NULL;
+ cpustate->out_sc2_func.resolve(nullcb, *device);
+ }
+}
+
+static ADDRESS_MAP_START(m6803_mem, AS_PROGRAM, 8, legacy_cpu_device)
+ AM_RANGE(0x0000, 0x001f) AM_READWRITE_LEGACY(m6801_io_r, m6801_io_w)
+ AM_RANGE(0x0020, 0x007f) AM_NOP /* unused */
+ AM_RANGE(0x0080, 0x00ff) AM_RAM /* 6803 internal RAM */
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * M6808 almost (fully?) equal to the M6800
+ ****************************************************************************/
+static CPU_INIT( m6808 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ // cpustate->subtype = SUBTYPE_M6808;
+ cpustate->insn = m6800_insn;
+ cpustate->cycles = cycles_6800;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ state_register(cpustate, "m6808");
+}
+
+/****************************************************************************
+ * HD6301 similiar to the M6800
+ ****************************************************************************/
+
+static CPU_INIT( hd6301 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ // cpustate->subtype = SUBTYPE_HD6301;
+ cpustate->insn = hd63701_insn;
+ cpustate->cycles = cycles_63701;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ cpustate->clock = device->clock() / 4;
+ cpustate->sci_timer = device->machine().scheduler().timer_alloc(FUNC(sci_tick), cpustate);
+
+ state_register(cpustate, "hd6301");
+}
+
+/****************************************************************************
+ * HD63701 similiar to the HD6301
+ ****************************************************************************/
+
+static CPU_INIT( hd63701 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ // cpustate->subtype = SUBTYPE_HD63701;
+ cpustate->insn = hd63701_insn;
+ cpustate->cycles = cycles_63701;
+ cpustate->irq_callback = irqcallback;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ cpustate->clock = device->clock() / 4;
+ cpustate->sci_timer = device->machine().scheduler().timer_alloc(FUNC(sci_tick), cpustate);
+
+ state_register(cpustate, "hd63701");
+}
+
+/*
+ if change_pc(cpustate) direccted these areas ,Call hd63701_trap_pc(cpustate).
+ 'mode' is selected by the sense of p2.0,p2.1,and p2.3 at reset timming.
+ mode 0,1,2,4,6 : $0000-$001f
+ mode 5 : $0000-$001f,$0200-$efff
+ mode 7 : $0000-$001f,$0100-$efff
+*/
+#if 0
+static void hd63701_trap_pc(m6800_state *cpustate)
+{
+ TAKE_TRAP;
+}
+#endif
+
+/****************************************************************************
+ * NSC-8105 similiar to the M6800, but the opcodes are scrambled and there
+ * is at least one new opcode ($fc)
+ ****************************************************************************/
+static CPU_INIT( nsc8105 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+ // cpustate->subtype = SUBTYPE_NSC8105;
+ cpustate->device = device;
+
+ cpustate->program = device->space(AS_PROGRAM);
+ cpustate->direct = &cpustate->program->direct();
+ cpustate->data = device->space(AS_DATA);
+ cpustate->io = device->space(AS_IO);
+
+ cpustate->insn = nsc8105_insn;
+ cpustate->cycles = cycles_nsc8105;
+ state_register(cpustate, "nsc8105");
+}
+
+INLINE void set_os3(m6800_state *cpustate, int state)
+{
+ //logerror("M6801 '%s' OS3: %u\n", cpustate->device->tag(), state);
+
+ cpustate->out_sc2_func(state);
+}
+
+READ8_HANDLER( m6801_io_r )
+{
+ m6800_state *cpustate = get_safe_token(&space->device());
+
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case IO_P1DDR:
+ data = cpustate->port1_ddr;
+ break;
+
+ case IO_P2DDR:
+ data = cpustate->port2_ddr;
+ break;
+
+ case IO_P1DATA:
+ if(cpustate->port1_ddr == 0xff)
+ data = cpustate->port1_data;
+ else
+ data = (cpustate->io->read_byte(M6801_PORT1) & (cpustate->port1_ddr ^ 0xff))
+ | (cpustate->port1_data & cpustate->port1_ddr);
+ break;
+
+ case IO_P2DATA:
+ if(cpustate->port2_ddr == 0xff)
+ data = cpustate->port2_data;
+ else
+ data = (cpustate->io->read_byte(M6801_PORT2) & (cpustate->port2_ddr ^ 0xff))
+ | (cpustate->port2_data & cpustate->port2_ddr);
+ break;
+
+ case IO_P3DDR:
+ logerror("M6801 '%s' Port 3 DDR is a write-only register\n", space->device().tag());
+ break;
+
+ case IO_P4DDR:
+ data = cpustate->port4_ddr;
+ break;
+
+ case IO_P3DATA:
+ if (!space->debugger_access())
+ {
+ if (cpustate->p3csr_is3_flag_read)
+ {
+ //logerror("M6801 '%s' Cleared IS3\n", space->device().tag());
+ cpustate->p3csr &= ~M6801_P3CSR_IS3_FLAG;
+ cpustate->p3csr_is3_flag_read = 0;
+ }
+
+ if (!(cpustate->p3csr & M6801_P3CSR_OSS))
+ {
+ set_os3(cpustate, ASSERT_LINE);
+ }
+ }
+
+ if ((cpustate->p3csr & M6801_P3CSR_LE) || (cpustate->port3_ddr == 0xff))
+ data = cpustate->port3_data;
+ else
+ data = (cpustate->io->read_byte(M6801_PORT3) & (cpustate->port3_ddr ^ 0xff))
+ | (cpustate->port3_data & cpustate->port3_ddr);
+
+ if (!space->debugger_access())
+ {
+ cpustate->port3_latched = 0;
+
+ if (!(cpustate->p3csr & M6801_P3CSR_OSS))
+ {
+ set_os3(cpustate, CLEAR_LINE);
+ }
+ }
+ break;
+
+ case IO_P4DATA:
+ if(cpustate->port4_ddr == 0xff)
+ data = cpustate->port4_data;
+ else
+ data = (cpustate->io->read_byte(M6801_PORT4) & (cpustate->port4_ddr ^ 0xff))
+ | (cpustate->port4_data & cpustate->port4_ddr);
+ break;
+
+ case IO_TCSR:
+ cpustate->pending_tcsr = 0;
+ data = cpustate->tcsr;
+ break;
+
+ case IO_CH:
+ if(!(cpustate->pending_tcsr&TCSR_TOF) && !space->debugger_access())
+ {
+ cpustate->tcsr &= ~TCSR_TOF;
+ MODIFIED_tcsr;
+ }
+ data = cpustate->counter.b.h;
+ break;
+
+ case IO_CL:
+ data = cpustate->counter.b.l;
+
+ case IO_OCRH:
+ if(!(cpustate->pending_tcsr&TCSR_OCF) && !space->debugger_access())
+ {
+ cpustate->tcsr &= ~TCSR_OCF;
+ MODIFIED_tcsr;
+ }
+ data = cpustate->output_compare.b.h;
+ break;
+
+ case IO_OCRL:
+ if(!(cpustate->pending_tcsr&TCSR_OCF) && !space->debugger_access())
+ {
+ cpustate->tcsr &= ~TCSR_OCF;
+ MODIFIED_tcsr;
+ }
+ data = cpustate->output_compare.b.l;
+ break;
+
+ case IO_ICRH:
+ if(!(cpustate->pending_tcsr&TCSR_ICF) && !space->debugger_access())
+ {
+ cpustate->tcsr &= ~TCSR_ICF;
+ MODIFIED_tcsr;
+ }
+ data = (cpustate->input_capture >> 0) & 0xff;
+ break;
+
+ case IO_ICRL:
+ data = (cpustate->input_capture >> 8) & 0xff;
+ break;
+
+ case IO_P3CSR:
+ if ((cpustate->p3csr & M6801_P3CSR_IS3_FLAG) && !space->debugger_access())
+ {
+ cpustate->p3csr_is3_flag_read = 1;
+ }
+
+ data = cpustate->p3csr;
+ break;
+
+ case IO_RMCR:
+ data = cpustate->rmcr;
+ break;
+
+ case IO_TRCSR:
+ if (!space->debugger_access())
+ {
+ if (cpustate->trcsr & M6800_TRCSR_TDRE)
+ {
+ cpustate->trcsr_read_tdre = 1;
+ }
+
+ if (cpustate->trcsr & M6800_TRCSR_ORFE)
+ {
+ cpustate->trcsr_read_orfe = 1;
+ }
+
+ if (cpustate->trcsr & M6800_TRCSR_RDRF)
+ {
+ cpustate->trcsr_read_rdrf = 1;
+ }
+ }
+
+ data = cpustate->trcsr;
+ break;
+
+ case IO_RDR:
+ if (!space->debugger_access())
+ {
+ if (cpustate->trcsr_read_orfe)
+ {
+ //logerror("M6801 '%s' Cleared ORFE\n", space->device().tag());
+ cpustate->trcsr_read_orfe = 0;
+ cpustate->trcsr &= ~M6800_TRCSR_ORFE;
+ }
+
+ if (cpustate->trcsr_read_rdrf)
+ {
+ //logerror("M6801 '%s' Cleared RDRF\n", space->device().tag());
+ cpustate->trcsr_read_rdrf = 0;
+ cpustate->trcsr &= ~M6800_TRCSR_RDRF;
+ }
+ }
+
+ data = cpustate->rdr;
+ break;
+
+ case IO_TDR:
+ data = cpustate->tdr;
+ break;
+
+ case IO_RCR:
+ data = cpustate->ram_ctrl;
+ break;
+
+ case IO_CAAH:
+ case IO_CAAL:
+ case IO_TCR1:
+ case IO_TCR2:
+ case IO_TSR:
+ case IO_OCR2H:
+ case IO_OCR2L:
+ case IO_OCR3H:
+ case IO_OCR3L:
+ case IO_ICR2H:
+ case IO_ICR2L:
+ default:
+ logerror("M6801 '%s' PC %04x: warning - read from reserved internal register %02x\n",space->device().tag(),cpu_get_pc(&space->device()),offset);
+ }
+
+ return data;
+}
+
+WRITE8_HANDLER( m6801_io_w )
+{
+ m6800_state *cpustate = get_safe_token(&space->device());
+
+ switch (offset)
+ {
+ case IO_P1DDR:
+ //logerror("M6801 '%s' Port 1 Data Direction Register: %02x\n", space->device().tag(), data);
+
+ if (cpustate->port1_ddr != data)
+ {
+ cpustate->port1_ddr = data;
+ if(cpustate->port1_ddr == 0xff)
+ cpustate->io->write_byte(M6801_PORT1,cpustate->port1_data);
+ else
+ cpustate->io->write_byte(M6801_PORT1,(cpustate->port1_data & cpustate->port1_ddr) | (cpustate->port1_ddr ^ 0xff));
+ }
+ break;
+
+ case IO_P2DDR:
+ //logerror("M6801 '%s' Port 2 Data Direction Register: %02x\n", space->device().tag(), data);
+
+ if (cpustate->port2_ddr != data)
+ {
+ cpustate->port2_ddr = data;
+ write_port2(cpustate);
+
+ if (cpustate->port2_ddr & 2)
+ logerror("CPU '%s' PC %04x: warning - port 2 bit 1 set as output (OLVL) - not supported\n",space->device().tag(),cpu_get_pc(&space->device()));
+ }
+ break;
+
+ case IO_P1DATA:
+ //logerror("M6801 '%s' Port 1 Data Register: %02x\n", space->device().tag(), data);
+
+ cpustate->port1_data = data;
+ if(cpustate->port1_ddr == 0xff)
+ cpustate->io->write_byte(M6801_PORT1,cpustate->port1_data);
+ else
+ cpustate->io->write_byte(M6801_PORT1,(cpustate->port1_data & cpustate->port1_ddr) | (cpustate->port1_ddr ^ 0xff));
+ break;
+
+ case IO_P2DATA:
+ //logerror("M6801 '%s' Port 2 Data Register: %02x\n", space->device().tag(), data);
+
+ cpustate->port2_data = data;
+ cpustate->port2_written = 1;
+ write_port2(cpustate);
+ break;
+
+ case IO_P3DDR:
+ //logerror("M6801 '%s' Port 3 Data Direction Register: %02x\n", space->device().tag(), data);
+
+ if (cpustate->port3_ddr != data)
+ {
+ cpustate->port3_ddr = data;
+ if(cpustate->port3_ddr == 0xff)
+ cpustate->io->write_byte(M6801_PORT3,cpustate->port3_data);
+ else
+ cpustate->io->write_byte(M6801_PORT3,(cpustate->port3_data & cpustate->port3_ddr) | (cpustate->port3_ddr ^ 0xff));
+ }
+ break;
+
+ case IO_P4DDR:
+ //logerror("M6801 '%s' Port 4 Data Direction Register: %02x\n", space->device().tag(), data);
+
+ if (cpustate->port4_ddr != data)
+ {
+ cpustate->port4_ddr = data;
+ if(cpustate->port4_ddr == 0xff)
+ cpustate->io->write_byte(M6801_PORT4,cpustate->port4_data);
+ else
+ cpustate->io->write_byte(M6801_PORT4,(cpustate->port4_data & cpustate->port4_ddr) | (cpustate->port4_ddr ^ 0xff));
+ }
+ break;
+
+ case IO_P3DATA:
+ //logerror("M6801 '%s' Port 3 Data Register: %02x\n", space->device().tag(), data);
+
+ if (cpustate->p3csr_is3_flag_read)
+ {
+ //logerror("M6801 '%s' Cleared IS3\n", space->device().tag());
+ cpustate->p3csr &= ~M6801_P3CSR_IS3_FLAG;
+ cpustate->p3csr_is3_flag_read = 0;
+ }
+
+ if (cpustate->p3csr & M6801_P3CSR_OSS)
+ {
+ set_os3(cpustate, ASSERT_LINE);
+ }
+
+ cpustate->port3_data = data;
+ if(cpustate->port3_ddr == 0xff)
+ cpustate->io->write_byte(M6801_PORT3,cpustate->port3_data);
+ else
+ cpustate->io->write_byte(M6801_PORT3,(cpustate->port3_data & cpustate->port3_ddr) | (cpustate->port3_ddr ^ 0xff));
+
+ if (cpustate->p3csr & M6801_P3CSR_OSS)
+ {
+ set_os3(cpustate, CLEAR_LINE);
+ }
+ break;
+
+ case IO_P4DATA:
+ //logerror("M6801 '%s' Port 4 Data Register: %02x\n", space->device().tag(), data);
+
+ cpustate->port4_data = data;
+ if(cpustate->port4_ddr == 0xff)
+ cpustate->io->write_byte(M6801_PORT4,cpustate->port4_data);
+ else
+ cpustate->io->write_byte(M6801_PORT4,(cpustate->port4_data & cpustate->port4_ddr) | (cpustate->port4_ddr ^ 0xff));
+ break;
+
+ case IO_TCSR:
+ //logerror("M6801 '%s' Timer Control and Status Register: %02x\n", space->device().tag(), data);
+
+ cpustate->tcsr = data;
+ cpustate->pending_tcsr &= cpustate->tcsr;
+ MODIFIED_tcsr;
+ if( !(CC & 0x10) )
+ m6800_check_irq2(cpustate);
+ break;
+
+ case IO_CH:
+ //logerror("M6801 '%s' Counter High Register: %02x\n", space->device().tag(), data);
+
+ cpustate->latch09 = data & 0xff; /* 6301 only */
+ CT = 0xfff8;
+ TOH = CTH;
+ MODIFIED_counters;
+ break;
+
+ case IO_CL: /* 6301 only */
+ //logerror("M6801 '%s' Counter Low Register: %02x\n", space->device().tag(), data);
+
+ CT = (cpustate->latch09 << 8) | (data & 0xff);
+ TOH = CTH;
+ MODIFIED_counters;
+ break;
+
+ case IO_OCRH:
+ //logerror("M6801 '%s' Output Compare High Register: %02x\n", space->device().tag(), data);
+
+ if( cpustate->output_compare.b.h != data)
+ {
+ cpustate->output_compare.b.h = data;
+ MODIFIED_counters;
+ }
+ break;
+
+ case IO_OCRL:
+ //logerror("M6801 '%s' Output Compare Low Register: %02x\n", space->device().tag(), data);
+
+ if( cpustate->output_compare.b.l != data)
+ {
+ cpustate->output_compare.b.l = data;
+ MODIFIED_counters;
+ }
+ break;
+
+ case IO_ICRH:
+ case IO_ICRL:
+ case IO_RDR:
+ //logerror("CPU '%s' PC %04x: warning - write %02x to read only internal register %02x\n",space->device().tag(),cpu_get_pc(&space->device()),data,offset);
+ break;
+
+ case IO_P3CSR:
+ //logerror("M6801 '%s' Port 3 Control and Status Register: %02x\n", space->device().tag(), data);
+
+ cpustate->p3csr = data;
+ break;
+
+ case IO_RMCR:
+ //logerror("M6801 '%s' Rate and Mode Control Register: %02x\n", space->device().tag(), data);
+
+ set_rmcr(cpustate, data);
+ break;
+
+ case IO_TRCSR:
+ //logerror("M6801 '%s' Transmit/Receive Control and Status Register: %02x\n", space->device().tag(), data);
+
+ if ((data & M6800_TRCSR_TE) && !(cpustate->trcsr & M6800_TRCSR_TE))
+ {
+ cpustate->txstate = M6800_TX_STATE_INIT;
+ cpustate->txbits = 0;
+ cpustate->tx = 1;
+ }
+
+ if ((data & M6800_TRCSR_RE) && !(cpustate->trcsr & M6800_TRCSR_RE))
+ {
+ cpustate->rxbits = 0;
+ }
+
+ cpustate->trcsr = (cpustate->trcsr & 0xe0) | (data & 0x1f);
+ break;
+
+ case IO_TDR:
+ //logerror("M6800 '%s' Transmit Data Register: %02x\n", space->device().tag(), data);
+
+ if (cpustate->trcsr_read_tdre)
+ {
+ cpustate->trcsr_read_tdre = 0;
+ cpustate->trcsr &= ~M6800_TRCSR_TDRE;
+ }
+ cpustate->tdr = data;
+ break;
+
+ case IO_RCR:
+ //logerror("M6801 '%s' RAM Control Register: %02x\n", space->device().tag(), data);
+
+ cpustate->ram_ctrl = data;
+ break;
+
+ case IO_CAAH:
+ case IO_CAAL:
+ case IO_TCR1:
+ case IO_TCR2:
+ case IO_TSR:
+ case IO_OCR2H:
+ case IO_OCR2L:
+ case IO_OCR3H:
+ case IO_OCR3L:
+ case IO_ICR2H:
+ case IO_ICR2L:
+ default:
+ logerror("M6801 '%s' PC %04x: warning - write %02x to reserved internal register %02x\n",space->device().tag(),cpu_get_pc(&space->device()),data,offset);
+ break;
+ }
+}
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static CPU_SET_INFO( m6800 )
+{
+ m6800_state *cpustate = get_safe_token(device);
+
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + M6800_IRQ_LINE: set_irq_line(cpustate, M6800_IRQ_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6801_TIN_LINE: set_irq_line(cpustate, M6801_TIN_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + M6801_SC1_LINE: set_irq_line(cpustate, M6801_SC1_LINE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(cpustate, INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_PC: PC = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_PC: cpustate->pc.w.l = info->i; break;
+ case CPUINFO_INT_SP: S = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_S: cpustate->s.w.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_CC: cpustate->cc = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_A: cpustate->d.b.h = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_B: cpustate->d.b.l = info->i; break;
+ case CPUINFO_INT_REGISTER + M6800_X: cpustate->x.w.l = info->i; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+CPU_GET_INFO( m6800 )
+{
+ m6800_state *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(m6800_state); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break;
+ case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 12; break;
+
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 16; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 9; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + M6800_IRQ_LINE: info->i = cpustate->irq_state[M6800_IRQ_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + M6801_TIN_LINE: info->i = cpustate->irq_state[M6801_TIN_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + M6801_SC1_LINE: info->i = cpustate->irq_state[M6801_SC1_LINE]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = cpustate->nmi_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = cpustate->ppc.w.l; break;
+
+ case CPUINFO_INT_PC: info->i = PC; break;
+ case CPUINFO_INT_REGISTER + M6800_PC: info->i = cpustate->pc.w.l; break;
+ case CPUINFO_INT_SP: info->i = S; break;
+ case CPUINFO_INT_REGISTER + M6800_S: info->i = cpustate->s.w.l; break;
+ case CPUINFO_INT_REGISTER + M6800_CC: info->i = cpustate->cc; break;
+ case CPUINFO_INT_REGISTER + M6800_A: info->i = cpustate->d.b.h; break;
+ case CPUINFO_INT_REGISTER + M6800_B: info->i = cpustate->d.b.l; break;
+ case CPUINFO_INT_REGISTER + M6800_X: info->i = cpustate->x.w.l; break;
+ case CPUINFO_INT_REGISTER + M6800_WAI_STATE: info->i = cpustate->wai_state; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(m6800); break;
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m6800); break;
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(m6800); break;
+ case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(m6800); break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(m6800); break;
+ case CPUINFO_FCT_BURN: info->burn = NULL; break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(m6800); break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "M6800"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Motorola 6800"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.1"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "The MAME team."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c%c%c%c%c",
+ cpustate->cc & 0x80 ? '?':'.',
+ cpustate->cc & 0x40 ? '?':'.',
+ cpustate->cc & 0x20 ? 'H':'.',
+ cpustate->cc & 0x10 ? 'I':'.',
+ cpustate->cc & 0x08 ? 'N':'.',
+ cpustate->cc & 0x04 ? 'Z':'.',
+ cpustate->cc & 0x02 ? 'V':'.',
+ cpustate->cc & 0x01 ? 'C':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + M6800_A: sprintf(info->s, "A:%02X", cpustate->d.b.h); break;
+ case CPUINFO_STR_REGISTER + M6800_B: sprintf(info->s, "B:%02X", cpustate->d.b.l); break;
+ case CPUINFO_STR_REGISTER + M6800_PC: sprintf(info->s, "PC:%04X", cpustate->pc.w.l); break;
+ case CPUINFO_STR_REGISTER + M6800_S: sprintf(info->s, "S:%04X", cpustate->s.w.l); break;
+ case CPUINFO_STR_REGISTER + M6800_X: sprintf(info->s, "X:%04X", cpustate->x.w.l); break;
+ case CPUINFO_STR_REGISTER + M6800_CC: sprintf(info->s, "CC:%02X", cpustate->cc); break;
+ case CPUINFO_STR_REGISTER + M6800_WAI_STATE: sprintf(info->s, "WAI:%X", cpustate->wai_state); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( m6801 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m6801); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(m6801); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "M6801"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( m6802 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m6802); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(m6802); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "M6802"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( m6803 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m6803); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(m6803); break;
+
+ case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map8 = ADDRESS_MAP_NAME(m6803_mem); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "M6803"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( m6808 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m6808); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(m6808); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "M6808"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( hd6301 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(hd6301); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(hd6301); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "HD6301"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( hd63701 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 9; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(hd63701); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(hd63701); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "HD63701"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+
+/**************************************************************************
+ * CPU-specific set_info
+ **************************************************************************/
+
+CPU_GET_INFO( nsc8105 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(nsc8105); break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(nsc8105); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "NSC8105"); break;
+
+ default: CPU_GET_INFO_CALL(m6800); break;
+ }
+}
+
+DEFINE_LEGACY_CPU_DEVICE(M6800, m6800);
+DEFINE_LEGACY_CPU_DEVICE(M6801, m6801);
+DEFINE_LEGACY_CPU_DEVICE(M6802, m6802);
+DEFINE_LEGACY_CPU_DEVICE(M6803, m6803);
+DEFINE_LEGACY_CPU_DEVICE(M6808, m6808);
+DEFINE_LEGACY_CPU_DEVICE(HD6301, hd6301);
+DEFINE_LEGACY_CPU_DEVICE(HD63701, hd63701);
+DEFINE_LEGACY_CPU_DEVICE(NSC8105, nsc8105);