diff options
Diffstat (limited to 'trunk/src/emu/cpu/m6800/m6800.c')
-rw-r--r-- | trunk/src/emu/cpu/m6800/m6800.c | 2130 |
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); |