summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/sh2/sh2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/sh2/sh2.c')
-rw-r--r--src/emu/cpu/sh2/sh2.c3181
1 files changed, 3181 insertions, 0 deletions
diff --git a/src/emu/cpu/sh2/sh2.c b/src/emu/cpu/sh2/sh2.c
new file mode 100644
index 00000000000..e6d486cfd77
--- /dev/null
+++ b/src/emu/cpu/sh2/sh2.c
@@ -0,0 +1,3181 @@
+/*****************************************************************************
+ *
+ * sh2.c
+ * Portable Hitachi SH-2 (SH7600 family) emulator
+ *
+ * Copyright (c) 2000 Juergen Buchmueller <pullmoll@t-online.de>,
+ * all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * pullmoll@t-online.de
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on <tiraniddo@hotmail.com> C/C++ implementation of
+ * the SH-2 CPU core and was adapted to the MAME CPU core requirements.
+ * Thanks also go to Chuck Mason <chukjr@sundail.net> and Olivier Galibert
+ * <galibert@pobox.com> for letting me peek into their SEMU code :-)
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ Changes
+ 20051129 Mariusz Wojcieszek
+ - introduced cpu_readop16() for opcode fetching
+
+ 20050813 Mariusz Wojcieszek
+ - fixed 64 bit / 32 bit division in division unit
+
+ 20031015 O. Galibert
+ - dma fixes, thanks to sthief
+
+ 20031013 O. Galibert, A. Giles
+ - timer fixes
+ - multi-cpu simplifications
+
+ 20030915 O. Galibert
+ - fix DMA1 irq vector
+ - ignore writes to DRCRx
+ - fix cpu number issues
+ - fix slave/master recognition
+ - fix wrong-cpu-in-context problem with the timers
+
+ 20021020 O. Galibert
+ - DMA implementation, lightly tested
+ - change_pc() crap fixed
+ - delay slot in debugger fixed
+ - add divide box mirrors
+ - Nicola-ify the indentation
+ - Uncrapify sh2_internal_*
+ - Put back nmi support that had been lost somehow
+
+ 20020914 R. Belmont
+ - Initial SH2 internal timers implementation, based on code by O. Galibert.
+ Makes music work in galspanic4/s/s2, panic street, cyvern, other SKNS games.
+ - Fix to external division, thanks to "spice" on the E2J board.
+ Corrects behavior of s1945ii turret boss.
+
+ 20020302 Olivier Galibert (galibert@mame.net)
+ - Fixed interrupt in delay slot
+ - Fixed rotcr
+ - Fixed div1
+ - Fixed mulu
+ - Fixed negc
+
+ 20020301 R. Belmont
+ - Fixed external division
+
+ 20020225 Olivier Galibert (galibert@mame.net)
+ - Fixed interrupt handling
+
+ 20010207 Sylvain Glaize (mokona@puupuu.org)
+
+ - Bug fix in INLINE void MOVBM(UINT32 m, UINT32 n) (see comment)
+ - Support of full 32 bit addressing (RB, RW, RL and WB, WW, WL functions)
+ reason : when the two high bits of the address are set, access is
+ done directly in the cache data array. The SUPER KANEKO NOVA SYSTEM
+ sets the stack pointer here, using these addresses as usual RAM access.
+
+ No real cache support has been added.
+ - Read/Write memory format correction (_bew to _bedw) (see also SH2
+ definition in cpuintrf.c and DasmSH2(..) in sh2dasm.c )
+
+ 20010623 James Forshaw (TyRaNiD@totalise.net)
+
+ - Modified operation of sh2_exception. Done cause mame irq system is stupid, and
+ doesnt really seem designed for any more than 8 interrupt lines.
+
+ 20010701 James Forshaw (TyRaNiD@totalise.net)
+
+ - Fixed DIV1 operation. Q bit now correctly generated
+
+ 20020218 Added save states (mokona@puupuu.org)
+
+ *****************************************************************************/
+
+#include "debugger.h"
+#include "sh2.h"
+
+/* speed up delay loops, bail out of tight loops */
+#define BUSY_LOOP_HACKS 1
+
+#define VERBOSE 0
+
+#if VERBOSE
+#define LOG(x) logerror x
+#else
+#define LOG(x)
+#endif
+
+typedef struct
+{
+ int irq_vector;
+ int irq_priority;
+} irq_entry;
+
+typedef struct
+{
+ UINT32 ppc;
+ UINT32 pc;
+ UINT32 pr;
+ UINT32 sr;
+ UINT32 gbr, vbr;
+ UINT32 mach, macl;
+ UINT32 r[16];
+ UINT32 ea;
+ UINT32 delay;
+ UINT32 cpu_off;
+ UINT32 dvsr, dvdnth, dvdntl, dvcr;
+ UINT32 pending_irq;
+ UINT32 test_irq;
+ irq_entry irq_queue[16];
+
+ INT8 irq_line_state[17];
+ int (*irq_callback)(int irqline);
+ UINT32 *m;
+ INT8 nmi_line_state;
+
+ UINT16 frc;
+ UINT16 ocra, ocrb, icr;
+ UINT32 frc_base;
+
+ int frt_input;
+ int internal_irq_level;
+ int internal_irq_vector;
+
+ emu_timer *timer;
+ emu_timer *dma_timer[2];
+ int dma_timer_active[2];
+
+ int is_slave, cpu_number;
+
+ void (*ftcsr_read_callback)(UINT32 data);
+} SH2;
+
+static int sh2_icount;
+static SH2 sh2;
+
+// Atrocious hack that makes the soldivid music correct
+
+//static const int div_tab[4] = { 3, 5, 7, 0 };
+static const int div_tab[4] = { 3, 5, 3, 0 };
+
+enum {
+ ICF = 0x00800000,
+ OCFA = 0x00080000,
+ OCFB = 0x00040000,
+ OVF = 0x00020000
+};
+
+static TIMER_CALLBACK( sh2_timer_callback );
+
+#define T 0x00000001
+#define S 0x00000002
+#define I 0x000000f0
+#define Q 0x00000100
+#define M 0x00000200
+
+#define AM 0xc7ffffff
+
+#define FLAGS (M|Q|I|S|T)
+
+#define Rn ((opcode>>8)&15)
+#define Rm ((opcode>>4)&15)
+
+INLINE UINT8 RB(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return sh2_internal_r((A & 0x1fc)>>2, ~(0xff << (((~A) & 3)*8))) >> (((~A) & 3)*8);
+
+ if (A >= 0xc0000000)
+ return program_read_byte_32be(A);
+
+ if (A >= 0x40000000)
+ return 0xa5;
+
+ return program_read_byte_32be(A & AM);
+}
+
+INLINE UINT16 RW(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return sh2_internal_r((A & 0x1fc)>>2, ~(0xffff << (((~A) & 2)*8))) >> (((~A) & 2)*8);
+
+ if (A >= 0xc0000000)
+ return program_read_word_32be(A);
+
+ if (A >= 0x40000000)
+ return 0xa5a5;
+
+ return program_read_word_32be(A & AM);
+}
+
+INLINE UINT32 RL(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return sh2_internal_r((A & 0x1fc)>>2, 0);
+
+ if (A >= 0xc0000000)
+ return program_read_dword_32be(A);
+
+ if (A >= 0x40000000)
+ return 0xa5a5a5a5;
+
+ return program_read_dword_32be(A & AM);
+}
+
+INLINE void WB(offs_t A, UINT8 V)
+{
+
+ if (A >= 0xe0000000)
+ {
+ sh2_internal_w((A & 0x1fc)>>2, V << (((~A) & 3)*8), ~(0xff << (((~A) & 3)*8)));
+ return;
+ }
+
+ if (A >= 0xc0000000)
+ {
+ program_write_byte_32be(A,V);
+ return;
+ }
+
+ if (A >= 0x40000000)
+ return;
+
+ program_write_byte_32be(A & AM,V);
+}
+
+INLINE void WW(offs_t A, UINT16 V)
+{
+ if (A >= 0xe0000000)
+ {
+ sh2_internal_w((A & 0x1fc)>>2, V << (((~A) & 2)*8), ~(0xffff << (((~A) & 2)*8)));
+ return;
+ }
+
+ if (A >= 0xc0000000)
+ {
+ program_write_word_32be(A,V);
+ return;
+ }
+
+ if (A >= 0x40000000)
+ return;
+
+ program_write_word_32be(A & AM,V);
+}
+
+INLINE void WL(offs_t A, UINT32 V)
+{
+ if (A >= 0xe0000000)
+ {
+ sh2_internal_w((A & 0x1fc)>>2, V, 0);
+ return;
+ }
+
+ if (A >= 0xc0000000)
+ {
+ program_write_dword_32be(A,V);
+ return;
+ }
+
+ if (A >= 0x40000000)
+ return;
+
+ program_write_dword_32be(A & AM,V);
+}
+
+INLINE void sh2_exception(const char *message, int irqline)
+{
+ int vector;
+
+ if (irqline != 16)
+ {
+ if (irqline <= ((sh2.sr >> 4) & 15)) /* If the cpu forbids this interrupt */
+ return;
+
+ // if this is an sh2 internal irq, use its vector
+ if (sh2.internal_irq_level == irqline)
+ {
+ vector = sh2.internal_irq_vector;
+ LOG(("SH-2 #%d exception #%d (internal vector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
+ }
+ else
+ {
+ if(sh2.m[0x38] & 0x00010000)
+ {
+ vector = sh2.irq_callback(irqline);
+ LOG(("SH-2 #%d exception #%d (external vector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
+ }
+ else
+ {
+ sh2.irq_callback(irqline);
+ vector = 64 + irqline/2;
+ LOG(("SH-2 #%d exception #%d (autovector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
+ }
+ }
+ }
+ else
+ {
+ vector = 11;
+ LOG(("SH-2 #%d nmi exception (autovector: $%x) after [%s]\n", cpu_getactivecpu(), vector, message));
+ }
+
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.sr ); /* push SR onto stack */
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.pc ); /* push PC onto stack */
+
+ /* set I flags in SR */
+ if (irqline > SH2_INT_15)
+ sh2.sr = sh2.sr | I;
+ else
+ sh2.sr = (sh2.sr & ~I) | (irqline << 4);
+
+ /* fetch PC */
+ sh2.pc = RL( sh2.vbr + vector * 4 );
+ change_pc(sh2.pc & AM);
+}
+
+#define CHECK_PENDING_IRQ(message) \
+do { \
+ int irq = -1; \
+ if (sh2.pending_irq & (1 << 0)) irq = 0; \
+ if (sh2.pending_irq & (1 << 1)) irq = 1; \
+ if (sh2.pending_irq & (1 << 2)) irq = 2; \
+ if (sh2.pending_irq & (1 << 3)) irq = 3; \
+ if (sh2.pending_irq & (1 << 4)) irq = 4; \
+ if (sh2.pending_irq & (1 << 5)) irq = 5; \
+ if (sh2.pending_irq & (1 << 6)) irq = 6; \
+ if (sh2.pending_irq & (1 << 7)) irq = 7; \
+ if (sh2.pending_irq & (1 << 8)) irq = 8; \
+ if (sh2.pending_irq & (1 << 9)) irq = 9; \
+ if (sh2.pending_irq & (1 << 10)) irq = 10; \
+ if (sh2.pending_irq & (1 << 11)) irq = 11; \
+ if (sh2.pending_irq & (1 << 12)) irq = 12; \
+ if (sh2.pending_irq & (1 << 13)) irq = 13; \
+ if (sh2.pending_irq & (1 << 14)) irq = 14; \
+ if (sh2.pending_irq & (1 << 15)) irq = 15; \
+ if ((sh2.internal_irq_level != -1) && (sh2.internal_irq_level > irq)) irq = sh2.internal_irq_level; \
+ if (irq >= 0) \
+ sh2_exception(message,irq); \
+} while(0)
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1100 1 -
+ * ADD Rm,Rn
+ */
+INLINE void ADD(UINT32 m, UINT32 n)
+{
+ sh2.r[n] += sh2.r[m];
+}
+
+/* code cycles t-bit
+ * 0111 nnnn iiii iiii 1 -
+ * ADD #imm,Rn
+ */
+INLINE void ADDI(UINT32 i, UINT32 n)
+{
+ sh2.r[n] += (INT32)(INT16)(INT8)i;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1110 1 carry
+ * ADDC Rm,Rn
+ */
+INLINE void ADDC(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0, tmp1;
+
+ tmp1 = sh2.r[n] + sh2.r[m];
+ tmp0 = sh2.r[n];
+ sh2.r[n] = tmp1 + (sh2.sr & T);
+ if (tmp0 > tmp1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ if (tmp1 > sh2.r[n])
+ sh2.sr |= T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1111 1 overflow
+ * ADDV Rm,Rn
+ */
+INLINE void ADDV(UINT32 m, UINT32 n)
+{
+ INT32 dest, src, ans;
+
+ if ((INT32) sh2.r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) sh2.r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ sh2.r[n] += sh2.r[m];
+ if ((INT32) sh2.r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 0 || src == 2)
+ {
+ if (ans == 1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ }
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1001 1 -
+ * AND Rm,Rn
+ */
+INLINE void AND(UINT32 m, UINT32 n)
+{
+ sh2.r[n] &= sh2.r[m];
+}
+
+
+/* code cycles t-bit
+ * 1100 1001 iiii iiii 1 -
+ * AND #imm,R0
+ */
+INLINE void ANDI(UINT32 i)
+{
+ sh2.r[0] &= i;
+}
+
+/* code cycles t-bit
+ * 1100 1101 iiii iiii 1 -
+ * AND.B #imm,@(R0,GBR)
+ */
+INLINE void ANDM(UINT32 i)
+{
+ UINT32 temp;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ temp = i & RB( sh2.ea );
+ WB( sh2.ea, temp );
+ sh2_icount -= 2;
+}
+
+/* code cycles t-bit
+ * 1000 1011 dddd dddd 3/1 -
+ * BF disp8
+ */
+INLINE void BF(UINT32 d)
+{
+ if ((sh2.sr & T) == 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ change_pc(sh2.pc & AM);
+ sh2_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1111 dddd dddd 3/1 -
+ * BFS disp8
+ */
+INLINE void BFS(UINT32 d)
+{
+ if ((sh2.sr & T) == 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 1010 dddd dddd dddd 2 -
+ * BRA disp12
+ */
+INLINE void BRA(UINT32 d)
+{
+ INT32 disp = ((INT32)d << 20) >> 20;
+
+#if BUSY_LOOP_HACKS
+ if (disp == -2)
+ {
+ UINT32 next_opcode = RW(sh2.ppc & AM);
+ /* BRA $
+ * NOP
+ */
+ if (next_opcode == 0x0009)
+ sh2_icount %= 3; /* cycles for BRA $ and NOP taken (3) */
+ }
+#endif
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0010 0011 2 -
+ * BRAF Rm
+ */
+INLINE void BRAF(UINT32 m)
+{
+ sh2.delay = sh2.pc;
+ sh2.pc += sh2.r[m] + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 1011 dddd dddd dddd 2 -
+ * BSR disp12
+ */
+INLINE void BSR(UINT32 d)
+{
+ INT32 disp = ((INT32)d << 20) >> 20;
+
+ sh2.pr = sh2.pc + 2;
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0000 0011 2 -
+ * BSRF Rm
+ */
+INLINE void BSRF(UINT32 m)
+{
+ sh2.pr = sh2.pc + 2;
+ sh2.delay = sh2.pc;
+ sh2.pc += sh2.r[m] + 2;
+ sh2_icount--;
+}
+
+/* code cycles t-bit
+ * 1000 1001 dddd dddd 3/1 -
+ * BT disp8
+ */
+INLINE void BT(UINT32 d)
+{
+ if ((sh2.sr & T) != 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ change_pc(sh2.pc & AM);
+ sh2_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1101 dddd dddd 2/1 -
+ * BTS disp8
+ */
+INLINE void BTS(UINT32 d)
+{
+ if ((sh2.sr & T) != 0)
+ {
+ INT32 disp = ((INT32)d << 24) >> 24;
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 0000 0000 0010 1000 1 -
+ * CLRMAC
+ */
+INLINE void CLRMAC(void)
+{
+ sh2.mach = 0;
+ sh2.macl = 0;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0000 1000 1 -
+ * CLRT
+ */
+INLINE void CLRT(void)
+{
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0000 1 comparison result
+ * CMP_EQ Rm,Rn
+ */
+INLINE void CMPEQ(UINT32 m, UINT32 n)
+{
+ if (sh2.r[n] == sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0011 1 comparison result
+ * CMP_GE Rm,Rn
+ */
+INLINE void CMPGE(UINT32 m, UINT32 n)
+{
+ if ((INT32) sh2.r[n] >= (INT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0111 1 comparison result
+ * CMP_GT Rm,Rn
+ */
+INLINE void CMPGT(UINT32 m, UINT32 n)
+{
+ if ((INT32) sh2.r[n] > (INT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0110 1 comparison result
+ * CMP_HI Rm,Rn
+ */
+INLINE void CMPHI(UINT32 m, UINT32 n)
+{
+ if ((UINT32) sh2.r[n] > (UINT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0010 1 comparison result
+ * CMP_HS Rm,Rn
+ */
+INLINE void CMPHS(UINT32 m, UINT32 n)
+{
+ if ((UINT32) sh2.r[n] >= (UINT32) sh2.r[m])
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0101 1 comparison result
+ * CMP_PL Rn
+ */
+INLINE void CMPPL(UINT32 n)
+{
+ if ((INT32) sh2.r[n] > 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0001 1 comparison result
+ * CMP_PZ Rn
+ */
+INLINE void CMPPZ(UINT32 n)
+{
+ if ((INT32) sh2.r[n] >= 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1100 1 comparison result
+ * CMP_STR Rm,Rn
+ */
+INLINE void CMPSTR(UINT32 m, UINT32 n)
+ {
+ UINT32 temp;
+ INT32 HH, HL, LH, LL;
+ temp = sh2.r[n] ^ sh2.r[m];
+ HH = (temp >> 24) & 0xff;
+ HL = (temp >> 16) & 0xff;
+ LH = (temp >> 8) & 0xff;
+ LL = temp & 0xff;
+ if (HH && HL && LH && LL)
+ sh2.sr &= ~T;
+ else
+ sh2.sr |= T;
+ }
+
+
+/* code cycles t-bit
+ * 1000 1000 iiii iiii 1 comparison result
+ * CMP/EQ #imm,R0
+ */
+INLINE void CMPIM(UINT32 i)
+{
+ UINT32 imm = (UINT32)(INT32)(INT16)(INT8)i;
+
+ if (sh2.r[0] == imm)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 0111 1 calculation result
+ * DIV0S Rm,Rn
+ */
+INLINE void DIV0S(UINT32 m, UINT32 n)
+{
+ if ((sh2.r[n] & 0x80000000) == 0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ if ((sh2.r[m] & 0x80000000) == 0)
+ sh2.sr &= ~M;
+ else
+ sh2.sr |= M;
+ if ((sh2.r[m] ^ sh2.r[n]) & 0x80000000)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0001 1001 1 0
+ * DIV0U
+ */
+INLINE void DIV0U(void)
+{
+ sh2.sr &= ~(M | Q | T);
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0100 1 calculation result
+ * DIV1 Rm,Rn
+ */
+INLINE void DIV1(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0;
+ UINT32 old_q;
+
+ old_q = sh2.sr & Q;
+ if (0x80000000 & sh2.r[n])
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+
+ sh2.r[n] = (sh2.r[n] << 1) | (sh2.sr & T);
+
+ if (!old_q)
+ {
+ if (!(sh2.sr & M))
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] -= sh2.r[m];
+ if(!(sh2.sr & Q))
+ if(sh2.r[n] > tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ else
+ if(sh2.r[n] > tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ }
+ else
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] += sh2.r[m];
+ if(!(sh2.sr & Q))
+ {
+ if(sh2.r[n] < tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ }
+ else
+ {
+ if(sh2.r[n] < tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ }
+ }
+ }
+ else
+ {
+ if (!(sh2.sr & M))
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] += sh2.r[m];
+ if(!(sh2.sr & Q))
+ if(sh2.r[n] < tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ else
+ if(sh2.r[n] < tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ }
+ else
+ {
+ tmp0 = sh2.r[n];
+ sh2.r[n] -= sh2.r[m];
+ if(!(sh2.sr & Q))
+ if(sh2.r[n] > tmp0)
+ sh2.sr &= ~Q;
+ else
+ sh2.sr |= Q;
+ else
+ if(sh2.r[n] > tmp0)
+ sh2.sr |= Q;
+ else
+ sh2.sr &= ~Q;
+ }
+ }
+
+ tmp0 = (sh2.sr & (Q | M));
+ if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* DMULS.L Rm,Rn */
+INLINE void DMULS(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+ INT32 tempm, tempn, fnLmL;
+
+ tempn = (INT32) sh2.r[n];
+ tempm = (INT32) sh2.r[m];
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ if ((INT32) (sh2.r[n] ^ sh2.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;
+ }
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ sh2_icount--;
+}
+
+/* DMULU.L Rm,Rn */
+INLINE void DMULU(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+
+ RnL = sh2.r[n] & 0x0000ffff;
+ RnH = (sh2.r[n] >> 16) & 0x0000ffff;
+ RmL = sh2.r[m] & 0x0000ffff;
+ RmH = (sh2.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;
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ sh2_icount--;
+}
+
+/* DT Rn */
+INLINE void DT(UINT32 n)
+{
+ sh2.r[n]--;
+ if (sh2.r[n] == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+#if BUSY_LOOP_HACKS
+ {
+ UINT32 next_opcode = RW(sh2.ppc & AM);
+ /* DT Rn
+ * BF $-2
+ */
+ if (next_opcode == 0x8bfd)
+ {
+ while (sh2.r[n] > 1 && sh2_icount > 4)
+ {
+ sh2.r[n]--;
+ sh2_icount -= 4; /* cycles for DT (1) and BF taken (3) */
+ }
+ }
+ }
+#endif
+}
+
+/* EXTS.B Rm,Rn */
+INLINE void EXTSB(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = ((INT32)sh2.r[m] << 24) >> 24;
+}
+
+/* EXTS.W Rm,Rn */
+INLINE void EXTSW(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = ((INT32)sh2.r[m] << 16) >> 16;
+}
+
+/* EXTU.B Rm,Rn */
+INLINE void EXTUB(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = sh2.r[m] & 0x000000ff;
+}
+
+/* EXTU.W Rm,Rn */
+INLINE void EXTUW(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = sh2.r[m] & 0x0000ffff;
+}
+
+/* JMP @Rm */
+INLINE void JMP(UINT32 m)
+{
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.r[m];
+}
+
+/* JSR @Rm */
+INLINE void JSR(UINT32 m)
+{
+ sh2.delay = sh2.pc;
+ sh2.pr = sh2.pc + 2;
+ sh2.pc = sh2.ea = sh2.r[m];
+ sh2_icount--;
+}
+
+
+/* LDC Rm,SR */
+INLINE void LDCSR(UINT32 m)
+{
+ sh2.sr = sh2.r[m] & FLAGS;
+ sh2.test_irq = 1;
+}
+
+/* LDC Rm,GBR */
+INLINE void LDCGBR(UINT32 m)
+{
+ sh2.gbr = sh2.r[m];
+}
+
+/* LDC Rm,VBR */
+INLINE void LDCVBR(UINT32 m)
+{
+ sh2.vbr = sh2.r[m];
+}
+
+/* LDC.L @Rm+,SR */
+INLINE void LDCMSR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.sr = RL( sh2.ea ) & FLAGS;
+ sh2.r[m] += 4;
+ sh2_icount -= 2;
+ sh2.test_irq = 1;
+}
+
+/* LDC.L @Rm+,GBR */
+INLINE void LDCMGBR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.gbr = RL( sh2.ea );
+ sh2.r[m] += 4;
+ sh2_icount -= 2;
+}
+
+/* LDC.L @Rm+,VBR */
+INLINE void LDCMVBR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.vbr = RL( sh2.ea );
+ sh2.r[m] += 4;
+ sh2_icount -= 2;
+}
+
+/* LDS Rm,MACH */
+INLINE void LDSMACH(UINT32 m)
+{
+ sh2.mach = sh2.r[m];
+}
+
+/* LDS Rm,MACL */
+INLINE void LDSMACL(UINT32 m)
+{
+ sh2.macl = sh2.r[m];
+}
+
+/* LDS Rm,PR */
+INLINE void LDSPR(UINT32 m)
+{
+ sh2.pr = sh2.r[m];
+}
+
+/* LDS.L @Rm+,MACH */
+INLINE void LDSMMACH(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.mach = RL( sh2.ea );
+ sh2.r[m] += 4;
+}
+
+/* LDS.L @Rm+,MACL */
+INLINE void LDSMMACL(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.macl = RL( sh2.ea );
+ sh2.r[m] += 4;
+}
+
+/* LDS.L @Rm+,PR */
+INLINE void LDSMPR(UINT32 m)
+{
+ sh2.ea = sh2.r[m];
+ sh2.pr = RL( sh2.ea );
+ sh2.r[m] += 4;
+}
+
+/* MAC.L @Rm+,@Rn+ */
+INLINE void MAC_L(UINT32 m, UINT32 n)
+{
+ UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ UINT32 temp0, temp1, temp2, temp3;
+ INT32 tempm, tempn, fnLmL;
+
+ tempn = (INT32) RL( sh2.r[n] );
+ sh2.r[n] += 4;
+ tempm = (INT32) RL( sh2.r[m] );
+ sh2.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 (sh2.sr & S)
+ {
+ Res0 = sh2.macl + Res0;
+ if (sh2.macl > Res0)
+ Res2++;
+ Res2 += (sh2.mach & 0x0000ffff);
+ if (((INT32) Res2 < 0) && (Res2 < 0xffff8000))
+ {
+ Res2 = 0x00008000;
+ Res0 = 0x00000000;
+ }
+ else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff))
+ {
+ Res2 = 0x00007fff;
+ Res0 = 0xffffffff;
+ }
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ }
+ else
+ {
+ Res0 = sh2.macl + Res0;
+ if (sh2.macl > Res0)
+ Res2++;
+ Res2 += sh2.mach;
+ sh2.mach = Res2;
+ sh2.macl = Res0;
+ }
+ sh2_icount -= 2;
+}
+
+/* MAC.W @Rm+,@Rn+ */
+INLINE void MAC_W(UINT32 m, UINT32 n)
+{
+ INT32 tempm, tempn, dest, src, ans;
+ UINT32 templ;
+
+ tempn = (INT32) RW( sh2.r[n] );
+ sh2.r[n] += 2;
+ tempm = (INT32) RW( sh2.r[m] );
+ sh2.r[m] += 2;
+ templ = sh2.macl;
+ tempm = ((INT32) (short) tempn * (INT32) (short) tempm);
+ if ((INT32) sh2.macl >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) tempm >= 0)
+ {
+ src = 0;
+ tempn = 0;
+ }
+ else
+ {
+ src = 1;
+ tempn = 0xffffffff;
+ }
+ src += dest;
+ sh2.macl += tempm;
+ if ((INT32) sh2.macl >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (sh2.sr & S)
+ {
+ if (ans == 1)
+ {
+ if (src == 0)
+ sh2.macl = 0x7fffffff;
+ if (src == 2)
+ sh2.macl = 0x80000000;
+ }
+ }
+ else
+ {
+ sh2.mach += tempn;
+ if (templ > sh2.macl)
+ sh2.mach += 1;
+ }
+ sh2_icount -= 2;
+}
+
+/* MOV Rm,Rn */
+INLINE void MOV(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = sh2.r[m];
+}
+
+/* MOV.B Rm,@Rn */
+INLINE void MOVBS(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n];
+ WB( sh2.ea, sh2.r[m] & 0x000000ff);
+}
+
+/* MOV.W Rm,@Rn */
+INLINE void MOVWS(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n];
+ WW( sh2.ea, sh2.r[m] & 0x0000ffff);
+}
+
+/* MOV.L Rm,@Rn */
+INLINE void MOVLS(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.r[m] );
+}
+
+/* MOV.B @Rm,Rn */
+INLINE void MOVBL(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m];
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @Rm,Rn */
+INLINE void MOVWL(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m];
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @Rm,Rn */
+INLINE void MOVLL(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m];
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOV.B Rm,@-Rn */
+INLINE void MOVBM(UINT32 m, UINT32 n)
+{
+ /* SMG : bug fix, was reading sh2.r[n] */
+ UINT32 data = sh2.r[m] & 0x000000ff;
+
+ sh2.r[n] -= 1;
+ WB( sh2.r[n], data );
+}
+
+/* MOV.W Rm,@-Rn */
+INLINE void MOVWM(UINT32 m, UINT32 n)
+{
+ UINT32 data = sh2.r[m] & 0x0000ffff;
+
+ sh2.r[n] -= 2;
+ WW( sh2.r[n], data );
+}
+
+/* MOV.L Rm,@-Rn */
+INLINE void MOVLM(UINT32 m, UINT32 n)
+{
+ UINT32 data = sh2.r[m];
+
+ sh2.r[n] -= 4;
+ WL( sh2.r[n], data );
+}
+
+/* MOV.B @Rm+,Rn */
+INLINE void MOVBP(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.r[m] );
+ if (n != m)
+ sh2.r[m] += 1;
+}
+
+/* MOV.W @Rm+,Rn */
+INLINE void MOVWP(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.r[m] );
+ if (n != m)
+ sh2.r[m] += 2;
+}
+
+/* MOV.L @Rm+,Rn */
+INLINE void MOVLP(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = RL( sh2.r[m] );
+ if (n != m)
+ sh2.r[m] += 4;
+}
+
+/* MOV.B Rm,@(R0,Rn) */
+INLINE void MOVBS0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n] + sh2.r[0];
+ WB( sh2.ea, sh2.r[m] & 0x000000ff );
+}
+
+/* MOV.W Rm,@(R0,Rn) */
+INLINE void MOVWS0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n] + sh2.r[0];
+ WW( sh2.ea, sh2.r[m] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(R0,Rn) */
+INLINE void MOVLS0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[n] + sh2.r[0];
+ WL( sh2.ea, sh2.r[m] );
+}
+
+/* MOV.B @(R0,Rm),Rn */
+INLINE void MOVBL0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m] + sh2.r[0];
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @(R0,Rm),Rn */
+INLINE void MOVWL0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m] + sh2.r[0];
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(R0,Rm),Rn */
+INLINE void MOVLL0(UINT32 m, UINT32 n)
+{
+ sh2.ea = sh2.r[m] + sh2.r[0];
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOV #imm,Rn */
+INLINE void MOVI(UINT32 i, UINT32 n)
+{
+ sh2.r[n] = (UINT32)(INT32)(INT16)(INT8) i;
+}
+
+/* MOV.W @(disp8,PC),Rn */
+INLINE void MOVWI(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.pc + disp * 2 + 2;
+ sh2.r[n] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(disp8,PC),Rn */
+INLINE void MOVLI(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = ((sh2.pc + 2) & ~3) + disp * 4;
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOV.B @(disp8,GBR),R0 */
+INLINE void MOVBLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp;
+ sh2.r[0] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @(disp8,GBR),R0 */
+INLINE void MOVWLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 2;
+ sh2.r[0] = (INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(disp8,GBR),R0 */
+INLINE void MOVLLG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 4;
+ sh2.r[0] = RL( sh2.ea );
+}
+
+/* MOV.B R0,@(disp8,GBR) */
+INLINE void MOVBSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp;
+ WB( sh2.ea, sh2.r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp8,GBR) */
+INLINE void MOVWSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 2;
+ WW( sh2.ea, sh2.r[0] & 0x0000ffff );
+}
+
+/* MOV.L R0,@(disp8,GBR) */
+INLINE void MOVLSG(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = sh2.gbr + disp * 4;
+ WL( sh2.ea, sh2.r[0] );
+}
+
+/* MOV.B R0,@(disp4,Rn) */
+INLINE void MOVBS4(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[n] + disp;
+ WB( sh2.ea, sh2.r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp4,Rn) */
+INLINE void MOVWS4(UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[n] + disp * 2;
+ WW( sh2.ea, sh2.r[0] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(disp4,Rn) */
+INLINE void MOVLS4(UINT32 m, UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[n] + disp * 4;
+ WL( sh2.ea, sh2.r[m] );
+}
+
+/* MOV.B @(disp4,Rm),R0 */
+INLINE void MOVBL4(UINT32 m, UINT32 d)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[m] + disp;
+ sh2.r[0] = (UINT32)(INT32)(INT16)(INT8) RB( sh2.ea );
+}
+
+/* MOV.W @(disp4,Rm),R0 */
+INLINE void MOVWL4(UINT32 m, UINT32 d)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[m] + disp * 2;
+ sh2.r[0] = (UINT32)(INT32)(INT16) RW( sh2.ea );
+}
+
+/* MOV.L @(disp4,Rm),Rn */
+INLINE void MOVLL4(UINT32 m, UINT32 d, UINT32 n)
+{
+ UINT32 disp = d & 0x0f;
+ sh2.ea = sh2.r[m] + disp * 4;
+ sh2.r[n] = RL( sh2.ea );
+}
+
+/* MOVA @(disp8,PC),R0 */
+INLINE void MOVA(UINT32 d)
+{
+ UINT32 disp = d & 0xff;
+ sh2.ea = ((sh2.pc + 2) & ~3) + disp * 4;
+ sh2.r[0] = sh2.ea;
+}
+
+/* MOVT Rn */
+INLINE void MOVT(UINT32 n)
+{
+ sh2.r[n] = sh2.sr & T;
+}
+
+/* MUL.L Rm,Rn */
+INLINE void MULL(UINT32 m, UINT32 n)
+{
+ sh2.macl = sh2.r[n] * sh2.r[m];
+ sh2_icount--;
+}
+
+/* MULS Rm,Rn */
+INLINE void MULS(UINT32 m, UINT32 n)
+{
+ sh2.macl = (INT16) sh2.r[n] * (INT16) sh2.r[m];
+}
+
+/* MULU Rm,Rn */
+INLINE void MULU(UINT32 m, UINT32 n)
+{
+ sh2.macl = (UINT16) sh2.r[n] * (UINT16) sh2.r[m];
+}
+
+/* NEG Rm,Rn */
+INLINE void NEG(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = 0 - sh2.r[m];
+}
+
+/* NEGC Rm,Rn */
+INLINE void NEGC(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = sh2.r[m];
+ sh2.r[n] = -temp - (sh2.sr & T);
+ if (temp || (sh2.sr & T))
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* NOP */
+INLINE void NOP(void)
+{
+}
+
+/* NOT Rm,Rn */
+INLINE void NOT(UINT32 m, UINT32 n)
+{
+ sh2.r[n] = ~sh2.r[m];
+}
+
+/* OR Rm,Rn */
+INLINE void OR(UINT32 m, UINT32 n)
+{
+ sh2.r[n] |= sh2.r[m];
+}
+
+/* OR #imm,R0 */
+INLINE void ORI(UINT32 i)
+{
+ sh2.r[0] |= i;
+ sh2_icount -= 2;
+}
+
+/* OR.B #imm,@(R0,GBR) */
+INLINE void ORM(UINT32 i)
+{
+ UINT32 temp;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ temp = RB( sh2.ea );
+ temp |= i;
+ WB( sh2.ea, temp );
+}
+
+/* ROTCL Rn */
+INLINE void ROTCL(UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh2.r[n] >> 31) & T;
+ sh2.r[n] = (sh2.r[n] << 1) | (sh2.sr & T);
+ sh2.sr = (sh2.sr & ~T) | temp;
+}
+
+/* ROTCR Rn */
+INLINE void ROTCR(UINT32 n)
+{
+ UINT32 temp;
+ temp = (sh2.sr & T) << 31;
+ if (sh2.r[n] & T)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ sh2.r[n] = (sh2.r[n] >> 1) | temp;
+}
+
+/* ROTL Rn */
+INLINE void ROTL(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | ((sh2.r[n] >> 31) & T);
+ sh2.r[n] = (sh2.r[n] << 1) | (sh2.r[n] >> 31);
+}
+
+/* ROTR Rn */
+INLINE void ROTR(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | (sh2.r[n] & T);
+ sh2.r[n] = (sh2.r[n] >> 1) | (sh2.r[n] << 31);
+}
+
+/* RTE */
+INLINE void RTE(void)
+{
+ sh2.ea = sh2.r[15];
+ sh2.delay = sh2.pc;
+ sh2.pc = RL( sh2.ea );
+ sh2.r[15] += 4;
+ sh2.ea = sh2.r[15];
+ sh2.sr = RL( sh2.ea ) & FLAGS;
+ sh2.r[15] += 4;
+ sh2_icount -= 3;
+ sh2.test_irq = 1;
+}
+
+/* RTS */
+INLINE void RTS(void)
+{
+ sh2.delay = sh2.pc;
+ sh2.pc = sh2.ea = sh2.pr;
+ sh2_icount--;
+}
+
+/* SETT */
+INLINE void SETT(void)
+{
+ sh2.sr |= T;
+}
+
+/* SHAL Rn (same as SHLL) */
+INLINE void SHAL(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | ((sh2.r[n] >> 31) & T);
+ sh2.r[n] <<= 1;
+}
+
+/* SHAR Rn */
+INLINE void SHAR(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | (sh2.r[n] & T);
+ sh2.r[n] = (UINT32)((INT32)sh2.r[n] >> 1);
+}
+
+/* SHLL Rn (same as SHAL) */
+INLINE void SHLL(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | ((sh2.r[n] >> 31) & T);
+ sh2.r[n] <<= 1;
+}
+
+/* SHLL2 Rn */
+INLINE void SHLL2(UINT32 n)
+{
+ sh2.r[n] <<= 2;
+}
+
+/* SHLL8 Rn */
+INLINE void SHLL8(UINT32 n)
+{
+ sh2.r[n] <<= 8;
+}
+
+/* SHLL16 Rn */
+INLINE void SHLL16(UINT32 n)
+{
+ sh2.r[n] <<= 16;
+}
+
+/* SHLR Rn */
+INLINE void SHLR(UINT32 n)
+{
+ sh2.sr = (sh2.sr & ~T) | (sh2.r[n] & T);
+ sh2.r[n] >>= 1;
+}
+
+/* SHLR2 Rn */
+INLINE void SHLR2(UINT32 n)
+{
+ sh2.r[n] >>= 2;
+}
+
+/* SHLR8 Rn */
+INLINE void SHLR8(UINT32 n)
+{
+ sh2.r[n] >>= 8;
+}
+
+/* SHLR16 Rn */
+INLINE void SHLR16(UINT32 n)
+{
+ sh2.r[n] >>= 16;
+}
+
+/* SLEEP */
+INLINE void SLEEP(void)
+{
+ sh2.pc -= 2;
+ sh2_icount -= 2;
+ /* Wait_for_exception; */
+}
+
+/* STC SR,Rn */
+INLINE void STCSR(UINT32 n)
+{
+ sh2.r[n] = sh2.sr;
+}
+
+/* STC GBR,Rn */
+INLINE void STCGBR(UINT32 n)
+{
+ sh2.r[n] = sh2.gbr;
+}
+
+/* STC VBR,Rn */
+INLINE void STCVBR(UINT32 n)
+{
+ sh2.r[n] = sh2.vbr;
+}
+
+/* STC.L SR,@-Rn */
+INLINE void STCMSR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.sr );
+ sh2_icount--;
+}
+
+/* STC.L GBR,@-Rn */
+INLINE void STCMGBR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.gbr );
+ sh2_icount--;
+}
+
+/* STC.L VBR,@-Rn */
+INLINE void STCMVBR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.vbr );
+ sh2_icount--;
+}
+
+/* STS MACH,Rn */
+INLINE void STSMACH(UINT32 n)
+{
+ sh2.r[n] = sh2.mach;
+}
+
+/* STS MACL,Rn */
+INLINE void STSMACL(UINT32 n)
+{
+ sh2.r[n] = sh2.macl;
+}
+
+/* STS PR,Rn */
+INLINE void STSPR(UINT32 n)
+{
+ sh2.r[n] = sh2.pr;
+}
+
+/* STS.L MACH,@-Rn */
+INLINE void STSMMACH(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.mach );
+}
+
+/* STS.L MACL,@-Rn */
+INLINE void STSMMACL(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.macl );
+}
+
+/* STS.L PR,@-Rn */
+INLINE void STSMPR(UINT32 n)
+{
+ sh2.r[n] -= 4;
+ sh2.ea = sh2.r[n];
+ WL( sh2.ea, sh2.pr );
+}
+
+/* SUB Rm,Rn */
+INLINE void SUB(UINT32 m, UINT32 n)
+{
+ sh2.r[n] -= sh2.r[m];
+}
+
+/* SUBC Rm,Rn */
+INLINE void SUBC(UINT32 m, UINT32 n)
+{
+ UINT32 tmp0, tmp1;
+
+ tmp1 = sh2.r[n] - sh2.r[m];
+ tmp0 = sh2.r[n];
+ sh2.r[n] = tmp1 - (sh2.sr & T);
+ if (tmp0 < tmp1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ if (tmp1 < sh2.r[n])
+ sh2.sr |= T;
+}
+
+/* SUBV Rm,Rn */
+INLINE void SUBV(UINT32 m, UINT32 n)
+{
+ INT32 dest, src, ans;
+
+ if ((INT32) sh2.r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((INT32) sh2.r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ sh2.r[n] -= sh2.r[m];
+ if ((INT32) sh2.r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 1)
+ {
+ if (ans == 1)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ }
+ else
+ sh2.sr &= ~T;
+}
+
+/* SWAP.B Rm,Rn */
+INLINE void SWAPB(UINT32 m, UINT32 n)
+{
+ UINT32 temp0, temp1;
+
+ temp0 = sh2.r[m] & 0xffff0000;
+ temp1 = (sh2.r[m] & 0x000000ff) << 8;
+ sh2.r[n] = (sh2.r[m] >> 8) & 0x000000ff;
+ sh2.r[n] = sh2.r[n] | temp1 | temp0;
+}
+
+/* SWAP.W Rm,Rn */
+INLINE void SWAPW(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh2.r[m] >> 16) & 0x0000ffff;
+ sh2.r[n] = (sh2.r[m] << 16) | temp;
+}
+
+/* TAS.B @Rn */
+INLINE void TAS(UINT32 n)
+{
+ UINT32 temp;
+ sh2.ea = sh2.r[n];
+ /* Bus Lock enable */
+ temp = RB( sh2.ea );
+ if (temp == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ temp |= 0x80;
+ /* Bus Lock disable */
+ WB( sh2.ea, temp );
+ sh2_icount -= 3;
+}
+
+/* TRAPA #imm */
+INLINE void TRAPA(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ sh2.ea = sh2.vbr + imm * 4;
+
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.sr );
+ sh2.r[15] -= 4;
+ WL( sh2.r[15], sh2.pc );
+
+ sh2.pc = RL( sh2.ea );
+ change_pc(sh2.pc & AM);
+
+ sh2_icount -= 7;
+}
+
+/* TST Rm,Rn */
+INLINE void TST(UINT32 m, UINT32 n)
+{
+ if ((sh2.r[n] & sh2.r[m]) == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* TST #imm,R0 */
+INLINE void TSTI(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ if ((imm & sh2.r[0]) == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+}
+
+/* TST.B #imm,@(R0,GBR) */
+INLINE void TSTM(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ if ((imm & RB( sh2.ea )) == 0)
+ sh2.sr |= T;
+ else
+ sh2.sr &= ~T;
+ sh2_icount -= 2;
+}
+
+/* XOR Rm,Rn */
+INLINE void XOR(UINT32 m, UINT32 n)
+{
+ sh2.r[n] ^= sh2.r[m];
+}
+
+/* XOR #imm,R0 */
+INLINE void XORI(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+ sh2.r[0] ^= imm;
+}
+
+/* XOR.B #imm,@(R0,GBR) */
+INLINE void XORM(UINT32 i)
+{
+ UINT32 imm = i & 0xff;
+ UINT32 temp;
+
+ sh2.ea = sh2.gbr + sh2.r[0];
+ temp = RB( sh2.ea );
+ temp ^= imm;
+ WB( sh2.ea, temp );
+ sh2_icount -= 2;
+}
+
+/* XTRCT Rm,Rn */
+INLINE void XTRCT(UINT32 m, UINT32 n)
+{
+ UINT32 temp;
+
+ temp = (sh2.r[m] << 16) & 0xffff0000;
+ sh2.r[n] = (sh2.r[n] >> 16) & 0x0000ffff;
+ sh2.r[n] |= temp;
+}
+
+/*****************************************************************************
+ * OPCODE DISPATCHERS
+ *****************************************************************************/
+
+INLINE void op0000(UINT16 opcode)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: NOP(); break;
+ case 0x01: NOP(); break;
+ case 0x02: STCSR(Rn); break;
+ case 0x03: BSRF(Rn); break;
+ case 0x04: MOVBS0(Rm, Rn); break;
+ case 0x05: MOVWS0(Rm, Rn); break;
+ case 0x06: MOVLS0(Rm, Rn); break;
+ case 0x07: MULL(Rm, Rn); break;
+ case 0x08: CLRT(); break;
+ case 0x09: NOP(); break;
+ case 0x0a: STSMACH(Rn); break;
+ case 0x0b: RTS(); break;
+ case 0x0c: MOVBL0(Rm, Rn); break;
+ case 0x0d: MOVWL0(Rm, Rn); break;
+ case 0x0e: MOVLL0(Rm, Rn); break;
+ case 0x0f: MAC_L(Rm, Rn); break;
+
+ case 0x10: NOP(); break;
+ case 0x11: NOP(); break;
+ case 0x12: STCGBR(Rn); break;
+ case 0x13: NOP(); break;
+ case 0x14: MOVBS0(Rm, Rn); break;
+ case 0x15: MOVWS0(Rm, Rn); break;
+ case 0x16: MOVLS0(Rm, Rn); break;
+ case 0x17: MULL(Rm, Rn); break;
+ case 0x18: SETT(); break;
+ case 0x19: DIV0U(); break;
+ case 0x1a: STSMACL(Rn); break;
+ case 0x1b: SLEEP(); break;
+ case 0x1c: MOVBL0(Rm, Rn); break;
+ case 0x1d: MOVWL0(Rm, Rn); break;
+ case 0x1e: MOVLL0(Rm, Rn); break;
+ case 0x1f: MAC_L(Rm, Rn); break;
+
+ case 0x20: NOP(); break;
+ case 0x21: NOP(); break;
+ case 0x22: STCVBR(Rn); break;
+ case 0x23: BRAF(Rn); break;
+ case 0x24: MOVBS0(Rm, Rn); break;
+ case 0x25: MOVWS0(Rm, Rn); break;
+ case 0x26: MOVLS0(Rm, Rn); break;
+ case 0x27: MULL(Rm, Rn); break;
+ case 0x28: CLRMAC(); break;
+ case 0x29: MOVT(Rn); break;
+ case 0x2a: STSPR(Rn); break;
+ case 0x2b: RTE(); break;
+ case 0x2c: MOVBL0(Rm, Rn); break;
+ case 0x2d: MOVWL0(Rm, Rn); break;
+ case 0x2e: MOVLL0(Rm, Rn); break;
+ case 0x2f: MAC_L(Rm, Rn); break;
+
+ case 0x30: NOP(); break;
+ case 0x31: NOP(); break;
+ case 0x32: NOP(); break;
+ case 0x33: NOP(); break;
+ case 0x34: MOVBS0(Rm, Rn); break;
+ case 0x35: MOVWS0(Rm, Rn); break;
+ case 0x36: MOVLS0(Rm, Rn); break;
+ case 0x37: MULL(Rm, Rn); break;
+ case 0x38: NOP(); break;
+ case 0x39: NOP(); break;
+ case 0x3c: MOVBL0(Rm, Rn); break;
+ case 0x3d: MOVWL0(Rm, Rn); break;
+ case 0x3e: MOVLL0(Rm, Rn); break;
+ case 0x3f: MAC_L(Rm, Rn); break;
+ case 0x3a: NOP(); break;
+ case 0x3b: NOP(); break;
+
+
+
+ }
+}
+
+INLINE void op0001(UINT16 opcode)
+{
+ MOVLS4(Rm, opcode & 0x0f, Rn);
+}
+
+INLINE void op0010(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: MOVBS(Rm, Rn); break;
+ case 1: MOVWS(Rm, Rn); break;
+ case 2: MOVLS(Rm, Rn); break;
+ case 3: NOP(); break;
+ case 4: MOVBM(Rm, Rn); break;
+ case 5: MOVWM(Rm, Rn); break;
+ case 6: MOVLM(Rm, Rn); break;
+ case 7: DIV0S(Rm, Rn); break;
+ case 8: TST(Rm, Rn); break;
+ case 9: AND(Rm, Rn); break;
+ case 10: XOR(Rm, Rn); break;
+ case 11: OR(Rm, Rn); break;
+ case 12: CMPSTR(Rm, Rn); break;
+ case 13: XTRCT(Rm, Rn); break;
+ case 14: MULU(Rm, Rn); break;
+ case 15: MULS(Rm, Rn); break;
+ }
+}
+
+INLINE void op0011(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: CMPEQ(Rm, Rn); break;
+ case 1: NOP(); break;
+ case 2: CMPHS(Rm, Rn); break;
+ case 3: CMPGE(Rm, Rn); break;
+ case 4: DIV1(Rm, Rn); break;
+ case 5: DMULU(Rm, Rn); break;
+ case 6: CMPHI(Rm, Rn); break;
+ case 7: CMPGT(Rm, Rn); break;
+ case 8: SUB(Rm, Rn); break;
+ case 9: NOP(); break;
+ case 10: SUBC(Rm, Rn); break;
+ case 11: SUBV(Rm, Rn); break;
+ case 12: ADD(Rm, Rn); break;
+ case 13: DMULS(Rm, Rn); break;
+ case 14: ADDC(Rm, Rn); break;
+ case 15: ADDV(Rm, Rn); break;
+ }
+}
+
+INLINE void op0100(UINT16 opcode)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: SHLL(Rn); break;
+ case 0x01: SHLR(Rn); break;
+ case 0x02: STSMMACH(Rn); break;
+ case 0x03: STCMSR(Rn); break;
+ case 0x04: ROTL(Rn); break;
+ case 0x05: ROTR(Rn); break;
+ case 0x06: LDSMMACH(Rn); break;
+ case 0x07: LDCMSR(Rn); break;
+ case 0x08: SHLL2(Rn); break;
+ case 0x09: SHLR2(Rn); break;
+ case 0x0a: LDSMACH(Rn); break;
+ case 0x0b: JSR(Rn); break;
+ case 0x0c: NOP(); break;
+ case 0x0d: NOP(); break;
+ case 0x0e: LDCSR(Rn); break;
+ case 0x0f: MAC_W(Rm, Rn); break;
+
+ case 0x10: DT(Rn); break;
+ case 0x11: CMPPZ(Rn); break;
+ case 0x12: STSMMACL(Rn); break;
+ case 0x13: STCMGBR(Rn); break;
+ case 0x14: NOP(); break;
+ case 0x15: CMPPL(Rn); break;
+ case 0x16: LDSMMACL(Rn); break;
+ case 0x17: LDCMGBR(Rn); break;
+ case 0x18: SHLL8(Rn); break;
+ case 0x19: SHLR8(Rn); break;
+ case 0x1a: LDSMACL(Rn); break;
+ case 0x1b: TAS(Rn); break;
+ case 0x1c: NOP(); break;
+ case 0x1d: NOP(); break;
+ case 0x1e: LDCGBR(Rn); break;
+ case 0x1f: MAC_W(Rm, Rn); break;
+
+ case 0x20: SHAL(Rn); break;
+ case 0x21: SHAR(Rn); break;
+ case 0x22: STSMPR(Rn); break;
+ case 0x23: STCMVBR(Rn); break;
+ case 0x24: ROTCL(Rn); break;
+ case 0x25: ROTCR(Rn); break;
+ case 0x26: LDSMPR(Rn); break;
+ case 0x27: LDCMVBR(Rn); break;
+ case 0x28: SHLL16(Rn); break;
+ case 0x29: SHLR16(Rn); break;
+ case 0x2a: LDSPR(Rn); break;
+ case 0x2b: JMP(Rn); break;
+ case 0x2c: NOP(); break;
+ case 0x2d: NOP(); break;
+ case 0x2e: LDCVBR(Rn); break;
+ case 0x2f: MAC_W(Rm, Rn); break;
+
+ case 0x30: NOP(); break;
+ case 0x31: NOP(); break;
+ case 0x32: NOP(); break;
+ case 0x33: NOP(); break;
+ case 0x34: NOP(); break;
+ case 0x35: NOP(); break;
+ case 0x36: NOP(); break;
+ case 0x37: NOP(); break;
+ case 0x38: NOP(); break;
+ case 0x39: NOP(); break;
+ case 0x3a: NOP(); break;
+ case 0x3b: NOP(); break;
+ case 0x3c: NOP(); break;
+ case 0x3d: NOP(); break;
+ case 0x3e: NOP(); break;
+ case 0x3f: MAC_W(Rm, Rn); break;
+
+ }
+}
+
+INLINE void op0101(UINT16 opcode)
+{
+ MOVLL4(Rm, opcode & 0x0f, Rn);
+}
+
+INLINE void op0110(UINT16 opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: MOVBL(Rm, Rn); break;
+ case 1: MOVWL(Rm, Rn); break;
+ case 2: MOVLL(Rm, Rn); break;
+ case 3: MOV(Rm, Rn); break;
+ case 4: MOVBP(Rm, Rn); break;
+ case 5: MOVWP(Rm, Rn); break;
+ case 6: MOVLP(Rm, Rn); break;
+ case 7: NOT(Rm, Rn); break;
+ case 8: SWAPB(Rm, Rn); break;
+ case 9: SWAPW(Rm, Rn); break;
+ case 10: NEGC(Rm, Rn); break;
+ case 11: NEG(Rm, Rn); break;
+ case 12: EXTUB(Rm, Rn); break;
+ case 13: EXTUW(Rm, Rn); break;
+ case 14: EXTSB(Rm, Rn); break;
+ case 15: EXTSW(Rm, Rn); break;
+ }
+}
+
+INLINE void op0111(UINT16 opcode)
+{
+ ADDI(opcode & 0xff, Rn);
+}
+
+INLINE void op1000(UINT16 opcode)
+{
+ switch ( opcode & (15<<8) )
+ {
+ case 0 << 8: MOVBS4(opcode & 0x0f, Rm); break;
+ case 1 << 8: MOVWS4(opcode & 0x0f, Rm); break;
+ case 2<< 8: NOP(); break;
+ case 3<< 8: NOP(); break;
+ case 4<< 8: MOVBL4(Rm, opcode & 0x0f); break;
+ case 5<< 8: MOVWL4(Rm, opcode & 0x0f); break;
+ case 6<< 8: NOP(); break;
+ case 7<< 8: NOP(); break;
+ case 8<< 8: CMPIM(opcode & 0xff); break;
+ case 9<< 8: BT(opcode & 0xff); break;
+ case 10<< 8: NOP(); break;
+ case 11<< 8: BF(opcode & 0xff); break;
+ case 12<< 8: NOP(); break;
+ case 13<< 8: BTS(opcode & 0xff); break;
+ case 14<< 8: NOP(); break;
+ case 15<< 8: BFS(opcode & 0xff); break;
+ }
+}
+
+
+INLINE void op1001(UINT16 opcode)
+{
+ MOVWI(opcode & 0xff, Rn);
+}
+
+INLINE void op1010(UINT16 opcode)
+{
+ BRA(opcode & 0xfff);
+}
+
+INLINE void op1011(UINT16 opcode)
+{
+ BSR(opcode & 0xfff);
+}
+
+INLINE void op1100(UINT16 opcode)
+{
+ switch (opcode & (15<<8))
+ {
+ case 0<<8: MOVBSG(opcode & 0xff); break;
+ case 1<<8: MOVWSG(opcode & 0xff); break;
+ case 2<<8: MOVLSG(opcode & 0xff); break;
+ case 3<<8: TRAPA(opcode & 0xff); break;
+ case 4<<8: MOVBLG(opcode & 0xff); break;
+ case 5<<8: MOVWLG(opcode & 0xff); break;
+ case 6<<8: MOVLLG(opcode & 0xff); break;
+ case 7<<8: MOVA(opcode & 0xff); break;
+ case 8<<8: TSTI(opcode & 0xff); break;
+ case 9<<8: ANDI(opcode & 0xff); break;
+ case 10<<8: XORI(opcode & 0xff); break;
+ case 11<<8: ORI(opcode & 0xff); break;
+ case 12<<8: TSTM(opcode & 0xff); break;
+ case 13<<8: ANDM(opcode & 0xff); break;
+ case 14<<8: XORM(opcode & 0xff); break;
+ case 15<<8: ORM(opcode & 0xff); break;
+ }
+}
+
+INLINE void op1101(UINT16 opcode)
+{
+ MOVLI(opcode & 0xff, Rn);
+}
+
+INLINE void op1110(UINT16 opcode)
+{
+ MOVI(opcode & 0xff, Rn);
+}
+
+INLINE void op1111(UINT16 opcode)
+{
+ NOP();
+}
+
+/*****************************************************************************
+ * MAME CPU INTERFACE
+ *****************************************************************************/
+
+static void sh2_reset(void)
+{
+ void *tsave, *tsaved0, *tsaved1;
+ UINT32 *m;
+ int cpunum;
+ int save_is_slave;
+
+ void (*f)(UINT32 data);
+ int (*save_irqcallback)(int);
+
+ cpunum = sh2.cpu_number;
+ m = sh2.m;
+ tsave = sh2.timer;
+ tsaved0 = sh2.dma_timer[0];
+ tsaved1 = sh2.dma_timer[1];
+
+ f = sh2.ftcsr_read_callback;
+ save_irqcallback = sh2.irq_callback;
+ save_is_slave = sh2.is_slave;
+ memset(&sh2, 0, sizeof(SH2));
+ sh2.is_slave = save_is_slave;
+ sh2.ftcsr_read_callback = f;
+ sh2.irq_callback = save_irqcallback;
+
+ sh2.timer = tsave;
+ sh2.dma_timer[0] = tsaved0;
+ sh2.dma_timer[1] = tsaved1;
+ sh2.cpu_number = cpunum;
+ sh2.m = m;
+ memset(sh2.m, 0, 0x200);
+
+ sh2.pc = RL(0);
+ sh2.r[15] = RL(4);
+ sh2.sr = I;
+ change_pc(sh2.pc & AM);
+
+ sh2.internal_irq_level = -1;
+}
+
+/* Execute cycles - returns number of cycles actually run */
+static int sh2_execute(int cycles)
+{
+ sh2_icount = cycles;
+
+ if (sh2.cpu_off)
+ return 0;
+
+ do
+ {
+ UINT32 opcode;
+
+ if (sh2.delay)
+ {
+ opcode = cpu_readop16(WORD_XOR_BE((UINT32)(sh2.delay & AM)));
+ change_pc(sh2.pc & AM);
+ sh2.pc -= 2;
+ }
+ else
+ opcode = cpu_readop16(WORD_XOR_BE((UINT32)(sh2.pc & AM)));
+
+ CALL_MAME_DEBUG;
+
+ sh2.delay = 0;
+ sh2.pc += 2;
+ sh2.ppc = sh2.pc;
+
+ switch (opcode & ( 15 << 12))
+ {
+ case 0<<12: op0000(opcode); break;
+ case 1<<12: op0001(opcode); break;
+ case 2<<12: op0010(opcode); break;
+ case 3<<12: op0011(opcode); break;
+ case 4<<12: op0100(opcode); break;
+ case 5<<12: op0101(opcode); break;
+ case 6<<12: op0110(opcode); break;
+ case 7<<12: op0111(opcode); break;
+ case 8<<12: op1000(opcode); break;
+ case 9<<12: op1001(opcode); break;
+ case 10<<12: op1010(opcode); break;
+ case 11<<12: op1011(opcode); break;
+ case 12<<12: op1100(opcode); break;
+ case 13<<12: op1101(opcode); break;
+ case 14<<12: op1110(opcode); break;
+ default: op1111(opcode); break;
+ }
+
+ if(sh2.test_irq && !sh2.delay)
+ {
+ CHECK_PENDING_IRQ("mame_sh2_execute");
+ sh2.test_irq = 0;
+ }
+ sh2_icount--;
+ } while( sh2_icount > 0 );
+
+ return cycles - sh2_icount;
+}
+
+/* Get registers, return context size */
+static void sh2_get_context(void *dst)
+{
+ if( dst )
+ memcpy(dst, &sh2, sizeof(SH2));
+}
+
+/* Set registers */
+static void sh2_set_context(void *src)
+{
+ if( src )
+ memcpy(&sh2, src, sizeof(SH2));
+}
+
+static void sh2_timer_resync(void)
+{
+ int divider = div_tab[(sh2.m[5] >> 8) & 3];
+ UINT32 cur_time = cpunum_gettotalcycles(sh2.cpu_number);
+
+ if(divider)
+ sh2.frc += (cur_time - sh2.frc_base) >> divider;
+ sh2.frc_base = cur_time;
+}
+
+static void sh2_timer_activate(void)
+{
+ int max_delta = 0xfffff;
+ UINT16 frc;
+
+ timer_adjust(sh2.timer, attotime_never, 0, attotime_zero);
+
+ frc = sh2.frc;
+ if(!(sh2.m[4] & OCFA)) {
+ UINT16 delta = sh2.ocra - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(!(sh2.m[4] & OCFB) && (sh2.ocra <= sh2.ocrb || !(sh2.m[4] & 0x010000))) {
+ UINT16 delta = sh2.ocrb - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(!(sh2.m[4] & OVF) && !(sh2.m[4] & 0x010000)) {
+ int delta = 0x10000 - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(max_delta != 0xfffff) {
+ int divider = div_tab[(sh2.m[5] >> 8) & 3];
+ if(divider) {
+ max_delta <<= divider;
+ sh2.frc_base = cpunum_gettotalcycles(sh2.cpu_number);
+ timer_adjust(sh2.timer, ATTOTIME_IN_CYCLES(max_delta, sh2.cpu_number), sh2.cpu_number, attotime_zero);
+ } else {
+ logerror("SH2.%d: Timer event in %d cycles of external clock", sh2.cpu_number, max_delta);
+ }
+ }
+}
+
+static void sh2_recalc_irq(void)
+{
+ int irq = 0, vector = -1;
+ int level;
+
+ // Timer irqs
+ if((sh2.m[4]>>8) & sh2.m[4] & (ICF|OCFA|OCFB|OVF))
+ {
+ level = (sh2.m[0x18] >> 24) & 15;
+ if(level > irq)
+ {
+ int mask = (sh2.m[4]>>8) & sh2.m[4];
+ irq = level;
+ if(mask & ICF)
+ vector = (sh2.m[0x19] >> 8) & 0x7f;
+ else if(mask & (OCFA|OCFB))
+ vector = sh2.m[0x19] & 0x7f;
+ else
+ vector = (sh2.m[0x1a] >> 24) & 0x7f;
+ }
+ }
+
+ // DMA irqs
+ if((sh2.m[0x63] & 6) == 6) {
+ level = (sh2.m[0x38] >> 8) & 15;
+ if(level > irq) {
+ irq = level;
+ vector = (sh2.m[0x68] >> 24) & 0x7f;
+ }
+ }
+
+ if((sh2.m[0x67] & 6) == 6) {
+ level = (sh2.m[0x38] >> 8) & 15;
+ if(level > irq) {
+ irq = level;
+ vector = (sh2.m[0x6a] >> 24) & 0x7f;
+ }
+ }
+
+
+ sh2.internal_irq_level = irq;
+ sh2.internal_irq_vector = vector;
+ sh2.test_irq = 1;
+}
+
+static TIMER_CALLBACK( sh2_timer_callback )
+{
+ UINT16 frc;
+ int cpunum = param;
+
+ cpuintrf_push_context(cpunum);
+ sh2_timer_resync();
+
+ frc = sh2.frc;
+
+ if(frc == sh2.ocrb)
+ sh2.m[4] |= OCFB;
+
+ if(frc == 0x0000)
+ sh2.m[4] |= OVF;
+
+ if(frc == sh2.ocra)
+ {
+ sh2.m[4] |= OCFA;
+
+ if(sh2.m[4] & 0x010000)
+ sh2.frc = 0;
+ }
+
+ sh2_recalc_irq();
+ sh2_timer_activate();
+
+ cpuintrf_pop_context();
+}
+
+static TIMER_CALLBACK( sh2_dmac_callback )
+{
+ int cpunum = param >> 1;
+ int dma = param & 1;
+
+ cpuintrf_push_context(cpunum);
+ LOG(("SH2.%d: DMA %d complete\n", cpunum, dma));
+ sh2.m[0x63+4*dma] |= 2;
+ sh2.dma_timer_active[dma] = 0;
+ sh2_recalc_irq();
+ cpuintrf_pop_context();
+}
+
+static void sh2_dmac_check(int dma)
+{
+ if(sh2.m[0x63+4*dma] & sh2.m[0x6c] & 1)
+ {
+ if(!sh2.dma_timer_active[dma] && !(sh2.m[0x63+4*dma] & 2))
+ {
+ int incs, incd, size;
+ UINT32 src, dst, count;
+ incd = (sh2.m[0x63+4*dma] >> 14) & 3;
+ incs = (sh2.m[0x63+4*dma] >> 12) & 3;
+ size = (sh2.m[0x63+4*dma] >> 10) & 3;
+ if(incd == 3 || incs == 3)
+ {
+ logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, sh2.m[0x63+4*dma]);
+ return;
+ }
+ src = sh2.m[0x60+4*dma];
+ dst = sh2.m[0x61+4*dma];
+ count = sh2.m[0x62+4*dma];
+ if(!count)
+ count = 0x1000000;
+
+ LOG(("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, src, dst, count, sh2.m[0x63+4*dma], incs, incd, size));
+
+ sh2.dma_timer_active[dma] = 1;
+ timer_adjust(sh2.dma_timer[dma], ATTOTIME_IN_CYCLES(2*count+1, sh2.cpu_number), (sh2.cpu_number<<1)|dma, attotime_zero);
+
+ src &= AM;
+ dst &= AM;
+
+ switch(size)
+ {
+ case 0:
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src --;
+ if(incd == 2)
+ dst --;
+ program_write_byte_32be(dst, program_read_byte_32be(src));
+ if(incs == 1)
+ src ++;
+ if(incd == 1)
+ dst ++;
+ }
+ break;
+ case 1:
+ src &= ~1;
+ dst &= ~1;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 2;
+ if(incd == 2)
+ dst -= 2;
+ program_write_word_32be(dst, program_read_word_32be(src));
+ if(incs == 1)
+ src += 2;
+ if(incd == 1)
+ dst += 2;
+ }
+ break;
+ case 2:
+ src &= ~3;
+ dst &= ~3;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 4;
+ if(incd == 2)
+ dst -= 4;
+ program_write_dword_32be(dst, program_read_dword_32be(src));
+ if(incs == 1)
+ src += 4;
+ if(incd == 1)
+ dst += 4;
+
+ }
+ break;
+ case 3:
+ src &= ~3;
+ dst &= ~3;
+ count &= ~3;
+ for(;count > 0; count -= 4)
+ {
+ if(incd == 2)
+ dst -= 16;
+ program_write_dword_32be(dst, program_read_dword_32be(src));
+ program_write_dword_32be(dst+4, program_read_dword_32be(src+4));
+ program_write_dword_32be(dst+8, program_read_dword_32be(src+8));
+ program_write_dword_32be(dst+12, program_read_dword_32be(src+12));
+ src += 16;
+ if(incd == 1)
+ dst += 16;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ if(sh2.dma_timer_active[dma])
+ {
+ logerror("SH2: DMA %d cancelled in-flight", dma);
+ timer_adjust(sh2.dma_timer[dma], attotime_never, 0, attotime_zero);
+ sh2.dma_timer_active[dma] = 0;
+ }
+ }
+}
+
+WRITE32_HANDLER( sh2_internal_w )
+{
+ UINT32 old = sh2.m[offset];
+ COMBINE_DATA(sh2.m+offset);
+
+ // if(offset != 0x20)
+ // logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask);
+
+ switch( offset )
+ {
+ // Timers
+ case 0x04: // TIER, FTCSR, FRC
+ if((mem_mask & 0x00ffffff) != 0xffffff)
+ sh2_timer_resync();
+ logerror("SH2.%d: TIER write %04x @ %04x\n", sh2.cpu_number, data >> 16, mem_mask>>16);
+ sh2.m[4] = (sh2.m[4] & ~(ICF|OCFA|OCFB|OVF)) | (old & sh2.m[4] & (ICF|OCFA|OCFB|OVF));
+ COMBINE_DATA(&sh2.frc);
+ if((mem_mask & 0x00ffffff) != 0xffffff)
+ sh2_timer_activate();
+ sh2_recalc_irq();
+ break;
+ case 0x05: // OCRx, TCR, TOCR
+ logerror("SH2.%d: TCR write %08x @ %08x\n", sh2.cpu_number, data, mem_mask);
+ sh2_timer_resync();
+ if(sh2.m[5] & 0x10)
+ sh2.ocrb = (sh2.ocrb & (mem_mask >> 16)) | ((data & ~mem_mask) >> 16);
+ else
+ sh2.ocra = (sh2.ocra & (mem_mask >> 16)) | ((data & ~mem_mask) >> 16);
+ sh2_timer_activate();
+ break;
+
+ case 0x06: // ICR
+ break;
+
+ // Interrupt vectors
+ case 0x18: // IPRB, VCRA
+ case 0x19: // VCRB, VCRC
+ case 0x1a: // VCRD
+ sh2_recalc_irq();
+ break;
+
+ // DMA
+ case 0x1c: // DRCR0, DRCR1
+ break;
+
+ // Watchdog
+ case 0x20: // WTCNT, RSTCSR
+ break;
+
+ // Standby and cache
+ case 0x24: // SBYCR, CCR
+ break;
+
+ // Interrupt vectors cont.
+ case 0x38: // ICR, IRPA
+ break;
+ case 0x39: // VCRWDT
+ break;
+
+ // Division box
+ case 0x40: // DVSR
+ break;
+ case 0x41: // DVDNT
+ {
+ INT32 a = sh2.m[0x41];
+ INT32 b = sh2.m[0x40];
+ LOG(("SH2 #%d div+mod %d/%d\n", cpu_getactivecpu(), a, b));
+ if (b)
+ {
+ sh2.m[0x45] = a / b;
+ sh2.m[0x44] = a % b;
+ }
+ else
+ {
+ sh2.m[0x42] |= 0x00010000;
+ sh2.m[0x45] = 0x7fffffff;
+ sh2.m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ break;
+ }
+ case 0x42: // DVCR
+ sh2.m[0x42] = (sh2.m[0x42] & ~0x00001000) | (old & sh2.m[0x42] & 0x00010000);
+ sh2_recalc_irq();
+ break;
+ case 0x43: // VCRDIV
+ sh2_recalc_irq();
+ break;
+ case 0x44: // DVDNTH
+ break;
+ case 0x45: // DVDNTL
+ {
+ INT64 a = sh2.m[0x45] | ((UINT64)(sh2.m[0x44]) << 32);
+ INT64 b = (INT32)sh2.m[0x40];
+ LOG(("SH2 #%d div+mod %lld/%lld\n", cpu_getactivecpu(), a, b));
+ if (b)
+ {
+ INT64 q = a / b;
+ if (q != (INT32)q)
+ {
+ sh2.m[0x42] |= 0x00010000;
+ sh2.m[0x45] = 0x7fffffff;
+ sh2.m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ else
+ {
+ sh2.m[0x45] = q;
+ sh2.m[0x44] = a % b;
+ }
+ }
+ else
+ {
+ sh2.m[0x42] |= 0x00010000;
+ sh2.m[0x45] = 0x7fffffff;
+ sh2.m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ break;
+ }
+
+ // DMA controller
+ case 0x60: // SAR0
+ case 0x61: // DAR0
+ break;
+ case 0x62: // DTCR0
+ sh2.m[0x62] &= 0xffffff;
+ break;
+ case 0x63: // CHCR0
+ sh2.m[0x63] = (sh2.m[0x63] & ~2) | (old & sh2.m[0x63] & 2);
+ sh2_dmac_check(0);
+ break;
+ case 0x64: // SAR1
+ case 0x65: // DAR1
+ break;
+ case 0x66: // DTCR1
+ sh2.m[0x66] &= 0xffffff;
+ break;
+ case 0x67: // CHCR1
+ sh2.m[0x67] = (sh2.m[0x67] & ~2) | (old & sh2.m[0x67] & 2);
+ sh2_dmac_check(1);
+ break;
+ case 0x68: // VCRDMA0
+ case 0x6a: // VCRDMA1
+ sh2_recalc_irq();
+ break;
+ case 0x6c: // DMAOR
+ sh2.m[0x6c] = (sh2.m[0x6c] & ~6) | (old & sh2.m[0x6c] & 6);
+ sh2_dmac_check(0);
+ sh2_dmac_check(1);
+ break;
+
+ // Bus controller
+ case 0x78: // BCR1
+ case 0x79: // BCR2
+ case 0x7a: // WCR
+ case 0x7b: // MCR
+ case 0x7c: // RTCSR
+ case 0x7d: // RTCNT
+ case 0x7e: // RTCOR
+ break;
+
+ default:
+ logerror("sh2_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfffffe00+offset*4, data, mem_mask);
+ break;
+ }
+}
+
+READ32_HANDLER( sh2_internal_r )
+{
+ // logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask);
+ switch( offset )
+ {
+ case 0x04: // TIER, FTCSR, FRC
+ if ( mem_mask == 0xff00ffff )
+ if ( sh2.ftcsr_read_callback != NULL )
+ sh2.ftcsr_read_callback( (sh2.m[4] & 0xffff0000) | sh2.frc );
+ sh2_timer_resync();
+ return (sh2.m[4] & 0xffff0000) | sh2.frc;
+ case 0x05: // OCRx, TCR, TOCR
+ if(sh2.m[5] & 0x10)
+ return (sh2.ocrb << 16) | (sh2.m[5] & 0xffff);
+ else
+ return (sh2.ocra << 16) | (sh2.m[5] & 0xffff);
+ case 0x06: // ICR
+ return sh2.icr << 16;
+
+ case 0x38: // ICR, IPRA
+ return (sh2.m[0x38] & 0x7fffffff) | (sh2.nmi_line_state == ASSERT_LINE ? 0 : 0x80000000);
+
+ case 0x78: // BCR1
+ return sh2.is_slave ? 0x00008000 : 0;
+
+ case 0x41: // dvdntl mirrors
+ case 0x47:
+ return sh2.m[0x45];
+
+ case 0x46: // dvdnth mirror
+ return sh2.m[0x44];
+ }
+ return sh2.m[offset];
+}
+
+void sh2_set_frt_input(int cpunum, int state)
+{
+ if(state == PULSE_LINE)
+ {
+ sh2_set_frt_input(cpunum, ASSERT_LINE);
+ sh2_set_frt_input(cpunum, CLEAR_LINE);
+ return;
+ }
+
+ cpuintrf_push_context(cpunum);
+
+ if(sh2.frt_input == state) {
+ cpuintrf_pop_context();
+ return;
+ }
+
+ sh2.frt_input = state;
+
+ if(sh2.m[5] & 0x8000) {
+ if(state == CLEAR_LINE) {
+ cpuintrf_pop_context();
+ return;
+ }
+ } else {
+ if(state == ASSERT_LINE) {
+ cpuintrf_pop_context();
+ return;
+ }
+ }
+
+ sh2_timer_resync();
+ sh2.icr = sh2.frc;
+ sh2.m[4] |= ICF;
+ logerror("SH2.%d: ICF activated (%x)\n", sh2.cpu_number, sh2.pc & AM);
+ sh2_recalc_irq();
+ cpuintrf_pop_context();
+}
+
+static void set_irq_line(int irqline, int state)
+{
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (sh2.nmi_line_state == state)
+ return;
+ sh2.nmi_line_state = state;
+
+ if( state == CLEAR_LINE )
+ LOG(("SH-2 #%d cleared nmi\n", cpu_getactivecpu()));
+ else
+ {
+ LOG(("SH-2 #%d assert nmi\n", cpu_getactivecpu()));
+ sh2_exception("sh2_set_irq_line/nmi", 16);
+ }
+ }
+ else
+ {
+ if (sh2.irq_line_state[irqline] == state)
+ return;
+ sh2.irq_line_state[irqline] = state;
+
+ if( state == CLEAR_LINE )
+ {
+ LOG(("SH-2 #%d cleared irq #%d\n", cpu_getactivecpu(), irqline));
+ sh2.pending_irq &= ~(1 << irqline);
+ }
+ else
+ {
+ LOG(("SH-2 #%d assert irq #%d\n", cpu_getactivecpu(), irqline));
+ sh2.pending_irq |= 1 << irqline;
+ if(sh2.delay)
+ sh2.test_irq = 1;
+ else
+ CHECK_PENDING_IRQ("sh2_set_irq_line");
+ }
+ }
+}
+
+#ifdef MAME_DEBUG
+static offs_t sh2_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram)
+{
+ return DasmSH2( buffer, pc, (oprom[0] << 8) | oprom[1] );
+}
+#endif /* MAME_DEBUG */
+
+static void sh2_init(int index, int clock, const void *config, int (*irqcallback)(int))
+{
+ const struct sh2_config *conf = config;
+
+ sh2.timer = timer_alloc(sh2_timer_callback);
+ timer_adjust(sh2.timer, attotime_never, 0, attotime_zero);
+
+ sh2.dma_timer[0] = timer_alloc(sh2_dmac_callback);
+ timer_adjust(sh2.dma_timer[0], attotime_never, 0, attotime_zero);
+
+ sh2.dma_timer[1] = timer_alloc(sh2_dmac_callback);
+ timer_adjust(sh2.dma_timer[1], attotime_never, 0, attotime_zero);
+
+ sh2.m = auto_malloc(0x200);
+
+ if(conf)
+ sh2.is_slave = conf->is_slave;
+ else
+ sh2.is_slave = 0;
+
+ sh2.cpu_number = index;
+ sh2.irq_callback = irqcallback;
+
+ state_save_register_item("sh2", index, sh2.pc);
+ state_save_register_item("sh2", index, sh2.r[15]);
+ state_save_register_item("sh2", index, sh2.sr);
+ state_save_register_item("sh2", index, sh2.pr);
+ state_save_register_item("sh2", index, sh2.gbr);
+ state_save_register_item("sh2", index, sh2.vbr);
+ state_save_register_item("sh2", index, sh2.mach);
+ state_save_register_item("sh2", index, sh2.macl);
+ state_save_register_item("sh2", index, sh2.r[ 0]);
+ state_save_register_item("sh2", index, sh2.r[ 1]);
+ state_save_register_item("sh2", index, sh2.r[ 2]);
+ state_save_register_item("sh2", index, sh2.r[ 3]);
+ state_save_register_item("sh2", index, sh2.r[ 4]);
+ state_save_register_item("sh2", index, sh2.r[ 5]);
+ state_save_register_item("sh2", index, sh2.r[ 6]);
+ state_save_register_item("sh2", index, sh2.r[ 7]);
+ state_save_register_item("sh2", index, sh2.r[ 8]);
+ state_save_register_item("sh2", index, sh2.r[ 9]);
+ state_save_register_item("sh2", index, sh2.r[10]);
+ state_save_register_item("sh2", index, sh2.r[11]);
+ state_save_register_item("sh2", index, sh2.r[12]);
+ state_save_register_item("sh2", index, sh2.r[13]);
+ state_save_register_item("sh2", index, sh2.r[14]);
+ state_save_register_item("sh2", index, sh2.ea);
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static void sh2_set_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLIN: set_irq_line(SH2_INT_VBLIN, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLOUT: set_irq_line(SH2_INT_VBLOUT, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_HBLIN: set_irq_line(SH2_INT_HBLIN, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER0: set_irq_line(SH2_INT_TIMER0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER1: set_irq_line(SH2_INT_TIMER1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DSP: set_irq_line(SH2_INT_DSP, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SOUND: set_irq_line(SH2_INT_SOUND, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SMPC: set_irq_line(SH2_INT_SMPC, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_PAD: set_irq_line(SH2_INT_PAD, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA2: set_irq_line(SH2_INT_DMA2, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA1: set_irq_line(SH2_INT_DMA1, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA0: set_irq_line(SH2_INT_DMA0, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMAILL: set_irq_line(SH2_INT_DMAILL, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SPRITE: set_irq_line(SH2_INT_SPRITE, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_14: set_irq_line(SH2_INT_14, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_15: set_irq_line(SH2_INT_15, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_ABUS: set_irq_line(SH2_INT_ABUS, info->i); break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: set_irq_line(INPUT_LINE_NMI, info->i); break;
+
+ case CPUINFO_INT_REGISTER + SH2_PC:
+ case CPUINFO_INT_PC: sh2.pc = info->i; sh2.delay = 0; break;
+ case CPUINFO_INT_SP: sh2.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_PR: sh2.pr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_SR: sh2.sr = info->i; CHECK_PENDING_IRQ("sh2_set_reg"); break;
+ case CPUINFO_INT_REGISTER + SH2_GBR: sh2.gbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_VBR: sh2.vbr = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_MACH: sh2.mach = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_MACL: sh2.macl = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R0: sh2.r[ 0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R1: sh2.r[ 1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R2: sh2.r[ 2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R3: sh2.r[ 3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R4: sh2.r[ 4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R5: sh2.r[ 5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R6: sh2.r[ 6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R7: sh2.r[ 7] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R8: sh2.r[ 8] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R9: sh2.r[ 9] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R10: sh2.r[10] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R11: sh2.r[11] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R12: sh2.r[12] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R13: sh2.r[13] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R14: sh2.r[14] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_R15: sh2.r[15] = info->i; break;
+ case CPUINFO_INT_REGISTER + SH2_EA: sh2.ea = info->i; break;
+
+ case CPUINFO_INT_SH2_FRT_INPUT: sh2_set_frt_input(cpu_getactivecpu(), info->i); break;
+
+ /* --- the following bits of info are set as pointers to data or functions --- */
+ case CPUINFO_PTR_SH2_FTCSR_READ_CALLBACK: sh2.ftcsr_read_callback = (void (*) (UINT32 ))info->f; break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+void sh2_get_info(UINT32 state, cpuinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(sh2); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 16; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; 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 CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLIN: info->i = sh2.irq_line_state[SH2_INT_VBLIN]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_VBLOUT: info->i = sh2.irq_line_state[SH2_INT_VBLOUT]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_HBLIN: info->i = sh2.irq_line_state[SH2_INT_HBLIN]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER0: info->i = sh2.irq_line_state[SH2_INT_TIMER0]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_TIMER1: info->i = sh2.irq_line_state[SH2_INT_TIMER1]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DSP: info->i = sh2.irq_line_state[SH2_INT_DSP]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SOUND: info->i = sh2.irq_line_state[SH2_INT_SOUND]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SMPC: info->i = sh2.irq_line_state[SH2_INT_SMPC]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_PAD: info->i = sh2.irq_line_state[SH2_INT_PAD]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA2: info->i = sh2.irq_line_state[SH2_INT_DMA2]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA1: info->i = sh2.irq_line_state[SH2_INT_DMA1]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMA0: info->i = sh2.irq_line_state[SH2_INT_DMA0]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_DMAILL: info->i = sh2.irq_line_state[SH2_INT_DMAILL]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_SPRITE: info->i = sh2.irq_line_state[SH2_INT_SPRITE]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_14: info->i = sh2.irq_line_state[SH2_INT_14]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_15: info->i = sh2.irq_line_state[SH2_INT_15]; break;
+ case CPUINFO_INT_INPUT_STATE + SH2_INT_ABUS: info->i = sh2.irq_line_state[SH2_INT_ABUS]; break;
+ case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = sh2.nmi_line_state; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = sh2.ppc; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SH2_PC: info->i = (sh2.delay) ? (sh2.delay & AM) : (sh2.pc & AM); break;
+ case CPUINFO_INT_SP: info->i = sh2.r[15]; break;
+ case CPUINFO_INT_REGISTER + SH2_PR: info->i = sh2.pr; break;
+ case CPUINFO_INT_REGISTER + SH2_SR: info->i = sh2.sr; break;
+ case CPUINFO_INT_REGISTER + SH2_GBR: info->i = sh2.gbr; break;
+ case CPUINFO_INT_REGISTER + SH2_VBR: info->i = sh2.vbr; break;
+ case CPUINFO_INT_REGISTER + SH2_MACH: info->i = sh2.mach; break;
+ case CPUINFO_INT_REGISTER + SH2_MACL: info->i = sh2.macl; break;
+ case CPUINFO_INT_REGISTER + SH2_R0: info->i = sh2.r[ 0]; break;
+ case CPUINFO_INT_REGISTER + SH2_R1: info->i = sh2.r[ 1]; break;
+ case CPUINFO_INT_REGISTER + SH2_R2: info->i = sh2.r[ 2]; break;
+ case CPUINFO_INT_REGISTER + SH2_R3: info->i = sh2.r[ 3]; break;
+ case CPUINFO_INT_REGISTER + SH2_R4: info->i = sh2.r[ 4]; break;
+ case CPUINFO_INT_REGISTER + SH2_R5: info->i = sh2.r[ 5]; break;
+ case CPUINFO_INT_REGISTER + SH2_R6: info->i = sh2.r[ 6]; break;
+ case CPUINFO_INT_REGISTER + SH2_R7: info->i = sh2.r[ 7]; break;
+ case CPUINFO_INT_REGISTER + SH2_R8: info->i = sh2.r[ 8]; break;
+ case CPUINFO_INT_REGISTER + SH2_R9: info->i = sh2.r[ 9]; break;
+ case CPUINFO_INT_REGISTER + SH2_R10: info->i = sh2.r[10]; break;
+ case CPUINFO_INT_REGISTER + SH2_R11: info->i = sh2.r[11]; break;
+ case CPUINFO_INT_REGISTER + SH2_R12: info->i = sh2.r[12]; break;
+ case CPUINFO_INT_REGISTER + SH2_R13: info->i = sh2.r[13]; break;
+ case CPUINFO_INT_REGISTER + SH2_R14: info->i = sh2.r[14]; break;
+ case CPUINFO_INT_REGISTER + SH2_R15: info->i = sh2.r[15]; break;
+ case CPUINFO_INT_REGISTER + SH2_EA: info->i = sh2.ea; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_PTR_SET_INFO: info->setinfo = sh2_set_info; break;
+ case CPUINFO_PTR_GET_CONTEXT: info->getcontext = sh2_get_context; break;
+ case CPUINFO_PTR_SET_CONTEXT: info->setcontext = sh2_set_context; break;
+ case CPUINFO_PTR_INIT: info->init = sh2_init; break;
+ case CPUINFO_PTR_RESET: info->reset = sh2_reset; break;
+ case CPUINFO_PTR_EXECUTE: info->execute = sh2_execute; break;
+ case CPUINFO_PTR_BURN: info->burn = NULL; break;
+#ifdef MAME_DEBUG
+ case CPUINFO_PTR_DISASSEMBLE: info->disassemble = sh2_dasm; break;
+#endif /* MAME_DEBUG */
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &sh2_icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "SH-2"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Hitachi SH7600"); break;
+ case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.01"); break;
+ case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright (c) 2000 Juergen Buchmueller, all rights reserved."); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%d%c%c",
+ sh2.sr & M ? 'M':'.',
+ sh2.sr & Q ? 'Q':'.',
+ (sh2.sr & I) >> 4,
+ sh2.sr & S ? 'S':'.',
+ sh2.sr & T ? 'T':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + SH2_PC: sprintf(info->s, "PC :%08X", sh2.pc); break;
+ case CPUINFO_STR_REGISTER + SH2_SR: sprintf(info->s, "SR :%08X", sh2.sr); break;
+ case CPUINFO_STR_REGISTER + SH2_PR: sprintf(info->s, "PR :%08X", sh2.pr); break;
+ case CPUINFO_STR_REGISTER + SH2_GBR: sprintf(info->s, "GBR :%08X", sh2.gbr); break;
+ case CPUINFO_STR_REGISTER + SH2_VBR: sprintf(info->s, "VBR :%08X", sh2.vbr); break;
+ case CPUINFO_STR_REGISTER + SH2_MACH: sprintf(info->s, "MACH:%08X", sh2.mach); break;
+ case CPUINFO_STR_REGISTER + SH2_MACL: sprintf(info->s, "MACL:%08X", sh2.macl); break;
+ case CPUINFO_STR_REGISTER + SH2_R0: sprintf(info->s, "R0 :%08X", sh2.r[ 0]); break;
+ case CPUINFO_STR_REGISTER + SH2_R1: sprintf(info->s, "R1 :%08X", sh2.r[ 1]); break;
+ case CPUINFO_STR_REGISTER + SH2_R2: sprintf(info->s, "R2 :%08X", sh2.r[ 2]); break;
+ case CPUINFO_STR_REGISTER + SH2_R3: sprintf(info->s, "R3 :%08X", sh2.r[ 3]); break;
+ case CPUINFO_STR_REGISTER + SH2_R4: sprintf(info->s, "R4 :%08X", sh2.r[ 4]); break;
+ case CPUINFO_STR_REGISTER + SH2_R5: sprintf(info->s, "R5 :%08X", sh2.r[ 5]); break;
+ case CPUINFO_STR_REGISTER + SH2_R6: sprintf(info->s, "R6 :%08X", sh2.r[ 6]); break;
+ case CPUINFO_STR_REGISTER + SH2_R7: sprintf(info->s, "R7 :%08X", sh2.r[ 7]); break;
+ case CPUINFO_STR_REGISTER + SH2_R8: sprintf(info->s, "R8 :%08X", sh2.r[ 8]); break;
+ case CPUINFO_STR_REGISTER + SH2_R9: sprintf(info->s, "R9 :%08X", sh2.r[ 9]); break;
+ case CPUINFO_STR_REGISTER + SH2_R10: sprintf(info->s, "R10 :%08X", sh2.r[10]); break;
+ case CPUINFO_STR_REGISTER + SH2_R11: sprintf(info->s, "R11 :%08X", sh2.r[11]); break;
+ case CPUINFO_STR_REGISTER + SH2_R12: sprintf(info->s, "R12 :%08X", sh2.r[12]); break;
+ case CPUINFO_STR_REGISTER + SH2_R13: sprintf(info->s, "R13 :%08X", sh2.r[13]); break;
+ case CPUINFO_STR_REGISTER + SH2_R14: sprintf(info->s, "R14 :%08X", sh2.r[14]); break;
+ case CPUINFO_STR_REGISTER + SH2_R15: sprintf(info->s, "R15 :%08X", sh2.r[15]); break;
+ case CPUINFO_STR_REGISTER + SH2_EA: sprintf(info->s, "EA :%08X", sh2.ea); break;
+
+ case CPUINFO_PTR_SH2_FTCSR_READ_CALLBACK: info->f = (genf*)sh2.ftcsr_read_callback; break;
+
+ }
+}