/*
    Nintendo/SGI Reality Signal Processor (RSP) emulator

    Written by Ville Linde
*/

#include "emu.h"
#include "debugger.h"
#include "rsp.h"
#include "rspdiv.h"

CPU_DISASSEMBLE( rsp );

#ifndef USE_RSPDRC

#define LOG_INSTRUCTION_EXECUTION		0
#define SAVE_DISASM						0
#define SAVE_DMEM						0
#define RSP_TEST_SYNC                   0

#define PRINT_VECREG(x)		mame_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", (x), \
							(UINT16)VREG_S((x),0), (UINT16)VREG_S((x),1), \
							(UINT16)VREG_S((x),2), (UINT16)VREG_S((x),3), \
							(UINT16)VREG_S((x),4), (UINT16)VREG_S((x),5), \
							(UINT16)VREG_S((x),6), (UINT16)VREG_S((x),7))

#define PRINT_ACCUM(x)     mame_printf_debug("A%d: %08X|%08X\n", (x), \
                            (UINT32)( ( ACCUM(x) >> 32 ) & 0x00000000ffffffff ),    \
                            (UINT32)(   ACCUM(x)         & 0x00000000ffffffff ))

extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);

INLINE rsp_state *get_safe_token(device_t *device)
{
	assert(device != NULL);
	assert(device->type() == RSP);
	return (rsp_state *)downcast<legacy_cpu_device *>(device)->token();
}

#define SIMM16		((INT32)(INT16)(op))
#define UIMM16		((UINT16)(op))
#define UIMM26		(op & 0x03ffffff)

#define JUMP_ABS(addr)			{ rsp->nextpc = 0x04001000 | (((addr) << 2) & 0xfff); }
#define JUMP_ABS_L(addr,l)		{ rsp->nextpc = 0x04001000 | (((addr) << 2) & 0xfff); rsp->r[l] = rsp->pc + 4; }
#define JUMP_REL(offset)		{ rsp->nextpc = 0x04001000 | ((rsp->pc + ((offset) << 2)) & 0xfff); }
#define JUMP_REL_L(offset,l)	{ rsp->nextpc = 0x04001000 | ((rsp->pc + ((offset) << 2)) & 0xfff); rsp->r[l] = rsp->pc + 4; }
#define JUMP_PC(addr)			{ rsp->nextpc = 0x04001000 | ((addr) & 0xfff); }
#define JUMP_PC_L(addr,l)		{ rsp->nextpc = 0x04001000 | ((addr) & 0xfff); rsp->r[l] = rsp->pc + 4; }
#define LINK(l) 				{ rsp->r[l] = rsp->pc + 4; }

#define VREG_B(reg, offset)		rsp->v[(reg)].b[(offset)^1]
#define VREG_S(reg, offset)		rsp->v[(reg)].s[(offset)]
#define VREG_L(reg, offset)		rsp->v[(reg)].l[(offset)]

#define R_VREG_B(reg, offset)		rsp->v[(reg)].b[(offset)^1]
#define R_VREG_S(reg, offset)		(INT16)rsp->v[(reg)].s[(offset)]
#define R_VREG_L(reg, offset)		rsp->v[(reg)].l[(offset)]

#define W_VREG_B(reg, offset, val)	(rsp->v[(reg)].b[(offset)^1] = val)
#define W_VREG_S(reg, offset, val)	(rsp->v[(reg)].s[(offset)] = val)
#define W_VREG_L(reg, offset, val)	(rsp->v[(reg)].l[(offset)] = val)

#define VEC_EL_2(x,z)			(vector_elements[(x)][(z)])

#define ACCUM(x)		rsp->accum[((x))].q
#define ACCUM_H(x)		rsp->accum[((x))].w[3]
#define ACCUM_M(x)		rsp->accum[((x))].w[2]
#define ACCUM_L(x)		rsp->accum[((x))].w[1]

#define CARRY_FLAG(x)			((rsp->flag[0] & (1 << ((x)))) ? 1 : 0)
#define CLEAR_CARRY_FLAGS()		{ rsp->flag[0] &= ~0xff; }
#define SET_CARRY_FLAG(x)		{ rsp->flag[0] |= (1 << ((x))); }
#define CLEAR_CARRY_FLAG(x)		{ rsp->flag[0] &= ~(1 << ((x))); }

#define COMPARE_FLAG(x)			((rsp->flag[1] & (1 << ((x)))) ? 1 : 0)
#define CLEAR_COMPARE_FLAGS()	{ rsp->flag[1] &= ~0xff; }
#define SET_COMPARE_FLAG(x)		{ rsp->flag[1] |= (1 << ((x))); }
#define CLEAR_COMPARE_FLAG(x)	{ rsp->flag[1] &= ~(1 << ((x))); }

#define ZERO_FLAG(x)			((rsp->flag[0] & (1 << (8+(x)))) ? 1 : 0)
#define CLEAR_ZERO_FLAGS()		{ rsp->flag[0] &= ~0xff00; }
#define SET_ZERO_FLAG(x)		{ rsp->flag[0] |= (1 << (8+(x))); }
#define CLEAR_ZERO_FLAG(x)		{ rsp->flag[0] &= ~(1 << (8+(x))); }

#define EXTENSION_FLAG(x)		((rsp.flag[2] & (1 << ((x)))) ? 1 : 0)

#define ROPCODE(pc)		rsp->program->read_dword(pc)

INLINE UINT8 READ8(rsp_state *rsp, UINT32 address)
{
	UINT8 ret;
	address = 0x04000000 | (address & 0xfff);
	ret = rsp->program->read_byte(address);
	printf("%04xr%02x\n", address & 0x0000ffff, ret);
	return ret;
}

INLINE UINT16 READ16(rsp_state *rsp, UINT32 address)
{
	UINT16 ret;
	address = 0x04000000 | (address & 0xfff);

	if(address & 1)
	{
		ret = ((rsp->program->read_byte(address + 0) & 0xff) << 8) | (rsp->program->read_byte(address + 1) & 0xff);
	}
	else
	{
		ret = rsp->program->read_word(address);
	}

	printf("%04xr%04x\n", address & 0x0000ffff, ret);

	return ret;
}

INLINE UINT32 READ32(rsp_state *rsp, UINT32 address)
{
	UINT32 ret;
	address = 0x04000000 | (address & 0xfff);

	if(address & 3)
	{
		ret =  ((rsp->program->read_byte(address + 0) & 0xff) << 24) |
			   ((rsp->program->read_byte(address + 1) & 0xff) << 16) |
			   ((rsp->program->read_byte(address + 2) & 0xff) << 8) |
			   ((rsp->program->read_byte(address + 3) & 0xff) << 0);
	}
	else
	{
		ret = rsp->program->read_dword(address);
	}

	printf("%04xr%08x\n", address & 0x0000ffff, ret);
	return ret;
}

INLINE void WRITE8(rsp_state *rsp, UINT32 address, UINT8 data)
{
	address = 0x04000000 | (address & 0xfff);
	printf("%04x:%02x\n", address & 0x0000ffff, data);
	rsp->program->write_byte(address, data);
}

INLINE void WRITE16(rsp_state *rsp, UINT32 address, UINT16 data)
{
	address = 0x04000000 | (address & 0xfff);
	printf("%04x:%04x\n", address & 0x0000ffff, data);

	if(address & 1)
	{
		rsp->program->write_byte(address + 0, (data >> 8) & 0xff);
		rsp->program->write_byte(address + 1, (data >> 0) & 0xff);
		return;
	}

	rsp->program->write_word(address, data);
}

INLINE void WRITE32(rsp_state *rsp, UINT32 address, UINT32 data)
{
	address = 0x04000000 | (address & 0xfff);
	printf("%04x:%08x\n", address & 0x0000ffff, data);

	if(address & 3)
	{
		rsp->program->write_byte(address + 0, (data >> 24) & 0xff);
		rsp->program->write_byte(address + 1, (data >> 16) & 0xff);
		rsp->program->write_byte(address + 2, (data >> 8) & 0xff);
		rsp->program->write_byte(address + 3, (data >> 0) & 0xff);
		return;
	}

	rsp->program->write_dword(address, data);
}

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

static UINT32 get_cop0_reg(rsp_state *rsp, int reg)
{
	reg &= 0xf;
	if (reg < 8)
	{
		return (rsp->config->sp_reg_r)(rsp->device, reg, 0x00000000);
	}
	else if (reg >= 8 && reg < 16)
	{
		return (rsp->config->dp_reg_r)(rsp->device, reg - 8, 0x00000000);
	}

	return 0;
}

static void set_cop0_reg(rsp_state *rsp, int reg, UINT32 data)
{
	reg &= 0xf;
	if (reg < 8)
	{
		(rsp->config->sp_reg_w)(rsp->device, reg, data, 0x00000000);
	}
	else if (reg >= 8 && reg < 16)
	{
		(rsp->config->dp_reg_w)(rsp->device, reg - 8, data, 0x00000000);
	}
}

static void unimplemented_opcode(rsp_state *rsp, UINT32 op)
{
	if ((rsp->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
	{
		char string[200];
		rsp_dasm_one(string, rsp->ppc, op);
		mame_printf_debug("%08X: %s\n", rsp->ppc, string);
	}

#if SAVE_DISASM
	{
		char string[200];
		int i;
		FILE *dasm;
		dasm = fopen("rsp_disasm.txt", "wt");

		for (i=0; i < 0x1000; i+=4)
		{
			UINT32 opcode = ROPCODE(0x04001000 + i);
			rsp_dasm_one(string, 0x04001000 + i, opcode);
			fprintf(dasm, "%08X: %08X   %s\n", 0x04001000 + i, opcode, string);
		}
		fclose(dasm);
	}
#endif
#if SAVE_DMEM
	{
		int i;
		FILE *dmem;
		dmem = fopen("rsp_dmem.bin", "wb");

		for (i=0; i < 0x1000; i++)
		{
			fputc(READ8(rsp, 0x04000000 + i), dmem);
		}
		fclose(dmem);
	}
#endif

	fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", op >> 26, op, rsp->ppc);
}

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

static const int vector_elements[16][8] =
{
	{ 0, 1, 2, 3, 4, 5, 6, 7 },		// none
	{ 0, 1, 2, 3, 4, 5, 6, 7 },		// ???
	{ 0, 0, 2, 2, 4, 4, 6, 6 },		// 0q
	{ 1, 1, 3, 3, 5, 5, 7, 7 },		// 1q
	{ 0, 0, 0, 0, 4, 4, 4, 4 },		// 0h
	{ 1, 1, 1, 1, 5, 5, 5, 5 },		// 1h
	{ 2, 2, 2, 2, 6, 6, 6, 6 },		// 2h
	{ 3, 3, 3, 3, 7, 7, 7, 7 },		// 3h
	{ 0, 0, 0, 0, 0, 0, 0, 0 },		// 0
	{ 1, 1, 1, 1, 1, 1, 1, 1 },		// 1
	{ 2, 2, 2, 2, 2, 2, 2, 2 },		// 2
	{ 3, 3, 3, 3, 3, 3, 3, 3 },		// 3
	{ 4, 4, 4, 4, 4, 4, 4, 4 },		// 4
	{ 5, 5, 5, 5, 5, 5, 5, 5 },		// 5
	{ 6, 6, 6, 6, 6, 6, 6, 6 },		// 6
	{ 7, 7, 7, 7, 7, 7, 7, 7 },		// 7
};

static CPU_INIT( rsp )
{
	rsp_state *rsp = get_safe_token(device);
	int regIdx;
	int accumIdx;
	rsp->config = (const rsp_config *)device->static_config();

	if (LOG_INSTRUCTION_EXECUTION)
		rsp->exec_output = fopen("rsp_execute.txt", "wt");

	rsp->irq_callback = irqcallback;
	rsp->device = device;
	rsp->program = device->space(AS_PROGRAM);
	rsp->direct = &rsp->program->direct();

#if 1
	// Inaccurate.  RSP registers power on to a random state...
	for(regIdx = 0; regIdx < 32; regIdx++ )
	{
		rsp->r[regIdx] = 0;
		rsp->v[regIdx].d[0] = 0;
		rsp->v[regIdx].d[1] = 0;
	}
	rsp->flag[0] = 0;
	rsp->flag[1] = 0;
	rsp->flag[2] = 0;
	rsp->flag[3] = 0;
	rsp->square_root_res = 0;
	rsp->square_root_high = 0;
	rsp->reciprocal_res = 0;
	rsp->reciprocal_high = 0;
#endif

	// ...except for the accumulators.
	// We're not calling machine.rand() because initializing something with machine.rand()
	//   makes me retch uncontrollably.
	for(accumIdx = 0; accumIdx < 8; accumIdx++ )
	{
		rsp->accum[accumIdx].q = 0;
	}

	rsp->sr = RSP_STATUS_HALT;
	rsp->step_count = 0;
}

static CPU_EXIT( rsp )
{
	rsp_state *rsp = get_safe_token(device);

#if SAVE_DISASM
	{
		char string[200];
		int i;
		FILE *dasm;
		dasm = fopen("rsp_disasm.txt", "wt");

		for (i=0; i < 0x1000; i+=4)
		{
			UINT32 opcode = ROPCODE(0x04001000 + i);
			rsp_dasm_one(string, 0x04001000 + i, opcode);
			fprintf(dasm, "%08X: %08X   %s\n", 0x04001000 + i, opcode, string);
		}
		fclose(dasm);
	}
#endif
#if SAVE_DMEM
	{
		int i;
		FILE *dmem;
#if 0
		dmem = fopen("rsp_dmem.txt", "wt");

		for (i=0; i < 0x1000; i+=4)
		{
			fprintf(dmem, "%08X: %08X\n", 0x04000000 + i, READ32(rsp, 0x04000000 + i));
		}
		fclose(dmem);
#endif
		dmem = fopen("rsp_dmem.bin", "wb");

		for (i=0; i < 0x1000; i++)
		{
			fputc(READ8(rsp, 0x04000000 + i), dmem);
		}
		fclose(dmem);
	}
#endif

	if (rsp->exec_output)
		fclose(rsp->exec_output);
	rsp->exec_output = NULL;
}

static CPU_RESET( rsp )
{
	rsp_state *rsp = get_safe_token(device);
	rsp->nextpc = ~0;
}

static void handle_lwc2(rsp_state *rsp, UINT32 op)
{
	int i, end;
	UINT32 ea;
	int dest = (op >> 16) & 0x1f;
	int base = (op >> 21) & 0x1f;
	int index = (op >> 7) & 0xf;
	int offset = (op & 0x7f);
	if (offset & 0x40)
		offset |= 0xffffffc0;

	switch ((op >> 11) & 0x1f)
	{
		case 0x00:		/* LBV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset |
			// --------------------------------------------------
			//
			// Load 1 byte to vector byte index

			ea = (base) ? rsp->r[base] + offset : offset;
			VREG_B(dest, index) = READ8(rsp, ea);
			break;
		}
		case 0x01:		/* LSV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads 2 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 2) : (offset * 2);

			end = index + 2;

			for (i=index; i < end; i++)
			{
				VREG_B(dest, i) = READ8(rsp, ea);
				ea++;
			}
			break;
		}
		case 0x02:		/* LLV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads 4 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 4) : (offset * 4);

			end = index + 4;

			for (i=index; i < end; i++)
			{
				VREG_B(dest, i) = READ8(rsp, ea);
				ea++;
			}
			break;
		}
		case 0x03:		/* LDV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads 8 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8);

			end = index + 8;

			for (i=index; i < end; i++)
			{
				VREG_B(dest, i) = READ8(rsp, ea);
				ea++;
			}
			break;
		}
		case 0x04:		/* LQV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads up to 16 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			end = index + (16 - (ea & 0xf));
			if (end > 16) end = 16;

			for (i=index; i < end; i++)
			{
				VREG_B(dest, i) = READ8(rsp, ea);
				ea++;
			}
			break;
		}
		case 0x05:		/* LRV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores up to 16 bytes starting from right side until 16-byte boundary

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			index = 16 - ((ea & 0xf) - index);
			end = 16;
			ea &= ~0xf;

			for (i=index; i < end; i++)
			{
				VREG_B(dest, i) = READ8(rsp, ea);
				ea++;
			}
			break;
		}
		case 0x06:		/* LPV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads a byte as the upper 8 bits of each element

			ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8);

			for (i=0; i < 8; i++)
			{
				VREG_S(dest, i) = READ8(rsp, ea + (((16-index) + i) & 0xf)) << 8;
			}
			break;
		}
		case 0x07:		/* LUV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads a byte as the bits 14-7 of each element

			ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8);

			for (i=0; i < 8; i++)
			{
				VREG_S(dest, i) = READ8(rsp, ea + (((16-index) + i) & 0xf)) << 7;
			}
			break;
		}
		case 0x08:		/* LHV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads a byte as the bits 14-7 of each element, with 2-byte stride

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			for (i=0; i < 8; i++)
			{
				VREG_S(dest, i) = READ8(rsp, ea + (((16-index) + (i<<1)) & 0xf)) << 7;
			}
			break;
		}
		case 0x09:		/* LFV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			// not sure what happens if 16-byte boundary is crossed...

			end = (index >> 1) + 4;

			for (i=index >> 1; i < end; i++)
			{
				VREG_S(dest, i) = READ8(rsp, ea) << 7;
				ea += 4;
			}
			break;
		}
		case 0x0a:		/* LWV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads the full 128-bit vector starting from vector byte index and wrapping to index 0
			// after byte index 15

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			// not sure what happens if 16-byte boundary is crossed...
			if ((ea & 0xf) > 0) fatalerror("RSP: LWV: 16-byte boundary crossing at %08X, recheck this!\n", rsp->ppc);

			end = (16 - index) + 16;

			for (i=(16 - index); i < end; i++)
			{
				VREG_B(dest, i & 0xf) = READ8(rsp, ea);
				ea += 4;
			}
			break;
		}
		case 0x0b:		/* LTV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset |
			// --------------------------------------------------
			//
			// Loads one element to maximum of 8 vectors, while incrementing element index

			// FIXME: has a small problem with odd indices

			int element;
			int vs = dest;
			int ve = dest + 8;
			if (ve > 32)
				ve = 32;

			element = 7 - (index >> 1);

			if (index & 1)	fatalerror("RSP: LTV: index = %d\n", index);

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			ea = ((ea + 8) & ~0xf) + (index & 1);
			for (i=vs; i < ve; i++)
			{
				element = ((8 - (index >> 1) + (i-vs)) << 1);
				VREG_B(i, (element & 0xf)) = READ8(rsp, ea);
				VREG_B(i, ((element + 1) & 0xf)) = READ8(rsp, ea + 1);

				ea += 2;
			}
			break;
		}

		default:
		{
			unimplemented_opcode(rsp, op);
			break;
		}
	}
}

static void handle_swc2(rsp_state *rsp, UINT32 op)
{
	int i, end;
	int eaoffset;
	UINT32 ea;
	int dest = (op >> 16) & 0x1f;
	int base = (op >> 21) & 0x1f;
	int index = (op >> 7) & 0xf;
	int offset = (op & 0x7f);
	if (offset & 0x40)
		offset |= 0xffffffc0;

	switch ((op >> 11) & 0x1f)
	{
		case 0x00:		/* SBV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores 1 byte from vector byte index

			ea = (base) ? rsp->r[base] + offset : offset;
			WRITE8(rsp, ea, VREG_B(dest, index));
			break;
		}
		case 0x01:		/* SSV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores 2 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 2) : (offset * 2);

			end = index + 2;

			for (i=index; i < end; i++)
			{
				WRITE8(rsp, ea, VREG_B(dest, i));
				ea++;
			}
			break;
		}
		case 0x02:		/* SLV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores 4 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 4) : (offset * 4);

			end = index + 4;

			for (i=index; i < end; i++)
			{
				WRITE8(rsp, ea, VREG_B(dest, i));
				ea++;
			}
			break;
		}
		case 0x03:		/* SDV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores 8 bytes starting from vector byte index

			ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8);

			end = index + 8;

			for (i=index; i < end; i++)
			{
				WRITE8(rsp, ea, VREG_B(dest, i));
				ea++;
			}
			break;
		}
		case 0x04:		/* SQV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores up to 16 bytes starting from vector byte index until 16-byte boundary

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			end = index + (16 - (ea & 0xf));

			for (i=index; i < end; i++)
			{
				WRITE8(rsp, ea, VREG_B(dest, i & 0xf));
				ea++;
			}
			break;
		}
		case 0x05:		/* SRV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores up to 16 bytes starting from right side until 16-byte boundary

			int o;
			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			end = index + (ea & 0xf);
			o = (16 - (ea & 0xf)) & 0xf;
			ea &= ~0xf;

			for (i=index; i < end; i++)
			{
				WRITE8(rsp, ea, VREG_B(dest, ((i + o) & 0xf)));
				ea++;
			}
			break;
		}
		case 0x06:		/* SPV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores upper 8 bits of each element

			ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8);
			end = index + 8;

			for (i=index; i < end; i++)
			{
				if ((i & 0xf) < 8)
				{
					WRITE8(rsp, ea, VREG_B(dest, ((i & 0xf) << 1)));
				}
				else
				{
					WRITE8(rsp, ea, VREG_S(dest, (i & 0x7)) >> 7);
				}
				ea++;
			}
			break;
		}
		case 0x07:		/* SUV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores bits 14-7 of each element

			ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8);
			end = index + 8;

			for (i=index; i < end; i++)
			{
				if ((i & 0xf) < 8)
				{
					WRITE8(rsp, ea, VREG_S(dest, (i & 0x7)) >> 7);
				}
				else
				{
					WRITE8(rsp, ea, VREG_B(dest, ((i & 0x7) << 1)));
				}
				ea++;
			}
			break;
		}
		case 0x08:		/* SHV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores bits 14-7 of each element, with 2-byte stride

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			for (i=0; i < 8; i++)
			{
				UINT8 d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) |
						  ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7);

				WRITE8(rsp, ea, d);
				ea += 2;
			}
			break;
		}
		case 0x09:		/* SFV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores bits 14-7 of upper or lower quad, with 4-byte stride

			// FIXME: only works for index 0 and index 8

			if (index & 0x7)	mame_printf_debug("RSP: SFV: index = %d at %08X\n", index, rsp->ppc);

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			eaoffset = ea & 0xf;
			ea &= ~0xf;

			end = (index >> 1) + 4;

			for (i=index >> 1; i < end; i++)
			{
				WRITE8(rsp, ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7);
				eaoffset += 4;
			}
			break;
		}
		case 0x0a:		/* SWV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores the full 128-bit vector starting from vector byte index and wrapping to index 0
			// after byte index 15

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			eaoffset = ea & 0xf;
			ea &= ~0xf;

			end = index + 16;

			for (i=index; i < end; i++)
			{
				WRITE8(rsp, ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf));
				eaoffset++;
			}
			break;
		}
		case 0x0b:		/* STV */
		{
			// 31       25      20      15      10     6        0
			// --------------------------------------------------
			// | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset |
			// --------------------------------------------------
			//
			// Stores one element from maximum of 8 vectors, while incrementing element index

			int element;
			int vs = dest;
			int ve = dest + 8;
			if (ve > 32)
				ve = 32;

			element = 8 - (index >> 1);

			ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16);

			eaoffset = (ea & 0xf) + (element * 2);
			ea &= ~0xf;

			for (i=vs; i < ve; i++)
			{
				WRITE16(rsp, ea + (eaoffset & 0xf), VREG_S(i, element & 0x7));
				eaoffset += 2;
				element++;
			}
			break;
		}

		default:
		{
			unimplemented_opcode(rsp, op);
			break;
		}
	}
}

INLINE UINT16 SATURATE_ACCUM(rsp_state *rsp, int accum, int slice, UINT16 negative, UINT16 positive)
{
	if ((INT16)ACCUM_H(accum) < 0)
	{
		if ((UINT16)(ACCUM_H(accum)) != 0xffff)
		{
			return negative;
		}
		else
		{
			if ((INT16)ACCUM_M(accum) >= 0)
			{
				return negative;
			}
			else
			{
				if (slice == 0)
				{
					return ACCUM_L(accum);
				}
				else if (slice == 1)
				{
					return ACCUM_M(accum);
				}
			}
		}
	}
	else
	{
		if ((UINT16)(ACCUM_H(accum)) != 0)
		{
			return positive;
		}
		else
		{
			if ((INT16)ACCUM_M(accum) < 0)
			{
				return positive;
			}
			else
			{
				if (slice == 0)
				{
					return ACCUM_L(accum);
				}
				else
				{
					return ACCUM_M(accum);
				}
			}
		}
	}

	return 0;
}

INLINE UINT16 SATURATE_ACCUM1(rsp_state *rsp, int accum, UINT16 negative, UINT16 positive)
{
	if ((INT16)ACCUM_H(accum) < 0)
	{
		if ((UINT16)(ACCUM_H(accum)) != 0xffff)
		{
			return negative;
		}
		else
		{
			if ((INT16)ACCUM_M(accum) >= 0)
			{
				return negative;
			}
			else
			{
        		return ACCUM_M(accum);
			}
		}
	}
	else
	{
		if ((UINT16)(ACCUM_H(accum)) != 0)
		{
			return positive;
		}
		else
		{
			if ((INT16)ACCUM_M(accum) < 0)
			{
				return positive;
			}
			else
			{
        		return ACCUM_M(accum);
			}
		}
	}

	return 0;
}

#define WRITEBACK_RESULT() {memcpy(&rsp->v[VDREG].s[0], &vres[0], 16);}

#if 0
static float float_round(float input)
{
	INT32 integer = (INT32)input;
	float fraction = input - (float)integer;
	float output = 0.0f;
	if( fraction >= 0.5f )
	{
		output = (float)( integer + 1 );
	}
	else
	{
		output = (float)integer;
	}
	return output;
}
#endif

static void handle_vector_ops(rsp_state *rsp, UINT32 op)
{
	int i;
	UINT32 VS1REG = (op >> 11) & 0x1f;
	UINT32 VS2REG = (op >> 16) & 0x1f;
	UINT32 VDREG = (op >> 6) & 0x1f;
	UINT32 EL = (op >> 21) & 0xf;
	INT16 vres[8];

	// Opcode legend:
	//    E = VS2 element type
	//    S = VS1, Source vector 1
	//    T = VS2, Source vector 2
	//    D = Destination vector

	switch (op & 0x3f)
	{
		case 0x00:		/* VMULF */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 |
			// ------------------------------------------------------
			//
			// Multiplies signed integer by signed integer * 2

			int sel;
			INT32 s1, s2;
			INT64 r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				if (s1 == -32768 && s2 == -32768)
				{
					// overflow
					ACCUM_H(i) = 0;
					ACCUM_M(i) = -32768;
					ACCUM_L(i) = -32768;
					vres[i] = 0x7fff;
				}
				else
				{
					r =  s1 * s2 * 2;
					r += 0x8000;	// rounding ?
					ACCUM_H(i) = (r < 0) ? 0xffff : 0;		// sign-extend to 48-bit
					ACCUM_M(i) = (INT16)(r >> 16);
					ACCUM_L(i) = (UINT16)(r);
					vres[i] = ACCUM_M(i);
				}
			}
			WRITEBACK_RESULT();

			break;
		}

		case 0x01:		/* VMULU */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 |
			// ------------------------------------------------------
			//

			int sel;
			INT32 s1, s2;
			INT64 r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r = s1 * s2 * 2;
				r += 0x8000;	// rounding ?

				ACCUM_H(i) = (UINT16)(r >> 32);
				ACCUM_M(i) = (UINT16)(r >> 16);
				ACCUM_L(i) = (UINT16)(r);

				if (r < 0)
				{
					vres[i] = 0;
				}
				else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0)
				{
					vres[i] = -1;
				}
				else
				{
					vres[i] = ACCUM_M(i);
				}
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x04:		/* VMUDL */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 |
			// ------------------------------------------------------
			//
			// Multiplies unsigned fraction by unsigned fraction
			// Stores the higher 16 bits of the 32-bit result to accumulator
			// The low slice of accumulator is stored into destination element

			int sel;
			UINT32 s1, s2;
			UINT32 r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (UINT32)(UINT16)VREG_S(VS1REG, i);
				s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
				r = s1 * s2;

				ACCUM_H(i) = 0;
				ACCUM_M(i) = 0;
				ACCUM_L(i) = (UINT16)(r >> 16);

				vres[i] = ACCUM_L(i);
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x05:		/* VMUDM */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 |
			// ------------------------------------------------------
			//
			// Multiplies signed integer by unsigned fraction
			// The result is stored into accumulator
			// The middle slice of accumulator is stored into destination element

			int sel;
			INT32 s1, s2;
			INT32 r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (UINT16)VREG_S(VS2REG, sel);	// not sign-extended
				r =  s1 * s2;

				ACCUM_H(i) = (r < 0) ? 0xffff : 0;		// sign-extend to 48-bit
				ACCUM_M(i) = (INT16)(r >> 16);
				ACCUM_L(i) = (UINT16)(r);

				vres[i] = ACCUM_M(i);
			}
			WRITEBACK_RESULT();
			break;

		}

		case 0x06:		/* VMUDN */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 |
			// ------------------------------------------------------
			//
			// Multiplies unsigned fraction by signed integer
			// The result is stored into accumulator
			// The low slice of accumulator is stored into destination element

			int sel;
			INT32 s1, s2;
			INT32 r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (UINT16)VREG_S(VS1REG, i);		// not sign-extended
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r = s1 * s2;

				ACCUM_H(i) = (r < 0) ? 0xffff : 0;		// sign-extend to 48-bit
				ACCUM_M(i) = (INT16)(r >> 16);
				ACCUM_L(i) = (UINT16)(r);

				vres[i] = ACCUM_L(i);
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x07:		/* VMUDH */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 |
			// ------------------------------------------------------
			//
			// Multiplies signed integer by signed integer
			// The result is stored into highest 32 bits of accumulator, the low slice is zero
			// The highest 32 bits of accumulator is saturated into destination element

			int sel;
			INT32 s1, s2;
			INT32 r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r = s1 * s2;

				ACCUM_H(i) = (INT16)(r >> 16);
				ACCUM_M(i) = (UINT16)(r);
				ACCUM_L(i) = 0;

				if (r < -32768) r = -32768;
				if (r >  32767)	r = 32767;
				vres[i] = (INT16)(r);
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x08:		/* VMACF */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 |
			// ------------------------------------------------------
			//
			// Multiplies signed integer by signed integer * 2
			// The result is added to accumulator

			int sel;
			INT32 s1, s2;
			INT32 r;
			UINT16 res;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r = s1 * s2;

				ACCUM(i) += (INT64)(r) << 17;
				res = SATURATE_ACCUM(rsp, i, 1, 0x8000, 0x7fff);

				vres[i] = res;
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x09:		/* VMACU */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 |
			// ------------------------------------------------------
			//

			UINT16 res;
			int sel;
			INT32 s1, s2, r1;
			UINT32 r2, r3;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r1 = s1 * s2;
				r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2);
				r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16);

				ACCUM_L(i) = (UINT16)(r2);
				ACCUM_M(i) = (UINT16)(r3);
				ACCUM_H(i) += (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31);

				//res = SATURATE_ACCUM(i, 1, 0x0000, 0xffff);
				if ((INT16)ACCUM_H(i) < 0)
				{
					res = 0;
				}
				else
				{
					if (ACCUM_H(i) != 0)
					{
						res = 0xffff;
					}
					else
					{
						if ((INT16)ACCUM_M(i) < 0)
						{
							res = 0xffff;
						}
						else
						{
							res = ACCUM_M(i);
						}
					}
				}

				vres[i] = res;
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x0c:		/* VMADL */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 |
			// ------------------------------------------------------
			//
			// Multiplies unsigned fraction by unsigned fraction
			// Adds the higher 16 bits of the 32-bit result to accumulator
			// The low slice of accumulator is stored into destination element

			UINT16 res;
			int sel;
			UINT32 s1, s2, r1;
			UINT32 r2, r3;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (UINT32)(UINT16)VREG_S(VS1REG, i);
				s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
				r1 = s1 * s2;
				r2 = (UINT16)ACCUM_L(i) + (r1 >> 16);
				r3 = (UINT16)ACCUM_M(i) + (r2 >> 16);

				ACCUM_L(i) = (UINT16)(r2);
				ACCUM_M(i) = (UINT16)(r3);
				ACCUM_H(i) += (INT16)(r3 >> 16);

				res = SATURATE_ACCUM(rsp, i, 0, 0x0000, 0xffff);

				vres[i] = res;
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x0d:		/* VMADM */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 |
			// ------------------------------------------------------
			//
			// Multiplies signed integer by unsigned fraction
			// The result is added into accumulator
			// The middle slice of accumulator is stored into destination element

			UINT16 res;
			int sel;
			UINT32 s1, s2, r1;
			UINT32 r2, r3;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (UINT16)VREG_S(VS2REG, sel);	// not sign-extended
				r1 = s1 * s2;
				r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1);
				r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16);

				ACCUM_L(i) = (UINT16)(r2);
				ACCUM_M(i) = (UINT16)(r3);
				ACCUM_H(i) += (UINT16)(r3 >> 16);
				if ((INT32)(r1) < 0)
					ACCUM_H(i) -= 1;

				res = SATURATE_ACCUM(rsp, i, 1, 0x8000, 0x7fff);

				vres[i] = res;
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x0e:		/* VMADN */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 |
			// ------------------------------------------------------
			//
			// Multiplies unsigned fraction by signed integer
			// The result is added into accumulator
			// The low slice of accumulator is stored into destination element

			INT32 s1, s2;
			UINT16 res;
			int sel;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (UINT16)VREG_S(VS1REG, i);		// not sign-extended
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);

				ACCUM(i) += (INT64)(s1*s2)<<16;

				res = SATURATE_ACCUM(rsp, i, 0, 0x0000, 0xffff);
				vres[i] = res;
			}
			WRITEBACK_RESULT();

			break;
		}

		case 0x0f:		/* VMADH */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 |
			// ------------------------------------------------------
			//
			// Multiplies signed integer by signed integer
			// The result is added into highest 32 bits of accumulator, the low slice is zero
			// The highest 32 bits of accumulator is saturated into destination element

			UINT16 res;
			int sel;
			INT32 s1, s2;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);

				rsp->accum[i].l[1] += s1*s2;

				res = SATURATE_ACCUM1(rsp, i, 0x8000, 0x7fff);

				vres[i] = res;
			}
			WRITEBACK_RESULT();

			break;
		}

		case 0x10:		/* VADD */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 |
			// ------------------------------------------------------
			//
			// Adds two vector registers and carry flag, the result is saturated to 32767

			// TODO: check VS2REG == VDREG

			int sel;
			INT32 s1, s2, r;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r = s1 + s2 + CARRY_FLAG(i);

				ACCUM_L(i) = (INT16)(r);

				if (r > 32767) r = 32767;
				if (r < -32768) r = -32768;
				vres[i] = (INT16)(r);
			}
			CLEAR_ZERO_FLAGS();
			CLEAR_CARRY_FLAGS();
			WRITEBACK_RESULT();
			break;
		}

		case 0x11:		/* VSUB */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 |
			// ------------------------------------------------------
			//
			// Subtracts two vector registers and carry flag, the result is saturated to -32768

			// TODO: check VS2REG == VDREG

			int sel;
			INT32 s1, s2, r;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT32)(INT16)VREG_S(VS1REG, i);
				s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
				r = s1 - s2 - CARRY_FLAG(i);

				ACCUM_L(i) = (INT16)(r);

				if (r > 32767) r = 32767;
				if (r < -32768) r = -32768;

				vres[i] = (INT16)(r);
			}
			CLEAR_ZERO_FLAGS();
			CLEAR_CARRY_FLAGS();
			WRITEBACK_RESULT();
			break;
		}

		case 0x13:		/* VABS */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 |
			// ------------------------------------------------------
			//
			// Changes the sign of source register 2 if source register 1 is negative and stores
			// the result to destination register

			int sel;
			INT16 s1, s2;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (INT16)VREG_S(VS1REG, i);
				s2 = (INT16)VREG_S(VS2REG, sel);

				if (s1 < 0)
				{
					if (s2 == -32768)
					{
						vres[i] = 32767;
					}
					else
					{
						vres[i] = -s2;
					}
				}
				else if (s1 > 0)
				{
					vres[i] = s2;
				}
				else
				{
					vres[i] = 0;
				}

				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x14:		/* VADDC */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 |
			// ------------------------------------------------------
			//
			// Adds two vector registers, the carry out is stored into carry register

			// TODO: check VS2REG = VDREG

			int sel;
			INT32 s1, s2, r;
			CLEAR_ZERO_FLAGS();
			CLEAR_CARRY_FLAGS();

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (UINT32)(UINT16)VREG_S(VS1REG, i);
				s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
				r = s1 + s2;

				vres[i] = (INT16)(r);
				ACCUM_L(i) = (INT16)(r);

				if (r & 0xffff0000)
				{
					SET_CARRY_FLAG(i);
				}
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x15:		/* VSUBC */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 |
			// ------------------------------------------------------
			//
			// Subtracts two vector registers, the carry out is stored into carry register

			// TODO: check VS2REG = VDREG

			int sel;
			INT32 s1, s2, r;
			CLEAR_ZERO_FLAGS();
			CLEAR_CARRY_FLAGS();

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = (UINT32)(UINT16)VREG_S(VS1REG, i);
				s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
				r = s1 - s2;

				vres[i] = (INT16)(r);
				ACCUM_L(i) = (UINT16)(r);

				if ((UINT16)(r) != 0)
				{
					SET_ZERO_FLAG(i);
				}
				if (r & 0xffff0000)
				{
					SET_CARRY_FLAG(i);
				}
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x1d:		/* VSAW */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 |
			// ------------------------------------------------------
			//
			// Stores high, middle or low slice of accumulator to destination vector

			switch (EL)
			{
				case 0x08:		// VSAWH
				{
					for (i=0; i < 8; i++)
					{
						VREG_S(VDREG, i) = ACCUM_H(i);
					}
					break;
				}
				case 0x09:		// VSAWM
				{
					for (i=0; i < 8; i++)
					{
						VREG_S(VDREG, i) = ACCUM_M(i);
					}
					break;
				}
				case 0x0a:		// VSAWL
				{
					for (i=0; i < 8; i++)
					{
						VREG_S(VDREG, i) = ACCUM_L(i);
					}
					break;
				}
				default:	//fatalerror("RSP: VSAW: el = %d\n", EL);//???????
					printf("RSP: VSAW: el = %d\n", EL);//??? ???
					exit(0);
			}
			break;
		}

		case 0x20:		/* VLT */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 |
			// ------------------------------------------------------
			//
			// Sets compare flags if elements in VS1 are less than VS2
			// Moves the element in VS2 to destination vector

			int sel;
			rsp->flag[1] = 0;

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);

				if (VREG_S(VS1REG, i) < VREG_S(VS2REG, sel))
				{
					SET_COMPARE_FLAG(i);
				}
				else if (VREG_S(VS1REG, i) == VREG_S(VS2REG, sel))
				{
					if (ZERO_FLAG(i) == 1 && CARRY_FLAG(i) != 0)
					{
						SET_COMPARE_FLAG(i);
					}
				}

				if (COMPARE_FLAG(i))
				{
					vres[i] = VREG_S(VS1REG, i);
				}
				else
				{
					vres[i] = VREG_S(VS2REG, sel);
				}

				ACCUM_L(i) = vres[i];
			}

			rsp->flag[0] = 0;
			WRITEBACK_RESULT();
			break;
		}

		case 0x21:		/* VEQ */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 |
			// ------------------------------------------------------
			//
			// Sets compare flags if elements in VS1 are equal with VS2
			// Moves the element in VS2 to destination vector

			int sel;
			rsp->flag[1] = 0;

			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);

				if ((VREG_S(VS1REG, i) == VREG_S(VS2REG, sel)) && ZERO_FLAG(i) == 0)
				{
					SET_COMPARE_FLAG(i);
					vres[i] = VREG_S(VS1REG, i);
				}
				else
				{
					vres[i] = VREG_S(VS2REG, sel);
				}
				ACCUM_L(i) = vres[i];
			}

			rsp->flag[0] = 0;
			WRITEBACK_RESULT();
			break;
		}

		case 0x22:		/* VNE */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 |
			// ------------------------------------------------------
			//
			// Sets compare flags if elements in VS1 are not equal with VS2
			// Moves the element in VS2 to destination vector

			int sel;
			rsp->flag[1] = 0;

			for (i=0; i < 8; i++)//?????????? ????
			{
				sel = VEC_EL_2(EL, i);

				if (VREG_S(VS1REG, i) != VREG_S(VS2REG, sel))
				{
					SET_COMPARE_FLAG(i);
				}
				else
				{
					if (ZERO_FLAG(i) == 1)
					{
						SET_COMPARE_FLAG(i);
					}
				}
				if (COMPARE_FLAG(i))
				{
					vres[i] = VREG_S(VS1REG, i);
				}
				else
				{
					vres[i] = VREG_S(VS2REG, sel);
				}
				ACCUM_L(i) = vres[i];
			}

			rsp->flag[0] = 0;
			WRITEBACK_RESULT();
			break;
		}

		case 0x23:		/* VGE */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 |
			// ------------------------------------------------------
			//
			// Sets compare flags if elements in VS1 are greater or equal with VS2
			// Moves the element in VS2 to destination vector

			int sel;
			rsp->flag[1] = 0;

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);

				if (VREG_S(VS1REG, i) == VREG_S(VS2REG, sel))
				{
					if (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0)
					{
						SET_COMPARE_FLAG(i);
					}
				}
				else if (VREG_S(VS1REG, i) > VREG_S(VS2REG, sel))
				{
					SET_COMPARE_FLAG(i);
				}

				if (COMPARE_FLAG(i) != 0)
				{
					vres[i] = VREG_S(VS1REG, i);
				}
				else
				{
					vres[i] = VREG_S(VS2REG, sel);
				}

				ACCUM_L(i) = vres[i];
			}

			rsp->flag[0] = 0;
			WRITEBACK_RESULT();
			break;
		}

		case 0x24:		/* VCL */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 |
			// ------------------------------------------------------
			//
			// Vector clip low

			int sel;
			INT16 s1, s2;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = VREG_S(VS1REG, i);
				s2 = VREG_S(VS2REG, sel);

				if (CARRY_FLAG(i) != 0)
				{

					if (ZERO_FLAG(i) != 0)
					{

						if (COMPARE_FLAG(i) != 0)
						{
							ACCUM_L(i) = -(UINT16)s2;
						}
						else
						{
							ACCUM_L(i) = s1;
						}
					}
					else//ZERO_FLAG(i)==0
					{

						if (rsp->flag[2] & (1 << (i)))
						{

							if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000)
							{//proper fix for Harvest Moon 64, r4

								ACCUM_L(i) = s1;
								CLEAR_COMPARE_FLAG(i);
							}
							else
							{

								ACCUM_L(i) = -((UINT16)s2);
								SET_COMPARE_FLAG(i);
							}
						}
						else
						{
							if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0)
							{
								ACCUM_L(i) = s1;
								CLEAR_COMPARE_FLAG(i);
							}
							else
							{
								ACCUM_L(i) = -((UINT16)s2);
								SET_COMPARE_FLAG(i);
							}
						}
					}
				}//
				else//CARRY_FLAG(i)==0
				{

					if (ZERO_FLAG(i) != 0)
					{

						if (rsp->flag[1] & (1 << (8+i)))
						{
							ACCUM_L(i) = s2;
						}
						else
						{
							ACCUM_L(i) = s1;
						}
					}
					else
					{
						if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0)
						{
							ACCUM_L(i) = s2;
							rsp->flag[1] |= (1 << (8+i));
						}
						else
						{
							ACCUM_L(i) = s1;
							rsp->flag[1] &= ~(1 << (8+i));
						}
					}
				}

				vres[i] = ACCUM_L(i);
			}
			rsp->flag[0] = 0;
			rsp->flag[2] = 0;
			WRITEBACK_RESULT();
			break;
		}

		case 0x25:		/* VCH */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 |
			// ------------------------------------------------------
			//
			// Vector clip high

			int sel;
			INT16 s1, s2;
			rsp->flag[0] = 0;
			rsp->flag[1] = 0;
			rsp->flag[2] = 0;
			UINT32 vce = 0;

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = VREG_S(VS1REG, i);
				s2 = VREG_S(VS2REG, sel);

				if ((s1 ^ s2) < 0)
				{
					vce = (s1 + s2 == -1);
					SET_CARRY_FLAG(i);
					if (s2 < 0)
					{
						rsp->flag[1] |= (1 << (8+i));
					}

					if (s1 + s2 <= 0)
					{
						SET_COMPARE_FLAG(i);
						vres[i] = -((UINT16)s2);
					}
					else
					{
						vres[i] = s1;
					}

					if (s1 + s2 != 0)
					{
						if (s1 != ~s2)
						{
							SET_ZERO_FLAG(i);
						}
					}
				}//sign
				else
				{
					vce = 0;
					if (s2 < 0)
					{
						SET_COMPARE_FLAG(i);
					}
					if (s1 - s2 >= 0)
					{
						rsp->flag[1] |= (1 << (8+i));
						vres[i] = s2;
					}
					else
					{
						vres[i] = s1;
					}

					if ((s1 - s2) != 0)
					{
						if (s1 != ~s2)
						{
							SET_ZERO_FLAG(i);
						}
					}
				}
				rsp->flag[2] |= (vce << (i));
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x26:		/* VCR */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 |
			// ------------------------------------------------------
			//
			// Vector clip reverse

			int sel;
			INT16 s1, s2;
			rsp->flag[0] = 0;
			rsp->flag[1] = 0;
			rsp->flag[2] = 0;

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				s1 = VREG_S(VS1REG, i);
				s2 = VREG_S(VS2REG, sel);

				if ((INT16)(s1 ^ s2) < 0)
				{
					if (s2 < 0)
					{
						rsp->flag[1] |= (1 << (8+i));
					}
					if ((s1 + s2) <= 0)
					{
						ACCUM_L(i) = ~((UINT16)s2);
						SET_COMPARE_FLAG(i);
					}
					else
					{
						ACCUM_L(i) = s1;
					}
				}
				else
				{
					if (s2 < 0)
					{
						SET_COMPARE_FLAG(i);
					}
					if ((s1 - s2) >= 0)
					{
						ACCUM_L(i) = s2;
						rsp->flag[1] |= (1 << (8+i));
					}
					else
					{
						ACCUM_L(i) = s1;
					}
				}

				vres[i] = ACCUM_L(i);
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x27:		/* VMRG */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 |
			// ------------------------------------------------------
			//
			// Merges two vectors according to compare flags

			int sel;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				if (COMPARE_FLAG(i) != 0)
				{
					vres[i] = VREG_S(VS1REG, i);
				}
				else
				{
					vres[i] = VREG_S(VS2REG, sel);//??? ???????????
				}

				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}
		case 0x28:		/* VAND */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 |
			// ------------------------------------------------------
			//
			// Bitwise AND of two vector registers

			int sel;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				vres[i] = VREG_S(VS1REG, i) & VREG_S(VS2REG, sel);
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}
		case 0x29:		/* VNAND */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 |
			// ------------------------------------------------------
			//
			// Bitwise NOT AND of two vector registers

			int sel;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				vres[i] = ~((VREG_S(VS1REG, i) & VREG_S(VS2REG, sel)));
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}
		case 0x2a:		/* VOR */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 |
			// ------------------------------------------------------
			//
			// Bitwise OR of two vector registers

			int sel;
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				vres[i] = VREG_S(VS1REG, i) | VREG_S(VS2REG, sel);
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}
		case 0x2b:		/* VNOR */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 |
			// ------------------------------------------------------
			//
			// Bitwise NOT OR of two vector registers

			int sel;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				vres[i] = ~((VREG_S(VS1REG, i) | VREG_S(VS2REG, sel)));
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}
		case 0x2c:		/* VXOR */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 |
			// ------------------------------------------------------
			//
			// Bitwise XOR of two vector registers

			int sel;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				vres[i] = VREG_S(VS1REG, i) ^ VREG_S(VS2REG, sel);
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}
		case 0x2d:		/* VNXOR */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
			// ------------------------------------------------------
			//
			// Bitwise NOT XOR of two vector registers

			int sel;
			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				vres[i] = ~((VREG_S(VS1REG, i) ^ VREG_S(VS2REG, sel)));
				ACCUM_L(i) = vres[i];
			}
			WRITEBACK_RESULT();
			break;
		}

		case 0x30:		/* VRCP */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 |
			// ------------------------------------------------------
			//
			// Calculates reciprocal
			int del = VS1REG & 7;
			int sel = EL & 7;
			INT32 shifter = 0;

			INT32 rec = (INT16)(VREG_S(VS2REG, sel));
			INT32 datainput = (rec < 0) ? (-rec) : rec;
			if (datainput)
			{
				for (i = 0; i < 32; i++)
				{
					if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i
					{
						shifter = i;
						break;
					}
				}
			}
			else
			{
				shifter = 0x10;
			}

			INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22;
			INT32 fetchval = rsp_divtable[address];
			INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f);
			if (rec < 0)
			{
				temp = ~temp;
			}
			if (!rec)
			{
				temp = 0x7fffffff;
			}
			else if (rec == 0xffff8000)
			{
				temp = 0xffff0000;
			}
			rec = temp;

			rsp->reciprocal_res = rec;
			rsp->dp_allowed = 0;

			VREG_S(VDREG, del) = (UINT16)(rec & 0xffff);

			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}


			break;
		}

		case 0x31:		/* VRCPL */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 |
			// ------------------------------------------------------
			//
			// Calculates reciprocal low part

			int del = VS1REG & 7;
			int sel = EL & 7;
			INT32 shifter = 0;

			INT32 rec = ((UINT16)(VREG_S(VS2REG, sel)) | ((UINT32)(rsp->reciprocal_high) & 0xffff0000));

			INT32 datainput = rec;

			if (rec < 0)
			{
				if (rsp->dp_allowed)
				{
					if (rec < -32768)
					{
						datainput = ~datainput;
					}
					else
					{
						datainput = -datainput;
					}
				}
				else
				{
					datainput = -datainput;
				}
			}


			if (datainput)
			{
				for (i = 0; i < 32; i++)
				{
					if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i
					{
						shifter = i;
						break;
					}
				}
			}
			else
			{
				if (rsp->dp_allowed)
				{
					shifter = 0;
				}
				else
				{
					shifter = 0x10;
				}
			}

			INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22;
			INT32 fetchval = rsp_divtable[address];
			INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f);
			if (rec < 0)
			{
				temp = ~temp;
			}
			if (!rec)
			{
				temp = 0x7fffffff;
			}
			else if (rec == 0xffff8000)
			{
				temp = 0xffff0000;
			}
			rec = temp;

			rsp->reciprocal_res = rec;
			rsp->dp_allowed = 0;

			VREG_S(VDREG, del) = (UINT16)(rec & 0xffff);

			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}

			break;
		}

		case 0x32:		/* VRCPH */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 |
			// ------------------------------------------------------
			//
			// Calculates reciprocal high part

			int del = VS1REG & 7;
			int sel = EL & 7;

			rsp->reciprocal_high = (VREG_S(VS2REG, sel)) << 16;
			rsp->dp_allowed = 1;

			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}

			VREG_S(VDREG, del) = (INT16)(rsp->reciprocal_res >> 16);

			break;
		}

		case 0x33:		/* VMOV */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 |
			// ------------------------------------------------------
			//
			// Moves element from vector to destination vector

			int del = VS1REG & 7;
			int sel = EL & 7;

			VREG_S(VDREG, del) = VREG_S(VS2REG, sel);
			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}
			break;
		}

		case 0x34:		/* VRSQ */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 |
			// ------------------------------------------------------
			//
			// Calculates reciprocal square-root

			int del = VS1REG & 7;
			int sel = EL & 7;
			INT32 shifter = 0;

			INT32 rec = (INT16)(VREG_S(VS2REG, sel));
			INT32 datainput = (rec < 0) ? (-rec) : rec;
			if (datainput)
			{
				for (i = 0; i < 32; i++)
				{
					if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i
					{
						shifter = i;
						break;
					}
				}
			}
			else
			{
				shifter = 0x10;
			}

			INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22;
			address = ((address | 0x200) & 0x3fe) | (shifter & 1);

			INT32 fetchval = rsp_divtable[address];
			INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1);
			if (rec < 0)
			{
				temp = ~temp;
			}
			if (!rec)
			{
				temp = 0x7fffffff;
			}
			else if (rec == 0xffff8000)
			{
				temp = 0xffff0000;
			}
			rec = temp;

			rsp->reciprocal_res = rec;
			rsp->dp_allowed = 0;

			VREG_S(VDREG, del) = (UINT16)(rec & 0xffff);

			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}

			break;
		}

		case 0x35:		/* VRSQL */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 |
			// ------------------------------------------------------
			//
			// Calculates reciprocal square-root low part

			int del = VS1REG & 7;
			int sel = EL & 7;
			INT32 shifter = 0;

			INT32 rec = ((UINT16)(VREG_S(VS2REG, sel)) | ((UINT32)(rsp->reciprocal_high) & 0xffff0000));

			INT32 datainput = rec;

			if (rec < 0)
			{
				if (rsp->dp_allowed)
				{
					if (rec < -32768)//VDIV.C,208
					{
						datainput = ~datainput;
					}
					else
					{
						datainput = -datainput;
					}
				}
				else
				{
					datainput = -datainput;
				}
			}

			if (datainput)
			{
				for (i = 0; i < 32; i++)
				{
					if (datainput & (1 << ((~i) & 0x1f)))
					{
						shifter = i;
						break;
					}
				}
			}
			else
			{
				if (rsp->dp_allowed)
				{
					shifter = 0;
				}
				else
				{
					shifter = 0x10;
				}
			}

			INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22;
			address = ((address | 0x200) & 0x3fe) | (shifter & 1);

			INT32 fetchval = rsp_divtable[address];
			INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1);
			if (rec < 0)
			{
				temp = ~temp;
			}
			if (!rec)
			{
				temp = 0x7fffffff;
			}
			else if (rec == 0xffff8000)
			{
				temp = 0xffff0000;
			}
			rec = temp;

			rsp->reciprocal_res = rec;
			rsp->dp_allowed = 0;

			VREG_S(VDREG, del) = (UINT16)(rec & 0xffff);

			for (i = 0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}

			break;
		}

		case 0x36:		/* VRSQH */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 |
			// ------------------------------------------------------
			//
			// Calculates reciprocal square-root high part

			int del = VS1REG & 7;
			int sel = EL & 7;

			rsp->reciprocal_high = (VREG_S(VS2REG, sel)) << 16;
			rsp->dp_allowed = 1;

			for (i=0; i < 8; i++)
			{
				sel = VEC_EL_2(EL, i);
				ACCUM_L(i) = VREG_S(VS2REG, sel);
			}

			VREG_S(VDREG, del) = (INT16)(rsp->reciprocal_res >> 16);	// store high part
			break;
		}

		case 0x37:		/* VNOP */
		{
			// 31       25  24     20      15      10      5        0
			// ------------------------------------------------------
			// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110111 |
			// ------------------------------------------------------
			//
			// Vector null instruction

			break;
		}

		default:	unimplemented_opcode(rsp, op); break;
	}
}

static CPU_EXECUTE( rsp )
{
	rsp_state *rsp = get_safe_token(device);
	UINT32 op;

	rsp->pc = 0x4001000 | (rsp->pc & 0xfff);

	if( rsp->sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
	{
		rsp->icount = MIN(rsp->icount, 0);
	}

	while (rsp->icount > 0)
	{
		rsp->ppc = rsp->pc;
		debugger_instruction_hook(device, rsp->pc);

		op = ROPCODE(rsp->pc);
		if (rsp->nextpc != ~0)
		{
			rsp->pc = rsp->nextpc;
			rsp->nextpc = ~0;
		}
		else
		{
			rsp->pc += 4;
		}

		switch (op >> 26)
		{
			case 0x00:	/* SPECIAL */
			{
				switch (op & 0x3f)
				{
					case 0x00:	/* SLL */		if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break;
					case 0x02:	/* SRL */		if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break;
					case 0x03:	/* SRA */		if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
					case 0x04:	/* SLLV */		if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break;
					case 0x06:	/* SRLV */		if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break;
					case 0x07:	/* SRAV */		if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break;
					case 0x08:	/* JR */		JUMP_PC(RSVAL); break;
					case 0x09:	/* JALR */		JUMP_PC_L(RSVAL, RDREG); break;
					case 0x0d:	/* BREAK */
					{
						(rsp->config->sp_set_status)(rsp->device, 0x3);
						rsp->icount = MIN(rsp->icount, 1);

						if (LOG_INSTRUCTION_EXECUTION) fprintf(rsp->exec_output, "\n---------- break ----------\n\n");

						break;
					}
					case 0x20:	/* ADD */		if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
					case 0x21:	/* ADDU */		if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
					case 0x22:	/* SUB */		if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
					case 0x23:	/* SUBU */		if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
					case 0x24:	/* AND */		if (RDREG) RDVAL = RSVAL & RTVAL; break;
					case 0x25:	/* OR */		if (RDREG) RDVAL = RSVAL | RTVAL; break;
					case 0x26:	/* XOR */		if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
					case 0x27:	/* NOR */		if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
					case 0x2a:	/* SLT */		if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
					case 0x2b:	/* SLTU */		if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
					default:	unimplemented_opcode(rsp, op); break;
				}
				break;
			}

			case 0x01:	/* REGIMM */
			{
				switch (RTREG)
				{
					case 0x00:	/* BLTZ */		if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); break;
					case 0x01:	/* BGEZ */		if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
					case 0x10:	/* BLTZAL */	if ((INT32)(RSVAL) < 0) JUMP_REL_L(SIMM16, 31); break;
					case 0x11:	/* BGEZAL */	if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break;
					default:	unimplemented_opcode(rsp, op); break;
				}
				break;
			}

			case 0x02:	/* J */			JUMP_ABS(UIMM26); break;
			case 0x03:	/* JAL */		JUMP_ABS_L(UIMM26, 31); break;
			case 0x04:	/* BEQ */		if (RSVAL == RTVAL) JUMP_REL(SIMM16); break;
			case 0x05:	/* BNE */		if (RSVAL != RTVAL) JUMP_REL(SIMM16); break;
			case 0x06:	/* BLEZ */		if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); break;
			case 0x07:	/* BGTZ */		if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); break;
			case 0x08:	/* ADDI */		if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
			case 0x09:	/* ADDIU */		if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
			case 0x0a:	/* SLTI */		if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break;
			case 0x0b:	/* SLTIU */		if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break;
			case 0x0c:	/* ANDI */		if (RTREG) RTVAL = RSVAL & UIMM16; break;
			case 0x0d:	/* ORI */		if (RTREG) RTVAL = RSVAL | UIMM16; break;
			case 0x0e:	/* XORI */		if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
			case 0x0f:	/* LUI */		if (RTREG) RTVAL = UIMM16 << 16; break;

			case 0x10:	/* COP0 */
			{
				switch ((op >> 21) & 0x1f)
				{
					case 0x00:	/* MFC0 */		if (RTREG) RTVAL = get_cop0_reg(rsp, RDREG); break;
					case 0x04:	/* MTC0 */		set_cop0_reg(rsp, RDREG, RTVAL); break;
					default:	unimplemented_opcode(rsp, op); break;
				}
				break;
			}

			case 0x12:	/* COP2 */
			{
				switch ((op >> 21) & 0x1f)
				{
					case 0x00:	/* MFC2 */
					{
						// 31       25      20      15      10     6         0
						// ---------------------------------------------------
						// | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
						// ---------------------------------------------------
						//

						int el = (op >> 7) & 0xf;
						UINT16 b1 = VREG_B(RDREG, (el+0) & 0xf);
						UINT16 b2 = VREG_B(RDREG, (el+1) & 0xf);
						if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2));
						break;
					}
					case 0x02:	/* CFC2 */
					{
						// 31       25      20      15      10            0
						// ------------------------------------------------
						// | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
						// ------------------------------------------------
						//

						if (RTREG)
						{
							if (RDREG == 2)
							{
								// Anciliary clipping flags
								RTVAL = rsp->flag[RDREG] & 0x00ff;
							}
							else
							{
								// All other flags are 16 bits but sign-extended at retrieval
								RTVAL = (UINT32)rsp->flag[RDREG] | ( ( rsp->flag[RDREG] & 0x8000 ) ? 0xffff0000 : 0 );
							}
						}
						break;
					}
					case 0x04:	/* MTC2 */
					{
						// 31       25      20      15      10     6         0
						// ---------------------------------------------------
						// | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
						// ---------------------------------------------------
						//

						int el = (op >> 7) & 0xf;
						W_VREG_B(RDREG, (el+0) & 0xf, (RTVAL >> 8) & 0xff);
						W_VREG_B(RDREG, (el+1) & 0xf, (RTVAL >> 0) & 0xff);
						break;
					}
					case 0x06:	/* CTC2 */
					{
						// 31       25      20      15      10            0
						// ------------------------------------------------
						// | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
						// ------------------------------------------------
						//

						rsp->flag[RDREG] = RTVAL & 0xffff;
						break;
					}

					case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
					case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
					{
						handle_vector_ops(rsp, op);
						break;
					}

					default:	unimplemented_opcode(rsp, op); break;
				}
				break;
			}

			case 0x20:	/* LB */		if (RTREG) RTVAL = (INT32)(INT8)READ8(rsp, RSVAL + SIMM16); break;
			case 0x21:	/* LH */		if (RTREG) RTVAL = (INT32)(INT16)READ16(rsp, RSVAL + SIMM16); break;
			case 0x23:	/* LW */		if (RTREG) RTVAL = READ32(rsp, RSVAL + SIMM16); break;
			case 0x24:	/* LBU */		if (RTREG) RTVAL = (UINT8)READ8(rsp, RSVAL + SIMM16); break;
			case 0x25:	/* LHU */		if (RTREG) RTVAL = (UINT16)READ16(rsp, RSVAL + SIMM16); break;
			case 0x28:	/* SB */		WRITE8(rsp, RSVAL + SIMM16, RTVAL); break;
			case 0x29:	/* SH */		WRITE16(rsp, RSVAL + SIMM16, RTVAL); break;
			case 0x2b:	/* SW */		WRITE32(rsp, RSVAL + SIMM16, RTVAL); break;
			case 0x32:	/* LWC2 */		handle_lwc2(rsp, op); break;
			case 0x3a:	/* SWC2 */		handle_swc2(rsp, op); break;

			default:
			{
				unimplemented_opcode(rsp, op);
				break;
			}
		}

		if (LOG_INSTRUCTION_EXECUTION)
		{
			int i, l;
			static UINT32 prev_regs[32];
			static VECTOR_REG prev_vecs[32];
			char string[200];
			rsp_dasm_one(string, rsp->ppc, op);

			fprintf(rsp->exec_output, "%08X: %s", rsp->ppc, string);

			l = strlen(string);
			if (l < 36)
			{
				for (i=l; i < 36; i++)
				{
					fprintf(rsp->exec_output, " ");
				}
			}

			fprintf(rsp->exec_output, "| ");

			for (i=0; i < 32; i++)
			{
				if (rsp->r[i] != prev_regs[i])
				{
					fprintf(rsp->exec_output, "R%d: %08X ", i, rsp->r[i]);
				}
				prev_regs[i] = rsp->r[i];
			}

			for (i=0; i < 32; i++)
			{
				if (rsp->v[i].d[0] != prev_vecs[i].d[0] || rsp->v[i].d[1] != prev_vecs[i].d[1])
				{
					fprintf(rsp->exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i,
					(UINT16)VREG_S(i,0), (UINT16)VREG_S(i,1), (UINT16)VREG_S(i,2), (UINT16)VREG_S(i,3), (UINT16)VREG_S(i,4), (UINT16)VREG_S(i,5), (UINT16)VREG_S(i,6), (UINT16)VREG_S(i,7));
				}
				prev_vecs[i].d[0] = rsp->v[i].d[0];
				prev_vecs[i].d[1] = rsp->v[i].d[1];
			}

			fprintf(rsp->exec_output, "\n");

		}

		--rsp->icount;

		if( rsp->sr & RSP_STATUS_SSTEP )
		{
			if( rsp->step_count )
			{
				rsp->step_count--;
			}
			else
			{
				rsp->sr |= RSP_STATUS_BROKE;
			}
		}

		if( rsp->sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
		{
			rsp->icount = MIN(rsp->icount, 0);
		}

	}
}




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

static CPU_SET_INFO( rsp )
{
	rsp_state *rsp = get_safe_token(device);

	switch (state)
	{
		/* --- the following bits of info are set as 64-bit signed integers --- */
		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + RSP_PC:             rsp->pc = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R0:             rsp->r[0] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R1:             rsp->r[1] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R2:             rsp->r[2] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R3:             rsp->r[3] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R4:             rsp->r[4] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R5:             rsp->r[5] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R6:             rsp->r[6] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R7:             rsp->r[7] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R8:             rsp->r[8] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R9:             rsp->r[9] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R10:            rsp->r[10] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R11:            rsp->r[11] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R12:            rsp->r[12] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R13:            rsp->r[13] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R14:            rsp->r[14] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R15:            rsp->r[15] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R16:            rsp->r[16] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R17:            rsp->r[17] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R18:            rsp->r[18] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R19:            rsp->r[19] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R20:            rsp->r[20] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R21:            rsp->r[21] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R22:            rsp->r[22] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R23:            rsp->r[23] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R24:            rsp->r[24] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R25:            rsp->r[25] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R26:            rsp->r[26] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R27:            rsp->r[27] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R28:            rsp->r[28] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R29:            rsp->r[29] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_R30:            rsp->r[30] = info->i;        break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + RSP_R31:            rsp->r[31] = info->i;        break;
		case CPUINFO_INT_REGISTER + RSP_SR:             rsp->sr = info->i;           break;
		case CPUINFO_INT_REGISTER + RSP_NEXTPC:         rsp->nextpc = info->i;       break;
		case CPUINFO_INT_REGISTER + RSP_STEPCNT:        rsp->step_count = info->i;   break;
	}
}

CPU_GET_INFO( rsp )
{
	rsp_state *rsp = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;

	switch(state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case CPUINFO_INT_CONTEXT_SIZE:					info->i = sizeof(rsp_state);			break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 1;							break;
		case CPUINFO_INT_DEFAULT_IRQ_VECTOR:			info->i = 0;							break;
		case DEVINFO_INT_ENDIANNESS:					info->i = ENDIANNESS_BIG;				break;
		case CPUINFO_INT_CLOCK_MULTIPLIER:				info->i = 1;							break;
		case CPUINFO_INT_CLOCK_DIVIDER:					info->i = 1;							break;
		case CPUINFO_INT_MIN_INSTRUCTION_BYTES:			info->i = 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 = 1;							break;

		case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM:	info->i = 32;					break;
		case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32;					break;
		case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0;					break;
		case DEVINFO_INT_DATABUS_WIDTH + AS_DATA:	info->i = 0;					break;
		case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA:	info->i = 0;					break;
		case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA:	info->i = 0;					break;
		case DEVINFO_INT_DATABUS_WIDTH + AS_IO:		info->i = 0;					break;
		case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO:		info->i = 0;					break;
		case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO:		info->i = 0;					break;

		case CPUINFO_INT_INPUT_STATE:					info->i = CLEAR_LINE;					break;

		case CPUINFO_INT_PREVIOUSPC:					info->i = rsp->ppc;						break;

		case CPUINFO_INT_PC:	/* intentional fallthrough */
		case CPUINFO_INT_REGISTER + RSP_PC:				info->i = rsp->pc;						break;

		case CPUINFO_INT_REGISTER + RSP_R0:				info->i = rsp->r[0];						break;
		case CPUINFO_INT_REGISTER + RSP_R1:				info->i = rsp->r[1];						break;
		case CPUINFO_INT_REGISTER + RSP_R2:				info->i = rsp->r[2];						break;
		case CPUINFO_INT_REGISTER + RSP_R3:				info->i = rsp->r[3];						break;
		case CPUINFO_INT_REGISTER + RSP_R4:				info->i = rsp->r[4];						break;
		case CPUINFO_INT_REGISTER + RSP_R5:				info->i = rsp->r[5];						break;
		case CPUINFO_INT_REGISTER + RSP_R6:				info->i = rsp->r[6];						break;
		case CPUINFO_INT_REGISTER + RSP_R7:				info->i = rsp->r[7];						break;
		case CPUINFO_INT_REGISTER + RSP_R8:				info->i = rsp->r[8];						break;
		case CPUINFO_INT_REGISTER + RSP_R9:				info->i = rsp->r[9];						break;
		case CPUINFO_INT_REGISTER + RSP_R10:			info->i = rsp->r[10];					break;
		case CPUINFO_INT_REGISTER + RSP_R11:			info->i = rsp->r[11];					break;
		case CPUINFO_INT_REGISTER + RSP_R12:			info->i = rsp->r[12];					break;
		case CPUINFO_INT_REGISTER + RSP_R13:			info->i = rsp->r[13];					break;
		case CPUINFO_INT_REGISTER + RSP_R14:			info->i = rsp->r[14];					break;
		case CPUINFO_INT_REGISTER + RSP_R15:			info->i = rsp->r[15];					break;
		case CPUINFO_INT_REGISTER + RSP_R16:			info->i = rsp->r[16];					break;
		case CPUINFO_INT_REGISTER + RSP_R17:			info->i = rsp->r[17];					break;
		case CPUINFO_INT_REGISTER + RSP_R18:			info->i = rsp->r[18];					break;
		case CPUINFO_INT_REGISTER + RSP_R19:			info->i = rsp->r[19];					break;
		case CPUINFO_INT_REGISTER + RSP_R20:			info->i = rsp->r[20];					break;
		case CPUINFO_INT_REGISTER + RSP_R21:			info->i = rsp->r[21];					break;
		case CPUINFO_INT_REGISTER + RSP_R22:			info->i = rsp->r[22];					break;
		case CPUINFO_INT_REGISTER + RSP_R23:			info->i = rsp->r[23];					break;
		case CPUINFO_INT_REGISTER + RSP_R24:			info->i = rsp->r[24];					break;
		case CPUINFO_INT_REGISTER + RSP_R25:			info->i = rsp->r[25];					break;
		case CPUINFO_INT_REGISTER + RSP_R26:			info->i = rsp->r[26];					break;
		case CPUINFO_INT_REGISTER + RSP_R27:			info->i = rsp->r[27];					break;
		case CPUINFO_INT_REGISTER + RSP_R28:			info->i = rsp->r[28];					break;
		case CPUINFO_INT_REGISTER + RSP_R29:			info->i = rsp->r[29];					break;
		case CPUINFO_INT_REGISTER + RSP_R30:			info->i = rsp->r[30];					break;
		case CPUINFO_INT_SP:
		case CPUINFO_INT_REGISTER + RSP_R31:			info->i = rsp->r[31];					break;
		case CPUINFO_INT_REGISTER + RSP_SR:             info->i = rsp->sr;                       break;
		case CPUINFO_INT_REGISTER + RSP_NEXTPC:         info->i = rsp->nextpc;                   break;
		case CPUINFO_INT_REGISTER + RSP_STEPCNT:        info->i = rsp->step_count;               break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case CPUINFO_FCT_SET_INFO:						info->setinfo = CPU_SET_INFO_NAME(rsp);			break;
		case CPUINFO_FCT_INIT:							info->init = CPU_INIT_NAME(rsp);					break;
		case CPUINFO_FCT_RESET:							info->reset = CPU_RESET_NAME(rsp);				break;
		case CPUINFO_FCT_EXIT:							info->exit = CPU_EXIT_NAME(rsp);					break;
		case CPUINFO_FCT_EXECUTE:						info->execute = CPU_EXECUTE_NAME(rsp);			break;
		case CPUINFO_FCT_BURN:							info->burn = NULL;						break;
		case CPUINFO_FCT_DISASSEMBLE:					info->disassemble = CPU_DISASSEMBLE_NAME(rsp);			break;
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &rsp->icount;				break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "RSP");					break;
		case DEVINFO_STR_FAMILY:					strcpy(info->s, "RSP");					break;
		case DEVINFO_STR_VERSION:					strcpy(info->s, "1.0");					break;
		case DEVINFO_STR_SOURCE_FILE:						strcpy(info->s, __FILE__);				break;
		case DEVINFO_STR_CREDITS:					strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team");	break;

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

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

		case CPUINFO_STR_REGISTER + RSP_R0:				sprintf(info->s, "R0: %08X", rsp->r[0]); break;
		case CPUINFO_STR_REGISTER + RSP_R1:				sprintf(info->s, "R1: %08X", rsp->r[1]); break;
		case CPUINFO_STR_REGISTER + RSP_R2:				sprintf(info->s, "R2: %08X", rsp->r[2]); break;
		case CPUINFO_STR_REGISTER + RSP_R3:				sprintf(info->s, "R3: %08X", rsp->r[3]); break;
		case CPUINFO_STR_REGISTER + RSP_R4:				sprintf(info->s, "R4: %08X", rsp->r[4]); break;
		case CPUINFO_STR_REGISTER + RSP_R5:				sprintf(info->s, "R5: %08X", rsp->r[5]); break;
		case CPUINFO_STR_REGISTER + RSP_R6:				sprintf(info->s, "R6: %08X", rsp->r[6]); break;
		case CPUINFO_STR_REGISTER + RSP_R7:				sprintf(info->s, "R7: %08X", rsp->r[7]); break;
		case CPUINFO_STR_REGISTER + RSP_R8:				sprintf(info->s, "R8: %08X", rsp->r[8]); break;
		case CPUINFO_STR_REGISTER + RSP_R9:				sprintf(info->s, "R9: %08X", rsp->r[9]); break;
		case CPUINFO_STR_REGISTER + RSP_R10:			sprintf(info->s, "R10: %08X", rsp->r[10]); break;
		case CPUINFO_STR_REGISTER + RSP_R11:			sprintf(info->s, "R11: %08X", rsp->r[11]); break;
		case CPUINFO_STR_REGISTER + RSP_R12:			sprintf(info->s, "R12: %08X", rsp->r[12]); break;
		case CPUINFO_STR_REGISTER + RSP_R13:			sprintf(info->s, "R13: %08X", rsp->r[13]); break;
		case CPUINFO_STR_REGISTER + RSP_R14:			sprintf(info->s, "R14: %08X", rsp->r[14]); break;
		case CPUINFO_STR_REGISTER + RSP_R15:			sprintf(info->s, "R15: %08X", rsp->r[15]); break;
		case CPUINFO_STR_REGISTER + RSP_R16:			sprintf(info->s, "R16: %08X", rsp->r[16]); break;
		case CPUINFO_STR_REGISTER + RSP_R17:			sprintf(info->s, "R17: %08X", rsp->r[17]); break;
		case CPUINFO_STR_REGISTER + RSP_R18:			sprintf(info->s, "R18: %08X", rsp->r[18]); break;
		case CPUINFO_STR_REGISTER + RSP_R19:			sprintf(info->s, "R19: %08X", rsp->r[19]); break;
		case CPUINFO_STR_REGISTER + RSP_R20:			sprintf(info->s, "R20: %08X", rsp->r[20]); break;
		case CPUINFO_STR_REGISTER + RSP_R21:			sprintf(info->s, "R21: %08X", rsp->r[21]); break;
		case CPUINFO_STR_REGISTER + RSP_R22:			sprintf(info->s, "R22: %08X", rsp->r[22]); break;
		case CPUINFO_STR_REGISTER + RSP_R23:			sprintf(info->s, "R23: %08X", rsp->r[23]); break;
		case CPUINFO_STR_REGISTER + RSP_R24:			sprintf(info->s, "R24: %08X", rsp->r[24]); break;
		case CPUINFO_STR_REGISTER + RSP_R25:			sprintf(info->s, "R25: %08X", rsp->r[25]); break;
		case CPUINFO_STR_REGISTER + RSP_R26:			sprintf(info->s, "R26: %08X", rsp->r[26]); break;
		case CPUINFO_STR_REGISTER + RSP_R27:			sprintf(info->s, "R27: %08X", rsp->r[27]); break;
		case CPUINFO_STR_REGISTER + RSP_R28:			sprintf(info->s, "R28: %08X", rsp->r[28]); break;
		case CPUINFO_STR_REGISTER + RSP_R29:			sprintf(info->s, "R29: %08X", rsp->r[29]); break;
		case CPUINFO_STR_REGISTER + RSP_R30:			sprintf(info->s, "R30: %08X", rsp->r[30]); break;
		case CPUINFO_STR_REGISTER + RSP_R31:			sprintf(info->s, "R31: %08X", rsp->r[31]); break;
		case CPUINFO_STR_REGISTER + RSP_SR:             sprintf(info->s, "SR: %08X",  rsp->sr);    break;
		case CPUINFO_STR_REGISTER + RSP_NEXTPC:         sprintf(info->s, "NPC: %08X", rsp->nextpc);break;
		case CPUINFO_STR_REGISTER + RSP_STEPCNT:        sprintf(info->s, "STEP: %d",  rsp->step_count);  break;
	}
}

void rspdrc_set_options(device_t *device, UINT32 options)
{
}

void rspdrc_add_imem(device_t *device, void *base)
{
}

void rspdrc_add_dmem(device_t *device, void *base)
{
}

void rspdrc_flush_drc_cache(device_t *device)
{
}

DEFINE_LEGACY_CPU_DEVICE(RSP, rsp);

#endif // USE_RSPDRC
