diff options
Diffstat (limited to 'src/devices/cpu/sh2/sh2.c')
-rw-r--r-- | src/devices/cpu/sh2/sh2.c | 2685 |
1 files changed, 2685 insertions, 0 deletions
diff --git a/src/devices/cpu/sh2/sh2.c b/src/devices/cpu/sh2/sh2.c new file mode 100644 index 00000000000..629d447323e --- /dev/null +++ b/src/devices/cpu/sh2/sh2.c @@ -0,0 +1,2685 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * sh2.c + * Portable Hitachi SH-2 (SH7600 family) emulator + * + * 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 + 20130129 Angelo Salese + - added illegal opcode exception handling, side effect of some Saturn games + on loading like Feda or Falcom Classics Vol. 1 + (i.e. Master CPU Incautiously transfers memory from CD to work RAM H, and + wipes out Slave CPU program code too while at it). + + 20051129 Mariusz Wojcieszek + - introduced memory_decrypted_read_word() 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 + - 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 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 "emu.h" +#include "debugger.h" +#include "sh2.h" +#include "sh2comn.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define DISABLE_FAST_REGISTERS (0) // set to 1 to turn off usage of register caching +#define SINGLE_INSTRUCTION_MODE (0) + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 64 +#define COMPILE_FORWARDS_BYTES 256 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/2) + (COMPILE_FORWARDS_BYTES/2)) +#define COMPILE_MAX_SEQUENCE 64 + + +const device_type SH1 = &device_creator<sh1_device>; +const device_type SH2 = &device_creator<sh2_device>; +const device_type SH2A = &device_creator<sh2a_device>; + +/*------------------------------------------------- + sh2_internal_a5 - read handler for + SH2 internal map +-------------------------------------------------*/ + +READ32_MEMBER(sh2_device::sh2_internal_a5) +{ + return 0xa5a5a5a5; +} + + +/*------------------------------------------------- + sh2_internal_map - maps SH2 built-ins +-------------------------------------------------*/ + +static ADDRESS_MAP_START( sh7604_map, AS_PROGRAM, 32, sh2_device ) + AM_RANGE(0x40000000, 0xbfffffff) AM_READ(sh2_internal_a5) +/*! + @todo: cps3boot breaks with this enabled. Needs customization ... + */ +// AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM // cache data array +// AM_RANGE(0xffffff88, 0xffffff8b) AM_READWRITE(dma_dtcr0_r,dma_dtcr0_w) + AM_RANGE(0xe0000000, 0xe00001ff) AM_MIRROR(0x1ffffe00) AM_READWRITE(sh7604_r, sh7604_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sh7021_map, AS_PROGRAM, 32, sh2a_device ) +// overrides + AM_RANGE(0x05ffff40, 0x05ffff43) AM_READWRITE(dma_sar0_r, dma_sar0_w) + AM_RANGE(0x05ffff44, 0x05ffff47) AM_READWRITE(dma_dar0_r, dma_dar0_w) + AM_RANGE(0x05ffff48, 0x05ffff4b) AM_READWRITE16(dmaor_r, dmaor_w,0xffff0000) + AM_RANGE(0x05ffff48, 0x05ffff4b) AM_READWRITE16(dma_tcr0_r, dma_tcr0_w,0x0000ffff) + AM_RANGE(0x05ffff4c, 0x05ffff4f) AM_READWRITE16(dma_chcr0_r, dma_chcr0_w, 0x0000ffff) +// fall-back + AM_RANGE(0x05fffe00, 0x05ffffff) AM_READWRITE16(sh7021_r,sh7021_w,0xffffffff) // SH-7032H internal i/o +// AM_RANGE(0x07000000, 0x070003ff) AM_RAM AM_SHARE("oram")// on-chip RAM, actually at 0xf000000 (1 kb) +// AM_RANGE(0x0f000000, 0x0f0003ff) AM_RAM AM_SHARE("oram")// on-chip RAM, actually at 0xf000000 (1 kb) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sh7032_map, AS_PROGRAM, 32, sh1_device ) +// fall-back + AM_RANGE(0x05fffe00, 0x05ffffff) AM_READWRITE16(sh7032_r,sh7032_w,0xffffffff) // SH-7032H internal i/o +ADDRESS_MAP_END + +sh2_device::sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SH2, "SH-2", tag, owner, clock, "sh2", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0, ADDRESS_MAP_NAME(sh7604_map)) + , m_decrypted_program_config("decrypted_opcodes", ENDIANNESS_BIG, 32, 32, 0) + , m_is_slave(0) + , m_cpu_type(CPU_TYPE_SH2) + , m_cache(CACHE_SIZE + sizeof(internal_sh2_state)) + , m_drcuml(NULL) +// , m_drcuml(*this, m_cache, 0, 1, 32, 1) + , m_drcfe(NULL) + , m_drcoptions(0) + , m_sh2_state(NULL) + , m_entry(NULL) + , m_read8(NULL) + , m_write8(NULL) + , m_read16(NULL) + , m_write16(NULL) + , m_read32(NULL) + , m_write32(NULL) + , m_interrupt(NULL) + , m_nocode(NULL) + , m_out_of_cycles(NULL) + , m_debugger_temp(0) +{ + m_isdrc = (mconfig.options().drc() && !mconfig.m_force_no_drc) ? true : false; +} + + +void sh2_device::device_stop() +{ + /* clean up the DRC */ + if ( m_drcuml ) + { + auto_free(machine(), m_drcuml); + } +} + + +sh2_device::sh2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cpu_type, address_map_constructor internal_map, int addrlines ) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 32, addrlines, 0, internal_map) + , m_decrypted_program_config("decrypted_opcodes", ENDIANNESS_BIG, 32, addrlines, 0) + , m_is_slave(0) + , m_cpu_type(cpu_type) + , m_cache(CACHE_SIZE + sizeof(internal_sh2_state)) + , m_drcuml(NULL) +// , m_drcuml(*this, m_cache, 0, 1, 32, 1) + , m_drcfe(NULL) + , m_drcoptions(0) + , m_sh2_state(NULL) + , m_entry(NULL) + , m_read8(NULL) + , m_write8(NULL) + , m_read16(NULL) + , m_write16(NULL) + , m_read32(NULL) + , m_write32(NULL) + , m_interrupt(NULL) + , m_nocode(NULL) + , m_out_of_cycles(NULL) +{ + m_isdrc = (mconfig.options().drc() && !mconfig.m_force_no_drc) ? true : false; +} + +sh2a_device::sh2a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh2_device(mconfig, SH1, "SH-2A", tag, owner, clock, "sh2a", __FILE__, CPU_TYPE_SH2, ADDRESS_MAP_NAME(sh7021_map), 28 ) +{ +} + +sh1_device::sh1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh2_device(mconfig, SH1, "SH-1", tag, owner, clock, "sh1", __FILE__, CPU_TYPE_SH1, ADDRESS_MAP_NAME(sh7032_map), 28 ) +{ +} + +const address_space_config *sh2_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &m_decrypted_program_config : NULL; + default: return NULL; + } +} + +offs_t sh2_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sh2 ); + return CPU_DISASSEMBLE_NAME( sh2 )(this, buffer, pc, oprom, opram, options); +} + + +/* speed up delay loops, bail out of tight loops */ +#define BUSY_LOOP_HACKS 1 + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +UINT8 sh2_device::RB(offs_t A) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + return m_program->read_byte(A & AM); + + return m_program->read_byte(A); +} + +UINT16 sh2_device::RW(offs_t A) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + return m_program->read_word(A & AM); + + return m_program->read_word(A); +} + +UINT32 sh2_device::RL(offs_t A) +{ + /* 0x20000000 no Cache */ + /* 0x00000000 read thru Cache if CE bit is 1 */ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + return m_program->read_dword(A & AM); + + return m_program->read_dword(A); +} + +void sh2_device::WB(offs_t A, UINT8 V) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + { + m_program->write_byte(A & AM,V); + return; + } + + m_program->write_byte(A,V); +} + +void sh2_device::WW(offs_t A, UINT16 V) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + { + m_program->write_word(A & AM,V); + return; + } + + m_program->write_word(A,V); +} + +void sh2_device::WL(offs_t A, UINT32 V) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + { + m_program->write_dword(A & AM,V); + return; + } + + /* 0x20000000 no Cache */ + /* 0x00000000 read thru Cache if CE bit is 1 */ + m_program->write_dword(A,V); +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1100 1 - + * ADD Rm,Rn + */ +void sh2_device::ADD(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] += m_sh2_state->r[m]; +} + +/* code cycles t-bit + * 0111 nnnn iiii iiii 1 - + * ADD #imm,Rn + */ +void sh2_device::ADDI(UINT32 i, UINT32 n) +{ + m_sh2_state->r[n] += (INT32)(INT16)(INT8)i; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1110 1 carry + * ADDC Rm,Rn + */ +void sh2_device::ADDC(UINT32 m, UINT32 n) +{ + UINT32 tmp0, tmp1; + + tmp1 = m_sh2_state->r[n] + m_sh2_state->r[m]; + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] = tmp1 + (m_sh2_state->sr & T); + if (tmp0 > tmp1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + if (tmp1 > m_sh2_state->r[n]) + m_sh2_state->sr |= T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1111 1 overflow + * ADDV Rm,Rn + */ +void sh2_device::ADDV(UINT32 m, UINT32 n) +{ + INT32 dest, src, ans; + + if ((INT32) m_sh2_state->r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_sh2_state->r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if ((INT32) m_sh2_state->r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 0 || src == 2) + { + if (ans == 1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + } + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 1001 1 - + * AND Rm,Rn + */ +void sh2_device::AND(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] &= m_sh2_state->r[m]; +} + + +/* code cycles t-bit + * 1100 1001 iiii iiii 1 - + * AND #imm,R0 + */ +void sh2_device::ANDI(UINT32 i) +{ + m_sh2_state->r[0] &= i; +} + +/* code cycles t-bit + * 1100 1101 iiii iiii 1 - + * AND.B #imm,@(R0,GBR) + */ +void sh2_device::ANDM(UINT32 i) +{ + UINT32 temp; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + temp = i & RB( m_sh2_state->ea ); + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 2; +} + +/* code cycles t-bit + * 1000 1011 dddd dddd 3/1 - + * BF disp8 + */ +void sh2_device::BF(UINT32 d) +{ + if ((m_sh2_state->sr & T) == 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount -= 2; + } +} + +/* code cycles t-bit + * 1000 1111 dddd dddd 3/1 - + * BFS disp8 + */ +void sh2_device::BFS(UINT32 d) +{ + if ((m_sh2_state->sr & T) == 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; + } +} + +/* code cycles t-bit + * 1010 dddd dddd dddd 2 - + * BRA disp12 + */ +void sh2_device::BRA(UINT32 d) +{ + INT32 disp = ((INT32)d << 20) >> 20; + +#if BUSY_LOOP_HACKS + if (disp == -2) + { + UINT32 next_opcode = RW( m_sh2_state->ppc & AM ); + /* BRA $ + * NOP + */ + if (next_opcode == 0x0009) + m_sh2_state->icount %= 3; /* cycles for BRA $ and NOP taken (3) */ + } +#endif + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 0000 mmmm 0010 0011 2 - + * BRAF Rm + */ +void sh2_device::BRAF(UINT32 m) +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pc += m_sh2_state->r[m] + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 1011 dddd dddd dddd 2 - + * BSR disp12 + */ +void sh2_device::BSR(UINT32 d) +{ + INT32 disp = ((INT32)d << 20) >> 20; + + m_sh2_state->pr = m_sh2_state->pc + 2; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 0000 mmmm 0000 0011 2 - + * BSRF Rm + */ +void sh2_device::BSRF(UINT32 m) +{ + m_sh2_state->pr = m_sh2_state->pc + 2; + m_delay = m_sh2_state->pc; + m_sh2_state->pc += m_sh2_state->r[m] + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 1000 1001 dddd dddd 3/1 - + * BT disp8 + */ +void sh2_device::BT(UINT32 d) +{ + if ((m_sh2_state->sr & T) != 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount -= 2; + } +} + +/* code cycles t-bit + * 1000 1101 dddd dddd 2/1 - + * BTS disp8 + */ +void sh2_device::BTS(UINT32 d) +{ + if ((m_sh2_state->sr & T) != 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; + } +} + +/* code cycles t-bit + * 0000 0000 0010 1000 1 - + * CLRMAC + */ +void sh2_device::CLRMAC() +{ + m_sh2_state->mach = 0; + m_sh2_state->macl = 0; +} + +/* code cycles t-bit + * 0000 0000 0000 1000 1 - + * CLRT + */ +void sh2_device::CLRT() +{ + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0000 1 comparison result + * CMP_EQ Rm,Rn + */ +void sh2_device::CMPEQ(UINT32 m, UINT32 n) +{ + if (m_sh2_state->r[n] == m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0011 1 comparison result + * CMP_GE Rm,Rn + */ +void sh2_device::CMPGE(UINT32 m, UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] >= (INT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0111 1 comparison result + * CMP_GT Rm,Rn + */ +void sh2_device::CMPGT(UINT32 m, UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] > (INT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0110 1 comparison result + * CMP_HI Rm,Rn + */ +void sh2_device::CMPHI(UINT32 m, UINT32 n) +{ + if ((UINT32) m_sh2_state->r[n] > (UINT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0010 1 comparison result + * CMP_HS Rm,Rn + */ +void sh2_device::CMPHS(UINT32 m, UINT32 n) +{ + if ((UINT32) m_sh2_state->r[n] >= (UINT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + + +/* code cycles t-bit + * 0100 nnnn 0001 0101 1 comparison result + * CMP_PL Rn + */ +void sh2_device::CMPPL(UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] > 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0100 nnnn 0001 0001 1 comparison result + * CMP_PZ Rn + */ +void sh2_device::CMPPZ(UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] >= 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 1100 1 comparison result + * CMP_STR Rm,Rn + */ +void sh2_device::CMPSTR(UINT32 m, UINT32 n) + { + UINT32 temp; + INT32 HH, HL, LH, LL; + temp = m_sh2_state->r[n] ^ m_sh2_state->r[m]; + HH = (temp >> 24) & 0xff; + HL = (temp >> 16) & 0xff; + LH = (temp >> 8) & 0xff; + LL = temp & 0xff; + if (HH && HL && LH && LL) + m_sh2_state->sr &= ~T; + else + m_sh2_state->sr |= T; + } + + +/* code cycles t-bit + * 1000 1000 iiii iiii 1 comparison result + * CMP/EQ #imm,R0 + */ +void sh2_device::CMPIM(UINT32 i) +{ + UINT32 imm = (UINT32)(INT32)(INT16)(INT8)i; + + if (m_sh2_state->r[0] == imm) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 0111 1 calculation result + * DIV0S Rm,Rn + */ +void sh2_device::DIV0S(UINT32 m, UINT32 n) +{ + if ((m_sh2_state->r[n] & 0x80000000) == 0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + if ((m_sh2_state->r[m] & 0x80000000) == 0) + m_sh2_state->sr &= ~M; + else + m_sh2_state->sr |= M; + if ((m_sh2_state->r[m] ^ m_sh2_state->r[n]) & 0x80000000) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0000 0000 0001 1001 1 0 + * DIV0U + */ +void sh2_device::DIV0U() +{ + m_sh2_state->sr &= ~(M | Q | T); +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0100 1 calculation result + * DIV1 Rm,Rn + */ +void sh2_device::DIV1(UINT32 m, UINT32 n) +{ + UINT32 tmp0; + UINT32 old_q; + + old_q = m_sh2_state->sr & Q; + if (0x80000000 & m_sh2_state->r[n]) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->sr & T); + + if (!old_q) + { + if (!(m_sh2_state->sr & M)) + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + else + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + { + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + } + } + } + else + { + if (!(m_sh2_state->sr & M)) + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + else + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + else + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + } + } + + tmp0 = (m_sh2_state->sr & (Q | M)); + if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */ + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* DMULS.L Rm,Rn */ +void sh2_device::DMULS(UINT32 m, UINT32 n) +{ + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + INT32 tempm, tempn, fnLmL; + + tempn = (INT32) m_sh2_state->r[n]; + tempm = (INT32) m_sh2_state->r[m]; + if (tempn < 0) + tempn = 0 - tempn; + if (tempm < 0) + tempm = 0 - tempm; + if ((INT32) (m_sh2_state->r[n] ^ m_sh2_state->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; + } + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + m_sh2_state->icount--; +} + +/* DMULU.L Rm,Rn */ +void sh2_device::DMULU(UINT32 m, UINT32 n) +{ + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + + RnL = m_sh2_state->r[n] & 0x0000ffff; + RnH = (m_sh2_state->r[n] >> 16) & 0x0000ffff; + RmL = m_sh2_state->r[m] & 0x0000ffff; + RmH = (m_sh2_state->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; + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + m_sh2_state->icount--; +} + +/* DT Rn */ +void sh2_device::DT(UINT32 n) +{ + m_sh2_state->r[n]--; + if (m_sh2_state->r[n] == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +#if BUSY_LOOP_HACKS + { + UINT32 next_opcode = RW( m_sh2_state->ppc & AM ); + /* DT Rn + * BF $-2 + */ + if (next_opcode == 0x8bfd) + { + while (m_sh2_state->r[n] > 1 && m_sh2_state->icount > 4) + { + m_sh2_state->r[n]--; + m_sh2_state->icount -= 4; /* cycles for DT (1) and BF taken (3) */ + } + } + } +#endif +} + +/* EXTS.B Rm,Rn */ +void sh2_device::EXTSB(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = ((INT32)m_sh2_state->r[m] << 24) >> 24; +} + +/* EXTS.W Rm,Rn */ +void sh2_device::EXTSW(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = ((INT32)m_sh2_state->r[m] << 16) >> 16; +} + +/* EXTU.B Rm,Rn */ +void sh2_device::EXTUB(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->r[m] & 0x000000ff; +} + +/* EXTU.W Rm,Rn */ +void sh2_device::EXTUW(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->r[m] & 0x0000ffff; +} + +/* ILLEGAL */ +void sh2_device::ILLEGAL() +{ + logerror("SH2.%s: Illegal opcode at %08x\n", tag(), m_sh2_state->pc - 2); + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->sr ); /* push SR onto stack */ + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->pc - 2 ); /* push PC onto stack */ + + /* fetch PC */ + m_sh2_state->pc = RL( m_sh2_state->vbr + 4 * 4 ); + + /* TODO: timing is a guess */ + m_sh2_state->icount -= 5; +} + + +/* JMP @Rm */ +void sh2_device::JMP(UINT32 m) +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->icount--; +} + +/* JSR @Rm */ +void sh2_device::JSR(UINT32 m) +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pr = m_sh2_state->pc + 2; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->icount--; +} + + +/* LDC Rm,SR */ +void sh2_device::LDCSR(UINT32 m) +{ + m_sh2_state->sr = m_sh2_state->r[m] & FLAGS; + m_test_irq = 1; +} + +/* LDC Rm,GBR */ +void sh2_device::LDCGBR(UINT32 m) +{ + m_sh2_state->gbr = m_sh2_state->r[m]; +} + +/* LDC Rm,VBR */ +void sh2_device::LDCVBR(UINT32 m) +{ + m_sh2_state->vbr = m_sh2_state->r[m]; +} + +/* LDC.L @Rm+,SR */ +void sh2_device::LDCMSR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->sr = RL( m_sh2_state->ea ) & FLAGS; + m_sh2_state->r[m] += 4; + m_sh2_state->icount -= 2; + m_test_irq = 1; +} + +/* LDC.L @Rm+,GBR */ +void sh2_device::LDCMGBR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->gbr = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; + m_sh2_state->icount -= 2; +} + +/* LDC.L @Rm+,VBR */ +void sh2_device::LDCMVBR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->vbr = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; + m_sh2_state->icount -= 2; +} + +/* LDS Rm,MACH */ +void sh2_device::LDSMACH(UINT32 m) +{ + m_sh2_state->mach = m_sh2_state->r[m]; +} + +/* LDS Rm,MACL */ +void sh2_device::LDSMACL(UINT32 m) +{ + m_sh2_state->macl = m_sh2_state->r[m]; +} + +/* LDS Rm,PR */ +void sh2_device::LDSPR(UINT32 m) +{ + m_sh2_state->pr = m_sh2_state->r[m]; +} + +/* LDS.L @Rm+,MACH */ +void sh2_device::LDSMMACH(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->mach = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; +} + +/* LDS.L @Rm+,MACL */ +void sh2_device::LDSMMACL(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->macl = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; +} + +/* LDS.L @Rm+,PR */ +void sh2_device::LDSMPR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->pr = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; +} + +/* MAC.L @Rm+,@Rn+ */ +void sh2_device::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( m_sh2_state->r[n] ); + m_sh2_state->r[n] += 4; + tempm = (INT32) RL( m_sh2_state->r[m] ); + m_sh2_state->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 (m_sh2_state->sr & S) + { + Res0 = m_sh2_state->macl + Res0; + if (m_sh2_state->macl > Res0) + Res2++; + Res2 += (m_sh2_state->mach & 0x0000ffff); + if (((INT32) Res2 < 0) && (Res2 < 0xffff8000)) + { + Res2 = 0x00008000; + Res0 = 0x00000000; + } + else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff)) + { + Res2 = 0x00007fff; + Res0 = 0xffffffff; + } + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + } + else + { + Res0 = m_sh2_state->macl + Res0; + if (m_sh2_state->macl > Res0) + Res2++; + Res2 += m_sh2_state->mach; + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + } + m_sh2_state->icount -= 2; +} + +/* MAC.W @Rm+,@Rn+ */ +void sh2_device::MAC_W(UINT32 m, UINT32 n) +{ + INT32 tempm, tempn, dest, src, ans; + UINT32 templ; + + tempn = (INT32) RW( m_sh2_state->r[n] ); + m_sh2_state->r[n] += 2; + tempm = (INT32) RW( m_sh2_state->r[m] ); + m_sh2_state->r[m] += 2; + templ = m_sh2_state->macl; + tempm = ((INT32) (short) tempn * (INT32) (short) tempm); + if ((INT32) m_sh2_state->macl >= 0) + dest = 0; + else + dest = 1; + if ((INT32) tempm >= 0) + { + src = 0; + tempn = 0; + } + else + { + src = 1; + tempn = 0xffffffff; + } + src += dest; + m_sh2_state->macl += tempm; + if ((INT32) m_sh2_state->macl >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (m_sh2_state->sr & S) + { + if (ans == 1) + { + if (src == 0) + m_sh2_state->macl = 0x7fffffff; + if (src == 2) + m_sh2_state->macl = 0x80000000; + } + } + else + { + m_sh2_state->mach += tempn; + if (templ > m_sh2_state->macl) + m_sh2_state->mach += 1; + } + m_sh2_state->icount -= 2; +} + +/* MOV Rm,Rn */ +void sh2_device::MOV(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->r[m]; +} + +/* MOV.B Rm,@Rn */ +void sh2_device::MOVBS(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n]; + WB( m_sh2_state->ea, m_sh2_state->r[m] & 0x000000ff); +} + +/* MOV.W Rm,@Rn */ +void sh2_device::MOVWS(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n]; + WW( m_sh2_state->ea, m_sh2_state->r[m] & 0x0000ffff); +} + +/* MOV.L Rm,@Rn */ +void sh2_device::MOVLS(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->r[m] ); +} + +/* MOV.B @Rm,Rn */ +void sh2_device::MOVBL(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @Rm,Rn */ +void sh2_device::MOVWL(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @Rm,Rn */ +void sh2_device::MOVLL(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOV.B Rm,@-Rn */ +void sh2_device::MOVBM(UINT32 m, UINT32 n) +{ + /* SMG : bug fix, was reading m_sh2_state->r[n] */ + UINT32 data = m_sh2_state->r[m] & 0x000000ff; + + m_sh2_state->r[n] -= 1; + WB( m_sh2_state->r[n], data ); +} + +/* MOV.W Rm,@-Rn */ +void sh2_device::MOVWM(UINT32 m, UINT32 n) +{ + UINT32 data = m_sh2_state->r[m] & 0x0000ffff; + + m_sh2_state->r[n] -= 2; + WW( m_sh2_state->r[n], data ); +} + +/* MOV.L Rm,@-Rn */ +void sh2_device::MOVLM(UINT32 m, UINT32 n) +{ + UINT32 data = m_sh2_state->r[m]; + + m_sh2_state->r[n] -= 4; + WL( m_sh2_state->r[n], data ); +} + +/* MOV.B @Rm+,Rn */ +void sh2_device::MOVBP(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->r[m] ); + if (n != m) + m_sh2_state->r[m] += 1; +} + +/* MOV.W @Rm+,Rn */ +void sh2_device::MOVWP(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->r[m] ); + if (n != m) + m_sh2_state->r[m] += 2; +} + +/* MOV.L @Rm+,Rn */ +void sh2_device::MOVLP(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = RL( m_sh2_state->r[m] ); + if (n != m) + m_sh2_state->r[m] += 4; +} + +/* MOV.B Rm,@(R0,Rn) */ +void sh2_device::MOVBS0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n] + m_sh2_state->r[0]; + WB( m_sh2_state->ea, m_sh2_state->r[m] & 0x000000ff ); +} + +/* MOV.W Rm,@(R0,Rn) */ +void sh2_device::MOVWS0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n] + m_sh2_state->r[0]; + WW( m_sh2_state->ea, m_sh2_state->r[m] & 0x0000ffff ); +} + +/* MOV.L Rm,@(R0,Rn) */ +void sh2_device::MOVLS0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n] + m_sh2_state->r[0]; + WL( m_sh2_state->ea, m_sh2_state->r[m] ); +} + +/* MOV.B @(R0,Rm),Rn */ +void sh2_device::MOVBL0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @(R0,Rm),Rn */ +void sh2_device::MOVWL0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(R0,Rm),Rn */ +void sh2_device::MOVLL0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0]; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOV #imm,Rn */ +void sh2_device::MOVI(UINT32 i, UINT32 n) +{ + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) i; +} + +/* MOV.W @(disp8,PC),Rn */ +void sh2_device::MOVWI(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(disp8,PC),Rn */ +void sh2_device::MOVLI(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = ((m_sh2_state->pc + 2) & ~3) + disp * 4; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOV.B @(disp8,GBR),R0 */ +void sh2_device::MOVBLG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp; + m_sh2_state->r[0] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @(disp8,GBR),R0 */ +void sh2_device::MOVWLG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 2; + m_sh2_state->r[0] = (INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(disp8,GBR),R0 */ +void sh2_device::MOVLLG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 4; + m_sh2_state->r[0] = RL( m_sh2_state->ea ); +} + +/* MOV.B R0,@(disp8,GBR) */ +void sh2_device::MOVBSG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp; + WB( m_sh2_state->ea, m_sh2_state->r[0] & 0x000000ff ); +} + +/* MOV.W R0,@(disp8,GBR) */ +void sh2_device::MOVWSG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 2; + WW( m_sh2_state->ea, m_sh2_state->r[0] & 0x0000ffff ); +} + +/* MOV.L R0,@(disp8,GBR) */ +void sh2_device::MOVLSG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 4; + WL( m_sh2_state->ea, m_sh2_state->r[0] ); +} + +/* MOV.B R0,@(disp4,Rn) */ +void sh2_device::MOVBS4(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[n] + disp; + WB( m_sh2_state->ea, m_sh2_state->r[0] & 0x000000ff ); +} + +/* MOV.W R0,@(disp4,Rn) */ +void sh2_device::MOVWS4(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[n] + disp * 2; + WW( m_sh2_state->ea, m_sh2_state->r[0] & 0x0000ffff ); +} + +/* MOV.L Rm,@(disp4,Rn) */ +void sh2_device::MOVLS4(UINT32 m, UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[n] + disp * 4; + WL( m_sh2_state->ea, m_sh2_state->r[m] ); +} + +/* MOV.B @(disp4,Rm),R0 */ +void sh2_device::MOVBL4(UINT32 m, UINT32 d) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[m] + disp; + m_sh2_state->r[0] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @(disp4,Rm),R0 */ +void sh2_device::MOVWL4(UINT32 m, UINT32 d) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[m] + disp * 2; + m_sh2_state->r[0] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(disp4,Rm),Rn */ +void sh2_device::MOVLL4(UINT32 m, UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[m] + disp * 4; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOVA @(disp8,PC),R0 */ +void sh2_device::MOVA(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = ((m_sh2_state->pc + 2) & ~3) + disp * 4; + m_sh2_state->r[0] = m_sh2_state->ea; +} + +/* MOVT Rn */ +void sh2_device::MOVT(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->sr & T; +} + +/* MUL.L Rm,Rn */ +void sh2_device::MULL(UINT32 m, UINT32 n) +{ + m_sh2_state->macl = m_sh2_state->r[n] * m_sh2_state->r[m]; + m_sh2_state->icount--; +} + +/* MULS Rm,Rn */ +void sh2_device::MULS(UINT32 m, UINT32 n) +{ + m_sh2_state->macl = (INT16) m_sh2_state->r[n] * (INT16) m_sh2_state->r[m]; +} + +/* MULU Rm,Rn */ +void sh2_device::MULU(UINT32 m, UINT32 n) +{ + m_sh2_state->macl = (UINT16) m_sh2_state->r[n] * (UINT16) m_sh2_state->r[m]; +} + +/* NEG Rm,Rn */ +void sh2_device::NEG(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = 0 - m_sh2_state->r[m]; +} + +/* NEGC Rm,Rn */ +void sh2_device::NEGC(UINT32 m, UINT32 n) +{ + UINT32 temp; + + temp = m_sh2_state->r[m]; + m_sh2_state->r[n] = -temp - (m_sh2_state->sr & T); + if (temp || (m_sh2_state->sr & T)) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* NOP */ +void sh2_device::NOP(void) +{ +} + +/* NOT Rm,Rn */ +void sh2_device::NOT(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = ~m_sh2_state->r[m]; +} + +/* OR Rm,Rn */ +void sh2_device::OR(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] |= m_sh2_state->r[m]; +} + +/* OR #imm,R0 */ +void sh2_device::ORI(UINT32 i) +{ + m_sh2_state->r[0] |= i; +} + +/* OR.B #imm,@(R0,GBR) */ +void sh2_device::ORM(UINT32 i) +{ + UINT32 temp; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + temp = RB( m_sh2_state->ea ); + temp |= i; + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 2; +} + +/* ROTCL Rn */ +void sh2_device::ROTCL(UINT32 n) +{ + UINT32 temp; + + temp = (m_sh2_state->r[n] >> 31) & T; + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->sr & T); + m_sh2_state->sr = (m_sh2_state->sr & ~T) | temp; +} + +/* ROTCR Rn */ +void sh2_device::ROTCR(UINT32 n) +{ + UINT32 temp; + temp = (m_sh2_state->sr & T) << 31; + if (m_sh2_state->r[n] & T) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + m_sh2_state->r[n] = (m_sh2_state->r[n] >> 1) | temp; +} + +/* ROTL Rn */ +void sh2_device::ROTL(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | ((m_sh2_state->r[n] >> 31) & T); + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->r[n] >> 31); +} + +/* ROTR Rn */ +void sh2_device::ROTR(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T); + m_sh2_state->r[n] = (m_sh2_state->r[n] >> 1) | (m_sh2_state->r[n] << 31); +} + +/* RTE */ +void sh2_device::RTE() +{ + m_sh2_state->ea = m_sh2_state->r[15]; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = RL( m_sh2_state->ea ); + m_sh2_state->r[15] += 4; + m_sh2_state->ea = m_sh2_state->r[15]; + m_sh2_state->sr = RL( m_sh2_state->ea ) & FLAGS; + m_sh2_state->r[15] += 4; + m_sh2_state->icount -= 3; + m_test_irq = 1; +} + +/* RTS */ +void sh2_device::RTS() +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pr; + m_sh2_state->icount--; +} + +/* SETT */ +void sh2_device::SETT() +{ + m_sh2_state->sr |= T; +} + +/* SHAL Rn (same as SHLL) */ +void sh2_device::SHAL(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | ((m_sh2_state->r[n] >> 31) & T); + m_sh2_state->r[n] <<= 1; +} + +/* SHAR Rn */ +void sh2_device::SHAR(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T); + m_sh2_state->r[n] = (UINT32)((INT32)m_sh2_state->r[n] >> 1); +} + +/* SHLL Rn (same as SHAL) */ +void sh2_device::SHLL(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | ((m_sh2_state->r[n] >> 31) & T); + m_sh2_state->r[n] <<= 1; +} + +/* SHLL2 Rn */ +void sh2_device::SHLL2(UINT32 n) +{ + m_sh2_state->r[n] <<= 2; +} + +/* SHLL8 Rn */ +void sh2_device::SHLL8(UINT32 n) +{ + m_sh2_state->r[n] <<= 8; +} + +/* SHLL16 Rn */ +void sh2_device::SHLL16(UINT32 n) +{ + m_sh2_state->r[n] <<= 16; +} + +/* SHLR Rn */ +void sh2_device::SHLR(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T); + m_sh2_state->r[n] >>= 1; +} + +/* SHLR2 Rn */ +void sh2_device::SHLR2(UINT32 n) +{ + m_sh2_state->r[n] >>= 2; +} + +/* SHLR8 Rn */ +void sh2_device::SHLR8(UINT32 n) +{ + m_sh2_state->r[n] >>= 8; +} + +/* SHLR16 Rn */ +void sh2_device::SHLR16(UINT32 n) +{ + m_sh2_state->r[n] >>= 16; +} + +/* SLEEP */ +void sh2_device::SLEEP() +{ + if(m_sh2_state->sleep_mode != 2) + m_sh2_state->pc -= 2; + m_sh2_state->icount -= 2; + /* Wait_for_exception; */ + if(m_sh2_state->sleep_mode == 0) + m_sh2_state->sleep_mode = 1; + else if(m_sh2_state->sleep_mode == 2) + m_sh2_state->sleep_mode = 0; +} + +/* STC SR,Rn */ +void sh2_device::STCSR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->sr; +} + +/* STC GBR,Rn */ +void sh2_device::STCGBR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->gbr; +} + +/* STC VBR,Rn */ +void sh2_device::STCVBR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->vbr; +} + +/* STC.L SR,@-Rn */ +void sh2_device::STCMSR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->sr ); + m_sh2_state->icount--; +} + +/* STC.L GBR,@-Rn */ +void sh2_device::STCMGBR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->gbr ); + m_sh2_state->icount--; +} + +/* STC.L VBR,@-Rn */ +void sh2_device::STCMVBR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->vbr ); + m_sh2_state->icount--; +} + +/* STS MACH,Rn */ +void sh2_device::STSMACH(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->mach; +} + +/* STS MACL,Rn */ +void sh2_device::STSMACL(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->macl; +} + +/* STS PR,Rn */ +void sh2_device::STSPR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->pr; +} + +/* STS.L MACH,@-Rn */ +void sh2_device::STSMMACH(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->mach ); +} + +/* STS.L MACL,@-Rn */ +void sh2_device::STSMMACL(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->macl ); +} + +/* STS.L PR,@-Rn */ +void sh2_device::STSMPR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->pr ); +} + +/* SUB Rm,Rn */ +void sh2_device::SUB(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] -= m_sh2_state->r[m]; +} + +/* SUBC Rm,Rn */ +void sh2_device::SUBC(UINT32 m, UINT32 n) +{ + UINT32 tmp0, tmp1; + + tmp1 = m_sh2_state->r[n] - m_sh2_state->r[m]; + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] = tmp1 - (m_sh2_state->sr & T); + if (tmp0 < tmp1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + if (tmp1 < m_sh2_state->r[n]) + m_sh2_state->sr |= T; +} + +/* SUBV Rm,Rn */ +void sh2_device::SUBV(UINT32 m, UINT32 n) +{ + INT32 dest, src, ans; + + if ((INT32) m_sh2_state->r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_sh2_state->r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if ((INT32) m_sh2_state->r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 1) + { + if (ans == 1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + } + else + m_sh2_state->sr &= ~T; +} + +/* SWAP.B Rm,Rn */ +void sh2_device::SWAPB(UINT32 m, UINT32 n) +{ + UINT32 temp0, temp1; + + temp0 = m_sh2_state->r[m] & 0xffff0000; + temp1 = (m_sh2_state->r[m] & 0x000000ff) << 8; + m_sh2_state->r[n] = (m_sh2_state->r[m] >> 8) & 0x000000ff; + m_sh2_state->r[n] = m_sh2_state->r[n] | temp1 | temp0; +} + +/* SWAP.W Rm,Rn */ +void sh2_device::SWAPW(UINT32 m, UINT32 n) +{ + UINT32 temp; + + temp = (m_sh2_state->r[m] >> 16) & 0x0000ffff; + m_sh2_state->r[n] = (m_sh2_state->r[m] << 16) | temp; +} + +/* TAS.B @Rn */ +void sh2_device::TAS(UINT32 n) +{ + UINT32 temp; + m_sh2_state->ea = m_sh2_state->r[n]; + /* Bus Lock enable */ + temp = RB( m_sh2_state->ea ); + if (temp == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + temp |= 0x80; + /* Bus Lock disable */ + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 3; +} + +/* TRAPA #imm */ +void sh2_device::TRAPA(UINT32 i) +{ + UINT32 imm = i & 0xff; + + m_sh2_state->ea = m_sh2_state->vbr + imm * 4; + + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->sr ); + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->pc ); + + m_sh2_state->pc = RL( m_sh2_state->ea ); + + m_sh2_state->icount -= 7; +} + +/* TST Rm,Rn */ +void sh2_device::TST(UINT32 m, UINT32 n) +{ + if ((m_sh2_state->r[n] & m_sh2_state->r[m]) == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* TST #imm,R0 */ +void sh2_device::TSTI(UINT32 i) +{ + UINT32 imm = i & 0xff; + + if ((imm & m_sh2_state->r[0]) == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* TST.B #imm,@(R0,GBR) */ +void sh2_device::TSTM(UINT32 i) +{ + UINT32 imm = i & 0xff; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + if ((imm & RB( m_sh2_state->ea )) == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + m_sh2_state->icount -= 2; +} + +/* XOR Rm,Rn */ +void sh2_device::XOR(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] ^= m_sh2_state->r[m]; +} + +/* XOR #imm,R0 */ +void sh2_device::XORI(UINT32 i) +{ + UINT32 imm = i & 0xff; + m_sh2_state->r[0] ^= imm; +} + +/* XOR.B #imm,@(R0,GBR) */ +void sh2_device::XORM(UINT32 i) +{ + UINT32 imm = i & 0xff; + UINT32 temp; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + temp = RB( m_sh2_state->ea ); + temp ^= imm; + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 2; +} + +/* XTRCT Rm,Rn */ +void sh2_device::XTRCT(UINT32 m, UINT32 n) +{ + UINT32 temp; + + temp = (m_sh2_state->r[m] << 16) & 0xffff0000; + m_sh2_state->r[n] = (m_sh2_state->r[n] >> 16) & 0x0000ffff; + m_sh2_state->r[n] |= temp; +} + +/***************************************************************************** + * OPCODE DISPATCHERS + *****************************************************************************/ + +void sh2_device::op0000(UINT16 opcode) +{ + switch (opcode & 0x3F) + { + case 0x00: ILLEGAL(); break; + case 0x01: ILLEGAL(); 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: ILLEGAL(); break; + case 0x11: ILLEGAL(); break; + case 0x12: STCGBR(Rn); break; + case 0x13: ILLEGAL(); 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: ILLEGAL(); break; + case 0x21: ILLEGAL(); 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: ILLEGAL(); break; + case 0x31: ILLEGAL(); break; + case 0x32: ILLEGAL(); break; + case 0x33: ILLEGAL(); 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: ILLEGAL(); break; + case 0x39: ILLEGAL(); 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: ILLEGAL(); break; + case 0x3b: ILLEGAL(); break; + + + + } +} + +void sh2_device::op0001(UINT16 opcode) +{ + MOVLS4(Rm, opcode & 0x0f, Rn); +} + +void sh2_device::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: ILLEGAL(); 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; + } +} + +void sh2_device::op0011(UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: CMPEQ(Rm, Rn); break; + case 1: ILLEGAL(); 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: ILLEGAL(); 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; + } +} + +void sh2_device::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: ILLEGAL(); break; + case 0x0d: ILLEGAL(); 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: ILLEGAL(); 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: ILLEGAL(); break; + case 0x1d: ILLEGAL(); 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: ILLEGAL(); break; + case 0x2d: ILLEGAL(); break; + case 0x2e: LDCVBR(Rn); break; + case 0x2f: MAC_W(Rm, Rn); break; + + case 0x30: ILLEGAL(); break; + case 0x31: ILLEGAL(); break; + case 0x32: ILLEGAL(); break; + case 0x33: ILLEGAL(); break; + case 0x34: ILLEGAL(); break; + case 0x35: ILLEGAL(); break; + case 0x36: ILLEGAL(); break; + case 0x37: ILLEGAL(); break; + case 0x38: ILLEGAL(); break; + case 0x39: ILLEGAL(); break; + case 0x3a: ILLEGAL(); break; + case 0x3b: ILLEGAL(); break; + case 0x3c: ILLEGAL(); break; + case 0x3d: ILLEGAL(); break; + case 0x3e: ILLEGAL(); break; + case 0x3f: MAC_W(Rm, Rn); break; + + } +} + +void sh2_device::op0101(UINT16 opcode) +{ + MOVLL4(Rm, opcode & 0x0f, Rn); +} + +void sh2_device::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; + } +} + +void sh2_device::op0111(UINT16 opcode) +{ + ADDI(opcode & 0xff, Rn); +} + +void sh2_device::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: ILLEGAL(); break; + case 3<< 8: ILLEGAL(); break; + case 4<< 8: MOVBL4(Rm, opcode & 0x0f); break; + case 5<< 8: MOVWL4(Rm, opcode & 0x0f); break; + case 6<< 8: ILLEGAL(); break; + case 7<< 8: ILLEGAL(); break; + case 8<< 8: CMPIM(opcode & 0xff); break; + case 9<< 8: BT(opcode & 0xff); break; + case 10<< 8: ILLEGAL(); break; + case 11<< 8: BF(opcode & 0xff); break; + case 12<< 8: ILLEGAL(); break; + case 13<< 8: BTS(opcode & 0xff); break; + case 14<< 8: ILLEGAL(); break; + case 15<< 8: BFS(opcode & 0xff); break; + } +} + + +void sh2_device::op1001(UINT16 opcode) +{ + MOVWI(opcode & 0xff, Rn); +} + +void sh2_device::op1010(UINT16 opcode) +{ + BRA(opcode & 0xfff); +} + +void sh2_device::op1011(UINT16 opcode) +{ + BSR(opcode & 0xfff); +} + +void sh2_device::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; + } +} + +void sh2_device::op1101(UINT16 opcode) +{ + MOVLI(opcode & 0xff, Rn); +} + +void sh2_device::op1110(UINT16 opcode) +{ + MOVI(opcode & 0xff, Rn); +} + +void sh2_device::op1111(UINT16 opcode) +{ + ILLEGAL(); +} + +/***************************************************************************** + * MAME CPU INTERFACE + *****************************************************************************/ + +void sh2_device::device_reset() +{ + m_sh2_state->ppc = m_sh2_state->pc = m_sh2_state->pr = m_sh2_state->sr = m_sh2_state->gbr = m_sh2_state->vbr = m_sh2_state->mach = m_sh2_state->macl = 0; + m_sh2_state->evec = m_sh2_state->irqsr = 0; + memset(&m_sh2_state->r[0], 0, sizeof(m_sh2_state->r[0])*16); + m_sh2_state->ea = m_delay = m_cpu_off = m_dvsr = m_dvdnth = m_dvdntl = m_dvcr = 0; + m_sh2_state->pending_irq = m_test_irq = 0; + memset(&m_irq_queue[0], 0, sizeof(m_irq_queue[0])*16); + memset(&m_irq_line_state[0], 0, sizeof(m_irq_line_state[0])*17); + m_frc = m_ocra = m_ocrb = m_icr = 0; + m_frc_base = 0; + m_frt_input = m_sh2_state->internal_irq_level = m_internal_irq_vector = 0; + m_dma_timer_active[0] = m_dma_timer_active[1] = 0; + m_dma_irq[0] = m_dma_irq[1] = 0; + + memset(m_m, 0, 0x200); + + m_sh2_state->pc = RL(0); + m_sh2_state->r[15] = RL(4); + m_sh2_state->sr = I; + m_sh2_state->sleep_mode = 0; + + m_sh2_state->internal_irq_level = -1; + + m_cache_dirty = TRUE; +} + + +/* Execute cycles - returns number of cycles actually run */ +void sh2_device::execute_run() +{ + if ( m_isdrc ) + { + execute_run_drc(); + return; + } + + if (m_cpu_off) + { + m_sh2_state->icount = 0; + return; + } + + // run any active DMAs now +#ifndef USE_TIMER_FOR_DMA + for ( int i = 0; i < m_sh2_state->icount ; i++) + { + for( int dma=0;dma<1;dma++) + { + if (m_dma_timer_active[dma]) + sh2_do_dma(dma); + } + } +#endif + + do + { + UINT32 opcode; + + if (m_delay) + { + opcode = m_program->read_word(((UINT32)(m_delay & AM))); + m_sh2_state->pc -= 2; + } + else + opcode = m_program->read_word(((UINT32)(m_sh2_state->pc & AM))); + + debugger_instruction_hook(this, m_sh2_state->pc); + + m_delay = 0; + m_sh2_state->pc += 2; + m_sh2_state->ppc = m_sh2_state->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(m_test_irq && !m_delay) + { + CHECK_PENDING_IRQ("mame_sh2_execute"); + m_test_irq = 0; + } + m_sh2_state->icount--; + } while( m_sh2_state->icount > 0 ); +} + +void sh2_device::device_start() +{ + /* allocate the implementation-specific state from the full cache */ + m_sh2_state = (internal_sh2_state *)m_cache.alloc_near(sizeof(internal_sh2_state)); + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_timer_callback), this)); + m_timer->adjust(attotime::never); + + m_dma_current_active_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_dma_current_active_callback), this)); + m_dma_current_active_timer[0]->adjust(attotime::never); + + m_dma_current_active_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_dma_current_active_callback), this)); + m_dma_current_active_timer[1]->adjust(attotime::never); + + /* resolve callbacks */ + m_dma_kludge_cb.bind_relative_to(*owner()); + m_dma_fifo_data_available_cb.bind_relative_to(*owner()); + m_ftcsr_read_cb.bind_relative_to(*owner()); + + m_program = &space(AS_PROGRAM); + m_decrypted_program = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : &space(AS_PROGRAM); + m_direct = &m_decrypted_program->direct(); + m_internal = &space(AS_PROGRAM); + + save_item(NAME(m_sh2_state->pc)); + save_item(NAME(m_sh2_state->sr)); + save_item(NAME(m_sh2_state->pr)); + save_item(NAME(m_sh2_state->gbr)); + save_item(NAME(m_sh2_state->vbr)); + save_item(NAME(m_sh2_state->mach)); + save_item(NAME(m_sh2_state->macl)); + save_item(NAME(m_sh2_state->r)); + save_item(NAME(m_sh2_state->ea)); + save_item(NAME(m_delay)); + save_item(NAME(m_cpu_off)); + save_item(NAME(m_dvsr)); + save_item(NAME(m_dvdnth)); + save_item(NAME(m_dvdntl)); + save_item(NAME(m_dvcr)); + save_item(NAME(m_sh2_state->pending_irq)); + save_item(NAME(m_test_irq)); + save_item(NAME(m_sh2_state->pending_nmi)); + save_item(NAME(m_sh2_state->irqline)); + save_item(NAME(m_sh2_state->evec)); + save_item(NAME(m_sh2_state->irqsr)); + save_item(NAME(m_sh2_state->target)); + for (int i = 0; i < 16; ++i) + { + save_item(NAME(m_irq_queue[i].irq_vector), i); + save_item(NAME(m_irq_queue[i].irq_priority), i); + } + save_item(NAME(m_pcfsel)); + save_item(NAME(m_maxpcfsel)); + save_item(NAME(m_pcflushes)); + save_item(NAME(m_irq_line_state)); + save_item(NAME(m_m)); + save_item(NAME(m_nmi_line_state)); + save_item(NAME(m_frc)); + save_item(NAME(m_ocra)); + save_item(NAME(m_ocrb)); + save_item(NAME(m_icr)); + save_item(NAME(m_frc_base)); + save_item(NAME(m_frt_input)); + save_item(NAME(m_sh2_state->internal_irq_level)); + save_item(NAME(m_internal_irq_vector)); + save_item(NAME(m_dma_timer_active)); + save_item(NAME(m_dma_irq)); + save_item(NAME(m_wtcnt)); + save_item(NAME(m_wtcsr)); + save_item(NAME(m_sh2_state->sleep_mode)); + + state_add( SH2_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( SH2_SR, "SR", m_sh2_state->sr).callimport().formatstr("%08X"); + state_add( SH2_PR, "PR", m_sh2_state->pr).formatstr("%08X"); + state_add( SH2_GBR, "GBR", m_sh2_state->gbr).formatstr("%08X"); + state_add( SH2_VBR, "VBR", m_sh2_state->vbr).formatstr("%08X"); + state_add( SH2_MACH, "MACH", m_sh2_state->mach).formatstr("%08X"); + state_add( SH2_MACL, "MACL", m_sh2_state->macl).formatstr("%08X"); + state_add( SH2_R0, "R0", m_sh2_state->r[ 0]).formatstr("%08X"); + state_add( SH2_R1, "R1", m_sh2_state->r[ 1]).formatstr("%08X"); + state_add( SH2_R2, "R2", m_sh2_state->r[ 2]).formatstr("%08X"); + state_add( SH2_R3, "R3", m_sh2_state->r[ 3]).formatstr("%08X"); + state_add( SH2_R4, "R4", m_sh2_state->r[ 4]).formatstr("%08X"); + state_add( SH2_R5, "R5", m_sh2_state->r[ 5]).formatstr("%08X"); + state_add( SH2_R6, "R6", m_sh2_state->r[ 6]).formatstr("%08X"); + state_add( SH2_R7, "R7", m_sh2_state->r[ 7]).formatstr("%08X"); + state_add( SH2_R8, "R8", m_sh2_state->r[ 8]).formatstr("%08X"); + state_add( SH2_R9, "R9", m_sh2_state->r[ 9]).formatstr("%08X"); + state_add( SH2_R10, "R10", m_sh2_state->r[10]).formatstr("%08X"); + state_add( SH2_R11, "R11", m_sh2_state->r[11]).formatstr("%08X"); + state_add( SH2_R12, "R12", m_sh2_state->r[12]).formatstr("%08X"); + state_add( SH2_R13, "R13", m_sh2_state->r[13]).formatstr("%08X"); + state_add( SH2_R14, "R14", m_sh2_state->r[14]).formatstr("%08X"); + state_add( SH2_R15, "R15", m_sh2_state->r[15]).formatstr("%08X"); + state_add( SH2_EA, "EA", m_sh2_state->ea).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", m_sh2_state->pc ).noshow(); + state_add( STATE_GENSP, "GENSP", m_sh2_state->r[15] ).noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_sh2_state->ppc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_sh2_state->sr ).formatstr("%6s").noshow(); + + m_icountptr = &m_sh2_state->icount; + + // Clear state + m_sh2_state->ppc = 0; + m_sh2_state->pc = 0; + m_sh2_state->pr = 0; + m_sh2_state->sr = 0; + m_sh2_state->gbr = 0; + m_sh2_state->vbr = 0; + m_sh2_state->mach = 0; + m_sh2_state->macl = 0; + memset(m_sh2_state->r, 0, sizeof(m_sh2_state->r)); + m_sh2_state->ea = 0; + m_delay = 0; + m_cpu_off = 0; + m_dvsr = 0; + m_dvdnth = 0; + m_dvdntl = 0; + m_dvcr = 0; + m_sh2_state->pending_irq = 0; + m_test_irq = 0; + m_sh2_state->pending_nmi = 0; + m_sh2_state->irqline = 0; + m_sh2_state->evec = 0; + m_sh2_state->irqsr = 0; + m_sh2_state->target = 0; + memset(m_irq_queue, 0, sizeof(m_irq_queue)); + m_maxpcfsel = 0; + memset(m_pcflushes, 0, sizeof(m_pcflushes)); + memset(m_irq_line_state, 0, sizeof(m_irq_line_state)); + memset(m_m, 0, sizeof(m_m)); + m_nmi_line_state = 0; + m_frc = 0; + m_ocra = 0; + m_ocrb = 0; + m_icr = 0; + m_frc_base = 0; + m_frt_input = 0; + m_sh2_state->internal_irq_level = 0; + m_internal_irq_vector = 0; + m_sh2_state->icount = 0; + for ( int i = 0; i < 2; i++ ) + { + m_dma_timer_active[i] = 0; + m_dma_irq[i] = 0; + m_active_dma_incs[i] = 0; + m_active_dma_incd[i] = 0; + m_active_dma_size[i] = 0; + m_active_dma_steal[i] = 0; + m_active_dma_src[i] = 0; + m_active_dma_dst[i] = 0; + m_active_dma_count[i] = 0; + } + m_wtcnt = 0; + m_wtcsr = 0; + m_sh2_state->sleep_mode = 0; + m_numcycles = 0; + m_sh2_state->arg0 = 0; + m_arg1 = 0; + m_irq = 0; + m_fastram_select = 0; + memset(m_fastram, 0, sizeof(m_fastram)); + + /* reset per-driver pcflushes */ + m_pcfsel = 0; + + /* initialize the UML generator */ + UINT32 flags = 0; + m_drcuml = auto_alloc(machine(), drcuml_state(*this, m_cache, flags, 1, 32, 1)); + + /* add symbols for our stuff */ + m_drcuml->symbol_add(&m_sh2_state->pc, sizeof(m_sh2_state->pc), "pc"); + m_drcuml->symbol_add(&m_sh2_state->icount, sizeof(m_sh2_state->icount), "icount"); + for (int regnum = 0; regnum < 16; regnum++) + { + char buf[10]; + sprintf(buf, "r%d", regnum); + m_drcuml->symbol_add(&m_sh2_state->r[regnum], sizeof(m_sh2_state->r[regnum]), buf); + } + m_drcuml->symbol_add(&m_sh2_state->pr, sizeof(m_sh2_state->pr), "pr"); + m_drcuml->symbol_add(&m_sh2_state->sr, sizeof(m_sh2_state->sr), "sr"); + m_drcuml->symbol_add(&m_sh2_state->gbr, sizeof(m_sh2_state->gbr), "gbr"); + m_drcuml->symbol_add(&m_sh2_state->vbr, sizeof(m_sh2_state->vbr), "vbr"); + m_drcuml->symbol_add(&m_sh2_state->macl, sizeof(m_sh2_state->macl), "macl"); + m_drcuml->symbol_add(&m_sh2_state->mach, sizeof(m_sh2_state->macl), "mach"); + + /* initialize the front-end helper */ + m_drcfe = auto_alloc(machine(), sh2_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + + /* compute the register parameters */ + for (int regnum = 0; regnum < 16; regnum++) + { + m_regmap[regnum] = uml::mem(&m_sh2_state->r[regnum]); + } + + /* if we have registers to spare, assign r0, r1, r2 to leftovers */ + /* WARNING: do not use synthetic registers that are mapped here! */ + if (!DISABLE_FAST_REGISTERS) + { + drcbe_info beinfo; + m_drcuml->get_backend_info(beinfo); + if (beinfo.direct_iregs > 4) + { + m_regmap[0] = uml::I4; + } + if (beinfo.direct_iregs > 5) + { + m_regmap[1] = uml::I5; + } + if (beinfo.direct_iregs > 6) + { + m_regmap[2] = uml::I6; + } + } + + /* mark the cache dirty so it is updated on next execute */ + m_cache_dirty = TRUE; +} + + +void sh2_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%d%c%c", + m_sh2_state->sr & M ? 'M':'.', + m_sh2_state->sr & Q ? 'Q':'.', + (m_sh2_state->sr & I) >> 4, + m_sh2_state->sr & S ? 'S':'.', + m_sh2_state->sr & T ? 'T':'.'); + break; + } +} + + +void sh2_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SH2_PC: + m_sh2_state->pc = m_debugger_temp; + m_delay = 0; + break; + + case SH2_SR: + CHECK_PENDING_IRQ("sh2_set_reg"); + break; + } +} + + +void sh2_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SH2_PC: + m_debugger_temp = (m_delay) ? (m_delay & AM) : (m_sh2_state->pc & AM); + break; + } +} + + +void sh2_device::execute_set_input(int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + if (m_nmi_line_state == state) + return; + m_nmi_line_state = state; + + if( state == CLEAR_LINE ) + { + LOG(("SH-2 '%s' cleared nmi\n", tag())); + } + else + { + LOG(("SH-2 '%s' assert nmi\n", tag())); + + sh2_exception("Set IRQ line", 16); + + if (m_isdrc) + m_sh2_state->pending_nmi = 1; + } + } + else + { + if (m_irq_line_state[irqline] == state) + return; + m_irq_line_state[irqline] = state; + + if( state == CLEAR_LINE ) + { + LOG(("SH-2 '%s' cleared irq #%d\n", tag(), irqline)); + m_sh2_state->pending_irq &= ~(1 << irqline); + } + else + { + LOG(("SH-2 '%s' assert irq #%d\n", tag(), irqline)); + m_sh2_state->pending_irq |= 1 << irqline; + if (m_isdrc) + { + m_test_irq = 1; + } else { + if(m_delay) + m_test_irq = 1; + else + CHECK_PENDING_IRQ("sh2_set_irq_line"); + } + } + } +} + +#include "sh2comn.c" +#include "sh2drc.c" |