/*****************************************************************************
 *
 *   sh4.c
 *   Portable Hitachi SH-4 (SH7750 family) emulator
 *
 *   By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek,
 *      Olivier Galibert, Sylvain Glaize, and James Forshaw.
 *
 *
 *   TODO: FPU
 *         DMA
 *         on-board peripherals
 *
 *   DONE: boot/reset setup
 *         64-bit data bus
 *         banked registers
 *         additional registers for supervisor mode
 *         FPU status and data registers
 *         state save for the new registers
 *         interrupts
 *         store queues
 *
 *****************************************************************************/

#include "emu.h"
#include "debugger.h"
#include "sh4.h"
#include "sh4regs.h"
#include "sh4comn.h"
#include "sh3comn.h"
#include "sh4tmu.h"

#ifndef USE_SH4DRC

CPU_DISASSEMBLE( sh4 );
CPU_DISASSEMBLE( sh4be );

typedef const void (*sh4ophandler)(sh4_state*, const UINT16);

sh4ophandler master_ophandler_table[0x10000];
void sh4_build_optable(sh4_state* sh4);


/* Called for unimplemented opcodes */
const void TODO(sh4_state *sh4, const UINT16 opcode)
{
}

#if 0
int sign_of(int n)
{
	return(sh4->fr[n]>>31);
}

void zero(int n,int sign)
{
if (sign == 0)
	sh4->fr[n] = 0x00000000;
else
	sh4->fr[n] = 0x80000000;
if ((sh4->fpscr & PR) == 1)
	sh4->fr[n+1] = 0x00000000;
}

int data_type_of(int n)
{
UINT32 abs;

	abs = sh4->fr[n] & 0x7fffffff;
	if ((sh4->fpscr & PR) == 0) { /* Single-precision */
		if (abs < 0x00800000) {
			if (((sh4->fpscr & DN) == 1) || (abs == 0x00000000)) {
				if (sign_of(n) == 0) {
					zero(n, 0);
					return(SH4_FPU_PZERO);
				} else {
					zero(n, 1);
					return(SH4_FPU_NZERO);
				}
			} else
				return(SH4_FPU_DENORM);
		} else
			if (abs < 0x7f800000)
				return(SH4_FPU_NORM);
			else
				if (abs == 0x7f800000) {
					if (sign_of(n) == 0)
						return(SH4_FPU_PINF);
					else
						return(SH4_FPU_NINF);
				} else
					if (abs < 0x7fc00000)
						return(SH4_FPU_qNaN);
					else
						return(SH4_FPU_sNaN);
	} else { /* Double-precision */
		if (abs < 0x00100000) {
			if (((sh4->fpscr & DN) == 1) || ((abs == 0x00000000) && (sh4->fr[n+1] == 0x00000000))) {
				if(sign_of(n) == 0) {
					zero(n, 0);
					return(SH4_FPU_PZERO);
				} else {
					zero(n, 1);
					return(SH4_FPU_NZERO);
				}
			} else
				return(SH4_FPU_DENORM);
		} else
			if (abs < 0x7ff00000)
				return(SH4_FPU_NORM);
			else
				if ((abs == 0x7ff00000) && (sh4->fr[n+1] == 0x00000000)) {
					if (sign_of(n) == 0)
						return(SH4_FPU_PINF);
					else
						return(SH4_FPU_NINF);
				} else
					if (abs < 0x7ff80000)
						return(SH4_FPU_qNaN);
					else
						return(SH4_FPU_sNaN);
	}
	return(SH4_FPU_NORM);
}
#endif

const UINT8 RB(sh4_state *sh4, offs_t A)
{
	if (A >= 0xe0000000)
		return sh4->program->read_byte(A);

	return sh4->program->read_byte(A & AM);
}

const UINT16 RW(sh4_state *sh4, offs_t A)
{
	if (A >= 0xe0000000)
		return sh4->program->read_word(A);

	return sh4->program->read_word(A & AM);
}

const UINT32 RL(sh4_state *sh4, offs_t A)
{
	if (A >= 0xe0000000)
		return sh4->program->read_dword(A);

	return sh4->program->read_dword(A & AM);
}

const void WB(sh4_state *sh4, offs_t A, UINT8 V)
{
	if (A >= 0xe0000000)
	{
		sh4->program->write_byte(A,V);
		return;
	}

	sh4->program->write_byte(A & AM,V);
}

const void WW(sh4_state *sh4, offs_t A, UINT16 V)
{
	if (A >= 0xe0000000)
	{
		sh4->program->write_word(A,V);
		return;
	}

	sh4->program->write_word(A & AM,V);
}

const void WL(sh4_state *sh4, offs_t A, UINT32 V)
{
	if (A >= 0xe0000000)
	{
		sh4->program->write_dword(A,V);
		return;
	}

	sh4->program->write_dword(A & AM,V);
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 1100  1       -
 *  ADD     Rm,Rn
 */
const void ADD(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] += sh4->r[Rm];
}

/*  code                 cycles  t-bit
 *  0111 nnnn iiii iiii  1       -
 *  ADD     #imm,Rn
 */
const void ADDI(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] += (INT32)(INT16)(INT8)(opcode&0xff);
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 1110  1       carry
 *  ADDC    Rm,Rn
 */
const void ADDC(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;
	UINT32 tmp0, tmp1;

	tmp1 = sh4->r[n] + sh4->r[m];
	tmp0 = sh4->r[n];
	sh4->r[n] = tmp1 + (sh4->sr & T);
	if (tmp0 > tmp1)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
	if (tmp1 > sh4->r[n])
		sh4->sr |= T;
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 1111  1       overflow
 *  ADDV    Rm,Rn
 */
const void ADDV(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;
	INT32 dest, src, ans;

	if ((INT32) sh4->r[n] >= 0)
		dest = 0;
	else
		dest = 1;
	if ((INT32) sh4->r[m] >= 0)
		src = 0;
	else
		src = 1;
	src += dest;
	sh4->r[n] += sh4->r[m];
	if ((INT32) sh4->r[n] >= 0)
		ans = 0;
	else
		ans = 1;
	ans += dest;
	if (src == 0 || src == 2)
	{
		if (ans == 1)
			sh4->sr |= T;
		else
			sh4->sr &= ~T;
	}
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0010 nnnn mmmm 1001  1       -
 *  AND     Rm,Rn
 */
const void AND(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] &= sh4->r[Rm];
}


/*  code                 cycles  t-bit
 *  1100 1001 iiii iiii  1       -
 *  AND     #imm,R0
 */
const void ANDI(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[0] &= (opcode&0xff);
}

/*  code                 cycles  t-bit
 *  1100 1101 iiii iiii  1       -
 *  AND.B   #imm,@(R0,GBR)
 */
const void ANDM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 temp;

	sh4->ea = sh4->gbr + sh4->r[0];
	temp = (opcode&0xff) & RB(sh4,  sh4->ea );
	WB(sh4, sh4->ea, temp );
	sh4->sh4_icount -= 2;
}

/*  code                 cycles  t-bit
 *  1000 1011 dddd dddd  3/1     -
 *  BF      disp8
 */
const void BF(sh4_state *sh4, const UINT16 opcode)
{
	if ((sh4->sr & T) == 0)
	{
		INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24;
		sh4->pc = sh4->ea = sh4->pc + disp * 2 + 2;
		sh4->sh4_icount -= 2;
	}
}

/*  code                 cycles  t-bit
 *  1000 1111 dddd dddd  3/1     -
 *  BFS     disp8
 */
const void BFS(sh4_state *sh4, const UINT16 opcode)
{
	if ((sh4->sr & T) == 0)
	{
		INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24;
		sh4->delay = sh4->pc;
		sh4->pc = sh4->ea = sh4->pc + disp * 2 + 2;
		sh4->sh4_icount--;
	}
}

/*  code                 cycles  t-bit
 *  1010 dddd dddd dddd  2       -
 *  BRA     disp12
 */
const void BRA(sh4_state *sh4, const UINT16 opcode)
{
	INT32 disp = ((INT32)(opcode&0xfff) << 20) >> 20;

#if BUSY_LOOP_HACKS
	if (disp == -2)
	{
		UINT32 next_opcode = RW(sh4,sh4->ppc & AM);
		/* BRA  $
         * NOP
         */
		if (next_opcode == 0x0009)
			sh4->sh4_icount %= 3;	/* cycles for BRA $ and NOP taken (3) */
	}
#endif
	sh4->delay = sh4->pc;
	sh4->pc = sh4->ea = sh4->pc + disp * 2 + 2;
	sh4->sh4_icount--;
}

/*  code                 cycles  t-bit
 *  0000 mmmm 0010 0011  2       -
 *  BRAF    Rm
 */
const void BRAF(sh4_state *sh4, const UINT16 opcode)
{
	sh4->delay = sh4->pc;
	sh4->pc += sh4->r[Rn] + 2;
	sh4->sh4_icount--;
}

/*  code                 cycles  t-bit
 *  1011 dddd dddd dddd  2       -
 *  BSR     disp12
 */
const void BSR(sh4_state *sh4, const UINT16 opcode)
{
	INT32 disp = ((INT32)(opcode&0xfff) << 20) >> 20;

	sh4->pr = sh4->pc + 2;
	sh4->delay = sh4->pc;
	sh4->pc = sh4->ea = sh4->pc + disp * 2 + 2;
	sh4->sh4_icount--;
}

/*  code                 cycles  t-bit
 *  0000 mmmm 0000 0011  2       -
 *  BSRF    Rm
 */
const void BSRF(sh4_state *sh4, const UINT16 opcode)
{
	sh4->pr = sh4->pc + 2;
	sh4->delay = sh4->pc;
	sh4->pc += sh4->r[Rn] + 2;
	sh4->sh4_icount--;
}

/*  code                 cycles  t-bit
 *  1000 1001 dddd dddd  3/1     -
 *  BT      disp8
 */
const void BT(sh4_state *sh4, const UINT16 opcode)
{
	if ((sh4->sr & T) != 0)
	{
		INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24;
		sh4->pc = sh4->ea = sh4->pc + disp * 2 + 2;
		sh4->sh4_icount -= 2;
	}
}

/*  code                 cycles  t-bit
 *  1000 1101 dddd dddd  2/1     -
 *  BTS     disp8
 */
const void BTS(sh4_state *sh4, const UINT16 opcode)
{
	if ((sh4->sr & T) != 0)
	{
		INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24;
		sh4->delay = sh4->pc;
		sh4->pc = sh4->ea = sh4->pc + disp * 2 + 2;
		sh4->sh4_icount--;
	}
}

/*  code                 cycles  t-bit
 *  0000 0000 0010 1000  1       -
 *  CLRMAC
 */
const void CLRMAC(sh4_state *sh4, const UINT16 opcode)
{
	sh4->mach = 0;
	sh4->macl = 0;
}

/*  code                 cycles  t-bit
 *  0000 0000 0000 1000  1       -
 *  CLRT
 */
const void CLRT(sh4_state *sh4, const UINT16 opcode)
{
	sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 0000  1       comparison result
 *  CMP_EQ  Rm,Rn
 */
const void CMPEQ(sh4_state *sh4, const UINT16 opcode)
{
	if (sh4->r[Rn] == sh4->r[Rm])
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 0011  1       comparison result
 *  CMP_GE  Rm,Rn
 */
const void CMPGE(sh4_state *sh4, const UINT16 opcode)
{
	if ((INT32) sh4->r[Rn] >= (INT32) sh4->r[Rm])
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 0111  1       comparison result
 *  CMP_GT  Rm,Rn
 */
const void CMPGT(sh4_state *sh4, const UINT16 opcode)
{
	if ((INT32) sh4->r[Rn] > (INT32) sh4->r[Rm])
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 0110  1       comparison result
 *  CMP_HI  Rm,Rn
 */
const void CMPHI(sh4_state *sh4, const UINT16 opcode)
{
	if ((UINT32) sh4->r[Rn] > (UINT32) sh4->r[Rm])
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 0010  1       comparison result
 *  CMP_HS  Rm,Rn
 */
const void CMPHS(sh4_state *sh4, const UINT16 opcode)
{
	if ((UINT32) sh4->r[Rn] >= (UINT32) sh4->r[Rm])
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}


/*  code                 cycles  t-bit
 *  0100 nnnn 0001 0101  1       comparison result
 *  CMP_PL  Rn
 */
const void CMPPL(sh4_state *sh4, const UINT16 opcode)
{
	if ((INT32) sh4->r[Rn] > 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0100 nnnn 0001 0001  1       comparison result
 *  CMP_PZ  Rn
 */
const void CMPPZ(sh4_state *sh4, const UINT16 opcode)
{
	if ((INT32) sh4->r[Rn] >= 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0010 nnnn mmmm 1100  1       comparison result
 * CMP_STR  Rm,Rn
 */
const void CMPSTR(sh4_state *sh4, const UINT16 opcode)
{
  UINT32 temp;
  INT32 HH, HL, LH, LL;
  temp = sh4->r[Rn] ^ sh4->r[Rm];
  HH = (temp >> 24) & 0xff;
  HL = (temp >> 16) & 0xff;
  LH = (temp >> 8) & 0xff;
  LL = temp & 0xff;
  if (HH && HL && LH && LL)
   sh4->sr &= ~T;
  else
   sh4->sr |= T;
 }


/*  code                 cycles  t-bit
 *  1000 1000 iiii iiii  1       comparison result
 *  CMP/EQ #imm,R0
 */
const void CMPIM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 imm = (UINT32)(INT32)(INT16)(INT8)(opcode&0xff);

	if (sh4->r[0] == imm)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0010 nnnn mmmm 0111  1       calculation result
 *  DIV0S   Rm,Rn
 */
const void DIV0S(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if ((sh4->r[n] & 0x80000000) == 0)
		sh4->sr &= ~Q;
	else
		sh4->sr |= Q;
	if ((sh4->r[m] & 0x80000000) == 0)
		sh4->sr &= ~M;
	else
		sh4->sr |= M;
	if ((sh4->r[m] ^ sh4->r[n]) & 0x80000000)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  code                 cycles  t-bit
 *  0000 0000 0001 1001  1       0
 *  DIV0U
 */
const void DIV0U(sh4_state *sh4, const UINT16 opcode)
{
	sh4->sr &= ~(M | Q | T);
}

/*  code                 cycles  t-bit
 *  0011 nnnn mmmm 0100  1       calculation result
 *  DIV1 Rm,Rn
 */
const void DIV1(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 tmp0;
	UINT32 old_q;

	old_q = sh4->sr & Q;
	if (0x80000000 & sh4->r[n])
		sh4->sr |= Q;
	else
		sh4->sr &= ~Q;

	sh4->r[n] = (sh4->r[n] << 1) | (sh4->sr & T);

	if (!old_q)
	{
		if (!(sh4->sr & M))
		{
			tmp0 = sh4->r[n];
			sh4->r[n] -= sh4->r[m];
			if(!(sh4->sr & Q))
				if(sh4->r[n] > tmp0)
					sh4->sr |= Q;
				else
					sh4->sr &= ~Q;
			else
				if(sh4->r[n] > tmp0)
					sh4->sr &= ~Q;
				else
					sh4->sr |= Q;
		}
		else
		{
			tmp0 = sh4->r[n];
			sh4->r[n] += sh4->r[m];
			if(!(sh4->sr & Q))
			{
				if(sh4->r[n] < tmp0)
					sh4->sr &= ~Q;
				else
					sh4->sr |= Q;
			}
			else
			{
				if(sh4->r[n] < tmp0)
					sh4->sr |= Q;
				else
					sh4->sr &= ~Q;
			}
		}
	}
	else
	{
		if (!(sh4->sr & M))
		{
			tmp0 = sh4->r[n];
			sh4->r[n] += sh4->r[m];
			if(!(sh4->sr & Q))
				if(sh4->r[n] < tmp0)
					sh4->sr |= Q;
				else
					sh4->sr &= ~Q;
			else
				if(sh4->r[n] < tmp0)
					sh4->sr &= ~Q;
				else
					sh4->sr |= Q;
		}
		else
		{
			tmp0 = sh4->r[n];
			sh4->r[n] -= sh4->r[m];
			if(!(sh4->sr & Q))
				if(sh4->r[n] > tmp0)
					sh4->sr &= ~Q;
				else
					sh4->sr |= Q;
			else
				if(sh4->r[n] > tmp0)
					sh4->sr |= Q;
				else
					sh4->sr &= ~Q;
		}
	}

	tmp0 = (sh4->sr & (Q | M));
	if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  DMULS.L Rm,Rn */
const void DMULS(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
	UINT32 temp0, temp1, temp2, temp3;
	INT32 tempm, tempn, fnLmL;

	tempn = (INT32) sh4->r[n];
	tempm = (INT32) sh4->r[m];
	if (tempn < 0)
		tempn = 0 - tempn;
	if (tempm < 0)
		tempm = 0 - tempm;
	if ((INT32) (sh4->r[n] ^ sh4->r[m]) < 0)
		fnLmL = -1;
	else
		fnLmL = 0;
	temp1 = (UINT32) tempn;
	temp2 = (UINT32) tempm;
	RnL = temp1 & 0x0000ffff;
	RnH = (temp1 >> 16) & 0x0000ffff;
	RmL = temp2 & 0x0000ffff;
	RmH = (temp2 >> 16) & 0x0000ffff;
	temp0 = RmL * RnL;
	temp1 = RmH * RnL;
	temp2 = RmL * RnH;
	temp3 = RmH * RnH;
	Res2 = 0;
	Res1 = temp1 + temp2;
	if (Res1 < temp1)
		Res2 += 0x00010000;
	temp1 = (Res1 << 16) & 0xffff0000;
	Res0 = temp0 + temp1;
	if (Res0 < temp0)
		Res2++;
	Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
	if (fnLmL < 0)
	{
		Res2 = ~Res2;
		if (Res0 == 0)
			Res2++;
		else
			Res0 = (~Res0) + 1;
	}
	sh4->mach = Res2;
	sh4->macl = Res0;
	sh4->sh4_icount--;
}

/*  DMULU.L Rm,Rn */
const void DMULU(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
	UINT32 temp0, temp1, temp2, temp3;

	RnL = sh4->r[n] & 0x0000ffff;
	RnH = (sh4->r[n] >> 16) & 0x0000ffff;
	RmL = sh4->r[m] & 0x0000ffff;
	RmH = (sh4->r[m] >> 16) & 0x0000ffff;
	temp0 = RmL * RnL;
	temp1 = RmH * RnL;
	temp2 = RmL * RnH;
	temp3 = RmH * RnH;
	Res2 = 0;
	Res1 = temp1 + temp2;
	if (Res1 < temp1)
		Res2 += 0x00010000;
	temp1 = (Res1 << 16) & 0xffff0000;
	Res0 = temp0 + temp1;
	if (Res0 < temp0)
		Res2++;
	Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
	sh4->mach = Res2;
	sh4->macl = Res0;
	sh4->sh4_icount--;
}

/*  DT      Rn */
const void DT(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n]--;
	if (sh4->r[n] == 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
#if BUSY_LOOP_HACKS
	{
		UINT32 next_opcode = RW(sh4,sh4->ppc & AM);
		/* DT   Rn
         * BF   $-2
         */
		if (next_opcode == 0x8bfd)
		{
			while (sh4->r[n] > 1 && sh4->sh4_icount > 4)
			{
				sh4->r[n]--;
				sh4->sh4_icount -= 4;	/* cycles for DT (1) and BF taken (3) */
			}
		}
	}
#endif
}

/*  EXTS.B  Rm,Rn */
const void EXTSB(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = ((INT32)sh4->r[Rm] << 24) >> 24;
}

/*  EXTS.W  Rm,Rn */
const void EXTSW(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = ((INT32)sh4->r[Rm] << 16) >> 16;
}

/*  EXTU.B  Rm,Rn */
const void EXTUB(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->r[Rm] & 0x000000ff;
}

/*  EXTU.W  Rm,Rn */
const void EXTUW(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->r[Rm] & 0x0000ffff;
}

/*  JMP     @Rm */
const void JMP(sh4_state *sh4, const UINT16 opcode)
{
	sh4->delay = sh4->pc;
	sh4->pc = sh4->ea = sh4->r[Rn];
}

/*  JSR     @Rm */
const void JSR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->delay = sh4->pc;
	sh4->pr = sh4->pc + 2;
	sh4->pc = sh4->ea = sh4->r[Rn];
	sh4->sh4_icount--;
}


/*  LDC     Rm,SR */
const void LDCSR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 reg;

	reg = sh4->r[Rn];
	if ((sh4->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
		sh4_syncronize_register_bank(sh4, (sh4->sr & sRB) >> 29);
	if ((sh4->r[Rn] & sRB) != (sh4->sr & sRB))
		sh4_change_register_bank(sh4, sh4->r[Rn] & sRB ? 1 : 0);
	sh4->sr = reg & FLAGS;
	sh4_exception_recompute(sh4);
}

/*  LDC     Rm,GBR */
const void LDCGBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->gbr = sh4->r[Rn];
}

/*  LDC     Rm,VBR */
const void LDCVBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->vbr = sh4->r[Rn];
}

/*  LDC.L   @Rm+,SR */
const void LDCMSR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 old;

	old = sh4->sr;
	sh4->ea = sh4->r[Rn];
	sh4->sr = RL(sh4, sh4->ea ) & FLAGS;
	if ((sh4->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
		sh4_syncronize_register_bank(sh4, (old & sRB) >> 29);
	if ((old & sRB) != (sh4->sr & sRB))
		sh4_change_register_bank(sh4, sh4->sr & sRB ? 1 : 0);
	sh4->r[Rn] += 4;
	sh4->sh4_icount -= 2;
	sh4_exception_recompute(sh4);
}

/*  LDC.L   @Rm+,GBR */
const void LDCMGBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->gbr = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
	sh4->sh4_icount -= 2;
}

/*  LDC.L   @Rm+,VBR */
const void LDCMVBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->vbr = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
	sh4->sh4_icount -= 2;
}

/*  LDS     Rm,MACH */
const void LDSMACH(sh4_state *sh4, const UINT16 opcode)
{
	sh4->mach = sh4->r[Rn];
}

/*  LDS     Rm,MACL */
const void LDSMACL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->macl = sh4->r[Rn];
}

/*  LDS     Rm,PR */
const void LDSPR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->pr = sh4->r[Rn];
}

/*  LDS.L   @Rm+,MACH */
const void LDSMMACH(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->mach = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  LDS.L   @Rm+,MACL */
const void LDSMMACL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->macl = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  LDS.L   @Rm+,PR */
const void LDSMPR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->pr = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  MAC.L   @Rm+,@Rn+ */
const void MAC_L(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
	UINT32 temp0, temp1, temp2, temp3;
	INT32 tempm, tempn, fnLmL;

	tempn = (INT32) RL(sh4, sh4->r[n] );
	sh4->r[n] += 4;
	tempm = (INT32) RL(sh4, sh4->r[m] );
	sh4->r[m] += 4;
	if ((INT32) (tempn ^ tempm) < 0)
		fnLmL = -1;
	else
		fnLmL = 0;
	if (tempn < 0)
		tempn = 0 - tempn;
	if (tempm < 0)
		tempm = 0 - tempm;
	temp1 = (UINT32) tempn;
	temp2 = (UINT32) tempm;
	RnL = temp1 & 0x0000ffff;
	RnH = (temp1 >> 16) & 0x0000ffff;
	RmL = temp2 & 0x0000ffff;
	RmH = (temp2 >> 16) & 0x0000ffff;
	temp0 = RmL * RnL;
	temp1 = RmH * RnL;
	temp2 = RmL * RnH;
	temp3 = RmH * RnH;
	Res2 = 0;
	Res1 = temp1 + temp2;
	if (Res1 < temp1)
		Res2 += 0x00010000;
	temp1 = (Res1 << 16) & 0xffff0000;
	Res0 = temp0 + temp1;
	if (Res0 < temp0)
		Res2++;
	Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3;
	if (fnLmL < 0)
	{
		Res2 = ~Res2;
		if (Res0 == 0)
			Res2++;
		else
			Res0 = (~Res0) + 1;
	}
	if (sh4->sr & S)
	{
		Res0 = sh4->macl + Res0;
		if (sh4->macl > Res0)
			Res2++;
		Res2 += (sh4->mach & 0x0000ffff);
		if (((INT32) Res2 < 0) && (Res2 < 0xffff8000))
		{
			Res2 = 0x00008000;
			Res0 = 0x00000000;
		}
		else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff))
		{
			Res2 = 0x00007fff;
			Res0 = 0xffffffff;
		}
		sh4->mach = Res2;
		sh4->macl = Res0;
	}
	else
	{
		Res0 = sh4->macl + Res0;
		if (sh4->macl > Res0)
			Res2++;
		Res2 += sh4->mach;
		sh4->mach = Res2;
		sh4->macl = Res0;
	}
	sh4->sh4_icount -= 2;
}

/*  MAC.W   @Rm+,@Rn+ */
const void MAC_W(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	INT32 tempm, tempn, dest, src, ans;
	UINT32 templ;

	tempn = (INT32) RW(sh4, sh4->r[n] );
	sh4->r[n] += 2;
	tempm = (INT32) RW(sh4, sh4->r[m] );
	sh4->r[m] += 2;
	templ = sh4->macl;
	tempm = ((INT32) (short) tempn * (INT32) (short) tempm);
	if ((INT32) sh4->macl >= 0)
		dest = 0;
	else
		dest = 1;
	if ((INT32) tempm >= 0)
	{
		src = 0;
		tempn = 0;
	}
	else
	{
		src = 1;
		tempn = 0xffffffff;
	}
	src += dest;
	sh4->macl += tempm;
	if ((INT32) sh4->macl >= 0)
		ans = 0;
	else
		ans = 1;
	ans += dest;
	if (sh4->sr & S)
	{
		if (ans == 1)
			{
				if (src == 0)
					sh4->macl = 0x7fffffff;
				if (src == 2)
					sh4->macl = 0x80000000;
			}
	}
	else
	{
		sh4->mach += tempn;
		if (templ > sh4->macl)
			sh4->mach += 1;
	}
	sh4->sh4_icount -= 2;
}

/*  MOV     Rm,Rn */
const void MOV(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->r[Rm];
}

/*  MOV.B   Rm,@Rn */
const void MOVBS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	WB(sh4, sh4->ea, sh4->r[Rm] & 0x000000ff);
}

/*  MOV.W   Rm,@Rn */
const void MOVWS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	WW(sh4, sh4->ea, sh4->r[Rm] & 0x0000ffff);
}

/*  MOV.L   Rm,@Rn */
const void MOVLS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	WL(sh4, sh4->ea, sh4->r[Rm] );
}

/*  MOV.B   @Rm,Rn */
const void MOVBL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rm];
	sh4->r[Rn] = (UINT32)(INT32)(INT16)(INT8) RB(sh4,  sh4->ea );
}

/*  MOV.W   @Rm,Rn */
const void MOVWL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rm];
	sh4->r[Rn] = (UINT32)(INT32)(INT16) RW(sh4, sh4->ea );
}

/*  MOV.L   @Rm,Rn */
const void MOVLL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rm];
	sh4->r[Rn] = RL(sh4, sh4->ea );
}

/*  MOV.B   Rm,@-Rn */
const void MOVBM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 data = sh4->r[Rm] & 0x000000ff;

	sh4->r[Rn] -= 1;
	WB(sh4, sh4->r[Rn], data );
}

/*  MOV.W   Rm,@-Rn */
const void MOVWM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 data = sh4->r[Rm] & 0x0000ffff;

	sh4->r[Rn] -= 2;
	WW(sh4, sh4->r[Rn], data );
}

/*  MOV.L   Rm,@-Rn */
const void MOVLM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 data = sh4->r[Rm];

	sh4->r[Rn] -= 4;
	WL(sh4, sh4->r[Rn], data );
}

/*  MOV.B   @Rm+,Rn */
const void MOVBP(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	sh4->r[n] = (UINT32)(INT32)(INT16)(INT8) RB(sh4,  sh4->r[m] );
	if (n != m)
		sh4->r[m] += 1;
}

/*  MOV.W   @Rm+,Rn */
const void MOVWP(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	sh4->r[n] = (UINT32)(INT32)(INT16) RW(sh4, sh4->r[m] );
	if (n != m)
		sh4->r[m] += 2;
}

/*  MOV.L   @Rm+,Rn */
const void MOVLP(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	sh4->r[n] = RL(sh4, sh4->r[m] );
	if (n != m)
		sh4->r[m] += 4;
}

/*  MOV.B   Rm,@(R0,Rn) */
const void MOVBS0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn] + sh4->r[0];
	WB(sh4, sh4->ea, sh4->r[Rm] & 0x000000ff );
}

/*  MOV.W   Rm,@(R0,Rn) */
const void MOVWS0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn] + sh4->r[0];
	WW(sh4, sh4->ea, sh4->r[Rm] & 0x0000ffff );
}

/*  MOV.L   Rm,@(R0,Rn) */
const void MOVLS0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn] + sh4->r[0];
	WL(sh4, sh4->ea, sh4->r[Rm] );
}

/*  MOV.B   @(R0,Rm),Rn */
const void MOVBL0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rm] + sh4->r[0];
	sh4->r[Rn] = (UINT32)(INT32)(INT16)(INT8) RB(sh4,  sh4->ea );
}

/*  MOV.W   @(R0,Rm),Rn */
const void MOVWL0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rm] + sh4->r[0];
	sh4->r[Rn] = (UINT32)(INT32)(INT16) RW(sh4, sh4->ea );
}

/*  MOV.L   @(R0,Rm),Rn */
const void MOVLL0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rm] + sh4->r[0];
	sh4->r[Rn] = RL(sh4, sh4->ea );
}

/*  MOV     #imm,Rn */
const void MOVI(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = (UINT32)(INT32)(INT16)(INT8)(opcode&0xff);
}

/*  MOV.W   @(disp8,PC),Rn */
const void MOVWI(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->pc + disp * 2 + 2;
	sh4->r[Rn] = (UINT32)(INT32)(INT16) RW(sh4, sh4->ea );
}

/*  MOV.L   @(disp8,PC),Rn */
const void MOVLI(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = ((sh4->pc + 2) & ~3) + disp * 4;
	sh4->r[Rn] = RL(sh4, sh4->ea );
}

/*  MOV.B   @(disp8,GBR),R0 */
const void MOVBLG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->gbr + disp;
	sh4->r[0] = (UINT32)(INT32)(INT16)(INT8) RB(sh4,  sh4->ea );
}

/*  MOV.W   @(disp8,GBR),R0 */
const void MOVWLG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->gbr + disp * 2;
	sh4->r[0] = (INT32)(INT16) RW(sh4, sh4->ea );
}

/*  MOV.L   @(disp8,GBR),R0 */
const void MOVLLG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->gbr + disp * 4;
	sh4->r[0] = RL(sh4, sh4->ea );
}

/*  MOV.B   R0,@(disp8,GBR) */
const void MOVBSG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->gbr + disp;
	WB(sh4, sh4->ea, sh4->r[0] & 0x000000ff );
}

/*  MOV.W   R0,@(disp8,GBR) */
const void MOVWSG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->gbr + disp * 2;
	WW(sh4, sh4->ea, sh4->r[0] & 0x0000ffff );
}

/*  MOV.L   R0,@(disp8,GBR) */
const void MOVLSG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = sh4->gbr + disp * 4;
	WL(sh4, sh4->ea, sh4->r[0] );
}

/*  MOV.B   R0,@(disp4,Rm) */
const void MOVBS4(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0x0f;
	sh4->ea = sh4->r[Rm] + disp;
	WB(sh4, sh4->ea, sh4->r[0] & 0x000000ff );
}

/*  MOV.W   R0,@(disp4,Rm) */
const void MOVWS4(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0x0f;
	sh4->ea = sh4->r[Rm] + disp * 2;
	WW(sh4, sh4->ea, sh4->r[0] & 0x0000ffff );
}

/* MOV.L Rm,@(disp4,Rn) */
const void MOVLS4(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0x0f;
	sh4->ea = sh4->r[Rn] + disp * 4;
	WL(sh4, sh4->ea, sh4->r[Rm] );
}

/*  MOV.B   @(disp4,Rm),R0 */
const void MOVBL4(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0x0f;
	sh4->ea = sh4->r[Rm] + disp;
	sh4->r[0] = (UINT32)(INT32)(INT16)(INT8) RB(sh4,  sh4->ea );
}

/*  MOV.W   @(disp4,Rm),R0 */
const void MOVWL4(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0x0f;
	sh4->ea = sh4->r[Rm] + disp * 2;
	sh4->r[0] = (UINT32)(INT32)(INT16) RW(sh4, sh4->ea );
}

/*  MOV.L   @(disp4,Rm),Rn */
const void MOVLL4(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0x0f;
	sh4->ea = sh4->r[Rm] + disp * 4;
	sh4->r[Rn] = RL(sh4, sh4->ea );
}

/*  MOVA    @(disp8,PC),R0 */
const void MOVA(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 disp = opcode & 0xff;
	sh4->ea = ((sh4->pc + 2) & ~3) + disp * 4;
	sh4->r[0] = sh4->ea;
}

/*  MOVT    Rn */
const void MOVT(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->sr & T;
}

/*  MUL.L   Rm,Rn */
const void MULL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->macl = sh4->r[Rn] * sh4->r[Rm];
	sh4->sh4_icount--;
}

/*  MULS    Rm,Rn */
const void MULS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->macl = (INT16) sh4->r[Rn] * (INT16) sh4->r[Rm];
}

/*  MULU    Rm,Rn */
const void MULU(sh4_state *sh4, const UINT16 opcode)
{
	sh4->macl = (UINT16) sh4->r[Rn] * (UINT16) sh4->r[Rm];
}

/*  NEG     Rm,Rn */
const void NEG(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = 0 - sh4->r[Rm];
}

/*  NEGC    Rm,Rn */
const void NEGC(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 temp;

	temp = sh4->r[Rm];
	sh4->r[Rn] = -temp - (sh4->sr & T);
	if (temp || (sh4->sr & T))
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  NOP */
const void NOP(sh4_state *sh4, const UINT16 opcode)
{
}

/*  NOT     Rm,Rn */
const void NOT(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = ~sh4->r[Rm];
}

/*  OR      Rm,Rn */
const void OR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] |= sh4->r[Rm];
}

/*  OR      #imm,R0 */
const void ORI(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[0] |= (opcode&0xff);
	sh4->sh4_icount -= 2;
}

/*  OR.B    #imm,@(R0,GBR) */
const void ORM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 temp;

	sh4->ea = sh4->gbr + sh4->r[0];
	temp = RB(sh4,  sh4->ea );
	temp |= (opcode&0xff);
	WB(sh4, sh4->ea, temp );
}

/*  ROTCL   Rn */
const void ROTCL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	UINT32 temp;

	temp = (sh4->r[n] >> 31) & T;
	sh4->r[n] = (sh4->r[n] << 1) | (sh4->sr & T);
	sh4->sr = (sh4->sr & ~T) | temp;
}

/*  ROTCR   Rn */
const void ROTCR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	UINT32 temp;
	temp = (sh4->sr & T) << 31;
	if (sh4->r[n] & T)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
	sh4->r[n] = (sh4->r[n] >> 1) | temp;
}

/*  ROTL    Rn */
const void ROTL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->sr = (sh4->sr & ~T) | ((sh4->r[n] >> 31) & T);
	sh4->r[n] = (sh4->r[n] << 1) | (sh4->r[n] >> 31);
}

/*  ROTR    Rn */
const void ROTR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->sr = (sh4->sr & ~T) | (sh4->r[n] & T);
	sh4->r[n] = (sh4->r[n] >> 1) | (sh4->r[n] << 31);
}

/*  RTE */
const void RTE(sh4_state *sh4, const UINT16 opcode)
{
	sh4->delay = sh4->pc;
	sh4->pc = sh4->ea = sh4->spc;
	if ((sh4->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
		sh4_syncronize_register_bank(sh4, (sh4->sr & sRB) >> 29);
	if ((sh4->ssr & sRB) != (sh4->sr & sRB))
		sh4_change_register_bank(sh4, sh4->ssr & sRB ? 1 : 0);
	sh4->sr = sh4->ssr;
	sh4->sh4_icount--;
	sh4_exception_recompute(sh4);
}

/*  RTS */
const void RTS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->delay = sh4->pc;
	sh4->pc = sh4->ea = sh4->pr;
	sh4->sh4_icount--;
}

/*  SETT */
const void SETT(sh4_state *sh4, const UINT16 opcode)
{
	sh4->sr |= T;
}

/*  SHAL    Rn      (same as SHLL) */
const void SHAL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->sr = (sh4->sr & ~T) | ((sh4->r[n] >> 31) & T);
	sh4->r[n] <<= 1;
}

/*  SHAR    Rn */
const void SHAR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->sr = (sh4->sr & ~T) | (sh4->r[n] & T);
	sh4->r[n] = (UINT32)((INT32)sh4->r[n] >> 1);
}

/*  SHLL    Rn      (same as SHAL) */
const void SHLL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->sr = (sh4->sr & ~T) | ((sh4->r[n] >> 31) & T);
	sh4->r[n] <<= 1;
}

/*  SHLL2   Rn */
const void SHLL2(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] <<= 2;
}

/*  SHLL8   Rn */
const void SHLL8(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] <<= 8;
}

/*  SHLL16  Rn */
const void SHLL16(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] <<= 16;
}

/*  SHLR    Rn */
const void SHLR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->sr = (sh4->sr & ~T) | (sh4->r[n] & T);
	sh4->r[n] >>= 1;
}

/*  SHLR2   Rn */
const void SHLR2(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] >>= 2;
}

/*  SHLR8   Rn */
const void SHLR8(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] >>= 8;
}

/*  SHLR16  Rn */
const void SHLR16(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] >>= 16;
}

/*  SLEEP */
const void SLEEP(sh4_state *sh4, const UINT16 opcode)
{
	/* 0 = normal mode */
	/* 1 = enters into power-down mode */
	/* 2 = go out the power-down mode after an exception */
	if(sh4->sleep_mode != 2)
		sh4->pc -= 2;
	sh4->sh4_icount -= 2;
	/* Wait_for_exception; */
	if(sh4->sleep_mode == 0)
		sh4->sleep_mode = 1;
	else if(sh4->sleep_mode == 2)
		sh4->sleep_mode = 0;
}

/*  STC     SR,Rn */
const void STCSR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->sr;
}

/*  STC     GBR,Rn */
const void STCGBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->gbr;
}

/*  STC     VBR,Rn */
const void STCVBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->vbr;
}

/*  STC.L   SR,@-Rn */
const void STCMSR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->sr );
	sh4->sh4_icount--;
}

/*  STC.L   GBR,@-Rn */
const void STCMGBR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->gbr );
	sh4->sh4_icount--;
}

/*  STC.L   VBR,@-Rn */
const void STCMVBR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->vbr );
	sh4->sh4_icount--;
}

/*  STS     MACH,Rn */
const void STSMACH(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->mach;
}

/*  STS     MACL,Rn */
const void STSMACL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->macl;
}

/*  STS     PR,Rn */
const void STSPR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->pr;
}

/*  STS.L   MACH,@-Rn */
const void STSMMACH(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->mach );
}

/*  STS.L   MACL,@-Rn */
const void STSMMACL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->macl );
}

/*  STS.L   PR,@-Rn */
const void STSMPR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->pr );
}

/*  SUB     Rm,Rn */
const void SUB(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] -= sh4->r[Rm];
}

/*  SUBC    Rm,Rn */
const void SUBC(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 tmp0, tmp1;

	tmp1 = sh4->r[n] - sh4->r[m];
	tmp0 = sh4->r[n];
	sh4->r[n] = tmp1 - (sh4->sr & T);
	if (tmp0 < tmp1)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
	if (tmp1 < sh4->r[n])
		sh4->sr |= T;
}

/*  SUBV    Rm,Rn */
const void SUBV(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	INT32 dest, src, ans;

	if ((INT32) sh4->r[n] >= 0)
		dest = 0;
	else
		dest = 1;
	if ((INT32) sh4->r[m] >= 0)
		src = 0;
	else
		src = 1;
	src += dest;
	sh4->r[n] -= sh4->r[m];
	if ((INT32) sh4->r[n] >= 0)
		ans = 0;
	else
		ans = 1;
	ans += dest;
	if (src == 1)
	{
		if (ans == 1)
			sh4->sr |= T;
		else
			sh4->sr &= ~T;
	}
	else
		sh4->sr &= ~T;
}

/*  SWAP.B  Rm,Rn */
const void SWAPB(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 temp0, temp1;

	temp0 = sh4->r[m] & 0xffff0000;
	temp1 = (sh4->r[m] & 0x000000ff) << 8;
	sh4->r[n] = (sh4->r[m] >> 8) & 0x000000ff;
	sh4->r[n] = sh4->r[n] | temp1 | temp0;
}

/*  SWAP.W  Rm,Rn */
const void SWAPW(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 temp;

	temp = (sh4->r[m] >> 16) & 0x0000ffff;
	sh4->r[n] = (sh4->r[m] << 16) | temp;
}

/*  TAS.B   @Rn */
const void TAS(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	UINT32 temp;
	sh4->ea = sh4->r[n];
	/* Bus Lock enable */
	temp = RB(sh4,  sh4->ea );
	if (temp == 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
	temp |= 0x80;
	/* Bus Lock disable */
	WB(sh4, sh4->ea, temp );
	sh4->sh4_icount -= 3;
}

/*  TRAPA   #imm */
const void TRAPA(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 imm = opcode & 0xff;

	if (sh4->cpu_type == CPU_TYPE_SH4)
	{
		sh4->m[TRA] = imm << 2;
	}
	else /* SH3 */
	{
		sh4->m_sh3internal_upper[SH3_TRA_ADDR] = imm << 2;
	}


	sh4->ssr = sh4->sr;
	sh4->spc = sh4->pc;
	sh4->sgr = sh4->r[15];

	sh4->sr |= MD;
	if ((sh4->device->machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
		sh4_syncronize_register_bank(sh4, (sh4->sr & sRB) >> 29);
	if (!(sh4->sr & sRB))
		sh4_change_register_bank(sh4, 1);
	sh4->sr |= sRB;
	sh4->sr |= BL;
	sh4_exception_recompute(sh4);

	if (sh4->cpu_type == CPU_TYPE_SH4)
	{
		sh4->m[EXPEVT] = 0x00000160;
	}
	else /* SH3 */
	{
		sh4->m_sh3internal_upper[SH3_EXPEVT_ADDR] = 0x00000160;
	}

	sh4->pc = sh4->vbr + 0x00000100;

	sh4->sh4_icount -= 7;
}

/*  TST     Rm,Rn */
const void TST(sh4_state *sh4, const UINT16 opcode)
{
	if ((sh4->r[Rn] & sh4->r[Rm]) == 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  TST     #imm,R0 */
const void TSTI(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 imm = opcode & 0xff;

	if ((imm & sh4->r[0]) == 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
}

/*  TST.B   #imm,@(R0,GBR) */
const void TSTM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 imm = opcode & 0xff;

	sh4->ea = sh4->gbr + sh4->r[0];
	if ((imm & RB(sh4,  sh4->ea )) == 0)
		sh4->sr |= T;
	else
		sh4->sr &= ~T;
	sh4->sh4_icount -= 2;
}

/*  XOR     Rm,Rn */
const void XOR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] ^= sh4->r[Rm];
}

/*  XOR     #imm,R0 */
const void XORI(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 imm = opcode & 0xff;
	sh4->r[0] ^= imm;
}

/*  XOR.B   #imm,@(R0,GBR) */
const void XORM(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 imm = opcode & 0xff;
	UINT32 temp;

	sh4->ea = sh4->gbr + sh4->r[0];
	temp = RB(sh4,  sh4->ea );
	temp ^= imm;
	WB(sh4, sh4->ea, temp );
	sh4->sh4_icount -= 2;
}

/*  XTRCT   Rm,Rn */
const void XTRCT(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	UINT32 temp;

	temp = (sh4->r[m] << 16) & 0xffff0000;
	sh4->r[n] = (sh4->r[n] >> 16) & 0x0000ffff;
	sh4->r[n] |= temp;
}

/*  STC     SSR,Rn */
const void STCSSR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->ssr;
}

/*  STC     SPC,Rn */
const void STCSPC(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->spc;
}

/*  STC     SGR,Rn */
const void STCSGR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->sgr;
}

/*  STS     FPUL,Rn */
const void STSFPUL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->fpul;
}

/*  STS     FPSCR,Rn */
const void STSFPSCR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->fpscr & 0x003FFFFF;
}

/*  STC     DBR,Rn */
const void STCDBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->r[Rn] = sh4->dbr;
}

/*  STCRBANK   Rm_BANK,Rn */
const void STCRBANK(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm;

	sh4->r[Rn] = sh4->rbnk[sh4->sr&sRB ? 0 : 1][m & 7];
}

/*  STCMRBANK   Rm_BANK,@-Rn */
const void STCMRBANK(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->rbnk[sh4->sr&sRB ? 0 : 1][m & 7]);
	sh4->sh4_icount--;
}

/*  MOVCA.L     R0,@Rn */
const void MOVCAL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	WL(sh4, sh4->ea, sh4->r[0] );
}

const void CLRS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->sr &= ~S;
}

const void SETS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->sr |= S;
}

/*  STS.L   SGR,@-Rn */
const void STCMSGR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->sgr );
}

/*  STS.L   FPUL,@-Rn */
const void STSMFPUL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->fpul );
}

/*  STS.L   FPSCR,@-Rn */
const void STSMFPSCR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->fpscr & 0x003FFFFF);
}

/*  STC.L   DBR,@-Rn */
const void STCMDBR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->dbr );
}

/*  STC.L   SSR,@-Rn */
const void STCMSSR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->ssr );
}

/*  STC.L   SPC,@-Rn */
const void STCMSPC(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	sh4->r[n] -= 4;
	sh4->ea = sh4->r[n];
	WL(sh4, sh4->ea, sh4->spc );
}

/*  LDS.L   @Rm+,FPUL */
const void LDSMFPUL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->fpul = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  LDS.L   @Rm+,FPSCR */
const void LDSMFPSCR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 s;

	s = sh4->fpscr;
	sh4->ea = sh4->r[Rn];
	sh4->fpscr = RL(sh4, sh4->ea );
	sh4->fpscr &= 0x003FFFFF;
	sh4->r[Rn] += 4;
	if ((s & FR) != (sh4->fpscr & FR))
		sh4_swap_fp_registers(sh4);
#ifdef LSB_FIRST
	if ((s & PR) != (sh4->fpscr & PR))
		sh4_swap_fp_couples(sh4);
#endif
	sh4->fpu_sz = (sh4->fpscr & SZ) ? 1 : 0;
	sh4->fpu_pr = (sh4->fpscr & PR) ? 1 : 0;
}

/*  LDC.L   @Rm+,DBR */
const void LDCMDBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->dbr = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  LDC.L   @Rn+,Rm_BANK */
const void LDCMRBANK(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	sh4->ea = sh4->r[n];
	sh4->rbnk[sh4->sr&sRB ? 0 : 1][m & 7] = RL(sh4, sh4->ea );
	sh4->r[n] += 4;
}

/*  LDC.L   @Rm+,SSR */
const void LDCMSSR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->ssr = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  LDC.L   @Rm+,SPC */
const void LDCMSPC(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ea = sh4->r[Rn];
	sh4->spc = RL(sh4, sh4->ea );
	sh4->r[Rn] += 4;
}

/*  LDS     Rm,FPUL */
const void LDSFPUL(sh4_state *sh4, const UINT16 opcode)
{
	sh4->fpul = sh4->r[Rn];
}

/*  LDS     Rm,FPSCR */
const void LDSFPSCR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 s;

	s = sh4->fpscr;
	sh4->fpscr = sh4->r[Rn] & 0x003FFFFF;
	if ((s & FR) != (sh4->fpscr & FR))
		sh4_swap_fp_registers(sh4);
#ifdef LSB_FIRST
	if ((s & PR) != (sh4->fpscr & PR))
		sh4_swap_fp_couples(sh4);
#endif
	sh4->fpu_sz = (sh4->fpscr & SZ) ? 1 : 0;
	sh4->fpu_pr = (sh4->fpscr & PR) ? 1 : 0;
}

/*  LDC     Rm,DBR */
const void LDCDBR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->dbr = sh4->r[Rn];
}

/*  SHAD    Rm,Rn */
const void SHAD(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if ((sh4->r[m] & 0x80000000) == 0)
		sh4->r[n] = sh4->r[n] << (sh4->r[m] & 0x1F);
	else if ((sh4->r[m] & 0x1F) == 0) {
		if ((sh4->r[n] & 0x80000000) == 0)
			sh4->r[n] = 0;
		else
			sh4->r[n] = 0xFFFFFFFF;
	} else
		sh4->r[n]=(INT32)sh4->r[n] >> ((~sh4->r[m] & 0x1F)+1);
}

/*  SHLD    Rm,Rn */
const void SHLD(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if ((sh4->r[m] & 0x80000000) == 0)
		sh4->r[n] = sh4->r[n] << (sh4->r[m] & 0x1F);
	else if ((sh4->r[m] & 0x1F) == 0)
		sh4->r[n] = 0;
	else
		sh4->r[n] = sh4->r[n] >> ((~sh4->r[m] & 0x1F)+1);
}

/*  LDCRBANK   Rn,Rm_BANK */
const void LDCRBANK(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm;

	sh4->rbnk[sh4->sr&sRB ? 0 : 1][m & 7] = sh4->r[Rn];
}

/*  LDC     Rm,SSR */
const void LDCSSR(sh4_state *sh4, const UINT16 opcode)
{
	sh4->ssr = sh4->r[Rn];
}

/*  LDC     Rm,SPC */
const void LDCSPC(sh4_state *sh4, const UINT16 opcode)
{
	sh4->spc = sh4->r[Rn];
}

/*  PREF     @Rn */
const void PREFM(sh4_state *sh4, const UINT16 opcode)
{
	int a;
	UINT32 addr,dest,sq;

	addr = sh4->r[Rn]; // address
	if ((addr >= 0xE0000000) && (addr <= 0xE3FFFFFF))
	{
		if (sh4->sh4_mmu_enabled)
		{
			addr = addr & 0xFFFFFFE0;
			dest = sh4_getsqremap(sh4, addr); // good enough for naomi-gd rom, probably not much else

		}
		else
		{
			sq = (addr & 0x20) >> 5;
			dest = addr & 0x03FFFFE0;
			if (sq == 0)
			{
				if (sh4->cpu_type == CPU_TYPE_SH4)
				{
					dest |= (sh4->m[QACR0] & 0x1C) << 24;
				}
				else
				{
					fatalerror("sh4->cpu_type != CPU_TYPE_SH4 but access internal regs\n");
				}
			}
			else
			{
				if (sh4->cpu_type == CPU_TYPE_SH4)
				{
					dest |= (sh4->m[QACR1] & 0x1C) << 24;
				}
				else
				{
					fatalerror("sh4->cpu_type != CPU_TYPE_SH4 but access internal regs\n");
				}

			}
			addr = addr & 0xFFFFFFE0;
		}

		for (a = 0;a < 4;a++)
		{
			// shouldn't be causing a memory read, should store sq writes in registers.
			sh4->program->write_qword(dest, sh4->program->read_qword(addr));
			addr += 8;
			dest += 8;
		}
	}
}

/*****************************************************************************
 *  OPCODE DISPATCHERS
 *****************************************************************************/

















/*  FMOV.S  @Rm+,FRn PR=0 SZ=0 1111nnnnmmmm1001 */
/*  FMOV    @Rm+,DRn PR=0 SZ=1 1111nnn0mmmm1001 */
/*  FMOV    @Rm+,XDn PR=0 SZ=1 1111nnn1mmmm1001 */
/*  FMOV    @Rm+,XDn PR=1      1111nnn1mmmm1001 */
const void FMOVMRIFR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		sh4->ea = sh4->r[m];
		sh4->r[m] += 8;
		sh4->xf[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(sh4, sh4->ea );
		sh4->xf[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(sh4, sh4->ea+4 );
	} else {              /* PR = 0 */
		if (sh4->fpu_sz) { /* SZ = 1 */
			if (n & 1) {
				n = n & 14;
				sh4->ea = sh4->r[m];
				sh4->xf[n] = RL(sh4, sh4->ea );
				sh4->r[m] += 4;
				sh4->xf[n+1] = RL(sh4, sh4->ea+4 );
				sh4->r[m] += 4;
			} else {
				sh4->ea = sh4->r[m];
				sh4->fr[n] = RL(sh4, sh4->ea );
				sh4->r[m] += 4;
				sh4->fr[n+1] = RL(sh4, sh4->ea+4 );
				sh4->r[m] += 4;
			}
		} else {              /* SZ = 0 */
			sh4->ea = sh4->r[m];
			sh4->fr[n] = RL(sh4, sh4->ea );
			sh4->r[m] += 4;
		}
	}
}

/*  FMOV.S  FRm,@Rn PR=0 SZ=0 1111nnnnmmmm1010 */
/*  FMOV    DRm,@Rn PR=0 SZ=1 1111nnnnmmm01010 */
/*  FMOV    XDm,@Rn PR=0 SZ=1 1111nnnnmmm11010 */
/*  FMOV    XDm,@Rn PR=1      1111nnnnmmm11010 */
const void FMOVFRMR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		m= m & 14;
		sh4->ea = sh4->r[n];
		WL(sh4, sh4->ea,sh4->xf[m+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] );
		WL(sh4, sh4->ea+4,sh4->xf[m+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] );
	} else {              /* PR = 0 */
		if (sh4->fpu_sz) { /* SZ = 1 */
			if (m & 1) {
				m= m & 14;
				sh4->ea = sh4->r[n];
				WL(sh4, sh4->ea,sh4->xf[m] );
				WL(sh4, sh4->ea+4,sh4->xf[m+1] );
			} else {
				sh4->ea = sh4->r[n];
				WL(sh4, sh4->ea,sh4->fr[m] );
				WL(sh4, sh4->ea+4,sh4->fr[m+1] );
			}
		} else {              /* SZ = 0 */
			sh4->ea = sh4->r[n];
			WL(sh4, sh4->ea,sh4->fr[m] );
		}
	}
}

/*  FMOV.S  FRm,@-Rn PR=0 SZ=0 1111nnnnmmmm1011 */
/*  FMOV    DRm,@-Rn PR=0 SZ=1 1111nnnnmmm01011 */
/*  FMOV    XDm,@-Rn PR=0 SZ=1 1111nnnnmmm11011 */
/*  FMOV    XDm,@-Rn PR=1      1111nnnnmmm11011 */
const void FMOVFRMDR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		m= m & 14;
		sh4->r[n] -= 8;
		sh4->ea = sh4->r[n];
		WL(sh4, sh4->ea,sh4->xf[m+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] );
		WL(sh4, sh4->ea+4,sh4->xf[m+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] );
	} else {              /* PR = 0 */
		if (sh4->fpu_sz) { /* SZ = 1 */
			if (m & 1) {
				m= m & 14;
				sh4->r[n] -= 8;
				sh4->ea = sh4->r[n];
				WL(sh4, sh4->ea,sh4->xf[m] );
				WL(sh4, sh4->ea+4,sh4->xf[m+1] );
			} else {
				sh4->r[n] -= 8;
				sh4->ea = sh4->r[n];
				WL(sh4, sh4->ea,sh4->fr[m] );
				WL(sh4, sh4->ea+4,sh4->fr[m+1] );
			}
		} else {              /* SZ = 0 */
			sh4->r[n] -= 4;
			sh4->ea = sh4->r[n];
			WL(sh4, sh4->ea,sh4->fr[m] );
		}
	}
}

/*  FMOV.S  FRm,@(R0,Rn) PR=0 SZ=0 1111nnnnmmmm0111 */
/*  FMOV    DRm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm00111 */
/*  FMOV    XDm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm10111 */
/*  FMOV    XDm,@(R0,Rn) PR=1      1111nnnnmmm10111 */
const void FMOVFRS0(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		m= m & 14;
		sh4->ea = sh4->r[0] + sh4->r[n];
		WL(sh4, sh4->ea,sh4->xf[m+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] );
		WL(sh4, sh4->ea+4,sh4->xf[m+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] );
	} else {              /* PR = 0 */
		if (sh4->fpu_sz) { /* SZ = 1 */
			if (m & 1) {
				m= m & 14;
				sh4->ea = sh4->r[0] + sh4->r[n];
				WL(sh4, sh4->ea,sh4->xf[m] );
				WL(sh4, sh4->ea+4,sh4->xf[m+1] );
			} else {
				sh4->ea = sh4->r[0] + sh4->r[n];
				WL(sh4, sh4->ea,sh4->fr[m] );
				WL(sh4, sh4->ea+4,sh4->fr[m+1] );
			}
		} else {              /* SZ = 0 */
			sh4->ea = sh4->r[0] + sh4->r[n];
			WL(sh4, sh4->ea,sh4->fr[m] );
		}
	}
}

/*  FMOV.S  @(R0,Rm),FRn PR=0 SZ=0 1111nnnnmmmm0110 */
/*  FMOV    @(R0,Rm),DRn PR=0 SZ=1 1111nnn0mmmm0110 */
/*  FMOV    @(R0,Rm),XDn PR=0 SZ=1 1111nnn1mmmm0110 */
/*  FMOV    @(R0,Rm),XDn PR=1      1111nnn1mmmm0110 */
const void FMOVS0FR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n= n & 14;
		sh4->ea = sh4->r[0] + sh4->r[m];
		sh4->xf[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(sh4, sh4->ea );
		sh4->xf[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(sh4, sh4->ea+4 );
	} else {              /* PR = 0 */
		if (sh4->fpu_sz) { /* SZ = 1 */
			if (n & 1) {
				n= n & 14;
				sh4->ea = sh4->r[0] + sh4->r[m];
				sh4->xf[n] = RL(sh4, sh4->ea );
				sh4->xf[n+1] = RL(sh4, sh4->ea+4 );
			} else {
				sh4->ea = sh4->r[0] + sh4->r[m];
				sh4->fr[n] = RL(sh4, sh4->ea );
				sh4->fr[n+1] = RL(sh4, sh4->ea+4 );
			}
		} else {              /* SZ = 0 */
			sh4->ea = sh4->r[0] + sh4->r[m];
			sh4->fr[n] = RL(sh4, sh4->ea );
		}
	}
}

/*  FMOV.S  @Rm,FRn PR=0 SZ=0 1111nnnnmmmm1000 */
/*  FMOV    @Rm,DRn PR=0 SZ=1 1111nnn0mmmm1000 */
/*  FMOV    @Rm,XDn PR=0 SZ=1 1111nnn1mmmm1000 */
/*  FMOV    @Rm,XDn PR=1      1111nnn1mmmm1000 */
/*  FMOV    @Rm,DRn PR=1      1111nnn0mmmm1000 */
const void FMOVMRFR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		if (n & 1) {
			n= n & 14;
			sh4->ea = sh4->r[m];
			sh4->xf[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(sh4, sh4->ea );
			sh4->xf[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(sh4, sh4->ea+4 );
		} else {
			n= n & 14;
			sh4->ea = sh4->r[m];
			sh4->fr[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(sh4, sh4->ea );
			sh4->fr[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(sh4, sh4->ea+4 );
		}
	} else {              /* PR = 0 */
		if (sh4->fpu_sz) { /* SZ = 1 */
			if (n & 1) {
				n= n & 14;
				sh4->ea = sh4->r[m];
				sh4->xf[n] = RL(sh4, sh4->ea );
				sh4->xf[n+1] = RL(sh4, sh4->ea+4 );
			} else {
				n= n & 14;
				sh4->ea = sh4->r[m];
				sh4->fr[n] = RL(sh4, sh4->ea );
				sh4->fr[n+1] = RL(sh4, sh4->ea+4 );
			}
		} else {              /* SZ = 0 */
			sh4->ea = sh4->r[m];
			sh4->fr[n] = RL(sh4, sh4->ea );
		}
	}
}

/*  FMOV    FRm,FRn PR=0 SZ=0 FRm -> FRn 1111nnnnmmmm1100 */
/*  FMOV    DRm,DRn PR=0 SZ=1 DRm -> DRn 1111nnn0mmm01100 */
/*  FMOV    XDm,DRn PR=1      XDm -> DRn 1111nnn0mmm11100 */
/*  FMOV    DRm,XDn PR=1      DRm -> XDn 1111nnn1mmm01100 */
/*  FMOV    XDm,XDn PR=1      XDm -> XDn 1111nnn1mmm11100 */
const void FMOVFR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if ((sh4->fpu_sz == 0) && (sh4->fpu_pr == 0)) /* SZ = 0 */
		sh4->fr[n] = sh4->fr[m];
	else { /* SZ = 1 or PR = 1 */
		if (m & 1) {
			if (n & 1) {
				sh4->xf[n & 14] = sh4->xf[m & 14];
				sh4->xf[n | 1] = sh4->xf[m | 1];
			} else {
				sh4->fr[n] = sh4->xf[m & 14];
				sh4->fr[n | 1] = sh4->xf[m | 1];
			}
		} else {
			if (n & 1) {
				sh4->xf[n & 14] = sh4->fr[m];
				sh4->xf[n | 1] = sh4->fr[m | 1]; // (a&14)+1 -> a|1
			} else {
				sh4->fr[n] = sh4->fr[m];
				sh4->fr[n | 1] = sh4->fr[m | 1];
			}
		}
	}
}

/*  FLDI1  FRn 1111nnnn10011101 */
const void FLDI1(sh4_state *sh4, const UINT16 opcode)
{
	sh4->fr[Rn] = 0x3F800000;
}

/*  FLDI0  FRn 1111nnnn10001101 */
const void FLDI0(sh4_state *sh4, const UINT16 opcode)
{
	sh4->fr[Rn] = 0;
}

/*  FLDS FRm,FPUL 1111mmmm00011101 */
const void	FLDS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->fpul = sh4->fr[Rn];
}

/*  FSTS FPUL,FRn 1111nnnn00001101 */
const void	FSTS(sh4_state *sh4, const UINT16 opcode)
{
	sh4->fr[Rn] = sh4->fpul;
}

/* FRCHG 1111101111111101 */
const void FRCHG(sh4_state *sh4)
{
	sh4->fpscr ^= FR;
	sh4_swap_fp_registers(sh4);
}

/* FSCHG 1111001111111101 */
const void FSCHG(sh4_state *sh4)
{
	sh4->fpscr ^= SZ;
	sh4->fpu_sz = (sh4->fpscr & SZ) ? 1 : 0;
}

/* FTRC FRm,FPUL PR=0 1111mmmm00111101 */
/* FTRC DRm,FPUL PR=1 1111mmm000111101 */
const void FTRC(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		*((INT32 *)&sh4->fpul) = (INT32)FP_RFD(n);
	} else {              /* PR = 0 */
		/* read sh4->fr[n] as float -> truncate -> fpul(32) */
		*((INT32 *)&sh4->fpul) = (INT32)FP_RFS(n);
	}
}

/* FLOAT FPUL,FRn PR=0 1111nnnn00101101 */
/* FLOAT FPUL,DRn PR=1 1111nnn000101101 */
const void FLOAT(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		FP_RFD(n) = (double)*((INT32 *)&sh4->fpul);
	} else {              /* PR = 0 */
		FP_RFS(n) = (float)*((INT32 *)&sh4->fpul);
	}
}

/* FNEG FRn PR=0 1111nnnn01001101 */
/* FNEG DRn PR=1 1111nnn001001101 */
const void FNEG(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		FP_RFD(n) = -FP_RFD(n);
	} else {              /* PR = 0 */
		FP_RFS(n) = -FP_RFS(n);
	}
}

/* FABS FRn PR=0 1111nnnn01011101 */
/* FABS DRn PR=1 1111nnn001011101 */
const void FABS(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
#ifdef LSB_FIRST
		n = n | 1; // n & 14 + 1
		sh4->fr[n] = sh4->fr[n] & 0x7fffffff;
#else
		n = n & 14;
		sh4->fr[n] = sh4->fr[n] & 0x7fffffff;
#endif
	} else {              /* PR = 0 */
		sh4->fr[n] = sh4->fr[n] & 0x7fffffff;
	}
}

/* FCMP/EQ FRm,FRn PR=0 1111nnnnmmmm0100 */
/* FCMP/EQ DRm,DRn PR=1 1111nnn0mmm00100 */
const void FCMP_EQ(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		m = m & 14;
		if (FP_RFD(n) == FP_RFD(m))
			sh4->sr |= T;
		else
			sh4->sr &= ~T;
	} else {              /* PR = 0 */
		if (FP_RFS(n) == FP_RFS(m))
			sh4->sr |= T;
		else
			sh4->sr &= ~T;
	}
}

/* FCMP/GT FRm,FRn PR=0 1111nnnnmmmm0101 */
/* FCMP/GT DRm,DRn PR=1 1111nnn0mmm00101 */
const void FCMP_GT(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		m = m & 14;
		if (FP_RFD(n) > FP_RFD(m))
			sh4->sr |= T;
		else
			sh4->sr &= ~T;
	} else {              /* PR = 0 */
		if (FP_RFS(n) > FP_RFS(m))
			sh4->sr |= T;
		else
			sh4->sr &= ~T;
	}
}

/* FCNVDS DRm,FPUL PR=1 1111mmm010111101 */
const void FCNVDS(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		if (sh4->fpscr & RM)
			sh4->fr[n | NATIVE_ENDIAN_VALUE_LE_BE(0,1)] &= 0xe0000000; /* round toward zero*/
		*((float *)&sh4->fpul) = (float)FP_RFD(n);
	}
}

/* FCNVSD FPUL, DRn PR=1 1111nnn010101101 */
const void FCNVSD(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		FP_RFD(n) = (double)*((float *)&sh4->fpul);
	}
}

/* FADD FRm,FRn PR=0 1111nnnnmmmm0000 */
/* FADD DRm,DRn PR=1 1111nnn0mmm00000 */
const void FADD(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		m = m & 14;
		FP_RFD(n) = FP_RFD(n) + FP_RFD(m);
	} else {              /* PR = 0 */
		FP_RFS(n) = FP_RFS(n) + FP_RFS(m);
	}
}

/* FSUB FRm,FRn PR=0 1111nnnnmmmm0001 */
/* FSUB DRm,DRn PR=1 1111nnn0mmm00001 */
const void FSUB(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		m = m & 14;
		FP_RFD(n) = FP_RFD(n) - FP_RFD(m);
	} else {              /* PR = 0 */
		FP_RFS(n) = FP_RFS(n) - FP_RFS(m);
	}
}


/* FMUL FRm,FRn PR=0 1111nnnnmmmm0010 */
/* FMUL DRm,DRn PR=1 1111nnn0mmm00010 */
const void FMUL(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		m = m & 14;
		FP_RFD(n) = FP_RFD(n) * FP_RFD(m);
	} else {              /* PR = 0 */
		FP_RFS(n) = FP_RFS(n) * FP_RFS(m);
	}
}

/* FDIV FRm,FRn PR=0 1111nnnnmmmm0011 */
/* FDIV DRm,DRn PR=1 1111nnn0mmm00011 */
const void FDIV(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		m = m & 14;
		if (FP_RFD(m) == 0)
			return;
		FP_RFD(n) = FP_RFD(n) / FP_RFD(m);
	} else {              /* PR = 0 */
		if (FP_RFS(m) == 0)
			return;
		FP_RFS(n) = FP_RFS(n) / FP_RFS(m);
	}
}

/* FMAC FR0,FRm,FRn PR=0 1111nnnnmmmm1110 */
const void FMAC(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 m = Rm; UINT32 n = Rn;

	if (sh4->fpu_pr == 0) { /* PR = 0 */
		FP_RFS(n) = (FP_RFS(0) * FP_RFS(m)) + FP_RFS(n);
	}
}

/* FSQRT FRn PR=0 1111nnnn01101101 */
/* FSQRT DRn PR=1 1111nnnn01101101 */
const void FSQRT(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (sh4->fpu_pr) { /* PR = 1 */
		n = n & 14;
		if (FP_RFD(n) < 0)
			return;
		FP_RFD(n) = sqrtf(FP_RFD(n));
	} else {              /* PR = 0 */
		if (FP_RFS(n) < 0)
			return;
		FP_RFS(n) = sqrtf(FP_RFS(n));
	}
}

/* FSRRA FRn PR=0 1111nnnn01111101 */
const void FSRRA(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

	if (FP_RFS(n) < 0)
		return;
	FP_RFS(n) = 1.0 / sqrtf(FP_RFS(n));
}

/*  FSSCA FPUL,FRn PR=0 1111nnn011111101 */
const void FSSCA(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

float angle;

	angle = (((float)(sh4->fpul & 0xFFFF)) / 65536.0) * 2.0 * M_PI;
	FP_RFS(n) = sinf(angle);
	FP_RFS(n+1) = cosf(angle);
}

/* FIPR FVm,FVn PR=0 1111nnmm11101101 */
const void FIPR(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

UINT32 m;
float ml[4];
int a;

	m = (n & 3) << 2;
	n = n & 12;
	for (a = 0;a < 4;a++)
		ml[a] = FP_RFS(n+a) * FP_RFS(m+a);
	FP_RFS(n+3) = ml[0] + ml[1] + ml[2] + ml[3];
}

/* FTRV XMTRX,FVn PR=0 1111nn0111111101 */
const void FTRV(sh4_state *sh4, const UINT16 opcode)
{
	UINT32 n = Rn;

int i,j;
float sum[4];

	n = n & 12;
	for (i = 0;i < 4;i++) {
		sum[i] = 0;
		for (j=0;j < 4;j++)
			sum[i] += FP_XFS((j << 2) + i)*FP_RFS(n + j);
	}
	for (i = 0;i < 4;i++)
		FP_RFS(n + i) = sum[i];
}

const void op1111_0xf13(sh4_state *sh4, const UINT16 opcode)
{
	if (opcode & 0x100) {
			if (opcode & 0x200) {
				switch (opcode & 0xC00)
				{
					case 0x000:
						FSCHG(sh4);
						break;
					case 0x800:
						FRCHG(sh4);
						break;
					default:
						debugger_break(sh4->device->machine());
						break;
				}
			} else {
				FTRV(sh4, opcode);
			}
		} else {
			FSSCA(sh4, opcode);
		}
}

const void dbreak(sh4_state *sh4, const UINT16 opcode)
{
	debugger_break(sh4->device->machine());
}


sh4ophandler op1111_0x13_handlers[] =
{
	FSTS,		FLDS,		FLOAT,		FTRC,		FNEG,		FABS,		FSQRT,		FSRRA,		FLDI0,		FLDI1,		FCNVSD,		FCNVDS,		dbreak, dbreak, FIPR,	op1111_0xf13
};

const void op1111_0x13(sh4_state *sh4, UINT16 opcode)
{
	op1111_0x13_handlers[(opcode&0xf0)>>4](sh4, opcode);
}


/*****************************************************************************
 *  MAME CPU INTERFACE
 *****************************************************************************/

static CPU_RESET( common_sh4_reset )
{
	sh4_state *sh4 = get_safe_token(device);
	emu_timer *tsaved[4];
	emu_timer *tsave[5];
	UINT32 *m;
	int save_is_slave;
	int	savecpu_clock, savebus_clock, savepm_clock;

	void (*f)(UINT32 data);
	device_irq_acknowledge_callback save_irqcallback;

	m = sh4->m;
	tsaved[0] = sh4->dma_timer[0];
	tsaved[1] = sh4->dma_timer[1];
	tsaved[2] = sh4->dma_timer[2];
	tsaved[3] = sh4->dma_timer[3];
	tsave[0] = sh4->refresh_timer;
	tsave[1] = sh4->rtc_timer;
	tsave[2] = sh4->timer[0];
	tsave[3] = sh4->timer[1];
	tsave[4] = sh4->timer[2];

	f = sh4->ftcsr_read_callback;
	save_irqcallback = sh4->irq_callback;
	save_is_slave = sh4->is_slave;
	savecpu_clock = sh4->cpu_clock;
	savebus_clock = sh4->bus_clock;
	savepm_clock = sh4->pm_clock;
	memset(sh4, 0, sizeof(*sh4));
	sh4->is_slave = save_is_slave;
	sh4->cpu_clock = savecpu_clock;
	sh4->bus_clock = savebus_clock;
	sh4->pm_clock = savepm_clock;
	sh4->ftcsr_read_callback = f;
	sh4->irq_callback = save_irqcallback;
	sh4->device = device;
	sh4->internal = device->space(AS_PROGRAM);
	sh4->program = device->space(AS_PROGRAM);
	sh4->direct = &sh4->program->direct();
	sh4->io = device->space(AS_IO);

	sh4->dma_timer[0] = tsaved[0];
	sh4->dma_timer[1] = tsaved[1];
	sh4->dma_timer[2] = tsaved[2];
	sh4->dma_timer[3] = tsaved[3];
	sh4->refresh_timer = tsave[0];
	sh4->rtc_timer = tsave[1];
	sh4->timer[0] = tsave[2];
	sh4->timer[1] = tsave[3];
	sh4->timer[2] = tsave[4];
	sh4->m = m;
	memset(sh4->m, 0, 16384*4);
	sh4_default_exception_priorities(sh4);
	memset(sh4->exception_requesting, 0, sizeof(sh4->exception_requesting));

	sh4->rtc_timer->adjust(attotime::from_hz(128));


	sh4->pc = 0xa0000000;
	sh4->r[15] = RL(sh4,4);
	sh4->sr = 0x700000f0;
	sh4->fpscr = 0x00040001;
	sh4->fpu_sz = (sh4->fpscr & SZ) ? 1 : 0;
	sh4->fpu_pr = (sh4->fpscr & PR) ? 1 : 0;
	sh4->fpul = 0;
	sh4->dbr = 0;

	sh4->internal_irq_level = -1;
	sh4->irln = 15;
	sh4->sleep_mode = 0;

	sh4->sh4_mmu_enabled = 0;

	sh4_build_optable(sh4);
}

/*-------------------------------------------------
    sh3_reset - reset the processor
-------------------------------------------------*/

static CPU_RESET( sh3 )
{
	sh4_state *sh4 = get_safe_token(device);

	CPU_RESET_CALL(common_sh4_reset);

	sh4->cpu_type = CPU_TYPE_SH3;

	sh4->SH4_TCOR0 = 0xffffffff;
	sh4->SH4_TCNT0 = 0xffffffff;
	sh4->SH4_TCOR1 = 0xffffffff;
	sh4->SH4_TCNT1 = 0xffffffff;
	sh4->SH4_TCOR2 = 0xffffffff;
	sh4->SH4_TCNT2 = 0xffffffff;

}

static CPU_RESET( sh4 )
{
	sh4_state *sh4 = get_safe_token(device);

	CPU_RESET_CALL(common_sh4_reset);

	sh4->cpu_type = CPU_TYPE_SH4;

	sh4->m[RCR2] = 0x09;
	sh4->SH4_TCOR0 = 0xffffffff;
	sh4->SH4_TCNT0 = 0xffffffff;
	sh4->SH4_TCOR1 = 0xffffffff;
	sh4->SH4_TCNT1 = 0xffffffff;
	sh4->SH4_TCOR2 = 0xffffffff;
	sh4->SH4_TCNT2 = 0xffffffff;
}

/* These tables are combined into our main opcode jump table, master_ophandler_table in the RESET function */

sh4ophandler op1000_handler[] =
{
	MOVBS4,		MOVWS4,		NOP,		NOP,		MOVBL4,		MOVWL4,		NOP,		NOP,		CMPIM,		BT,			NOP,		BF,			NOP,		BTS,		NOP,		BFS
};

sh4ophandler op1100_handler[] =
{
	MOVBSG,		MOVWSG,		MOVLSG,		TRAPA,		MOVBLG,		MOVWLG,		MOVLLG,		MOVA,		TSTI,		ANDI,		XORI,		ORI,		TSTM,		ANDM,		XORM,		ORM
};

sh4ophandler op0000_handlers[] =
{
	NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,
	NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,
	STCSR,		STCGBR,		STCVBR,		STCSSR,		STCSPC,		NOP,		NOP,		NOP,		STCRBANK,	STCRBANK,	STCRBANK,	STCRBANK,	STCRBANK,	STCRBANK,	STCRBANK,	STCRBANK,
	BSRF,		NOP,		BRAF,		NOP,		NOP,		NOP,		NOP,		NOP,		PREFM,		TODO,		TODO,		TODO,		MOVCAL,		NOP,		NOP,		NOP,
	MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,		MOVBS0,
	MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,		MOVWS0,
	MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,		MOVLS0,
	MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,		MULL,
	CLRT,		SETT,		CLRMAC,		TODO,		CLRS,		SETS,		NOP,		NOP,		CLRT,		SETT,		CLRMAC,		TODO,		CLRS,		SETS,		NOP,		NOP,
	NOP,		DIV0U,		MOVT,		NOP,		NOP,		DIV0U,		MOVT,		NOP,		NOP,		DIV0U,		MOVT,		NOP,		NOP,		DIV0U,		MOVT,		NOP,
	STSMACH,	STSMACL,	STSPR,		STCSGR,		NOP,		STSFPUL,	STSFPSCR,	STCDBR,		STSMACH,	STSMACL,	STSPR,		STCSGR,		NOP,		STSFPUL,	STSFPSCR,	STCDBR,
	RTS,		SLEEP,		RTE,		NOP,		RTS,		SLEEP,		RTE,		NOP,		RTS,		SLEEP,		RTE,		NOP,		RTS,		SLEEP,		RTE,		NOP,
	MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,		MOVBL0,
	MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,		MOVWL0,
	MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,		MOVLL0,
	MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,		MAC_L,
};

sh4ophandler op0100_handlers[] =
{
	SHLL,		DT,			SHAL,		NOP,		SHLL,		DT,			SHAL,		NOP,		SHLL,		DT,			SHAL,		NOP,		SHLL,		DT,			SHAL,		NOP,
	SHLR,		CMPPZ,		SHAR,		NOP,		SHLR,		CMPPZ,		SHAR,		NOP,		SHLR,		CMPPZ,		SHAR,		NOP,		SHLR,		CMPPZ,		SHAR,		NOP,
	STSMMACH,	STSMMACL,	STSMPR,		STCMSGR,	NOP,		STSMFPUL,	STSMFPSCR,	NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		STCMDBR,
	STCMSR,		STCMGBR,	STCMVBR,	STCMSSR,	STCMSPC,	NOP,		NOP,		NOP,		STCMRBANK,	STCMRBANK,	STCMRBANK,	STCMRBANK,	STCMRBANK,	STCMRBANK,	STCMRBANK,	STCMRBANK,
	ROTL,		NOP,		ROTCL,		NOP,		ROTL,		NOP,		ROTCL,		NOP,		ROTL,		NOP,		ROTCL,		NOP,		ROTL,		NOP,		ROTCL,		NOP,
	ROTR,		CMPPL,		ROTCR,		NOP,		ROTR,		CMPPL,		ROTCR,		NOP,		ROTR,		CMPPL,		ROTCR,		NOP,		ROTR,		CMPPL,		ROTCR,		NOP,
	LDSMMACH,	LDSMMACL,	LDSMPR,		NOP,		NOP,		LDSMFPUL,	LDSMFPSCR,	NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		LDCMDBR,
	LDCMSR,		LDCMGBR,	LDCMVBR,	LDCMSSR,	LDCMSPC,	NOP,		NOP,		NOP,		LDCMRBANK,	LDCMRBANK,	LDCMRBANK,	LDCMRBANK,	LDCMRBANK,	LDCMRBANK,	LDCMRBANK,	LDCMRBANK,
	SHLL2,		SHLL8,		SHLL16,		NOP,		SHLL2,		SHLL8,		SHLL16,		NOP,		SHLL2,		SHLL8,		SHLL16,		NOP,		SHLL2,		SHLL8,		SHLL16,		NOP,
	SHLR2,		SHLR8,		SHLR16,		NOP,		SHLR2,		SHLR8,		SHLR16,		NOP,		SHLR2,		SHLR8,		SHLR16,		NOP,		SHLR2,		SHLR8,		SHLR16,		NOP,
	LDSMACH,	LDSMACL,	LDSPR,		NOP,		NOP,		LDSFPUL,	LDSFPSCR,	NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		NOP,		LDCDBR,
	JSR,		TAS,		JMP,		NOP,		JSR,		TAS,		JMP,		NOP,		JSR,		TAS,		JMP,		NOP,		JSR,		TAS,		JMP,		NOP,
	SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,		SHAD,
	SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,		SHLD,
	LDCSR,		LDCGBR,		LDCVBR,		LDCSSR,		LDCSPC,		NOP,		NOP,		NOP,		LDCRBANK,	LDCRBANK,	LDCRBANK,	LDCRBANK,	LDCRBANK,	LDCRBANK,	LDCRBANK,	LDCRBANK,
	MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,		MAC_W,
};


sh4ophandler upper4bits[] =
{
	0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,		/* j = 0x0000 - uses op0000_handlers*/
	MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4,		MOVLS4, /* j = 0x1000 */
	MOVBS,		MOVWS,		MOVLS,		NOP,		MOVBM,		MOVWM,		MOVLM,		DIV0S,		TST,		AND,		XOR,		OR,			CMPSTR,		XTRCT,		MULU,		MULS,	/* j = 0x2000 */
	CMPEQ,		NOP,		CMPHS,		CMPGE,		DIV1,		DMULU,		CMPHI,		CMPGT,		SUB,		NOP,		SUBC,		SUBV,		ADD,		DMULS,		ADDC,		ADDV,	/* j = 0x3000 */
	0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,		/* j = 0x4000 - uses op0100_handlers*/
	MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4,		MOVLL4, /* j = 0x5000 */
	MOVBL,		MOVWL,		MOVLL,		MOV,		MOVBP,		MOVWP,		MOVLP,		NOT,		SWAPB,		SWAPW,		NEGC,		NEG,		EXTUB,		EXTUW,		EXTSB,		EXTSW,	/* j = 0x6000 */
	ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,		ADDI,	/* j = 0x7000 */
	0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,		/* j = 0x8000 - uses op1000_handlers */
	MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,		MOVWI,	/* j = 0x9000 */
	BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,		BRA,	/* j = 0xa000 */
	BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,		BSR,	/* j = 0xb000 */
	0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,			0,		/* j = 0xc000 - uses op1100_handlers */
	MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,		MOVLI,	/* j = 0xd000 */
	MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,		MOVI,	/* j = 0xe000 */
	FADD,		FSUB,		FMUL,		FDIV,		FCMP_EQ,	FCMP_GT,	FMOVS0FR,	FMOVFRS0,	FMOVMRFR,	FMOVMRIFR,	FMOVFRMR,	FMOVFRMDR,	FMOVFR,		op1111_0x13,FMAC,		dbreak	/* j = 0xf000 */
};

void sh4_build_optable(sh4_state *sh4)
{
	int j,y,x,z;

	// combine our opcode handler tables into one larger table thus reducing level of indirection on all opcode handlers
	for (j = 0; j<0x10000;j+=0x1000)
	{
		for (y = 0; y<0x1000;y+=0x100)
		{
			for (x=0; x<0x100;x+=0x10)
			{
				for (z=0;z<0x10;z++)
				{
					master_ophandler_table[j+y+x+z] = upper4bits[(((j+z)&0xf000)>>8) + (z & 0xf)];
				}
			}
		}
	}

	j = 0x0000;
	//for (j = 0; j<0x10000;j+=0x1000)
	{
		for (y = 0; y<0x1000;y+=0x100)
		{
			for (x=0; x<0x100;x+=0x10)
			{
				for (z=0;z<0x10;z++)
				{
					master_ophandler_table[j+y+x+z] = op0000_handlers[((((j+y+x+z)&0xf0)>>4)) | ((((j+y+x+z)&0xf)<<4))];
				}
			}
		}
	}

	j = 0x4000;
	//for (j = 0; j<0x10000;j+=0x1000)
	{
		for (y = 0; y<0x1000;y+=0x100)
		{
			for (x=0; x<0x100;x+=0x10)
			{
				for (z=0;z<0x10;z++)
				{
					master_ophandler_table[j+y+x+z] = op0100_handlers[((((j+y+x+z)&0xf0)>>4)) | ((((j+y+x+z)&0xf)<<4))];
				}
			}
		}
	}


	j = 0x8000;
	//for (j = 0; j<0x10000;j+=0x1000)
	{
		for (y = 0; y<0x1000;y+=0x100)
		{
			for (x=0; x<0x100;x+=0x10)
			{
				for (z=0;z<0x10;z++)
				{
					master_ophandler_table[j+y+x+z] = op1000_handler[((((j+y+x+z)&0xf00)>>8))];
				}
			}
		}
	}

	j = 0xc000;
	//for (j = 0; j<0x10000;j+=0x1000)
	{
		for (y = 0; y<0x1000;y+=0x100)
		{
			for (x=0; x<0x100;x+=0x10)
			{
				for (z=0;z<0x10;z++)
				{
					master_ophandler_table[j+y+x+z] = op1100_handler[((((j+y+x+z)&0xf00)>>8))];
				}
			}
		}
	}


}


/* Execute cycles - returns number of cycles actually run */
static CPU_EXECUTE( sh4 )
{
	sh4_state *sh4 = get_safe_token(device);

	if (sh4->cpu_off)
	{
		sh4->sh4_icount = 0;
		return;
	}

	do
	{
		if (sh4->delay)
		{
			const UINT16 opcode = sh4->direct->read_decrypted_word((UINT32)(sh4->delay & AM), WORD2_XOR_LE(0));

			debugger_instruction_hook(device, (sh4->pc-2) & AM);

			sh4->delay = 0;
			sh4->ppc = sh4->pc;

			master_ophandler_table[opcode](sh4, opcode);

			if (sh4->test_irq && !sh4->delay)
			{
				sh4_check_pending_irq(sh4, "mame_sh4_execute");
			}
		}
		else
		{
			const UINT16  opcode = sh4->direct->read_decrypted_word((UINT32)(sh4->pc & AM), WORD2_XOR_LE(0));

			debugger_instruction_hook(device, sh4->pc & AM);

			sh4->pc += 2;
			sh4->ppc = sh4->pc;

			master_ophandler_table[opcode](sh4, opcode);

			if (sh4->test_irq && !sh4->delay)
			{
				sh4_check_pending_irq(sh4, "mame_sh4_execute");
			}
		}

		sh4->sh4_icount--;
	} while( sh4->sh4_icount > 0 );
}

static CPU_EXECUTE( sh4be )
{
	sh4_state *sh4 = get_safe_token(device);

	if (sh4->cpu_off)
	{
		sh4->sh4_icount = 0;
		return;
	}

	do
	{
		if (sh4->delay)
		{
			const UINT16 opcode = sh4->direct->read_decrypted_word((UINT32)(sh4->delay & AM), WORD_XOR_LE(6));

			debugger_instruction_hook(device, sh4->delay & AM);

			sh4->delay = 0;
			sh4->ppc = sh4->pc;

			master_ophandler_table[opcode](sh4, opcode);


			if (sh4->test_irq && !sh4->delay)
			{
				sh4_check_pending_irq(sh4, "mame_sh4_execute");
			}


		}
		else
		{
			const UINT16 opcode = sh4->direct->read_decrypted_word((UINT32)(sh4->pc & AM), WORD_XOR_LE(6));

			debugger_instruction_hook(device, sh4->pc & AM);

			sh4->pc += 2;
			sh4->ppc = sh4->pc;

			master_ophandler_table[opcode](sh4, opcode);

			if (sh4->test_irq && !sh4->delay)
			{
				sh4_check_pending_irq(sh4, "mame_sh4_execute");
			}
		}

		sh4->sh4_icount--;
	} while( sh4->sh4_icount > 0 );
}

static CPU_INIT( sh4 )
{
	const struct sh4_config *conf = (const struct sh4_config *)device->static_config();
	sh4_state *sh4 = get_safe_token(device);

	sh4_common_init(device);

	sh4_parse_configuration(sh4, conf);

	sh4->irq_callback = irqcallback;
	sh4->device = device;
	sh4->internal = device->space(AS_PROGRAM);
	sh4->program = device->space(AS_PROGRAM);
	sh4->io = device->space(AS_IO);
	sh4_default_exception_priorities(sh4);
	sh4->irln = 15;
	sh4->test_irq = 0;

	device->save_item(NAME(sh4->pc));
	device->save_item(NAME(sh4->r[15]));
	device->save_item(NAME(sh4->sr));
	device->save_item(NAME(sh4->pr));
	device->save_item(NAME(sh4->gbr));
	device->save_item(NAME(sh4->vbr));
	device->save_item(NAME(sh4->mach));
	device->save_item(NAME(sh4->macl));
	device->save_item(NAME(sh4->spc));
	device->save_item(NAME(sh4->ssr));
	device->save_item(NAME(sh4->sgr));
	device->save_item(NAME(sh4->fpscr));
	device->save_item(NAME(sh4->r[ 0]));
	device->save_item(NAME(sh4->r[ 1]));
	device->save_item(NAME(sh4->r[ 2]));
	device->save_item(NAME(sh4->r[ 3]));
	device->save_item(NAME(sh4->r[ 4]));
	device->save_item(NAME(sh4->r[ 5]));
	device->save_item(NAME(sh4->r[ 6]));
	device->save_item(NAME(sh4->r[ 7]));
	device->save_item(NAME(sh4->r[ 8]));
	device->save_item(NAME(sh4->r[ 9]));
	device->save_item(NAME(sh4->r[10]));
	device->save_item(NAME(sh4->r[11]));
	device->save_item(NAME(sh4->r[12]));
	device->save_item(NAME(sh4->r[13]));
	device->save_item(NAME(sh4->r[14]));
	device->save_item(NAME(sh4->fr[ 0]));
	device->save_item(NAME(sh4->fr[ 1]));
	device->save_item(NAME(sh4->fr[ 2]));
	device->save_item(NAME(sh4->fr[ 3]));
	device->save_item(NAME(sh4->fr[ 4]));
	device->save_item(NAME(sh4->fr[ 5]));
	device->save_item(NAME(sh4->fr[ 6]));
	device->save_item(NAME(sh4->fr[ 7]));
	device->save_item(NAME(sh4->fr[ 8]));
	device->save_item(NAME(sh4->fr[ 9]));
	device->save_item(NAME(sh4->fr[10]));
	device->save_item(NAME(sh4->fr[11]));
	device->save_item(NAME(sh4->fr[12]));
	device->save_item(NAME(sh4->fr[13]));
	device->save_item(NAME(sh4->fr[14]));
	device->save_item(NAME(sh4->fr[15]));
	device->save_item(NAME(sh4->xf[ 0]));
	device->save_item(NAME(sh4->xf[ 1]));
	device->save_item(NAME(sh4->xf[ 2]));
	device->save_item(NAME(sh4->xf[ 3]));
	device->save_item(NAME(sh4->xf[ 4]));
	device->save_item(NAME(sh4->xf[ 5]));
	device->save_item(NAME(sh4->xf[ 6]));
	device->save_item(NAME(sh4->xf[ 7]));
	device->save_item(NAME(sh4->xf[ 8]));
	device->save_item(NAME(sh4->xf[ 9]));
	device->save_item(NAME(sh4->xf[10]));
	device->save_item(NAME(sh4->xf[11]));
	device->save_item(NAME(sh4->xf[12]));
	device->save_item(NAME(sh4->xf[13]));
	device->save_item(NAME(sh4->xf[14]));
	device->save_item(NAME(sh4->xf[15]));
	device->save_item(NAME(sh4->ea));
	device->save_item(NAME(sh4->fpul));
	device->save_item(NAME(sh4->dbr));
	device->save_item(NAME(sh4->exception_priority));
	device->save_item(NAME(sh4->exception_requesting));

	device->save_item(NAME(sh4->SH4_TSTR));
	device->save_item(NAME(sh4->SH4_TCNT0));
	device->save_item(NAME(sh4->SH4_TCNT1));
	device->save_item(NAME(sh4->SH4_TCNT2));
	device->save_item(NAME(sh4->SH4_TCR0));
	device->save_item(NAME(sh4->SH4_TCR1));
	device->save_item(NAME(sh4->SH4_TCR2));
	device->save_item(NAME(sh4->SH4_TCOR0));
	device->save_item(NAME(sh4->SH4_TCOR1));
	device->save_item(NAME(sh4->SH4_TCOR2));
	device->save_item(NAME(sh4->SH4_TOCR));
	device->save_item(NAME(sh4->SH4_TCPR2));

	device->save_item(NAME(sh4->SH4_IPRA));

	device->save_item(NAME(sh4->SH4_IPRC));



}

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

static CPU_SET_INFO( sh4 )
{
	sh4_state *sh4 = get_safe_token(device);

	switch (state)
	{
		/* --- the following bits of info are set as 64-bit signed integers --- */
		case CPUINFO_INT_INPUT_STATE + SH4_IRL0:		sh4_set_irq_line(sh4, SH4_IRL0, info->i);		break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRL1:		sh4_set_irq_line(sh4, SH4_IRL1, info->i);		break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRL2:		sh4_set_irq_line(sh4, SH4_IRL2, info->i);		break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRL3:		sh4_set_irq_line(sh4, SH4_IRL3, info->i);		break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRLn:		sh4_set_irq_line(sh4, SH4_IRLn, info->i);		break;
		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:	sh4_set_irq_line(sh4, INPUT_LINE_NMI, info->i);	break;

		case CPUINFO_INT_REGISTER + SH4_PC:
		case CPUINFO_INT_PC:							sh4->pc = info->i; sh4->delay = 0;		break;
		case CPUINFO_INT_SP:							sh4->r[15] = info->i;   				break;
		case CPUINFO_INT_REGISTER + SH4_PR: 			sh4->pr = info->i;						break;
		case CPUINFO_INT_REGISTER + SH4_SR:
			sh4->sr = info->i;
			sh4_exception_recompute(sh4);
			sh4_check_pending_irq(sh4, "sh4_set_info");
			break;
		case CPUINFO_INT_REGISTER + SH4_GBR:			sh4->gbr = info->i;						break;
		case CPUINFO_INT_REGISTER + SH4_VBR:			sh4->vbr = info->i;						break;
		case CPUINFO_INT_REGISTER + SH4_DBR:			sh4->dbr = info->i;						break;
		case CPUINFO_INT_REGISTER + SH4_MACH:			sh4->mach = info->i;						break;
		case CPUINFO_INT_REGISTER + SH4_MACL:			sh4->macl = info->i;						break;
		case CPUINFO_INT_REGISTER + SH4_R0:				sh4->r[ 0] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R1:				sh4->r[ 1] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R2:				sh4->r[ 2] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R3:				sh4->r[ 3] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R4:				sh4->r[ 4] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R5:				sh4->r[ 5] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R6:				sh4->r[ 6] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R7:				sh4->r[ 7] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R8:				sh4->r[ 8] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R9:				sh4->r[ 9] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R10:			sh4->r[10] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R11:			sh4->r[11] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R12:			sh4->r[12] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R13:			sh4->r[13] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R14:			sh4->r[14] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_R15:			sh4->r[15] = info->i;					break;
		case CPUINFO_INT_REGISTER + SH4_EA:				sh4->ea = info->i;						break;
		case CPUINFO_STR_REGISTER + SH4_R0_BK0:			sh4->rbnk[0][0] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R1_BK0:			sh4->rbnk[0][1] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R2_BK0:			sh4->rbnk[0][2] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R3_BK0:			sh4->rbnk[0][3] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R4_BK0:			sh4->rbnk[0][4] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R5_BK0:			sh4->rbnk[0][5] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R6_BK0:			sh4->rbnk[0][6] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R7_BK0:			sh4->rbnk[0][7] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R0_BK1:			sh4->rbnk[1][0] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R1_BK1:			sh4->rbnk[1][1] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R2_BK1:			sh4->rbnk[1][2] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R3_BK1:			sh4->rbnk[1][3] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R4_BK1:			sh4->rbnk[1][4] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R5_BK1:			sh4->rbnk[1][5] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R6_BK1:			sh4->rbnk[1][6] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_R7_BK1:			sh4->rbnk[1][7] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_SPC:			sh4->spc = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_SSR:			sh4->ssr = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_SGR:			sh4->sgr = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FPSCR:			sh4->fpscr = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FPUL:			sh4->fpul = info->i; break;
#ifdef LSB_FIRST
		case CPUINFO_STR_REGISTER + SH4_FR0:			sh4->fr[ 0 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR1:			sh4->fr[ 1 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR2:			sh4->fr[ 2 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR3:			sh4->fr[ 3 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR4:			sh4->fr[ 4 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR5:			sh4->fr[ 5 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR6:			sh4->fr[ 6 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR7:			sh4->fr[ 7 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR8:			sh4->fr[ 8 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR9:			sh4->fr[ 9 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR10:			sh4->fr[10 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR11:			sh4->fr[11 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR12:			sh4->fr[12 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR13:			sh4->fr[13 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR14:			sh4->fr[14 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR15:			sh4->fr[15 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF0:			sh4->xf[ 0 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF1:			sh4->xf[ 1 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF2:			sh4->xf[ 2 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF3:			sh4->xf[ 3 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF4:			sh4->xf[ 4 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF5:			sh4->xf[ 5 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF6:			sh4->xf[ 6 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF7:			sh4->xf[ 7 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF8:			sh4->xf[ 8 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF9:			sh4->xf[ 9 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF10:			sh4->xf[10 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF11:			sh4->xf[11 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF12:			sh4->xf[12 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF13:			sh4->xf[13 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF14:			sh4->xf[14 ^ sh4->fpu_pr] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF15:			sh4->xf[15 ^ sh4->fpu_pr] = info->i; break;
#else
		case CPUINFO_STR_REGISTER + SH4_FR0:			sh4->fr[ 0] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR1:			sh4->fr[ 1] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR2:			sh4->fr[ 2] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR3:			sh4->fr[ 3] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR4:			sh4->fr[ 4] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR5:			sh4->fr[ 5] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR6:			sh4->fr[ 6] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR7:			sh4->fr[ 7] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR8:			sh4->fr[ 8] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR9:			sh4->fr[ 9] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR10:			sh4->fr[10] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR11:			sh4->fr[11] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR12:			sh4->fr[12] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR13:			sh4->fr[13] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR14:			sh4->fr[14] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_FR15:			sh4->fr[15] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF0:			sh4->xf[ 0] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF1:			sh4->xf[ 1] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF2:			sh4->xf[ 2] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF3:			sh4->xf[ 3] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF4:			sh4->xf[ 4] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF5:			sh4->xf[ 5] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF6:			sh4->xf[ 6] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF7:			sh4->xf[ 7] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF8:			sh4->xf[ 8] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF9:			sh4->xf[ 9] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF10:			sh4->xf[10] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF11:			sh4->xf[11] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF12:			sh4->xf[12] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF13:			sh4->xf[13] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF14:			sh4->xf[14] = info->i; break;
		case CPUINFO_STR_REGISTER + SH4_XF15:			sh4->xf[15] = info->i; break;
#endif
	}
}

void sh4_set_ftcsr_callback(device_t *device, sh4_ftcsr_callback callback)
{
	sh4_state *sh4 = get_safe_token(device);
	sh4->ftcsr_read_callback = callback;
}


#if 0
/*When OC index mode is off (CCR.OIX = 0)*/
static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, legacy_cpu_device )
	AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x03FFD000)
	AM_RANGE(0x1C002000, 0x1C002FFF) AM_RAM AM_MIRROR(0x03FFD000)
	AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0)
ADDRESS_MAP_END
#endif

/*When OC index mode is on (CCR.OIX = 1)*/
static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, legacy_cpu_device )
	AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x01FFF000)
	AM_RANGE(0x1E000000, 0x1E000FFF) AM_RAM AM_MIRROR(0x01FFF000)
	AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0) // todo: store queues should be write only on DC's SH4, executing PREFM shouldn't cause an actual memory read access!
	AM_RANGE(0xF6000000, 0xF7FFFFFF) AM_READWRITE_LEGACY(sh4_tlb_r,sh4_tlb_w)
	AM_RANGE(0xFE000000, 0xFFFFFFFF) AM_READWRITE32_LEGACY(sh4_internal_r, sh4_internal_w, U64(0xffffffffffffffff))
ADDRESS_MAP_END

static ADDRESS_MAP_START( sh3_internal_map, AS_PROGRAM, 64, legacy_cpu_device )
	AM_RANGE(SH3_LOWER_REGBASE, SH3_LOWER_REGEND) AM_READWRITE32_LEGACY(sh3_internal_r, sh3_internal_w, U64(0xffffffffffffffff))
	AM_RANGE(SH3_UPPER_REGBASE, SH3_UPPER_REGEND) AM_READWRITE32_LEGACY(sh3_internal_high_r, sh3_internal_high_w, U64(0xffffffffffffffff))
ADDRESS_MAP_END


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

CPU_GET_INFO( sh4 )
{
	sh4_state *sh4 = (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(sh4_state);		break;
		case CPUINFO_INT_INPUT_LINES:					info->i = 5;						break;
		case CPUINFO_INT_DEFAULT_IRQ_VECTOR:			info->i = 0;						break;
		case DEVINFO_INT_ENDIANNESS:					info->i = ENDIANNESS_LITTLE;				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 = 2;						break;
		case CPUINFO_INT_MAX_INSTRUCTION_BYTES:			info->i = 2;						break;
		case CPUINFO_INT_MIN_CYCLES:					info->i = 1;						break;
		case CPUINFO_INT_MAX_CYCLES:					info->i = 4;						break;

		case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM:		info->i = 64;				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 = 64;					break;
		case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO:		info->i = 8;					break;
		case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO:		info->i = 0;					break;

		case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map64 = ADDRESS_MAP_NAME(sh4_internal_map); break;

		case CPUINFO_INT_INPUT_STATE + SH4_IRL0:		info->i = sh4->irq_line_state[SH4_IRL0]; break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRL1:		info->i = sh4->irq_line_state[SH4_IRL1]; break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRL2:		info->i = sh4->irq_line_state[SH4_IRL2]; break;
		case CPUINFO_INT_INPUT_STATE + SH4_IRL3:		info->i = sh4->irq_line_state[SH4_IRL3]; break;
		case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI:	info->i = sh4->nmi_line_state;			break;

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

		case CPUINFO_INT_PC:
		case CPUINFO_INT_REGISTER + SH4_PC:				info->i = (sh4->delay) ? (sh4->delay & AM) : (sh4->pc & AM); break;
		case CPUINFO_INT_SP:							info->i = sh4->r[15];					break;
		case CPUINFO_INT_REGISTER + SH4_PR:				info->i = sh4->pr;						break;
		case CPUINFO_INT_REGISTER + SH4_SR:				info->i = sh4->sr;						break;
		case CPUINFO_INT_REGISTER + SH4_GBR:			info->i = sh4->gbr;						break;
		case CPUINFO_INT_REGISTER + SH4_VBR:			info->i = sh4->vbr;						break;
		case CPUINFO_INT_REGISTER + SH4_DBR:			info->i = sh4->dbr;						break;
		case CPUINFO_INT_REGISTER + SH4_MACH:			info->i = sh4->mach;						break;
		case CPUINFO_INT_REGISTER + SH4_MACL:			info->i = sh4->macl;						break;
		case CPUINFO_INT_REGISTER + SH4_R0:				info->i = sh4->r[ 0];					break;
		case CPUINFO_INT_REGISTER + SH4_R1:				info->i = sh4->r[ 1];					break;
		case CPUINFO_INT_REGISTER + SH4_R2:				info->i = sh4->r[ 2];					break;
		case CPUINFO_INT_REGISTER + SH4_R3:				info->i = sh4->r[ 3];					break;
		case CPUINFO_INT_REGISTER + SH4_R4:				info->i = sh4->r[ 4];					break;
		case CPUINFO_INT_REGISTER + SH4_R5:				info->i = sh4->r[ 5];					break;
		case CPUINFO_INT_REGISTER + SH4_R6:				info->i = sh4->r[ 6];					break;
		case CPUINFO_INT_REGISTER + SH4_R7:				info->i = sh4->r[ 7];					break;
		case CPUINFO_INT_REGISTER + SH4_R8:				info->i = sh4->r[ 8];					break;
		case CPUINFO_INT_REGISTER + SH4_R9:				info->i = sh4->r[ 9];					break;
		case CPUINFO_INT_REGISTER + SH4_R10:			info->i = sh4->r[10];					break;
		case CPUINFO_INT_REGISTER + SH4_R11:			info->i = sh4->r[11];					break;
		case CPUINFO_INT_REGISTER + SH4_R12:			info->i = sh4->r[12];					break;
		case CPUINFO_INT_REGISTER + SH4_R13:			info->i = sh4->r[13];					break;
		case CPUINFO_INT_REGISTER + SH4_R14:			info->i = sh4->r[14];					break;
		case CPUINFO_INT_REGISTER + SH4_R15:			info->i = sh4->r[15];					break;
		case CPUINFO_INT_REGISTER + SH4_EA:				info->i = sh4->ea;						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(sh4);			break;
		case CPUINFO_FCT_INIT:							info->init = CPU_INIT_NAME(sh4);					break;
		case CPUINFO_FCT_RESET:							info->reset = CPU_RESET_NAME(sh4);				break;
		case CPUINFO_FCT_EXECUTE:						info->execute = CPU_EXECUTE_NAME(sh4);			break;
		case CPUINFO_FCT_BURN:							info->burn = NULL;						break;
		case CPUINFO_FCT_DISASSEMBLE:					info->disassemble = CPU_DISASSEMBLE_NAME(sh4);			break;
		case CPUINFO_PTR_INSTRUCTION_COUNTER:			info->icount = &sh4->sh4_icount;				break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:						strcpy(info->s, "SH-4");				break;
		case DEVINFO_STR_FAMILY:					strcpy(info->s, "Hitachi SH7750");		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 R. Belmont"); break;

		case CPUINFO_STR_FLAGS:
			sprintf(info->s, "%s%s%s%s%c%c%d%c%c",
					sh4->sr & MD ? "MD ":"   ",
					sh4->sr & sRB ? "RB ":"   ",
					sh4->sr & BL ? "BL ":"   ",
					sh4->sr & FD ? "FD ":"   ",
					sh4->sr & M ? 'M':'.',
					sh4->sr & Q ? 'Q':'.',
					(sh4->sr & I) >> 4,
					sh4->sr & S ? 'S':'.',
					sh4->sr & T ? 'T':'.');
			break;

		case CPUINFO_STR_REGISTER + SH4_PC:				sprintf(info->s, "PC  :%08X", sh4->pc); break;
		case CPUINFO_STR_REGISTER + SH4_SR:				sprintf(info->s, "SR  :%08X", sh4->sr); break;
		case CPUINFO_STR_REGISTER + SH4_PR:				sprintf(info->s, "PR  :%08X", sh4->pr); break;
		case CPUINFO_STR_REGISTER + SH4_GBR:			sprintf(info->s, "GBR :%08X", sh4->gbr); break;
		case CPUINFO_STR_REGISTER + SH4_VBR:			sprintf(info->s, "VBR :%08X", sh4->vbr); break;
		case CPUINFO_STR_REGISTER + SH4_DBR:			sprintf(info->s, "DBR :%08X", sh4->dbr); break;
		case CPUINFO_STR_REGISTER + SH4_MACH:			sprintf(info->s, "MACH:%08X", sh4->mach); break;
		case CPUINFO_STR_REGISTER + SH4_MACL:			sprintf(info->s, "MACL:%08X", sh4->macl); break;
		case CPUINFO_STR_REGISTER + SH4_R0:				sprintf(info->s, "R0  :%08X", sh4->r[ 0]); break;
		case CPUINFO_STR_REGISTER + SH4_R1:				sprintf(info->s, "R1  :%08X", sh4->r[ 1]); break;
		case CPUINFO_STR_REGISTER + SH4_R2:				sprintf(info->s, "R2  :%08X", sh4->r[ 2]); break;
		case CPUINFO_STR_REGISTER + SH4_R3:				sprintf(info->s, "R3  :%08X", sh4->r[ 3]); break;
		case CPUINFO_STR_REGISTER + SH4_R4:				sprintf(info->s, "R4  :%08X", sh4->r[ 4]); break;
		case CPUINFO_STR_REGISTER + SH4_R5:				sprintf(info->s, "R5  :%08X", sh4->r[ 5]); break;
		case CPUINFO_STR_REGISTER + SH4_R6:				sprintf(info->s, "R6  :%08X", sh4->r[ 6]); break;
		case CPUINFO_STR_REGISTER + SH4_R7:				sprintf(info->s, "R7  :%08X", sh4->r[ 7]); break;
		case CPUINFO_STR_REGISTER + SH4_R8:				sprintf(info->s, "R8  :%08X", sh4->r[ 8]); break;
		case CPUINFO_STR_REGISTER + SH4_R9:				sprintf(info->s, "R9  :%08X", sh4->r[ 9]); break;
		case CPUINFO_STR_REGISTER + SH4_R10:			sprintf(info->s, "R10 :%08X", sh4->r[10]); break;
		case CPUINFO_STR_REGISTER + SH4_R11:			sprintf(info->s, "R11 :%08X", sh4->r[11]); break;
		case CPUINFO_STR_REGISTER + SH4_R12:			sprintf(info->s, "R12 :%08X", sh4->r[12]); break;
		case CPUINFO_STR_REGISTER + SH4_R13:			sprintf(info->s, "R13 :%08X", sh4->r[13]); break;
		case CPUINFO_STR_REGISTER + SH4_R14:			sprintf(info->s, "R14 :%08X", sh4->r[14]); break;
		case CPUINFO_STR_REGISTER + SH4_R15:			sprintf(info->s, "R15 :%08X", sh4->r[15]); break;
		case CPUINFO_STR_REGISTER + SH4_EA:				sprintf(info->s, "EA  :%08X", sh4->ea);    break;
		case CPUINFO_STR_REGISTER + SH4_R0_BK0:			sprintf(info->s, "R0 BK 0  :%08X", sh4->rbnk[0][0]); break;
		case CPUINFO_STR_REGISTER + SH4_R1_BK0:			sprintf(info->s, "R1 BK 0 :%08X", sh4->rbnk[0][1]); break;
		case CPUINFO_STR_REGISTER + SH4_R2_BK0:			sprintf(info->s, "R2 BK 0 :%08X", sh4->rbnk[0][2]); break;
		case CPUINFO_STR_REGISTER + SH4_R3_BK0:			sprintf(info->s, "R3 BK 0 :%08X", sh4->rbnk[0][3]); break;
		case CPUINFO_STR_REGISTER + SH4_R4_BK0:			sprintf(info->s, "R4 BK 0 :%08X", sh4->rbnk[0][4]); break;
		case CPUINFO_STR_REGISTER + SH4_R5_BK0:			sprintf(info->s, "R5 BK 0 :%08X", sh4->rbnk[0][5]); break;
		case CPUINFO_STR_REGISTER + SH4_R6_BK0:			sprintf(info->s, "R6 BK 0 :%08X", sh4->rbnk[0][6]); break;
		case CPUINFO_STR_REGISTER + SH4_R7_BK0:			sprintf(info->s, "R7 BK 0 :%08X", sh4->rbnk[0][7]); break;
		case CPUINFO_STR_REGISTER + SH4_R0_BK1:			sprintf(info->s, "R0 BK 1 :%08X", sh4->rbnk[1][0]); break;
		case CPUINFO_STR_REGISTER + SH4_R1_BK1:			sprintf(info->s, "R1 BK 1 :%08X", sh4->rbnk[1][1]); break;
		case CPUINFO_STR_REGISTER + SH4_R2_BK1:			sprintf(info->s, "R2 BK 1 :%08X", sh4->rbnk[1][2]); break;
		case CPUINFO_STR_REGISTER + SH4_R3_BK1:			sprintf(info->s, "R3 BK 1 :%08X", sh4->rbnk[1][3]); break;
		case CPUINFO_STR_REGISTER + SH4_R4_BK1:			sprintf(info->s, "R4 BK 1 :%08X", sh4->rbnk[1][4]); break;
		case CPUINFO_STR_REGISTER + SH4_R5_BK1:			sprintf(info->s, "R5 BK 1 :%08X", sh4->rbnk[1][5]); break;
		case CPUINFO_STR_REGISTER + SH4_R6_BK1:			sprintf(info->s, "R6 BK 1 :%08X", sh4->rbnk[1][6]); break;
		case CPUINFO_STR_REGISTER + SH4_R7_BK1:			sprintf(info->s, "R7 BK 1 :%08X", sh4->rbnk[1][7]); break;
		case CPUINFO_STR_REGISTER + SH4_SPC:			sprintf(info->s, "SPC  :%08X", sh4->spc); break;
		case CPUINFO_STR_REGISTER + SH4_SSR:			sprintf(info->s, "SSR  :%08X", sh4->ssr); break;
		case CPUINFO_STR_REGISTER + SH4_SGR:			sprintf(info->s, "SGR  :%08X", sh4->sgr); break;
		case CPUINFO_STR_REGISTER + SH4_FPSCR:			sprintf(info->s, "FPSCR :%08X", sh4->fpscr); break;
		case CPUINFO_STR_REGISTER + SH4_FPUL:			sprintf(info->s, "FPUL :%08X", sh4->fpul); break;
#ifdef LSB_FIRST
		case CPUINFO_STR_REGISTER + SH4_FR0:			sprintf(info->s, "FR0  :%08X %f", FP_RS2( 0),(double)FP_RFS2( 0)); break;
		case CPUINFO_STR_REGISTER + SH4_FR1:			sprintf(info->s, "FR1  :%08X %f", FP_RS2( 1),(double)FP_RFS2( 1)); break;
		case CPUINFO_STR_REGISTER + SH4_FR2:			sprintf(info->s, "FR2  :%08X %f", FP_RS2( 2),(double)FP_RFS2( 2)); break;
		case CPUINFO_STR_REGISTER + SH4_FR3:			sprintf(info->s, "FR3  :%08X %f", FP_RS2( 3),(double)FP_RFS2( 3)); break;
		case CPUINFO_STR_REGISTER + SH4_FR4:			sprintf(info->s, "FR4  :%08X %f", FP_RS2( 4),(double)FP_RFS2( 4)); break;
		case CPUINFO_STR_REGISTER + SH4_FR5:			sprintf(info->s, "FR5  :%08X %f", FP_RS2( 5),(double)FP_RFS2( 5)); break;
		case CPUINFO_STR_REGISTER + SH4_FR6:			sprintf(info->s, "FR6  :%08X %f", FP_RS2( 6),(double)FP_RFS2( 6)); break;
		case CPUINFO_STR_REGISTER + SH4_FR7:			sprintf(info->s, "FR7  :%08X %f", FP_RS2( 7),(double)FP_RFS2( 7)); break;
		case CPUINFO_STR_REGISTER + SH4_FR8:			sprintf(info->s, "FR8  :%08X %f", FP_RS2( 8),(double)FP_RFS2( 8)); break;
		case CPUINFO_STR_REGISTER + SH4_FR9:			sprintf(info->s, "FR9  :%08X %f", FP_RS2( 9),(double)FP_RFS2( 9)); break;
		case CPUINFO_STR_REGISTER + SH4_FR10:			sprintf(info->s, "FR10 :%08X %f", FP_RS2(10),(double)FP_RFS2(10)); break;
		case CPUINFO_STR_REGISTER + SH4_FR11:			sprintf(info->s, "FR11 :%08X %f", FP_RS2(11),(double)FP_RFS2(11)); break;
		case CPUINFO_STR_REGISTER + SH4_FR12:			sprintf(info->s, "FR12 :%08X %f", FP_RS2(12),(double)FP_RFS2(12)); break;
		case CPUINFO_STR_REGISTER + SH4_FR13:			sprintf(info->s, "FR13 :%08X %f", FP_RS2(13),(double)FP_RFS2(13)); break;
		case CPUINFO_STR_REGISTER + SH4_FR14:			sprintf(info->s, "FR14 :%08X %f", FP_RS2(14),(double)FP_RFS2(14)); break;
		case CPUINFO_STR_REGISTER + SH4_FR15:			sprintf(info->s, "FR15 :%08X %f", FP_RS2(15),(double)FP_RFS2(15)); break;
		case CPUINFO_STR_REGISTER + SH4_XF0:			sprintf(info->s, "XF0  :%08X %f", FP_XS2( 0),(double)FP_XFS2( 0)); break;
		case CPUINFO_STR_REGISTER + SH4_XF1:			sprintf(info->s, "XF1  :%08X %f", FP_XS2( 1),(double)FP_XFS2( 1)); break;
		case CPUINFO_STR_REGISTER + SH4_XF2:			sprintf(info->s, "XF2  :%08X %f", FP_XS2( 2),(double)FP_XFS2( 2)); break;
		case CPUINFO_STR_REGISTER + SH4_XF3:			sprintf(info->s, "XF3  :%08X %f", FP_XS2( 3),(double)FP_XFS2( 3)); break;
		case CPUINFO_STR_REGISTER + SH4_XF4:			sprintf(info->s, "XF4  :%08X %f", FP_XS2( 4),(double)FP_XFS2( 4)); break;
		case CPUINFO_STR_REGISTER + SH4_XF5:			sprintf(info->s, "XF5  :%08X %f", FP_XS2( 5),(double)FP_XFS2( 5)); break;
		case CPUINFO_STR_REGISTER + SH4_XF6:			sprintf(info->s, "XF6  :%08X %f", FP_XS2( 6),(double)FP_XFS2( 6)); break;
		case CPUINFO_STR_REGISTER + SH4_XF7:			sprintf(info->s, "XF7  :%08X %f", FP_XS2( 7),(double)FP_XFS2( 7)); break;
		case CPUINFO_STR_REGISTER + SH4_XF8:			sprintf(info->s, "XF8  :%08X %f", FP_XS2( 8),(double)FP_XFS2( 8)); break;
		case CPUINFO_STR_REGISTER + SH4_XF9:			sprintf(info->s, "XF9  :%08X %f", FP_XS2( 9),(double)FP_XFS2( 9)); break;
		case CPUINFO_STR_REGISTER + SH4_XF10:			sprintf(info->s, "XF10 :%08X %f", FP_XS2(10),(double)FP_XFS2(10)); break;
		case CPUINFO_STR_REGISTER + SH4_XF11:			sprintf(info->s, "XF11 :%08X %f", FP_XS2(11),(double)FP_XFS2(11)); break;
		case CPUINFO_STR_REGISTER + SH4_XF12:			sprintf(info->s, "XF12 :%08X %f", FP_XS2(12),(double)FP_XFS2(12)); break;
		case CPUINFO_STR_REGISTER + SH4_XF13:			sprintf(info->s, "XF13 :%08X %f", FP_XS2(13),(double)FP_XFS2(13)); break;
		case CPUINFO_STR_REGISTER + SH4_XF14:			sprintf(info->s, "XF14 :%08X %f", FP_XS2(14),(double)FP_XFS2(14)); break;
		case CPUINFO_STR_REGISTER + SH4_XF15:			sprintf(info->s, "XF15 :%08X %f", FP_XS2(15),(double)FP_XFS2(15)); break;
#else
		case CPUINFO_STR_REGISTER + SH4_FR0:			sprintf(info->s, "FR0  :%08X %f", FP_RS( 0),(double)FP_RFS( 0)); break;
		case CPUINFO_STR_REGISTER + SH4_FR1:			sprintf(info->s, "FR1  :%08X %f", FP_RS( 1),(double)FP_RFS( 1)); break;
		case CPUINFO_STR_REGISTER + SH4_FR2:			sprintf(info->s, "FR2  :%08X %f", FP_RS( 2),(double)FP_RFS( 2)); break;
		case CPUINFO_STR_REGISTER + SH4_FR3:			sprintf(info->s, "FR3  :%08X %f", FP_RS( 3),(double)FP_RFS( 3)); break;
		case CPUINFO_STR_REGISTER + SH4_FR4:			sprintf(info->s, "FR4  :%08X %f", FP_RS( 4),(double)FP_RFS( 4)); break;
		case CPUINFO_STR_REGISTER + SH4_FR5:			sprintf(info->s, "FR5  :%08X %f", FP_RS( 5),(double)FP_RFS( 5)); break;
		case CPUINFO_STR_REGISTER + SH4_FR6:			sprintf(info->s, "FR6  :%08X %f", FP_RS( 6),(double)FP_RFS( 6)); break;
		case CPUINFO_STR_REGISTER + SH4_FR7:			sprintf(info->s, "FR7  :%08X %f", FP_RS( 7),(double)FP_RFS( 7)); break;
		case CPUINFO_STR_REGISTER + SH4_FR8:			sprintf(info->s, "FR8  :%08X %f", FP_RS( 8),(double)FP_RFS( 8)); break;
		case CPUINFO_STR_REGISTER + SH4_FR9:			sprintf(info->s, "FR9  :%08X %f", FP_RS( 9),(double)FP_RFS( 9)); break;
		case CPUINFO_STR_REGISTER + SH4_FR10:			sprintf(info->s, "FR10 :%08X %f", FP_RS(10),(double)FP_RFS(10)); break;
		case CPUINFO_STR_REGISTER + SH4_FR11:			sprintf(info->s, "FR11 :%08X %f", FP_RS(11),(double)FP_RFS(11)); break;
		case CPUINFO_STR_REGISTER + SH4_FR12:			sprintf(info->s, "FR12 :%08X %f", FP_RS(12),(double)FP_RFS(12)); break;
		case CPUINFO_STR_REGISTER + SH4_FR13:			sprintf(info->s, "FR13 :%08X %f", FP_RS(13),(double)FP_RFS(13)); break;
		case CPUINFO_STR_REGISTER + SH4_FR14:			sprintf(info->s, "FR14 :%08X %f", FP_RS(14),(double)FP_RFS(14)); break;
		case CPUINFO_STR_REGISTER + SH4_FR15:			sprintf(info->s, "FR15 :%08X %f", FP_RS(15),(double)FP_RFS(15)); break;
		case CPUINFO_STR_REGISTER + SH4_XF0:			sprintf(info->s, "XF0  :%08X %f", FP_XS( 0),(double)FP_XFS( 0)); break;
		case CPUINFO_STR_REGISTER + SH4_XF1:			sprintf(info->s, "XF1  :%08X %f", FP_XS( 1),(double)FP_XFS( 1)); break;
		case CPUINFO_STR_REGISTER + SH4_XF2:			sprintf(info->s, "XF2  :%08X %f", FP_XS( 2),(double)FP_XFS( 2)); break;
		case CPUINFO_STR_REGISTER + SH4_XF3:			sprintf(info->s, "XF3  :%08X %f", FP_XS( 3),(double)FP_XFS( 3)); break;
		case CPUINFO_STR_REGISTER + SH4_XF4:			sprintf(info->s, "XF4  :%08X %f", FP_XS( 4),(double)FP_XFS( 4)); break;
		case CPUINFO_STR_REGISTER + SH4_XF5:			sprintf(info->s, "XF5  :%08X %f", FP_XS( 5),(double)FP_XFS( 5)); break;
		case CPUINFO_STR_REGISTER + SH4_XF6:			sprintf(info->s, "XF6  :%08X %f", FP_XS( 6),(double)FP_XFS( 6)); break;
		case CPUINFO_STR_REGISTER + SH4_XF7:			sprintf(info->s, "XF7  :%08X %f", FP_XS( 7),(double)FP_XFS( 7)); break;
		case CPUINFO_STR_REGISTER + SH4_XF8:			sprintf(info->s, "XF8  :%08X %f", FP_XS( 8),(double)FP_XFS( 8)); break;
		case CPUINFO_STR_REGISTER + SH4_XF9:			sprintf(info->s, "XF9  :%08X %f", FP_XS( 9),(double)FP_XFS( 9)); break;
		case CPUINFO_STR_REGISTER + SH4_XF10:			sprintf(info->s, "XF10 :%08X %f", FP_XS(10),(double)FP_XFS(10)); break;
		case CPUINFO_STR_REGISTER + SH4_XF11:			sprintf(info->s, "XF11 :%08X %f", FP_XS(11),(double)FP_XFS(11)); break;
		case CPUINFO_STR_REGISTER + SH4_XF12:			sprintf(info->s, "XF12 :%08X %f", FP_XS(12),(double)FP_XFS(12)); break;
		case CPUINFO_STR_REGISTER + SH4_XF13:			sprintf(info->s, "XF13 :%08X %f", FP_XS(13),(double)FP_XFS(13)); break;
		case CPUINFO_STR_REGISTER + SH4_XF14:			sprintf(info->s, "XF14 :%08X %f", FP_XS(14),(double)FP_XFS(14)); break;
		case CPUINFO_STR_REGISTER + SH4_XF15:			sprintf(info->s, "XF15 :%08X %f", FP_XS(15),(double)FP_XFS(15)); break; //%01.2e
#endif
	}
}

CPU_GET_INFO( sh3 )
{
	switch (state)
	{
	/* --- the following bits of info are returned as pointers to data or functions --- */
	case CPUINFO_FCT_RESET:						info->reset = CPU_RESET_NAME(sh3);				break;

	/* --- the following bits of info are returned as NULL-terminated strings --- */
	case DEVINFO_STR_NAME:						strcpy(info->s, "SH-3");				break;
	case DEVINFO_STR_FAMILY:					strcpy(info->s, "Hitachi SH7700");		break;

	case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map64 = ADDRESS_MAP_NAME(sh3_internal_map); break;

	default:									CPU_GET_INFO_CALL(sh4);					break;
	}
}

CPU_GET_INFO( sh3be )
{
	switch (state)
	{
	/* --- the following bits of info are returned as pointers to data or functions --- */
	case CPUINFO_FCT_RESET:						info->reset = CPU_RESET_NAME(sh3);				break;
	case CPUINFO_FCT_EXECUTE:					info->execute = CPU_EXECUTE_NAME(sh4be);			break;
	case CPUINFO_FCT_DISASSEMBLE:				info->disassemble = CPU_DISASSEMBLE_NAME(sh4be);			break;

	/* --- the following bits of info are returned as NULL-terminated strings --- */
	case DEVINFO_STR_NAME:						strcpy(info->s, "SH-3");				break;
	case DEVINFO_STR_FAMILY:					strcpy(info->s, "Hitachi SH7700");		break;

	case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map64 = ADDRESS_MAP_NAME(sh3_internal_map); break;

	case DEVINFO_INT_ENDIANNESS:				info->i = ENDIANNESS_BIG;				break;

	default:									CPU_GET_INFO_CALL(sh4);					break;
	}
}

CPU_GET_INFO( sh4be )
{
	switch (state)
	{
	case CPUINFO_FCT_EXECUTE:					info->execute = CPU_EXECUTE_NAME(sh4be);			break;
	case CPUINFO_FCT_DISASSEMBLE:				info->disassemble = CPU_DISASSEMBLE_NAME(sh4be);			break;
	case DEVINFO_INT_ENDIANNESS:				info->i = ENDIANNESS_BIG;				break;
	default:									CPU_GET_INFO_CALL(sh4);					break;
	}
}

DEFINE_LEGACY_CPU_DEVICE(SH3LE, sh3);
DEFINE_LEGACY_CPU_DEVICE(SH3BE, sh3be);
DEFINE_LEGACY_CPU_DEVICE(SH4LE, sh4);
DEFINE_LEGACY_CPU_DEVICE(SH4BE, sh4be);

#endif	// USE_SH4DRC
