diff options
Diffstat (limited to 'src/emu/cpu/sh2/sh2.c')
-rw-r--r-- | src/emu/cpu/sh2/sh2.c | 3181 |
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; + + } +} |