/***************************************************************************

    tms32031.c
    Core implementation for the portable TMS32C031 emulator.
    Written by Aaron Giles

***************************************************************************/

#include "debugger.h"
#include "tms32031.h"
#include "eminline.h"


#define LOG_OPCODE_USAGE	(0)


/***************************************************************************
    CONSTANTS
***************************************************************************/

enum
{
	TMR_R0 = 0,
	TMR_R1,
	TMR_R2,
	TMR_R3,
	TMR_R4,
	TMR_R5,
	TMR_R6,
	TMR_R7,
	TMR_AR0,
	TMR_AR1,
	TMR_AR2,
	TMR_AR3,
	TMR_AR4,
	TMR_AR5,
	TMR_AR6,
	TMR_AR7,
	TMR_DP,
	TMR_IR0,
	TMR_IR1,
	TMR_BK,
	TMR_SP,
	TMR_ST,
	TMR_IE,
	TMR_IF,
	TMR_IOF,
	TMR_RS,
	TMR_RE,
	TMR_RC,
	TMR_R8,		/* 3204x only */
	TMR_R9,		/* 3204x only */
	TMR_R10,	/* 3204x only */
	TMR_R11,	/* 3204x only */
	TMR_TEMP1,	/* used by the interpreter */
	TMR_TEMP2,	/* used by the interpreter */
	TMR_TEMP3	/* used by the interpreter */
};

#define CFLAG		0x0001
#define VFLAG		0x0002
#define ZFLAG		0x0004
#define NFLAG		0x0008
#define UFFLAG		0x0010
#define LVFLAG		0x0020
#define LUFFLAG		0x0040
#define OVMFLAG		0x0080
#define RMFLAG		0x0100
#define CFFLAG		0x0400
#define CEFLAG		0x0800
#define CCFLAG		0x1000
#define GIEFLAG		0x2000

#define IREG(rnum)			(tms32031.r[rnum].i32[0])



/***************************************************************************
    STRUCTURES & TYPEDEFS
***************************************************************************/

union genreg
{
	UINT32		i32[2];
	UINT16		i16[4];
	UINT8		i8[8];
};

/* TMS34031 Registers */
typedef struct
{
	/* core registers */
	UINT32			pc;
	union genreg	r[36];
	UINT32			bkmask;

	/* internal stuff */
	UINT32			ppc;
	UINT32			op;
	UINT8			delayed;
	UINT8			irq_pending;
	UINT8			mcu_mode;
	UINT8			is_idling;
	int				interrupt_cycles;

	UINT32			bootoffset;
	void			(*xf0_w)(UINT8 val);
	void			(*xf1_w)(UINT8 val);
	void			(*iack_w)(UINT8 val, offs_t addr);
	int				(*irq_callback)(int state);
} tms32031_regs;



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

static void trap(int trapnum);
static UINT32 boot_loader(UINT32 boot_rom_addr);



/***************************************************************************
    PUBLIC GLOBAL VARIABLES
***************************************************************************/

static int	tms32031_icount;



/***************************************************************************
    PRIVATE GLOBAL VARIABLES
***************************************************************************/

static tms32031_regs tms32031;



/***************************************************************************
    MEMORY ACCESSORS
***************************************************************************/

#define ROPCODE(pc)		cpu_readop32((pc) << 2)
#define OP				tms32031.op

#define RMEM(addr)		program_read_dword_32le((addr) << 2)
#define WMEM(addr,data)	program_write_dword_32le((addr) << 2, data)
#define UPDATEPC(addr)	change_pc((addr) << 2)



/***************************************************************************
    HELPER MACROS
***************************************************************************/

#define MANTISSA(r)			((INT32)(r)->i32[0])
#define EXPONENT(r)			((INT8)(r)->i32[1])
#define SET_MANTISSA(r,v)	((r)->i32[0] = (v))
#define SET_EXPONENT(r,v)	((r)->i32[1] = (v))

typedef union int_double
{
	double d;
	float f[2];
	UINT32 i[2];
} int_double;


#if 0
static float dsp_to_float(union genreg *fp)
{
	int_double id;

	if (MANTISSA(fp) == 0 && EXPONENT(fp) == -128)
		return 0;
	else if (MANTISSA(fp) >= 0)
	{
		int exponent = (EXPONENT(fp) + 127) << 23;
		id.i[0] = exponent + (MANTISSA(fp) >> 8);
	}
	else
	{
		int exponent = (EXPONENT(fp) + 127) << 23;
		INT32 man = -MANTISSA(fp);
		id.i[0] = 0x80000000 + exponent + ((man >> 8) & 0x00ffffff);
	}
	return id.f[0];
}
#endif


static double dsp_to_double(union genreg *fp)
{
	int_double id;

	if (MANTISSA(fp) == 0 && EXPONENT(fp) == -128)
		return 0;
	else if (MANTISSA(fp) >= 0)
	{
		int exponent = (EXPONENT(fp) + 1023) << 20;
		id.i[BYTE_XOR_BE(0)] = exponent + (MANTISSA(fp) >> 11);
		id.i[BYTE_XOR_BE(1)] = (MANTISSA(fp) << 21) & 0xffe00000;
	}
	else
	{
		int exponent = (EXPONENT(fp) + 1023) << 20;
		INT32 man = -MANTISSA(fp);
		id.i[BYTE_XOR_BE(0)] = 0x80000000 + exponent + ((man >> 11) & 0x001fffff);
		id.i[BYTE_XOR_BE(1)] = (man << 21) & 0xffe00000;
	}
	return id.d;
}


static void double_to_dsp(double val, union genreg *result)
{
	int mantissa, exponent;
	int_double id;
	id.d = val;

	mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xffe00000) >> 21);
	exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023;
	if (exponent < -128)
	{
		SET_MANTISSA(result, 0);
		SET_EXPONENT(result, -128);
	}
	else if (exponent > 127)
	{
		if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
			SET_MANTISSA(result, 0x7fffffff);
		else
			SET_MANTISSA(result, 0x80000001);
		SET_EXPONENT(result, 127);
	}
	else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0)
	{
		SET_MANTISSA(result, mantissa);
		SET_EXPONENT(result, exponent);
	}
	else if (mantissa != 0)
	{
		SET_MANTISSA(result, 0x80000000 | -mantissa);
		SET_EXPONENT(result, exponent);
	}
	else
	{
		SET_MANTISSA(result, 0x80000000);
		SET_EXPONENT(result, exponent - 1);
	}
}



/***************************************************************************
    EXECEPTION HANDLING
***************************************************************************/

INLINE void generate_exception(int exception)
{
}


INLINE void invalid_instruction(UINT32 op)
{
}



/***************************************************************************
    IRQ HANDLING
***************************************************************************/

static void check_irqs(void)
{
	int validints = IREG(TMR_IF) & IREG(TMR_IE) & 0x07ff;
	if (validints && (IREG(TMR_ST) & GIEFLAG))
	{
		int whichtrap = 0;
		int i;

		for (i = 0; i < 11; i++)
			if (validints & (1 << i))
			{
				whichtrap = i + 1;
				break;
			}

		if (whichtrap)
		{
			tms32031.is_idling = 0;
			if (!tms32031.delayed)
			{
				trap(whichtrap);

				/* for internal sources, clear the interrupt when taken */
				if (whichtrap > 4)
					IREG(TMR_IF) &= ~(1 << (whichtrap - 1));
			}
			else
				tms32031.irq_pending = 1;
		}
	}
}


static void set_irq_line(int irqline, int state)
{
	if (irqline < 11)
	{
	    /* update the state */
	    if (state == ASSERT_LINE)
			IREG(TMR_IF) |= 1 << irqline;
		else
			IREG(TMR_IF) &= ~(1 << irqline);

		/* check for IRQs */
	    if (state != CLEAR_LINE)
	    	check_irqs();
	}
}



/***************************************************************************
    CONTEXT SWITCHING
***************************************************************************/

static void tms32031_get_context(void *dst)
{
	/* copy the context */
	if (dst)
		*(tms32031_regs *)dst = tms32031;
}


static void tms32031_set_context(void *src)
{
	/* copy the context */
	if (src)
		tms32031 = *(tms32031_regs *)src;
	UPDATEPC(tms32031.pc);

	/* check for IRQs */
	check_irqs();
}



/***************************************************************************
    INITIALIZATION AND SHUTDOWN
***************************************************************************/

static void tms32031_init(int index, int clock, const void *_config, int (*irqcallback)(int))
{
	const struct tms32031_config *config = _config;
	int i;
	char namebuf[30];

	tms32031.irq_callback = irqcallback;

	/* copy in the xf write routines */
	tms32031.bootoffset = config ? config->bootoffset : 0;
	if (config)
	{
		tms32031.xf0_w = config->xf0_w;
		tms32031.xf1_w = config->xf1_w;
		tms32031.iack_w = config->iack_w;
	}

	state_save_register_item("tms32031", index, tms32031.pc);
	for (i=0;i<36;i++)
	{
		sprintf(namebuf,"tms32031.r[%d]",i);
		state_save_register_generic("tms32031", index, namebuf, tms32031.r[i].i8, UINT8, 8);
	}
	state_save_register_item("tms32031", index, tms32031.bkmask);
	state_save_register_item("tms32031", index, tms32031.ppc);
	state_save_register_item("tms32031", index, tms32031.op);
	state_save_register_item("tms32031", index, tms32031.delayed);
	state_save_register_item("tms32031", index, tms32031.irq_pending);
	state_save_register_item("tms32031", index, tms32031.mcu_mode);
	state_save_register_item("tms32031", index, tms32031.is_idling);
	state_save_register_item("tms32031", index, tms32031.interrupt_cycles);

}

static void tms32031_reset(void)
{
	/* if we have a config struct, get the boot ROM address */
	if (tms32031.bootoffset)
	{
		tms32031.mcu_mode = 1;
		tms32031.pc = boot_loader(tms32031.bootoffset);
	}
	else
	{
		tms32031.mcu_mode = 0;
		tms32031.pc = RMEM(0);
	}

	/* reset some registers */
	IREG(TMR_IE) = 0;
	IREG(TMR_IF) = 0;
	IREG(TMR_ST) = 0;
	IREG(TMR_IOF) = 0;

	/* reset internal stuff */
	tms32031.delayed = tms32031.irq_pending = 0;
	tms32031.is_idling = 0;
}


#if (LOG_OPCODE_USAGE)
static UINT32 hits[0x200*4];
#endif

static void tms32031_exit(void)
{
#if (LOG_OPCODE_USAGE)
	int i;
	for (i = 0; i < 0x200*4; i++)
		if (hits[i])
			mame_printf_debug("%10d - %03X.%X\n", hits[i], i / 4, i % 4);
#endif
}



/***************************************************************************
    CORE OPCODES
***************************************************************************/

#include "32031ops.c"



/***************************************************************************
    CORE EXECUTION LOOP
***************************************************************************/

static int tms32031_execute(int cycles)
{
	/* count cycles and interrupt cycles */
	tms32031_icount = cycles;
	tms32031_icount -= tms32031.interrupt_cycles;
	tms32031.interrupt_cycles = 0;

	/* check IRQs up front */
	check_irqs();

	/* if we're idling, just eat the cycles */
	if (tms32031.is_idling)
		return tms32031_icount;

	while (tms32031_icount > 0)
	{
		if ((IREG(TMR_ST) & RMFLAG) && tms32031.pc == IREG(TMR_RE) + 1)
		{
			if ((INT32)--IREG(TMR_RC) >= 0)
				tms32031.pc = IREG(TMR_RS);
			else
			{
				IREG(TMR_ST) &= ~RMFLAG;
				if (tms32031.delayed)
				{
					tms32031.delayed = 0;
					if (tms32031.irq_pending)
					{
						tms32031.irq_pending = 0;
						check_irqs();
					}
				}
			}
			continue;
		}

		execute_one();
	}

	tms32031_icount -= tms32031.interrupt_cycles;
	tms32031.interrupt_cycles = 0;

	return cycles - tms32031_icount;
}



/***************************************************************************
    DISASSEMBLY HOOK
***************************************************************************/

#ifdef MAME_DEBUG
static offs_t tms32031_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
{
	UINT32 op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);
	extern unsigned dasm_tms32031(char *, unsigned, UINT32);
    return dasm_tms32031(buffer, pc, op);
}
#endif /* MAME_DEBUG */



/***************************************************************************
    BOOT LOADER
***************************************************************************/

static UINT32 boot_loader(UINT32 boot_rom_addr)
{
	UINT32 bits, control, advance;
	UINT32 start_offset = 0;
	UINT32 datamask;
	int first = 1, i;

	/* read the size of the data */
	bits = RMEM(boot_rom_addr);
	if (bits != 8 && bits != 16 && bits != 32)
		return 0;
	datamask = 0xffffffffUL >> (32 - bits);
	advance = 32 / bits;
	boot_rom_addr += advance;

	/* read the control register */
	control = RMEM(boot_rom_addr++) & datamask;
	for (i = 1; i < advance; i++)
		control |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);

	/* now parse the data */
	while (1)
	{
		UINT32 offs, len;

		/* read the length of this section */
		len = RMEM(boot_rom_addr++) & datamask;
		for (i = 1; i < advance; i++)
			len |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);

		/* stop at 0 */
		if (len == 0)
			return start_offset;

		/* read the destination offset of this section */
		offs = RMEM(boot_rom_addr++) & datamask;
		for (i = 1; i < advance; i++)
			offs |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);

		/* if this is the first block, that's where we boot to */
		if (first)
		{
			start_offset = offs;
			first = 0;
		}

		/* now copy the data */
		while (len--)
		{
			UINT32 data;

			/* extract the 32-bit word */
			data = RMEM(boot_rom_addr++) & datamask;
			for (i = 1; i < advance; i++)
				data |= (RMEM(boot_rom_addr++) & datamask) << (bits * i);

			/* write it out */
			WMEM(offs++, data);
		}
	}

	/* keep the compiler happy */
	return 0;
}



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

static void tms32031_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 + TMS32031_IRQ0:	set_irq_line(TMS32031_IRQ0, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ1:	set_irq_line(TMS32031_IRQ1, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ2:	set_irq_line(TMS32031_IRQ2, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ3:	set_irq_line(TMS32031_IRQ3, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_XINT0:	set_irq_line(TMS32031_XINT0, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_RINT0:	set_irq_line(TMS32031_RINT0, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_XINT1:	set_irq_line(TMS32031_XINT1, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_RINT1:	set_irq_line(TMS32031_RINT1, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_TINT0:	set_irq_line(TMS32031_TINT0, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_TINT1:	set_irq_line(TMS32031_TINT1, info->i);	break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_DINT:	set_irq_line(TMS32031_DINT, info->i);	break;

		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + TMS32031_PC:		tms32031.pc = info->i; 					break;
		case CPUINFO_INT_REGISTER + TMS32031_R0:		IREG(TMR_R0) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R1:		IREG(TMR_R1) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R2:		IREG(TMR_R2) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R3:		IREG(TMR_R3) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R4:		IREG(TMR_R4) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R5:		IREG(TMR_R5) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R6:		IREG(TMR_R6) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R7:		IREG(TMR_R7) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_R0F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R0]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R1F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R1]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R2F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R2]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R3F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R3]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R4F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R4]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R5F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R5]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R6F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R6]); break;
		case CPUINFO_INT_REGISTER + TMS32031_R7F:		double_to_dsp(*(float *)&info->i, &tms32031.r[TMR_R7]); break;
		case CPUINFO_INT_REGISTER + TMS32031_AR0:		IREG(TMR_AR0) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR1:		IREG(TMR_AR1) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR2:		IREG(TMR_AR2) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR3:		IREG(TMR_AR3) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR4:		IREG(TMR_AR4) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR5:		IREG(TMR_AR5) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR6:		IREG(TMR_AR6) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR7:		IREG(TMR_AR7) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_DP:		IREG(TMR_DP) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_IR0:		IREG(TMR_IR0) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_IR1:		IREG(TMR_IR1) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_BK:		IREG(TMR_BK) = info->i; 				break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + TMS32031_SP:		IREG(TMR_SP) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_ST:		IREG(TMR_ST) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_IE:		IREG(TMR_IE) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_IF:		IREG(TMR_IF) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_IOF:		IREG(TMR_IOF) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_RS:		IREG(TMR_RS) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_RE:		IREG(TMR_RE) = info->i; 				break;
		case CPUINFO_INT_REGISTER + TMS32031_RC:		IREG(TMR_RC) = info->i; 				break;
	}
}


/**************************************************************************
 * Internal memory map
 **************************************************************************/

static ADDRESS_MAP_START( internal_32031, ADDRESS_SPACE_PROGRAM, 32 )
	AM_RANGE(0x809800, 0x809fff) AM_RAM
ADDRESS_MAP_END

static ADDRESS_MAP_START( internal_32032, ADDRESS_SPACE_PROGRAM, 32 )
	AM_RANGE(0x87fe00, 0x87ffff) AM_RAM
ADDRESS_MAP_END


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

void tms32031_get_info(UINT32 state, cpuinfo *info)
{
	float ftemp;

	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CONTEXT_SIZE:					info->i = sizeof(tms32031);				break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 11;							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 = 4;							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 = 4;							break;

		case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM:	info->i = 32;					break;
		case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 24;					break;
		case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -2;					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 + TMS32031_IRQ0:	info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ0)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ1:	info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ1)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ2:	info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ2)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_IRQ3:	info->i = (IREG(TMR_IF) & (1 << TMS32031_IRQ3)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_XINT0:	info->i = (IREG(TMR_IF) & (1 << TMS32031_XINT0)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_RINT0:	info->i = (IREG(TMR_IF) & (1 << TMS32031_RINT0)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_XINT1:	info->i = (IREG(TMR_IF) & (1 << TMS32031_XINT1)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_RINT1:	info->i = (IREG(TMR_IF) & (1 << TMS32031_RINT1)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_TINT0:	info->i = (IREG(TMR_IF) & (1 << TMS32031_TINT0)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_TINT1:	info->i = (IREG(TMR_IF) & (1 << TMS32031_TINT1)) ? ASSERT_LINE : CLEAR_LINE; break;
		case CPUINFO_INT_INPUT_STATE + TMS32031_DINT:	info->i = (IREG(TMR_IF) & (1 << TMS32031_DINT)) ? ASSERT_LINE : CLEAR_LINE; break;

		case CPUINFO_INT_PREVIOUSPC:					info->i = tms32031.ppc;					break;

		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + TMS32031_PC:		info->i = tms32031.pc;					break;

		case CPUINFO_INT_REGISTER + TMS32031_R0:		info->i = IREG(TMR_R0);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R1:		info->i = IREG(TMR_R1);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R2:		info->i = IREG(TMR_R2);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R3:		info->i = IREG(TMR_R3);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R4:		info->i = IREG(TMR_R4);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R5:		info->i = IREG(TMR_R5);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R6:		info->i = IREG(TMR_R6);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R7:		info->i = IREG(TMR_R7);					break;
		case CPUINFO_INT_REGISTER + TMS32031_R0F:		ftemp = dsp_to_double(&tms32031.r[TMR_R0]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R1F:		ftemp = dsp_to_double(&tms32031.r[TMR_R1]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R2F:		ftemp = dsp_to_double(&tms32031.r[TMR_R2]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R3F:		ftemp = dsp_to_double(&tms32031.r[TMR_R3]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R4F:		ftemp = dsp_to_double(&tms32031.r[TMR_R4]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R5F:		ftemp = dsp_to_double(&tms32031.r[TMR_R5]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R6F:		ftemp = dsp_to_double(&tms32031.r[TMR_R6]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_R7F:		ftemp = dsp_to_double(&tms32031.r[TMR_R7]); info->i = f2u(ftemp); break;
		case CPUINFO_INT_REGISTER + TMS32031_AR0:		info->i = IREG(TMR_AR0);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR1:		info->i = IREG(TMR_AR1);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR2:		info->i = IREG(TMR_AR2);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR3:		info->i = IREG(TMR_AR3);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR4:		info->i = IREG(TMR_AR4);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR5:		info->i = IREG(TMR_AR5);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR6:		info->i = IREG(TMR_AR6);				break;
		case CPUINFO_INT_REGISTER + TMS32031_AR7:		info->i = IREG(TMR_AR7);				break;
		case CPUINFO_INT_REGISTER + TMS32031_DP:		info->i = IREG(TMR_DP);					break;
		case CPUINFO_INT_REGISTER + TMS32031_IR0:		info->i = IREG(TMR_IR0);				break;
		case CPUINFO_INT_REGISTER + TMS32031_IR1:		info->i = IREG(TMR_IR1);				break;
		case CPUINFO_INT_REGISTER + TMS32031_BK:		info->i = IREG(TMR_BK);					break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + TMS32031_SP:		info->i = IREG(TMR_SP);					break;
		case CPUINFO_INT_REGISTER + TMS32031_ST:		info->i = IREG(TMR_ST);					break;
		case CPUINFO_INT_REGISTER + TMS32031_IE:		info->i = IREG(TMR_IE);					break;
		case CPUINFO_INT_REGISTER + TMS32031_IF:		info->i = IREG(TMR_IF);					break;
		case CPUINFO_INT_REGISTER + TMS32031_IOF:		info->i = IREG(TMR_IOF);				break;
		case CPUINFO_INT_REGISTER + TMS32031_RS:		info->i = IREG(TMR_RS);					break;
		case CPUINFO_INT_REGISTER + TMS32031_RE:		info->i = IREG(TMR_RE);					break;
		case CPUINFO_INT_REGISTER + TMS32031_RC:		info->i = IREG(TMR_RC);					break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_PTR_SET_INFO:						info->setinfo = tms32031_set_info;		break;
		case CPUINFO_PTR_GET_CONTEXT:					info->getcontext = tms32031_get_context; break;
		case CPUINFO_PTR_SET_CONTEXT:					info->setcontext = tms32031_set_context; break;
		case CPUINFO_PTR_INIT:							info->init = tms32031_init;				break;
		case CPUINFO_PTR_RESET:							info->reset = tms32031_reset;			break;
		case CPUINFO_PTR_EXIT:							info->exit = tms32031_exit;				break;
		case CPUINFO_PTR_EXECUTE:						info->execute = tms32031_execute;		break;
		case CPUINFO_PTR_BURN:							info->burn = NULL;						break;
#ifdef MAME_DEBUG
		case CPUINFO_PTR_DISASSEMBLE:					info->disassemble = tms32031_dasm;		break;
#endif /* MAME_DEBUG */
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &tms32031_icount;		break;
		case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_internal_32031; break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case CPUINFO_STR_NAME:							strcpy(info->s, "TMS32031");			break;
		case CPUINFO_STR_CORE_FAMILY:					strcpy(info->s, "Texas Instruments TMS32031"); 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 (C) Aaron Giles 2002"); break;

		case CPUINFO_STR_FLAGS:
		{
			UINT32 temp = tms32031.r[TMR_ST].i32[0];
			sprintf(info->s, "%c%c%c%c%c%c%c%c",
				(temp & 0x80) ? 'O':'.',
				(temp & 0x40) ? 'U':'.',
                (temp & 0x20) ? 'V':'.',
                (temp & 0x10) ? 'u':'.',
                (temp & 0x08) ? 'n':'.',
                (temp & 0x04) ? 'z':'.',
                (temp & 0x02) ? 'v':'.',
                (temp & 0x01) ? 'c':'.');
            break;
        }

		case CPUINFO_STR_REGISTER + TMS32031_PC:  		sprintf(info->s, "PC: %08X", tms32031.pc); break;

		case CPUINFO_STR_REGISTER + TMS32031_R0:		sprintf(info->s, " R0:%08X", tms32031.r[TMR_R0].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R1:		sprintf(info->s, " R1:%08X", tms32031.r[TMR_R1].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R2:		sprintf(info->s, " R2:%08X", tms32031.r[TMR_R2].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R3:		sprintf(info->s, " R3:%08X", tms32031.r[TMR_R3].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R4:		sprintf(info->s, " R4:%08X", tms32031.r[TMR_R4].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R5:		sprintf(info->s, " R5:%08X", tms32031.r[TMR_R5].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R6:		sprintf(info->s, " R6:%08X", tms32031.r[TMR_R6].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R7:		sprintf(info->s, " R7:%08X", tms32031.r[TMR_R7].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_R0F:		sprintf(info->s, "R0F:!%12g", dsp_to_double(&tms32031.r[TMR_R0])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R1F:		sprintf(info->s, "R1F:!%12g", dsp_to_double(&tms32031.r[TMR_R1])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R2F:		sprintf(info->s, "R2F:!%12g", dsp_to_double(&tms32031.r[TMR_R2])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R3F:		sprintf(info->s, "R3F:!%12g", dsp_to_double(&tms32031.r[TMR_R3])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R4F:		sprintf(info->s, "R4F:!%12g", dsp_to_double(&tms32031.r[TMR_R4])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R5F:		sprintf(info->s, "R5F:!%12g", dsp_to_double(&tms32031.r[TMR_R5])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R6F:		sprintf(info->s, "R6F:!%12g", dsp_to_double(&tms32031.r[TMR_R6])); break;
		case CPUINFO_STR_REGISTER + TMS32031_R7F:		sprintf(info->s, "R7F:!%12g", dsp_to_double(&tms32031.r[TMR_R7])); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR0:		sprintf(info->s, "AR0:%08X", tms32031.r[TMR_AR0].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR1:		sprintf(info->s, "AR1:%08X", tms32031.r[TMR_AR1].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR2:		sprintf(info->s, "AR2:%08X", tms32031.r[TMR_AR2].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR3:		sprintf(info->s, "AR3:%08X", tms32031.r[TMR_AR3].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR4:		sprintf(info->s, "AR4:%08X", tms32031.r[TMR_AR4].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR5:		sprintf(info->s, "AR5:%08X", tms32031.r[TMR_AR5].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR6:		sprintf(info->s, "AR6:%08X", tms32031.r[TMR_AR6].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_AR7:		sprintf(info->s, "AR7:%08X", tms32031.r[TMR_AR7].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_DP:		sprintf(info->s, " DP:%02X", tms32031.r[TMR_DP].i8[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_IR0:		sprintf(info->s, "IR0:%08X", tms32031.r[TMR_IR0].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_IR1:		sprintf(info->s, "IR1:%08X", tms32031.r[TMR_IR1].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_BK:		sprintf(info->s, " BK:%08X", tms32031.r[TMR_BK].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_SP:		sprintf(info->s, " SP:%08X", tms32031.r[TMR_SP].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_ST:		sprintf(info->s, " ST:%08X", tms32031.r[TMR_ST].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_IE:		sprintf(info->s, " IE:%08X", tms32031.r[TMR_IE].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_IF:		sprintf(info->s, " IF:%08X", tms32031.r[TMR_IF].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_IOF:		sprintf(info->s, "IOF:%08X", tms32031.r[TMR_IOF].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_RS:		sprintf(info->s, " RS:%08X", tms32031.r[TMR_RS].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_RE:		sprintf(info->s, " RE:%08X", tms32031.r[TMR_RE].i32[0]); break;
		case CPUINFO_STR_REGISTER + TMS32031_RC:		sprintf(info->s, " RC:%08X", tms32031.r[TMR_RC].i32[0]); break;
	}
}

void tms32032_get_info(UINT32 state, cpuinfo *info)
{
	switch (state)
	{
		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map = construct_map_internal_32032; break;

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

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