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

#include "driver.h"	/* needed for hack below. */
#include "cpuintrf.h"
#include "osd_cpu.h"
#include "mamedbg.h"
#include "state.h"

#include <assert.h>
#include <stdio.h>
#include <stdarg.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)

/* Ultra Function Tables */
static UINT32 (*OpCodeTable[256])(void);

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

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

static int v60_ICount;

/*
 * 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]

#define PPC		v60.PPC

/* 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 */
#define TCB		v60.tcb

/* Register names */
const char *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",
	"TCB"
};

/* Defines... */
#define UPDATEPSW()	\
{ \
  PSW &= 0xfffffff0; \
  PSW |= (_Z?1:0) | (_S?2:0) | (_OV?4:0) | (_CY?8:0); \
}

#define UPDATECPUFLAGS() \
{ \
	_Z =  (UINT8)(PSW & 1); \
	_S =  (UINT8)(PSW & 2); \
	_OV = (UINT8)(PSW & 4); \
	_CY = (UINT8)(PSW & 8); \
}

#define UPDATEFPUFLAGS()	{ }

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

static void v60_try_irq(void);

#define STACK_REG(IS,EL)	((IS)==0?37+(EL):36)

static UINT32 v60ReadPSW(void)
{
	v60.reg[STACK_REG((v60.reg[33]>>28)&1, (v60.reg[33]>>24)&3)] = SP;
	UPDATEPSW();
	return PSW;
}

static void v60ReloadStack(void)
{
	SP = v60.reg[STACK_REG((v60.reg[33]>>28)&1, (v60.reg[33]>>24)&3)];
}

static void v60WritePSW(UINT32 newval)
{
	UINT32 oldval = v60ReadPSW();
	int oldIS, newIS, oldEL, newEL;

	PSW = newval;
	UPDATECPUFLAGS();

	/* Now check if we must swap SP */
	oldIS = (oldval >> 28) & 1;
	newIS = (newval >> 28) & 1;

	oldEL = (oldval >> 24) & 3;
	newEL = (newval >> 24) & 3;

	if (oldIS != newIS)
	{
		v60.reg[STACK_REG(oldIS,oldEL)] = SP;
		SP = v60.reg[STACK_REG(newIS,newEL)];
	}
}

#define GETINTVECT(nint)	MemRead32(SBR + (nint)*4)


/* 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"

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

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

static int v60_default_irq_cb(int irqline)
{
	return 0;
}

static void base_init(const char *type)
{
	int cpu = cpu_getactivecpu();
	static int opt_init = 0;
	if(!opt_init) {
		InitTables();	/* set up opcode tables */
#ifdef MAME_DEBUG
		v60_dasm_init();
#endif
		opt_init = 1;
	}

	v60.irq_cb = v60_default_irq_cb;
	v60.irq_line = CLEAR_LINE;
	v60.nmi_line = CLEAR_LINE;

	state_save_register_UINT32(type, cpu, "reg",       v60.reg, 68);
	state_save_register_UINT32(type, cpu, "tcb",      &v60.tcb, 1);
	state_save_register_int   (type, cpu, "irq_line", &v60.irq_line);
	state_save_register_int   (type, cpu, "nmi_line", &v60.nmi_line);
	state_save_register_UINT32(type, cpu, "ppc",      &PPC, 1);
	state_save_register_UINT8 (type, cpu, "f.cy",     &_CY, 1);
	state_save_register_UINT8 (type, cpu, "f.ov",     &_OV, 1);
	state_save_register_UINT8 (type, cpu, "f.f",      &_S, 1);
	state_save_register_UINT8 (type, cpu, "f.z",      &_Z, 1);
}

void v60_init(void)
{
	base_init("v60");
	/* 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;
}

void v70_init(void)
{
	base_init("v70");
	/* 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;
}

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

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

void v60_exit(void)
{
}


static void v60_do_irq(int vector)
{
	UINT32 tempPSW;
	UPDATEPSW();
	tempPSW=PSW;

	/* this is quite a horrible hack, if we do this then srmp7 breaks,
       if we don't then ultrax/twineag2 are broken, a real fix is needed */
	if (!strcmp(Machine->gamedrv->name,"ultrax") ||	/* from Mame32Plus */
	    !strcmp(Machine->gamedrv->name,"twineag2"))
		v60WritePSW(PSW|((1<<28)));

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

	/* Change to interrupt context */
	PSW &= ~(3 << 24);  /* PSW.EL = 0 */
	PSW &= ~(1 << 18);  /* PSW.IE = 0 */
	PSW &= ~(1 << 16);  /* PSW.TE = 0 */
	PSW &= ~(1 << 27);  /* PSW.TP = 0 */
	PSW &= ~(1 << 17);  /* PSW.AE = 0 */
	PSW &= ~(1 << 29);  /* PSW.EM = 0 */
	PSW |=  (1 << 31);  /* PSW.ASA = 1 */

	/* 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)
{
	v60_ICount = cycles;
	if(v60.irq_line != CLEAR_LINE)
		v60_try_irq();
	while(v60_ICount >= 0) {
		PPC = PC;
		CALL_MAME_DEBUG;
		v60_ICount--;
		PC += OpCodeTable[OpRead8(PC)]();
		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);
	}
}

static UINT8 v60_reg_layout[] = {
	V60_PC, V60_TR, -1,
	-1,
	V60_R0, V60_R1, -1,
	V60_R2, V60_R3, -1,
	V60_R4, V60_R5, -1,
	V60_R6, V60_R7, -1,
	V60_R8, V60_R9, -1,
	V60_R10, V60_R11, -1,
	V60_R12, V60_R13, -1,
	V60_R14, V60_R15, -1,
	V60_R16, V60_R17, -1,
	V60_R18, V60_R19, -1,
	V60_R20, V60_R21, -1,
	V60_R22, V60_R23, -1,
	V60_R24, V60_R25, -1,
	V60_R26, V60_R27, -1,
	V60_R28, V60_AP, -1,
	V60_FP, V60_SP, -1,
	-1,
	V60_SBR, V60_ISP, -1,
	V60_L0SP, V60_L1SP, -1,
	V60_L2SP, V60_L3SP, -1,
	V60_TCB, V60_PSW, 0
};

static UINT8 v60_win_layout[] = {
	45, 0,35,13,	/* register window (top right) */
	 0, 0,44,13,	/* disassembler window (left, upper) */
	 0,14,44, 8,	/* memory #1 window (left, middle) */
	45,14,35, 8,	/* memory #2 window (lower) */
	 0,23,80, 1 	/* command line window (bottom rows) */
};


#ifndef MAME_DEBUG
static offs_t v60_dasm(char *buffer,  offs_t pc)
{
	sprintf(buffer, "$%02X", program_read_byte_16le(pc));
	return 1;
}

static offs_t v70_dasm(char *buffer,  offs_t pc)
{
	sprintf(buffer, "$%02X", program_read_byte_32le(pc));
	return 1;
}
#else
offs_t v60_dasm(char *buffer,  offs_t pc);
offs_t v70_dasm(char *buffer,  offs_t pc);
#endif



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

static void v60_set_info(UINT32 state, union 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:			PSW = 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;
		case CPUINFO_INT_REGISTER + V60_TCB:			TCB = info->i;							break;

		/* --- the following bits of info are set as pointers to data or functions --- */
		case CPUINFO_PTR_IRQ_CALLBACK:					v60.irq_cb = info->irqcallback;			break;
	}
}



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

void v60_get_info(UINT32 state, union 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 = 2;							break;
		case CPUINFO_INT_MAX_INSTRUCTION_BYTES:			info->i = 11;							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 = 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 = PSW;							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;
		case CPUINFO_INT_REGISTER + V60_TCB:			info->i = TCB;							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;
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = v60_dasm;			break;
		case CPUINFO_PTR_IRQ_CALLBACK:					info->irqcallback = v60.irq_cb;			break;
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &v60_ICount;				break;
		case CPUINFO_PTR_REGISTER_LAYOUT:				info->p = v60_reg_layout;				break;
		case CPUINFO_PTR_WINDOW_LAYOUT:					info->p = v60_win_layout;				break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s = cpuintrf_temp_str(), "V60"); break;
		case CPUINFO_STR_CORE_FAMILY:					strcpy(info->s = cpuintrf_temp_str(), "NEC V60"); break;
		case CPUINFO_STR_CORE_VERSION:					strcpy(info->s = cpuintrf_temp_str(), "1.0"); break;
		case CPUINFO_STR_CORE_FILE:						strcpy(info->s = cpuintrf_temp_str(), __FILE__); break;
		case CPUINFO_STR_CORE_CREDITS:					strcpy(info->s = cpuintrf_temp_str(), "Farfetch'd and R.Belmont"); break;

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

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


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

void v70_get_info(UINT32 state, union 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;
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = v70_dasm;			break;

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

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