mirror of
https://github.com/holub/mame
synced 2025-05-20 12:48:53 +03:00
621 lines
23 KiB
C
621 lines
23 KiB
C
/*** konami: Portable Konami cpu emulator ******************************************
|
|
|
|
Copyright Nicola Salmoria and the MAME Team
|
|
|
|
Based on M6809 cpu core copyright John Butler
|
|
|
|
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:
|
|
991022 HJB:
|
|
Tried to improve speed: Using bit7 of cycles1 as flag for multi
|
|
byte opcodes is gone, those opcodes now instead go through opcode2().
|
|
Inlined fetch_effective_address() into that function as well.
|
|
Got rid of the slow/fast flags for stack (S and U) memory accesses.
|
|
Minor changes to use 32 bit values as arguments to memory functions
|
|
and added defines for that purpose (e.g. X = 16bit XD = 32bit).
|
|
|
|
990720 EHC:
|
|
Created this file
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "debugger.h"
|
|
#include "konami.h"
|
|
|
|
#define VERBOSE 0
|
|
|
|
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
|
|
|
/* Konami Registers */
|
|
typedef struct _konami_state konami_state;
|
|
struct _konami_state
|
|
{
|
|
PAIR pc; /* Program counter */
|
|
PAIR ppc; /* Previous program counter */
|
|
PAIR d; /* Accumulator a and b */
|
|
PAIR dp; /* Direct Page register (page in MSB) */
|
|
PAIR u, s; /* Stack pointers */
|
|
PAIR x, y; /* Index registers */
|
|
PAIR ea;
|
|
UINT8 cc;
|
|
UINT8 ireg;
|
|
UINT8 irq_state[2];
|
|
cpu_irq_callback irq_callback;
|
|
UINT8 int_state; /* SYNC and CWAI flags */
|
|
UINT8 nmi_state;
|
|
UINT8 nmi_pending;
|
|
int icount;
|
|
const device_config *device;
|
|
const address_space *program;
|
|
konami_set_lines_func setlines_callback;
|
|
};
|
|
|
|
/* flag bits in the cc register */
|
|
#define CC_C 0x01 /* Carry */
|
|
#define CC_V 0x02 /* Overflow */
|
|
#define CC_Z 0x04 /* Zero */
|
|
#define CC_N 0x08 /* Negative */
|
|
#define CC_II 0x10 /* Inhibit IRQ */
|
|
#define CC_H 0x20 /* Half (auxiliary) carry */
|
|
#define CC_IF 0x40 /* Inhibit FIRQ */
|
|
#define CC_E 0x80 /* entire state pushed */
|
|
|
|
/* Konami registers */
|
|
#define pPPC cpustate->ppc
|
|
#define pPC cpustate->pc
|
|
#define pU cpustate->u
|
|
#define pS cpustate->s
|
|
#define pX cpustate->x
|
|
#define pY cpustate->y
|
|
#define pD cpustate->d
|
|
|
|
#define PPC cpustate->ppc.w.l
|
|
#define PC cpustate->pc.w.l
|
|
#define PCD cpustate->pc.d
|
|
#define U cpustate->u.w.l
|
|
#define UD cpustate->u.d
|
|
#define S cpustate->s.w.l
|
|
#define SD cpustate->s.d
|
|
#define X cpustate->x.w.l
|
|
#define XD cpustate->x.d
|
|
#define Y cpustate->y.w.l
|
|
#define YD cpustate->y.d
|
|
#define D cpustate->d.w.l
|
|
#define A cpustate->d.b.h
|
|
#define B cpustate->d.b.l
|
|
#define DP cpustate->dp.b.h
|
|
#define DPD cpustate->dp.d
|
|
#define CC cpustate->cc
|
|
|
|
#define EAB cpustate->ea.b.l
|
|
#define EA cpustate->ea.w.l
|
|
#define EAD cpustate->ea.d
|
|
|
|
#define KONAMI_CWAI 8 /* set when CWAI is waiting for an interrupt */
|
|
#define KONAMI_SYNC 16 /* set when SYNC is waiting for an interrupt */
|
|
#define KONAMI_LDS 32 /* set when LDS occured at least once */
|
|
|
|
#define RM(cs,Addr) memory_read_byte_8be((cs)->program, Addr)
|
|
#define WM(cs,Addr,Value) memory_write_byte_8be((cs)->program, Addr,Value)
|
|
#define ROP(cs,Addr) memory_decrypted_read_byte((cs)->program, Addr)
|
|
#define ROP_ARG(cs,Addr) memory_raw_read_byte((cs)->program, Addr)
|
|
|
|
#define SIGNED(a) (UINT16)(INT16)(INT8)(a)
|
|
|
|
/* macros to access memory */
|
|
#define IMMBYTE(cs,b) { b = ROP_ARG(cs,PCD); PC++; }
|
|
#define IMMWORD(cs,w) { w.d = (ROP_ARG(cs,PCD)<<8) | ROP_ARG(cs,PCD+1); PC += 2; }
|
|
|
|
#define PUSHBYTE(cs,b) --S; WM(cs,SD,b)
|
|
#define PUSHWORD(cs,w) --S; WM(cs,SD,w.b.l); --S; WM(cs,SD,w.b.h)
|
|
#define PULLBYTE(cs,b) b=RM(cs,SD); S++
|
|
#define PULLWORD(cs,w) w=RM(cs,SD)<<8; S++; w|=RM(cs,SD); S++
|
|
|
|
#define PSHUBYTE(cs,b) --U; WM(cs,UD,b);
|
|
#define PSHUWORD(cs,w) --U; WM(cs,UD,w.b.l); --U; WM(cs,UD,w.b.h)
|
|
#define PULUBYTE(cs,b) b=RM(cs,UD); U++
|
|
#define PULUWORD(cs,w) w=RM(cs,UD)<<8; U++; w|=RM(cs,UD); U++
|
|
|
|
#define CLR_HNZVC CC&=~(CC_H|CC_N|CC_Z|CC_V|CC_C)
|
|
#define CLR_NZV CC&=~(CC_N|CC_Z|CC_V)
|
|
#define CLR_NZ CC&=~(CC_N|CC_Z)
|
|
#define CLR_HNZC CC&=~(CC_H|CC_N|CC_Z|CC_C)
|
|
#define CLR_NZVC CC&=~(CC_N|CC_Z|CC_V|CC_C)
|
|
#define CLR_Z CC&=~(CC_Z)
|
|
#define CLR_NZC CC&=~(CC_N|CC_Z|CC_C)
|
|
#define CLR_ZC CC&=~(CC_Z|CC_C)
|
|
|
|
/* 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 */
|
|
{
|
|
CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
CC_N|CC_V,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
|
|
};
|
|
static const UINT8 flags8d[256]= /* decrement */
|
|
{
|
|
CC_Z,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,CC_V,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,
|
|
CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N,CC_N
|
|
};
|
|
#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_Z(a);}
|
|
#define SET_NZ16(a) {SET_N16(a);SET_Z(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);}
|
|
|
|
/* macros for addressing modes (postbytes have their own code) */
|
|
#define DIRECT(cs) EAD = DPD; IMMBYTE(cs,EAB)
|
|
#define IMM8(cs) EAD = PCD; PC++
|
|
#define IMM16(cs) EAD = PCD; PC+=2
|
|
#define EXTENDED(cs) IMMWORD(cs,(cs)->ea)
|
|
|
|
/* macros to set status flags */
|
|
#if defined(SEC)
|
|
#undef SEC
|
|
#endif
|
|
#define SEC CC|=CC_C
|
|
#define CLC CC&=~CC_C
|
|
#define SEZ CC|=CC_Z
|
|
#define CLZ CC&=~CC_Z
|
|
#define SEN CC|=CC_N
|
|
#define CLN CC&=~CC_N
|
|
#define SEV CC|=CC_V
|
|
#define CLV CC&=~CC_V
|
|
#define SEH CC|=CC_H
|
|
#define CLH CC&=~CC_H
|
|
|
|
/* macros for convenience */
|
|
#define DIRBYTE(cs,b) DIRECT(cs); b=RM(cs,EAD)
|
|
#define DIRWORD(cs,w) DIRECT(cs); w.d=RM16(cs,EAD)
|
|
#define EXTBYTE(cs,b) EXTENDED(cs); b=RM(cs,EAD)
|
|
#define EXTWORD(cs,w) EXTENDED(cs); w.d=RM16(cs,EAD)
|
|
|
|
/* macros for branch instructions */
|
|
#define BRANCH(cs,f) { \
|
|
UINT8 t; \
|
|
IMMBYTE(cs,t); \
|
|
if( f ) \
|
|
{ \
|
|
PC += SIGNED(t); \
|
|
} \
|
|
}
|
|
|
|
#define LBRANCH(cs,f) { \
|
|
PAIR t; \
|
|
IMMWORD(cs,t); \
|
|
if( f ) \
|
|
{ \
|
|
cpustate->icount -= 1; \
|
|
PC += t.w.l; \
|
|
} \
|
|
}
|
|
|
|
#define NXORV ((CC&CC_N)^((CC&CC_V)<<2))
|
|
|
|
/* macros for setting/getting registers in TFR/EXG instructions */
|
|
#define GETREG(val,reg) \
|
|
switch(reg) { \
|
|
case 0: val = A; break; \
|
|
case 1: val = B; break; \
|
|
case 2: val = X; break; \
|
|
case 3: val = Y; break; \
|
|
case 4: val = S; break; /* ? */ \
|
|
case 5: val = U; break; \
|
|
default: val = 0xff; logerror("Unknown TFR/EXG idx at PC:%04x\n", PC ); break; \
|
|
}
|
|
|
|
#define SETREG(val,reg) \
|
|
switch(reg) { \
|
|
case 0: A = val; break; \
|
|
case 1: B = val; break; \
|
|
case 2: X = val; break; \
|
|
case 3: Y = val; break; \
|
|
case 4: S = val; break; /* ? */ \
|
|
case 5: U = val; break; \
|
|
default: logerror("Unknown TFR/EXG idx at PC:%04x\n", PC ); break; \
|
|
}
|
|
|
|
/* opcode timings */
|
|
static const UINT8 cycles1[] =
|
|
{
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/*0*/ 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 5, 5, 5, 5,
|
|
/*1*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
/*2*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
/*3*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 7, 6,
|
|
/*4*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4,
|
|
/*5*/ 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 1, 1, 1,
|
|
/*6*/ 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
/*7*/ 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
/*8*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
|
|
/*9*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
|
|
/*A*/ 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 3, 3, 2, 1,
|
|
/*B*/ 3, 2, 2,11,22,11, 2, 4, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
/*C*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 2,
|
|
/*D*/ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
/*E*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
/*F*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
|
};
|
|
|
|
INLINE UINT32 RM16( konami_state *cpustate, UINT32 Addr )
|
|
{
|
|
UINT32 result = RM(cpustate, Addr) << 8;
|
|
return result | RM(cpustate, (Addr+1)&0xffff);
|
|
}
|
|
|
|
INLINE void WM16( konami_state *cpustate, UINT32 Addr, PAIR *p )
|
|
{
|
|
WM(cpustate, Addr, p->b.h );
|
|
WM(cpustate, (Addr+1)&0xffff, p->b.l );
|
|
}
|
|
|
|
|
|
static void check_irq_lines(konami_state *cpustate)
|
|
{
|
|
if (cpustate->nmi_pending && (cpustate->int_state & KONAMI_LDS))
|
|
{
|
|
cpustate->nmi_pending = FALSE;
|
|
|
|
/* state already saved by CWAI? */
|
|
if (cpustate->int_state & KONAMI_CWAI)
|
|
{
|
|
cpustate->int_state &= ~KONAMI_CWAI;
|
|
cpustate->icount -= 7;
|
|
}
|
|
else
|
|
{
|
|
CC |= CC_E; /* save entire state */
|
|
PUSHWORD(cpustate, pPC);
|
|
PUSHWORD(cpustate, pU);
|
|
PUSHWORD(cpustate, pY);
|
|
PUSHWORD(cpustate, pX);
|
|
PUSHBYTE(cpustate, DP);
|
|
PUSHBYTE(cpustate, B);
|
|
PUSHBYTE(cpustate, A);
|
|
PUSHBYTE(cpustate, CC);
|
|
cpustate->icount -= 19;
|
|
}
|
|
CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
|
|
PCD = RM16(cpustate, 0xfffc);
|
|
(void)(*cpustate->irq_callback)(cpustate->device, INPUT_LINE_NMI);
|
|
}
|
|
|
|
else if (cpustate->irq_state[KONAMI_FIRQ_LINE] !=CLEAR_LINE && !(CC & CC_IF))
|
|
{
|
|
/* fast IRQ */
|
|
/* state already saved by CWAI? */
|
|
if (cpustate->int_state & KONAMI_CWAI)
|
|
{
|
|
cpustate->int_state &= ~KONAMI_CWAI; /* clear CWAI */
|
|
cpustate->icount -= 7;
|
|
}
|
|
else
|
|
{
|
|
CC &= ~CC_E; /* save 'short' state */
|
|
PUSHWORD(cpustate, pPC);
|
|
PUSHBYTE(cpustate, CC);
|
|
cpustate->icount -= 10;
|
|
}
|
|
CC |= CC_IF | CC_II; /* inhibit FIRQ and IRQ */
|
|
PCD = RM16(cpustate, 0xfff6);
|
|
(void)(*cpustate->irq_callback)(cpustate->device, KONAMI_FIRQ_LINE);
|
|
}
|
|
|
|
else if (cpustate->irq_state[KONAMI_IRQ_LINE] != CLEAR_LINE && !(CC & CC_II))
|
|
{
|
|
/* standard IRQ */
|
|
/* state already saved by CWAI? */
|
|
if (cpustate->int_state & KONAMI_CWAI)
|
|
{
|
|
cpustate->int_state &= ~KONAMI_CWAI; /* clear CWAI flag */
|
|
cpustate->icount -= 7;
|
|
}
|
|
else
|
|
{
|
|
CC |= CC_E; /* save entire state */
|
|
PUSHWORD(cpustate, pPC);
|
|
PUSHWORD(cpustate, pU);
|
|
PUSHWORD(cpustate, pY);
|
|
PUSHWORD(cpustate, pX);
|
|
PUSHBYTE(cpustate, DP);
|
|
PUSHBYTE(cpustate, B);
|
|
PUSHBYTE(cpustate, A);
|
|
PUSHBYTE(cpustate, CC);
|
|
cpustate->icount -= 19;
|
|
}
|
|
CC |= CC_II; /* inhibit IRQ */
|
|
PCD = RM16(cpustate, 0xfff8);
|
|
(void)(*cpustate->irq_callback)(cpustate->device, KONAMI_IRQ_LINE);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Reset registers to their initial values */
|
|
/****************************************************************************/
|
|
static CPU_INIT( konami )
|
|
{
|
|
konami_state *cpustate = device->token;
|
|
|
|
cpustate->irq_callback = irqcallback;
|
|
cpustate->device = device;
|
|
cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
|
|
|
|
state_save_register_device_item(device, 0, PC);
|
|
state_save_register_device_item(device, 0, U);
|
|
state_save_register_device_item(device, 0, S);
|
|
state_save_register_device_item(device, 0, X);
|
|
state_save_register_device_item(device, 0, Y);
|
|
state_save_register_device_item(device, 0, D);
|
|
state_save_register_device_item(device, 0, DP);
|
|
state_save_register_device_item(device, 0, CC);
|
|
state_save_register_device_item(device, 0, cpustate->int_state);
|
|
state_save_register_device_item(device, 0, cpustate->nmi_state);
|
|
state_save_register_device_item(device, 0, cpustate->nmi_pending);
|
|
state_save_register_device_item(device, 0, cpustate->irq_state[0]);
|
|
state_save_register_device_item(device, 0, cpustate->irq_state[1]);
|
|
}
|
|
|
|
static CPU_RESET( konami )
|
|
{
|
|
konami_state *cpustate = device->token;
|
|
|
|
cpustate->int_state = 0;
|
|
cpustate->nmi_state = CLEAR_LINE;
|
|
cpustate->nmi_pending = FALSE;
|
|
cpustate->irq_state[0] = CLEAR_LINE;
|
|
cpustate->irq_state[1] = CLEAR_LINE;
|
|
|
|
DPD = 0; /* Reset direct page register */
|
|
|
|
CC |= CC_II; /* IRQ disabled */
|
|
CC |= CC_IF; /* FIRQ disabled */
|
|
|
|
PCD = RM16(cpustate, 0xfffe);
|
|
}
|
|
|
|
static CPU_EXIT( konami )
|
|
{
|
|
}
|
|
|
|
/* Generate interrupts */
|
|
/****************************************************************************
|
|
* Set IRQ line state
|
|
****************************************************************************/
|
|
static void set_irq_line(konami_state *cpustate, int irqline, int state)
|
|
{
|
|
if (state != CLEAR_LINE)
|
|
cpustate->int_state &= ~KONAMI_SYNC;
|
|
|
|
if (irqline == INPUT_LINE_NMI)
|
|
{
|
|
if (cpustate->nmi_state == CLEAR_LINE && state != CLEAR_LINE)
|
|
cpustate->nmi_pending = TRUE;
|
|
cpustate->nmi_state = state;
|
|
}
|
|
else if (irqline < ARRAY_LENGTH(cpustate->irq_state))
|
|
cpustate->irq_state[irqline] = state;
|
|
}
|
|
|
|
/* includes the static function prototypes and the master opcode table */
|
|
#include "konamtbl.c"
|
|
|
|
/* includes the actual opcode implementations */
|
|
#include "konamops.c"
|
|
|
|
/* execute instructions on this CPU until icount expires */
|
|
static CPU_EXECUTE( konami )
|
|
{
|
|
konami_state *cpustate = device->token;
|
|
|
|
cpustate->icount = cycles;
|
|
check_irq_lines(cpustate);
|
|
|
|
if( cpustate->int_state & (KONAMI_CWAI | KONAMI_SYNC) )
|
|
{
|
|
cpustate->icount = 0;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
UINT8 ireg;
|
|
|
|
pPPC = pPC;
|
|
|
|
debugger_instruction_hook(device, PCD);
|
|
|
|
cpustate->ireg = ireg = ROP(cpustate, PCD);
|
|
PC++;
|
|
|
|
(*konami_main[ireg])(cpustate);
|
|
|
|
cpustate->icount -= cycles1[ireg];
|
|
|
|
} while( cpustate->icount > 0 );
|
|
}
|
|
|
|
return cycles - cpustate->icount;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic set_info
|
|
**************************************************************************/
|
|
|
|
static CPU_SET_INFO( konami )
|
|
{
|
|
konami_state *cpustate = device->token;
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are set as 64-bit signed integers --- */
|
|
case CPUINFO_INT_INPUT_STATE + KONAMI_IRQ_LINE: set_irq_line(cpustate, KONAMI_IRQ_LINE, info->i); break;
|
|
case CPUINFO_INT_INPUT_STATE + KONAMI_FIRQ_LINE:set_irq_line(cpustate, KONAMI_FIRQ_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:
|
|
case CPUINFO_INT_REGISTER + KONAMI_PC: PC = info->i; break;
|
|
case CPUINFO_INT_SP:
|
|
case CPUINFO_INT_REGISTER + KONAMI_S: S = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_CC: CC = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_U: U = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_A: A = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_B: B = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_X: X = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_Y: Y = info->i; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_DP: DP = info->i; break;
|
|
|
|
/* --- the following bits of info are set as pointers to data or functions --- */
|
|
case CPUINFO_PTR_KONAMI_SETLINES_CALLBACK: cpustate->setlines_callback = (konami_set_lines_func)info->f; break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
CPU_GET_INFO( konami )
|
|
{
|
|
konami_state *cpustate = (device != NULL) ? device->token : NULL;
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(konami_state); break;
|
|
case CPUINFO_INT_INPUT_LINES: info->i = 2; break;
|
|
case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
|
|
case CPUINFO_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 = 13; break;
|
|
|
|
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
|
|
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
|
|
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
|
|
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
|
|
|
|
case CPUINFO_INT_INPUT_STATE + KONAMI_IRQ_LINE: info->i = cpustate->irq_state[KONAMI_IRQ_LINE]; break;
|
|
case CPUINFO_INT_INPUT_STATE + KONAMI_FIRQ_LINE:info->i = cpustate->irq_state[KONAMI_FIRQ_LINE]; break;
|
|
case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = cpustate->nmi_state; break;
|
|
|
|
case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
|
|
|
|
case CPUINFO_INT_PC:
|
|
case CPUINFO_INT_REGISTER + KONAMI_PC: info->i = PC; break;
|
|
case CPUINFO_INT_SP:
|
|
case CPUINFO_INT_REGISTER + KONAMI_S: info->i = S; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_CC: info->i = CC; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_U: info->i = U; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_A: info->i = A; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_B: info->i = B; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_X: info->i = X; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_Y: info->i = Y; break;
|
|
case CPUINFO_INT_REGISTER + KONAMI_DP: info->i = DP; break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case CPUINFO_PTR_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(konami); break;
|
|
case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(konami); break;
|
|
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(konami); break;
|
|
case CPUINFO_PTR_EXIT: info->exit = CPU_EXIT_NAME(konami); break;
|
|
case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(konami); break;
|
|
case CPUINFO_PTR_BURN: info->burn = NULL; break;
|
|
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(konami);break;
|
|
case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break;
|
|
case CPUINFO_PTR_KONAMI_SETLINES_CALLBACK: info->f = (genf *)cpustate->setlines_callback; break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case CPUINFO_STR_NAME: strcpy(info->s, "KONAMI"); break;
|
|
case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "KONAMI 5000x"); break;
|
|
case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
|
|
case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
|
|
case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
|
|
|
|
case CPUINFO_STR_FLAGS:
|
|
sprintf(info->s, "%c%c%c%c%c%c%c%c",
|
|
cpustate->cc & 0x80 ? 'E':'.',
|
|
cpustate->cc & 0x40 ? 'F':'.',
|
|
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 + KONAMI_PC: sprintf(info->s, "PC:%04X", cpustate->pc.w.l); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_S: sprintf(info->s, "S:%04X", cpustate->s.w.l); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_CC: sprintf(info->s, "CC:%02X", cpustate->cc); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_U: sprintf(info->s, "U:%04X", cpustate->u.w.l); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_A: sprintf(info->s, "A:%02X", cpustate->d.b.h); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_B: sprintf(info->s, "B:%02X", cpustate->d.b.l); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_X: sprintf(info->s, "X:%04X", cpustate->x.w.l); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_Y: sprintf(info->s, "Y:%04X", cpustate->y.w.l); break;
|
|
case CPUINFO_STR_REGISTER + KONAMI_DP: sprintf(info->s, "DP:%02X", cpustate->dp.b.h); break;
|
|
}
|
|
}
|