// V60.C
// Undiscover the beast!
// Main hacking and coding by Farfetch'd
// Portability fixes by Richter Belmont

#include "debugger.h"
#include "v60.h"

// memory accessors
#include "v60mem.c"


// macros stolen from MAME for flags calc
// note that these types are in x86 naming:
// byte = 8 bit, word = 16 bit, long = 32 bit

// parameter x = result, y = source 1, z = source 2

#define SetOFL_Add(x,y,z)	(_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80000000) ? 1: 0)
#define SetOFW_Add(x,y,z)	(_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x8000) ? 1 : 0)
#define SetOFB_Add(x,y,z)	(_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80) ? 1 : 0)

#define SetOFL_Sub(x,y,z)	(_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80000000) ? 1 : 0)
#define SetOFW_Sub(x,y,z)	(_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x8000) ? 1 : 0)
#define SetOFB_Sub(x,y,z)	(_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80) ? 1 : 0)

#define SetCFB(x)		{_CY = ((x) & 0x100) ? 1 : 0; }
#define SetCFW(x)		{_CY = ((x) & 0x10000) ? 1 : 0; }
#define SetCFL(x)		{_CY = ((x) & (((UINT64)1) << 32)) ? 1 : 0; }

#define SetSF(x)		(_S = (x))
#define SetZF(x)		(_Z = (x))

#define SetSZPF_Byte(x) 	{_Z = ((UINT8)(x)==0);  _S = ((x)&0x80) ? 1 : 0; }
#define SetSZPF_Word(x) 	{_Z = ((UINT16)(x)==0);  _S = ((x)&0x8000) ? 1 : 0; }
#define SetSZPF_Long(x) 	{_Z = ((UINT32)(x)==0);  _S = ((x)&0x80000000) ? 1 : 0; }

#define ORB(dst,src)		{ (dst) |= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
#define ORW(dst,src)		{ (dst) |= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
#define ORL(dst,src)		{ (dst) |= (src); _CY = _OV = 0; SetSZPF_Long(dst); }

#define ANDB(dst,src)		{ (dst) &= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
#define ANDW(dst,src)		{ (dst) &= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
#define ANDL(dst,src)		{ (dst) &= (src); _CY = _OV = 0; SetSZPF_Long(dst); }

#define XORB(dst,src)		{ (dst) ^= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
#define XORW(dst,src)		{ (dst) ^= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
#define XORL(dst,src)		{ (dst) ^= (src); _CY = _OV = 0; SetSZPF_Long(dst); }

#define SUBB(dst, src)		{ unsigned res=(dst)-(src); SetCFB(res); SetOFB_Sub(res,src,dst); SetSZPF_Byte(res); dst=(UINT8)res; }
#define SUBW(dst, src)		{ unsigned res=(dst)-(src); SetCFW(res); SetOFW_Sub(res,src,dst); SetSZPF_Word(res); dst=(UINT16)res; }
#define SUBL(dst, src)		{ UINT64 res=(UINT64)(dst)-(INT64)(src); SetCFL(res); SetOFL_Sub(res,src,dst); SetSZPF_Long(res); dst=(UINT32)res; }

#define ADDB(dst, src)		{ unsigned res=(dst)+(src); SetCFB(res); SetOFB_Add(res,src,dst); SetSZPF_Byte(res); dst=(UINT8)res; }
#define ADDW(dst, src)		{ unsigned res=(dst)+(src); SetCFW(res); SetOFW_Add(res,src,dst); SetSZPF_Word(res); dst=(UINT16)res; }
#define ADDL(dst, src)		{ UINT64 res=(UINT64)(dst)+(UINT64)(src); SetCFL(res); SetOFL_Add(res,src,dst); SetSZPF_Long(res); dst=(UINT32)res; }

#define SETREG8(a, b)  (a) = ((a) & ~0xff) | ((b) & 0xff)
#define SETREG16(a, b) (a) = ((a) & ~0xffff) | ((b) & 0xffff)

typedef struct
{
	UINT8 CY;
	UINT8 OV;
	UINT8 S;
	UINT8 Z;
} Flags;

// v60 Register Inside (Hm... It's not a pentium inside :-))) )
static struct v60info {
	struct cpu_info info;
	UINT32 reg[68];
	Flags flags;
	UINT8 irq_line;
	UINT8 nmi_line;
	int (*irq_cb)(int irqline);
	UINT32 PPC;
} v60;

static int v60_ICount;
static int v60_stall_io;

/*
 * Prevent warnings on NetBSD.  All identifiers beginning with an underscore
 * followed by an uppercase letter are reserved by the C standard (ISO/IEC
 * 9899:1999, 7.1.3) to be used by the implementation.  It'd be best to rename
 * all such instances, but this is less intrusive and error-prone.
 */
#undef _S

#define _CY v60.flags.CY
#define _OV v60.flags.OV
#define _S v60.flags.S
#define _Z v60.flags.Z


// Defines of all v60 register...
#define R0 v60.reg[0]
#define R1 v60.reg[1]
#define R2 v60.reg[2]
#define R3 v60.reg[3]
#define R4 v60.reg[4]
#define R5 v60.reg[5]
#define R6 v60.reg[6]
#define R7 v60.reg[7]
#define R8 v60.reg[8]
#define R9 v60.reg[9]
#define R10 v60.reg[10]
#define R11 v60.reg[11]
#define R12 v60.reg[12]
#define R13 v60.reg[13]
#define R14 v60.reg[14]
#define R15 v60.reg[15]
#define R16 v60.reg[16]
#define R17 v60.reg[17]
#define R18 v60.reg[18]
#define R19 v60.reg[19]
#define R20 v60.reg[20]
#define R21 v60.reg[21]
#define R22 v60.reg[22]
#define R23 v60.reg[23]
#define R24 v60.reg[24]
#define R25 v60.reg[25]
#define R26 v60.reg[26]
#define R27 v60.reg[27]
#define R28 v60.reg[28]
#define AP v60.reg[29]
#define FP v60.reg[30]
#define SP v60.reg[31]

#define PC		v60.reg[32]
#define PSW		v60.reg[33]

// Privileged registers
#define ISP		v60.reg[36]
#define L0SP	v60.reg[37]
#define L1SP	v60.reg[38]
#define L2SP	v60.reg[39]
#define L3SP	v60.reg[40]
#define SBR		v60.reg[41]
#define TR		v60.reg[42]
#define SYCW	v60.reg[43]
#define TKCW	v60.reg[44]
#define PIR		v60.reg[45]
//10-14 reserved
#define PSW2	v60.reg[51]
#define ATBR0	v60.reg[52]
#define ATLR0	v60.reg[53]
#define ATBR1	v60.reg[54]
#define ATLR1	v60.reg[55]
#define ATBR2	v60.reg[56]
#define ATLR2	v60.reg[57]
#define ATBR3	v60.reg[58]
#define ATLR3	v60.reg[59]
#define TRMODE v60.reg[60]
#define ADTR0	v60.reg[61]
#define ADTR1	v60.reg[62]
#define ADTMR0	v60.reg[63]
#define ADTMR1	v60.reg[64]
//29-31 reserved

// Register names
const char *const v60_reg_names[69] = {
	"R0", "R1", "R2", "R3",
	"R4", "R5", "R6", "R7",
	"R8", "R9", "R10", "R11",
	"R12", "R13", "R14", "R15",
	"R16", "R17", "R18", "R19",
	"R20", "R21", "R22", "R23",
	"R24", "R25", "R26", "R27",
	"R28", "AP", "FP", "SP",
	"PC", "PSW","Unk","Unk",
	"ISP", "L0SP", "L1SP", "L2SP",
	"L3SP", "SBR","TR","SYCW",
	"TKCW", "PIR", "Reserved","Reserved",
	"Reserved","Reserved","Reserved","PSW2",
	"ATBR0", "ATLR0", "ATBR1", "ATLR1",
	"ATBR2", "ATLR2", "ATBR3", "ATLR3",
	"TRMODE", "ADTR0", "ADTR1","ADTMR0",
	"ADTMR1","Reserved","Reserved","Reserved"
};

// Defines...
#define NORMALIZEFLAGS() \
{ \
	_S	= _S  ? 1 : 0; \
	_OV	= _OV ? 1 : 0; \
	_Z	= _Z  ? 1 : 0; \
	_CY	= _CY ? 1 : 0; \
}

static void v60_try_irq(void);


INLINE void v60SaveStack(void)
{
	if (PSW & 0x10000000)
		ISP = SP;
	else
		v60.reg[37 + ((PSW >> 24) & 3)] = SP;
}

INLINE void v60ReloadStack(void)
{
	if (PSW & 0x10000000)
		SP = ISP;
	else
		SP = v60.reg[37 + ((PSW >> 24) & 3)];
}

INLINE UINT32 v60ReadPSW(void)
{
	PSW &= 0xfffffff0;
	PSW |= (_Z?1:0) | (_S?2:0) | (_OV?4:0) | (_CY?8:0);
	return PSW;
}

INLINE void v60WritePSW(UINT32 newval)
{
	/* determine if we need to save/restore the stacks */
	int updateStack = 0;

	/* if the interrupt state is changing, we definitely need to update */
	if ((newval ^ PSW) & 0x10000000)
		updateStack = 1;

	/* if we are not in interrupt mode and the level is changing, we also must update */
	else if (!(PSW & 0x10000000) && ((newval ^ PSW) & 0x03000000))
		updateStack = 1;

	/* save the previous stack value */
	if (updateStack)
		v60SaveStack();

	/* set the new value and update the flags */
	PSW = newval;
	_Z =  (UINT8)(PSW & 1);
	_S =  (UINT8)(PSW & 2);
	_OV = (UINT8)(PSW & 4);
	_CY = (UINT8)(PSW & 8);

	/* fetch the new stack value */
	if (updateStack)
		v60ReloadStack();
}


INLINE UINT32 v60_update_psw_for_exception(int is_interrupt, int target_level)
{
	UINT32 oldPSW = v60ReadPSW();
	UINT32 newPSW = oldPSW;

	// Change to interrupt context
	newPSW &= ~(3 << 24);  // PSW.EL = 0
	newPSW |= target_level << 24; // set target level
	newPSW &= ~(1 << 18);  // PSW.IE = 0
	newPSW &= ~(1 << 16);  // PSW.TE = 0
	newPSW &= ~(1 << 27);  // PSW.TP = 0
	newPSW &= ~(1 << 17);  // PSW.AE = 0
	newPSW &= ~(1 << 29);  // PSW.EM = 0
	if (is_interrupt)
		newPSW |=  (1 << 28);// PSW.IS = 1
	newPSW |=  (1 << 31);  // PSW.ASA = 1
	v60WritePSW(newPSW);

	return oldPSW;
}


#define GETINTVECT(nint)	MemRead32((SBR & ~0xfff) + (nint)*4)
#define EXCEPTION_CODE_AND_SIZE(code, size)	(((code) << 16) | (size))


// Addressing mode decoding functions
#include "am.c"

// Opcode functions
#include "op12.c"
#include "op2.c"
#include "op3.c"
#include "op4.c"
#include "op5.c"
#include "op6.c"
#include "op7a.c"

static UINT32 opUNHANDLED(void)
{
	fatalerror("Unhandled OpCode found : %02x at %08x", OpRead16(PC), PC);
	return 0; /* never reached, fatalerror won't return */
}

// Opcode jump table
#include "optable.c"

#ifdef UNUSED_FUNCTION
static int v60_default_irq_cb(int irqline)
{
	return 0;
}
#endif

static void base_init(const char *type, int index, int (*irqcallback)(int))
{
	v60_stall_io = 0;
	v60.irq_cb = irqcallback;
	v60.irq_line = CLEAR_LINE;
	v60.nmi_line = CLEAR_LINE;

	state_save_register_item_array(type, index, v60.reg);
	state_save_register_item(type, index, v60.irq_line);
	state_save_register_item(type, index, v60.nmi_line);
	state_save_register_item(type, index, v60.PPC);
	state_save_register_item(type, index, _CY);
	state_save_register_item(type, index, _OV);
	state_save_register_item(type, index, _S);
	state_save_register_item(type, index, _Z);
}

static void v60_init(int index, int clock, const void *config, int (*irqcallback)(int))
{
	base_init("v60", index, irqcallback);
	// Set PIR (Processor ID) for NEC v60. LSB is reserved to NEC,
	// so I don't know what it contains.
	PIR = 0x00006000;
	v60.info = v60_i;
}

static void v70_init(int index, int clock, const void *config, int (*irqcallback)(int))
{
	base_init("v70", index, irqcallback);
	// Set PIR (Processor ID) for NEC v70. LSB is reserved to NEC,
	// so I don't know what it contains.
	PIR = 0x00007000;
	v60.info = v70_i;
}

static void v60_reset(void)
{
	PSW		= 0x10000000;
	PC		= v60.info.start_pc;
	SBR		= 0x00000000;
	SYCW	= 0x00000070;
	TKCW	= 0x0000e000;
	PSW2	= 0x0000f002;
	ChangePC(PC);

	_CY	= 0;
	_OV	= 0;
	_S	= 0;
	_Z	= 0;
}

static void v60_exit(void)
{
}

void v60_stall(void)
{
	v60_stall_io = 1;
}

static void v60_do_irq(int vector)
{
	UINT32 oldPSW = v60_update_psw_for_exception(1, 0);

	// Push PC and PSW onto the stack
	SP-=4;
	MemWrite32(SP, oldPSW);
	SP-=4;
	MemWrite32(SP, PC);

	// Jump to vector for user interrupt
	PC = GETINTVECT(vector);
}

static void v60_try_irq(void)
{
	if(v60.irq_line == CLEAR_LINE)
		return;
	if((PSW & (1<<18)) != 0) {
		int vector;
		if(v60.irq_line != ASSERT_LINE)
			v60.irq_line = CLEAR_LINE;

		vector = v60.irq_cb(0);

		v60_do_irq(vector + 0x40);
	} else if(v60.irq_line == PULSE_LINE)
		v60.irq_line = CLEAR_LINE;
}

static void set_irq_line(int irqline, int state)
{
	if(irqline == INPUT_LINE_NMI) {
		switch(state) {
		case ASSERT_LINE:
			if(v60.nmi_line == CLEAR_LINE) {
				v60.nmi_line = ASSERT_LINE;
				v60_do_irq(2);
			}
			break;
		case CLEAR_LINE:
			v60.nmi_line = CLEAR_LINE;
			break;
		case HOLD_LINE:
		case PULSE_LINE:
			v60.nmi_line = CLEAR_LINE;
			v60_do_irq(2);
			break;
		}
	} else {
		v60.irq_line = state;
		v60_try_irq();
	}
}

// Actual cycles/instruction is unknown

static int v60_execute(int cycles)
{
	UINT32 inc;

	v60_ICount = cycles;
	if(v60.irq_line != CLEAR_LINE)
		v60_try_irq();
	while(v60_ICount >= 0) {
		v60.PPC = PC;
		CALL_MAME_DEBUG;
		v60_ICount -= 8;	/* fix me -- this is just an average */
		inc = OpCodeTable[OpRead8(PC)]();
		PC += inc;
		if(v60.irq_line != CLEAR_LINE)
			v60_try_irq();
	}

	return cycles - v60_ICount;
}

static void v60_get_context(void *dst)
{
	if(dst)
		*(struct v60info *)dst = v60;
}

static void v60_set_context(void *src)
{
	if(src)
	{
		v60 = *(struct v60info *)src;
		ChangePC(PC);
	}
}


#ifdef MAME_DEBUG
offs_t v60_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
offs_t v70_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
#endif /* MAME_DEBUG */


/**************************************************************************
 * Generic set_info
 **************************************************************************/

static void v60_set_info(UINT32 state, cpuinfo *info)
{
	switch (state)
	{
		/* --- the following bits of info are set as 64-bit signed integers --- */
		case CPUINFO_INT_INPUT_STATE + 0:				set_irq_line(0, info->i);				break;
		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:	set_irq_line(INPUT_LINE_NMI, info->i);	break;

		case CPUINFO_INT_PC:							PC = info->i; ChangePC(PC);				break;
		case CPUINFO_INT_SP:							SP = info->i;							break;

		case CPUINFO_INT_REGISTER + V60_R0:				R0 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R1:				R1 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R2:				R2 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R3:				R3 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R4:				R4 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R5:				R5 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R6:				R6 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R7:				R7 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R8:				R8 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R9:				R9 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R10:			R10 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R11:			R11 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R12:			R12 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R13:			R13 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R14:			R14 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R15:			R15 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R16:			R16 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R17:			R17 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R18:			R18 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R19:			R19 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R20:			R20 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R21:			R21 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R22:			R22 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R23:			R23 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R24:			R24 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R25:			R25 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R26:			R26 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R27:			R27 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_R28:			R28 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_AP:				AP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_FP:				FP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_SP:				SP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_PC:				PC = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_PSW:			v60WritePSW(info->i);					break;
		case CPUINFO_INT_REGISTER + V60_ISP:			ISP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_L0SP:			L0SP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_L1SP:			L1SP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_L2SP:			L2SP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_L3SP:			L3SP = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_SBR:			SBR = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_TR:				TR = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_SYCW:			SYCW = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_TKCW:			TKCW = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_PIR:			PIR = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_PSW2:			PSW2 = info->i;							break;
		case CPUINFO_INT_REGISTER + V60_ATBR0:			ATBR0 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR0:			ATLR0 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATBR1:			ATBR1 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR1:			ATLR1 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATBR2:			ATBR2 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR2:			ATLR2 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATBR3:			ATBR3 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR3:			ATLR3 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_TRMODE:			TRMODE = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ADTR0:			ADTR0 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ADTR1:			ADTR1 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ADTMR0:			ADTMR0 = info->i;						break;
		case CPUINFO_INT_REGISTER + V60_ADTMR1:			ADTMR1 = info->i;						break;
	}
}



/**************************************************************************
 * Generic get_info
 **************************************************************************/

void v60_get_info(UINT32 state, cpuinfo *info)
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CONTEXT_SIZE:					info->i = sizeof(v60);					break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 1;							break;
		case CPUINFO_INT_DEFAULT_IRQ_VECTOR:			info->i = 0;							break;
		case CPUINFO_INT_ENDIANNESS:					info->i = CPU_IS_LE;					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 = 22;							break;
		case CPUINFO_INT_MIN_CYCLES:					info->i = 1;							break;
		case CPUINFO_INT_MAX_CYCLES:					info->i = 1;							break;

		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 16;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24;					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 = 16;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: 		info->i = 24;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: 		info->i = 0;					break;

		case CPUINFO_INT_INPUT_STATE + 0:				info->i = v60.irq_line;					break;
		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:	info->i = v60.nmi_line;					break;

		case CPUINFO_INT_PREVIOUSPC:					info->i = v60.PPC;						break;

		case CPUINFO_INT_REGISTER + V60_R0:				info->i = R0;							break;
		case CPUINFO_INT_REGISTER + V60_R1:				info->i = R1;							break;
		case CPUINFO_INT_REGISTER + V60_R2:				info->i = R2;							break;
		case CPUINFO_INT_REGISTER + V60_R3:				info->i = R3;							break;
		case CPUINFO_INT_REGISTER + V60_R4:				info->i = R4;							break;
		case CPUINFO_INT_REGISTER + V60_R5:				info->i = R5;							break;
		case CPUINFO_INT_REGISTER + V60_R6:				info->i = R6;							break;
		case CPUINFO_INT_REGISTER + V60_R7:				info->i = R7;							break;
		case CPUINFO_INT_REGISTER + V60_R8:				info->i = R8;							break;
		case CPUINFO_INT_REGISTER + V60_R9:				info->i = R9;							break;
		case CPUINFO_INT_REGISTER + V60_R10:			info->i = R10;							break;
		case CPUINFO_INT_REGISTER + V60_R11:			info->i = R11;							break;
		case CPUINFO_INT_REGISTER + V60_R12:			info->i = R12;							break;
		case CPUINFO_INT_REGISTER + V60_R13:			info->i = R13;							break;
		case CPUINFO_INT_REGISTER + V60_R14:			info->i = R14;							break;
		case CPUINFO_INT_REGISTER + V60_R15:			info->i = R15;							break;
		case CPUINFO_INT_REGISTER + V60_R16:			info->i = R16;							break;
		case CPUINFO_INT_REGISTER + V60_R17:			info->i = R17;							break;
		case CPUINFO_INT_REGISTER + V60_R18:			info->i = R18;							break;
		case CPUINFO_INT_REGISTER + V60_R19:			info->i = R19;							break;
		case CPUINFO_INT_REGISTER + V60_R20:			info->i = R20;							break;
		case CPUINFO_INT_REGISTER + V60_R21:			info->i = R21;							break;
		case CPUINFO_INT_REGISTER + V60_R22:			info->i = R22;							break;
		case CPUINFO_INT_REGISTER + V60_R23:			info->i = R23;							break;
		case CPUINFO_INT_REGISTER + V60_R24:			info->i = R24;							break;
		case CPUINFO_INT_REGISTER + V60_R25:			info->i = R25;							break;
		case CPUINFO_INT_REGISTER + V60_R26:			info->i = R26;							break;
		case CPUINFO_INT_REGISTER + V60_R27:			info->i = R27;							break;
		case CPUINFO_INT_REGISTER + V60_R28:			info->i = R28;							break;
		case CPUINFO_INT_REGISTER + V60_AP:				info->i = AP;							break;
		case CPUINFO_INT_REGISTER + V60_FP:				info->i = FP;							break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + V60_SP:				info->i = SP;							break;
		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + V60_PC:				info->i = PC;							break;
		case CPUINFO_INT_REGISTER + V60_PSW:			info->i = v60ReadPSW();					break;
		case CPUINFO_INT_REGISTER + V60_ISP:			info->i = ISP;							break;
		case CPUINFO_INT_REGISTER + V60_L0SP:			info->i = L0SP;							break;
		case CPUINFO_INT_REGISTER + V60_L1SP:			info->i = L1SP;							break;
		case CPUINFO_INT_REGISTER + V60_L2SP:			info->i = L2SP;							break;
		case CPUINFO_INT_REGISTER + V60_L3SP:			info->i = L3SP;							break;
		case CPUINFO_INT_REGISTER + V60_SBR:			info->i = SBR;							break;
		case CPUINFO_INT_REGISTER + V60_TR:				info->i = TR;							break;
		case CPUINFO_INT_REGISTER + V60_SYCW:			info->i = SYCW;							break;
		case CPUINFO_INT_REGISTER + V60_TKCW:			info->i = TKCW;							break;
		case CPUINFO_INT_REGISTER + V60_PIR:			info->i = PIR;							break;
		case CPUINFO_INT_REGISTER + V60_PSW2:			info->i = PSW2;							break;
		case CPUINFO_INT_REGISTER + V60_ATBR0:			info->i = ATBR0;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR0:			info->i = ATLR0;						break;
		case CPUINFO_INT_REGISTER + V60_ATBR1:			info->i = ATBR1;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR1:			info->i = ATLR1;						break;
		case CPUINFO_INT_REGISTER + V60_ATBR2:			info->i = ATBR2;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR2:			info->i = ATLR2;						break;
		case CPUINFO_INT_REGISTER + V60_ATBR3:			info->i = ATBR3;						break;
		case CPUINFO_INT_REGISTER + V60_ATLR3:			info->i = ATLR3;						break;
		case CPUINFO_INT_REGISTER + V60_TRMODE:			info->i = TRMODE;						break;
		case CPUINFO_INT_REGISTER + V60_ADTR0:			info->i = ADTR0;						break;
		case CPUINFO_INT_REGISTER + V60_ADTR1:			info->i = ADTR1;						break;
		case CPUINFO_INT_REGISTER + V60_ADTMR0:			info->i = ADTMR0;						break;
		case CPUINFO_INT_REGISTER + V60_ADTMR1:			info->i = ADTMR1;						break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_PTR_SET_INFO:						info->setinfo = v60_set_info;			break;
		case CPUINFO_PTR_GET_CONTEXT:					info->getcontext = v60_get_context;		break;
		case CPUINFO_PTR_SET_CONTEXT:					info->setcontext = v60_set_context;		break;
		case CPUINFO_PTR_INIT:							info->init = v60_init;					break;
		case CPUINFO_PTR_RESET:							info->reset = v60_reset;				break;
		case CPUINFO_PTR_EXIT:							info->exit = v60_exit;					break;
		case CPUINFO_PTR_EXECUTE:						info->execute = v60_execute;			break;
		case CPUINFO_PTR_BURN:							info->burn = NULL;						break;
#ifdef MAME_DEBUG
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = v60_dasm;			break;
#endif /* MAME_DEBUG */
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &v60_ICount;				break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s, "V60");					break;
		case CPUINFO_STR_CORE_FAMILY:					strcpy(info->s, "NEC V60");				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, "Farfetch'd and R.Belmont"); break;

		case CPUINFO_STR_FLAGS:							strcpy(info->s, " ");					break;

		case CPUINFO_STR_REGISTER + V60_R0:				sprintf(info->s, "R0:%08X", R0);		break;
		case CPUINFO_STR_REGISTER + V60_R1:				sprintf(info->s, "R1:%08X", R1);		break;
		case CPUINFO_STR_REGISTER + V60_R2:				sprintf(info->s, "R2:%08X", R2);		break;
		case CPUINFO_STR_REGISTER + V60_R3:				sprintf(info->s, "R3:%08X", R3);		break;
		case CPUINFO_STR_REGISTER + V60_R4:				sprintf(info->s, "R4:%08X", R4);		break;
		case CPUINFO_STR_REGISTER + V60_R5:				sprintf(info->s, "R5:%08X", R5);		break;
		case CPUINFO_STR_REGISTER + V60_R6:				sprintf(info->s, "R6:%08X", R6);		break;
		case CPUINFO_STR_REGISTER + V60_R7:				sprintf(info->s, "R7:%08X", R7);		break;
		case CPUINFO_STR_REGISTER + V60_R8:				sprintf(info->s, "R8:%08X", R8);		break;
		case CPUINFO_STR_REGISTER + V60_R9:				sprintf(info->s, "R9:%08X", R9);		break;
		case CPUINFO_STR_REGISTER + V60_R10:			sprintf(info->s, "R10:%08X", R10);		break;
		case CPUINFO_STR_REGISTER + V60_R11:			sprintf(info->s, "R11:%08X", R11);		break;
		case CPUINFO_STR_REGISTER + V60_R12:			sprintf(info->s, "R12:%08X", R12);		break;
		case CPUINFO_STR_REGISTER + V60_R13:			sprintf(info->s, "R13:%08X", R13);		break;
		case CPUINFO_STR_REGISTER + V60_R14:			sprintf(info->s, "R14:%08X", R14);		break;
		case CPUINFO_STR_REGISTER + V60_R15:			sprintf(info->s, "R15:%08X", R15);		break;
		case CPUINFO_STR_REGISTER + V60_R16:			sprintf(info->s, "R16:%08X", R16);		break;
		case CPUINFO_STR_REGISTER + V60_R17:			sprintf(info->s, "R17:%08X", R17);		break;
		case CPUINFO_STR_REGISTER + V60_R18:			sprintf(info->s, "R18:%08X", R18);		break;
		case CPUINFO_STR_REGISTER + V60_R19:			sprintf(info->s, "R19:%08X", R19);		break;
		case CPUINFO_STR_REGISTER + V60_R20:			sprintf(info->s, "R20:%08X", R20);		break;
		case CPUINFO_STR_REGISTER + V60_R21:			sprintf(info->s, "R21:%08X", R21);		break;
		case CPUINFO_STR_REGISTER + V60_R22:			sprintf(info->s, "R22:%08X", R22);		break;
		case CPUINFO_STR_REGISTER + V60_R23:			sprintf(info->s, "R23:%08X", R23);		break;
		case CPUINFO_STR_REGISTER + V60_R24:			sprintf(info->s, "R24:%08X", R24);		break;
		case CPUINFO_STR_REGISTER + V60_R25:			sprintf(info->s, "R25:%08X", R25);		break;
		case CPUINFO_STR_REGISTER + V60_R26:			sprintf(info->s, "R26:%08X", R26);		break;
		case CPUINFO_STR_REGISTER + V60_R27:			sprintf(info->s, "R27:%08X", R27);		break;
		case CPUINFO_STR_REGISTER + V60_R28:			sprintf(info->s, "R28:%08X", R28);		break;
		case CPUINFO_STR_REGISTER + V60_AP:				sprintf(info->s, "AP:%08X", AP);		break;
		case CPUINFO_STR_REGISTER + V60_FP:				sprintf(info->s, "FP:%08X", FP);		break;
		case CPUINFO_STR_REGISTER + V60_SP:				sprintf(info->s, "SP:%08X", SP);		break;
		case CPUINFO_STR_REGISTER + V60_PC:				sprintf(info->s, "PC:%08X", PC);		break;
		case CPUINFO_STR_REGISTER + V60_PSW:			sprintf(info->s, "PSW:%08X", v60ReadPSW()); break;
		case CPUINFO_STR_REGISTER + V60_ISP:			sprintf(info->s, "ISP:%08X", ISP);		break;
		case CPUINFO_STR_REGISTER + V60_L0SP:			sprintf(info->s, "L0SP:%08X", L0SP);	break;
		case CPUINFO_STR_REGISTER + V60_L1SP:			sprintf(info->s, "L1SP:%08X", L1SP);	break;
		case CPUINFO_STR_REGISTER + V60_L2SP:			sprintf(info->s, "L2SP:%08X", L2SP);	break;
		case CPUINFO_STR_REGISTER + V60_L3SP:			sprintf(info->s, "L3SP:%08X", L3SP);	break;
		case CPUINFO_STR_REGISTER + V60_SBR:			sprintf(info->s, "SBR:%08X", SBR);		break;
		case CPUINFO_STR_REGISTER + V60_TR:				sprintf(info->s, "TR:%08X", TR);		break;
		case CPUINFO_STR_REGISTER + V60_SYCW:			sprintf(info->s, "SYCW:%08X", SYCW);	break;
		case CPUINFO_STR_REGISTER + V60_TKCW:			sprintf(info->s, "TKCW:%08X", TKCW);	break;
		case CPUINFO_STR_REGISTER + V60_PIR:			sprintf(info->s, "PIR:%08X", PIR);		break;
		case CPUINFO_STR_REGISTER + V60_PSW2:			sprintf(info->s, "PSW2:%08X", PSW2);	break;
		case CPUINFO_STR_REGISTER + V60_ATBR0:			sprintf(info->s, "ATBR0:%08X", ATBR0);	break;
		case CPUINFO_STR_REGISTER + V60_ATLR0:			sprintf(info->s, "ATLR0:%08X", ATLR0);	break;
		case CPUINFO_STR_REGISTER + V60_ATBR1:			sprintf(info->s, "ATBR1:%08X", ATBR1);	break;
		case CPUINFO_STR_REGISTER + V60_ATLR1:			sprintf(info->s, "ATLR1:%08X", ATLR1);	break;
		case CPUINFO_STR_REGISTER + V60_ATBR2:			sprintf(info->s, "ATBR2:%08X", ATBR2);	break;
		case CPUINFO_STR_REGISTER + V60_ATLR2:			sprintf(info->s, "ATLR2:%08X", ATLR2);	break;
		case CPUINFO_STR_REGISTER + V60_ATBR3:			sprintf(info->s, "ATBR3:%08X", ATBR3);	break;
		case CPUINFO_STR_REGISTER + V60_ATLR3:			sprintf(info->s, "ATLR3:%08X", ATLR3);	break;
		case CPUINFO_STR_REGISTER + V60_TRMODE:			sprintf(info->s, "TRMODE:%08X", TRMODE); break;
		case CPUINFO_STR_REGISTER + V60_ADTR0:			sprintf(info->s, "ADTR0:%08X", ADTR0);	break;
		case CPUINFO_STR_REGISTER + V60_ADTR1:			sprintf(info->s, "ADTR1:%08X", ADTR1);	break;
		case CPUINFO_STR_REGISTER + V60_ADTMR0:			sprintf(info->s, "ADTMR0:%08X", ADTMR0); break;
		case CPUINFO_STR_REGISTER + V60_ADTMR1:			sprintf(info->s, "ADTMR1:%08X", ADTMR1); break;
	}
}


/**************************************************************************
 * CPU-specific set_info
 **************************************************************************/

void v70_get_info(UINT32 state, cpuinfo *info)
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 32;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0;					break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_PTR_INIT:							info->init = v70_init;					break;
#ifdef MAME_DEBUG
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = v70_dasm;			break;
#endif /* MAME_DEBUG */

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s, "V70");					break;

		default:										v60_get_info(state, info);				break;
	}
}
