summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sh
diff options
context:
space:
mode:
author David Haywood <davidhaywood@users.noreply.github.com>2017-10-02 19:47:35 +0100
committer David Haywood <davidhaywood@users.noreply.github.com>2017-10-02 19:47:35 +0100
commitc0ee79f3db1d019c74cd199a99398bb5a04065c5 (patch)
tree6f329845f63f85efe3471222d7bfa07982f88a62 /src/devices/cpu/sh
parent48aabf412269e49dca22546bb408d6e34a9c79b7 (diff)
use 'sh' instead of 'superh'
Diffstat (limited to 'src/devices/cpu/sh')
-rw-r--r--src/devices/cpu/sh/sh2.cpp2704
-rw-r--r--src/devices/cpu/sh/sh2.h557
-rw-r--r--src/devices/cpu/sh/sh2comn.cpp946
-rw-r--r--src/devices/cpu/sh/sh2comn.h85
-rw-r--r--src/devices/cpu/sh/sh2dasm.cpp610
-rw-r--r--src/devices/cpu/sh/sh2drc.cpp2982
-rw-r--r--src/devices/cpu/sh/sh2fe.cpp762
-rw-r--r--src/devices/cpu/sh/sh3comn.cpp681
-rw-r--r--src/devices/cpu/sh/sh3comn.h96
-rw-r--r--src/devices/cpu/sh/sh4.cpp4743
-rw-r--r--src/devices/cpu/sh/sh4.h844
-rw-r--r--src/devices/cpu/sh/sh4comn.cpp1465
-rw-r--r--src/devices/cpu/sh/sh4comn.h174
-rw-r--r--src/devices/cpu/sh/sh4dasm.cpp905
-rw-r--r--src/devices/cpu/sh/sh4dmac.cpp666
-rw-r--r--src/devices/cpu/sh/sh4dmac.h63
-rw-r--r--src/devices/cpu/sh/sh4regs.h183
-rw-r--r--src/devices/cpu/sh/sh4tmu.cpp324
-rw-r--r--src/devices/cpu/sh/sh4tmu.h3
-rw-r--r--src/devices/cpu/sh/sh7604_bus.cpp162
-rw-r--r--src/devices/cpu/sh/sh7604_bus.h77
-rw-r--r--src/devices/cpu/sh/sh7604_sci.cpp156
-rw-r--r--src/devices/cpu/sh/sh7604_sci.h83
-rw-r--r--src/devices/cpu/sh/sh7604_wdt.cpp83
-rw-r--r--src/devices/cpu/sh/sh7604_wdt.h54
25 files changed, 19408 insertions, 0 deletions
diff --git a/src/devices/cpu/sh/sh2.cpp b/src/devices/cpu/sh/sh2.cpp
new file mode 100644
index 00000000000..9b1cf8dcbbf
--- /dev/null
+++ b/src/devices/cpu/sh/sh2.cpp
@@ -0,0 +1,2704 @@
+// 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_t m, uint32_t 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 "sh2.h"
+#include "sh2comn.h"
+
+#include "debugger.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define DISABLE_FAST_REGISTERS (0) // set to 1 to turn off usage of register caching
+#define SINGLE_INSTRUCTION_MODE (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
+
+
+DEFINE_DEVICE_TYPE(SH1, sh1_device, "sh1", "SH-1")
+DEFINE_DEVICE_TYPE(SH2, sh2_device, "sh2", "SH-2")
+DEFINE_DEVICE_TYPE(SH2A, sh2a_device, "sh21", "SH-2A")
+
+/*-------------------------------------------------
+ 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_t clock)
+ : sh2_device(mconfig, SH2, tag, owner, clock, CPU_TYPE_SH2, ADDRESS_MAP_NAME(sh7604_map), 32)
+{
+}
+
+
+void sh2_device::device_stop()
+{
+}
+
+
+sh2_device::sh2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int cpu_type, address_map_constructor internal_map, int addrlines)
+ : cpu_device(mconfig, type, tag, owner, clock)
+ , 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(nullptr)
+// , m_drcuml(*this, m_cache, 0, 1, 32, 1)
+ , m_drcfe(nullptr)
+ , m_drcoptions(0)
+ , m_sh2_state(nullptr)
+ , m_entry(nullptr)
+ , m_read8(nullptr)
+ , m_write8(nullptr)
+ , m_read16(nullptr)
+ , m_write16(nullptr)
+ , m_read32(nullptr)
+ , m_write32(nullptr)
+ , m_interrupt(nullptr)
+ , m_nocode(nullptr)
+ , m_out_of_cycles(nullptr)
+ , m_debugger_temp(0)
+{
+ m_isdrc = allow_drc();
+}
+
+sh2a_device::sh2a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh2_device(mconfig, SH2A, tag, owner, clock, CPU_TYPE_SH2, ADDRESS_MAP_NAME(sh7021_map), 28)
+{
+}
+
+sh1_device::sh1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh2_device(mconfig, SH1, tag, owner, clock, CPU_TYPE_SH1, ADDRESS_MAP_NAME(sh7032_map), 28)
+{
+}
+
+device_memory_interface::space_config_vector sh2_device::memory_space_config() const
+{
+ if(has_configured_map(AS_OPCODES))
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_OPCODES, &m_decrypted_program_config)
+ };
+ else
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config)
+ };
+}
+
+offs_t sh2_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
+{
+ extern CPU_DISASSEMBLE( sh2 );
+ return CPU_DISASSEMBLE_NAME( sh2 )(this, stream, pc, oprom, opram, options);
+}
+
+
+/* speed up delay loops, bail out of tight loops */
+#define BUSY_LOOP_HACKS 1
+
+uint8_t 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_t 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_t 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_t 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_t 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_t 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_t m, uint32_t 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_t i, uint32_t n)
+{
+ m_sh2_state->r[n] += (int32_t)(int16_t)(int8_t)i;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1110 1 carry
+ * ADDC Rm,Rn
+ */
+void sh2_device::ADDC(uint32_t m, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ int32_t dest, src, ans;
+
+ if ((int32_t) m_sh2_state->r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) 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_t) 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_t m, uint32_t 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_t 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_t i)
+{
+ uint32_t 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_t d)
+{
+ if ((m_sh2_state->sr & T) == 0)
+ {
+ int32_t disp = ((int32_t)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_t d)
+{
+ if ((m_sh2_state->sr & T) == 0)
+ {
+ int32_t disp = ((int32_t)d << 24) >> 24;
+ m_delay = 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_t d)
+{
+ int32_t disp = ((int32_t)d << 20) >> 20;
+
+#if BUSY_LOOP_HACKS
+ if (disp == -2)
+ {
+ uint32_t next_opcode = RW(m_sh2_state->pc & 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->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_t m)
+{
+ m_delay = 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_t d)
+{
+ int32_t disp = ((int32_t)d << 20) >> 20;
+
+ m_sh2_state->pr = m_sh2_state->pc + 2;
+ m_delay = 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_t m)
+{
+ m_sh2_state->pr = m_sh2_state->pc + 2;
+ m_delay = 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_t d)
+{
+ if ((m_sh2_state->sr & T) != 0)
+ {
+ int32_t disp = ((int32_t)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_t d)
+{
+ if ((m_sh2_state->sr & T) != 0)
+ {
+ int32_t disp = ((int32_t)d << 24) >> 24;
+ m_delay = 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_t m, uint32_t 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_t m, uint32_t n)
+{
+ if ((int32_t) m_sh2_state->r[n] >= (int32_t) 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_t m, uint32_t n)
+{
+ if ((int32_t) m_sh2_state->r[n] > (int32_t) 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_t m, uint32_t n)
+{
+ if ((uint32_t) m_sh2_state->r[n] > (uint32_t) 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_t m, uint32_t n)
+{
+ if ((uint32_t) m_sh2_state->r[n] >= (uint32_t) 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_t n)
+{
+ if ((int32_t) 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_t n)
+{
+ if ((int32_t) 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_t m, uint32_t n)
+ {
+ uint32_t temp;
+ int32_t 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_t i)
+{
+ uint32_t imm = (uint32_t)(int32_t)(int16_t)(int8_t)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_t m, uint32_t 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_t m, uint32_t n)
+{
+ uint32_t tmp0;
+ uint32_t 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_t m, uint32_t n)
+{
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t temp0, temp1, temp2, temp3;
+ int32_t tempm, tempn, fnLmL;
+
+ tempn = (int32_t) m_sh2_state->r[n];
+ tempm = (int32_t) m_sh2_state->r[m];
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ if ((int32_t) (m_sh2_state->r[n] ^ m_sh2_state->r[m]) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ temp1 = (uint32_t) tempn;
+ temp2 = (uint32_t) 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_t m, uint32_t n)
+{
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t 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_t 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_t next_opcode = RW(m_sh2_state->pc & 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_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = ((int32_t)m_sh2_state->r[m] << 24) >> 24;
+}
+
+/* EXTS.W Rm,Rn */
+void sh2_device::EXTSW(uint32_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = ((int32_t)m_sh2_state->r[m] << 16) >> 16;
+}
+
+/* EXTU.B Rm,Rn */
+void sh2_device::EXTUB(uint32_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->r[m] & 0x000000ff;
+}
+
+/* EXTU.W Rm,Rn */
+void sh2_device::EXTUW(uint32_t m, uint32_t 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_t m)
+{
+ m_delay = m_sh2_state->ea = m_sh2_state->r[m];
+ m_sh2_state->icount--;
+}
+
+/* JSR @Rm */
+void sh2_device::JSR(uint32_t m)
+{
+ m_sh2_state->pr = m_sh2_state->pc + 2;
+ m_delay = m_sh2_state->ea = m_sh2_state->r[m];
+ m_sh2_state->icount--;
+}
+
+
+/* LDC Rm,SR */
+void sh2_device::LDCSR(uint32_t m)
+{
+ m_sh2_state->sr = m_sh2_state->r[m] & FLAGS;
+ m_test_irq = 1;
+}
+
+/* LDC Rm,GBR */
+void sh2_device::LDCGBR(uint32_t m)
+{
+ m_sh2_state->gbr = m_sh2_state->r[m];
+}
+
+/* LDC Rm,VBR */
+void sh2_device::LDCVBR(uint32_t m)
+{
+ m_sh2_state->vbr = m_sh2_state->r[m];
+}
+
+/* LDC.L @Rm+,SR */
+void sh2_device::LDCMSR(uint32_t 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_t 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_t 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_t m)
+{
+ m_sh2_state->mach = m_sh2_state->r[m];
+}
+
+/* LDS Rm,MACL */
+void sh2_device::LDSMACL(uint32_t m)
+{
+ m_sh2_state->macl = m_sh2_state->r[m];
+}
+
+/* LDS Rm,PR */
+void sh2_device::LDSPR(uint32_t m)
+{
+ m_sh2_state->pr = m_sh2_state->r[m];
+}
+
+/* LDS.L @Rm+,MACH */
+void sh2_device::LDSMMACH(uint32_t 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_t 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_t 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_t m, uint32_t n)
+{
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t temp0, temp1, temp2, temp3;
+ int32_t tempm, tempn, fnLmL;
+
+ tempn = (int32_t) RL( m_sh2_state->r[n] );
+ m_sh2_state->r[n] += 4;
+ tempm = (int32_t) RL( m_sh2_state->r[m] );
+ m_sh2_state->r[m] += 4;
+ if ((int32_t) (tempn ^ tempm) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ temp1 = (uint32_t) tempn;
+ temp2 = (uint32_t) 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_t) Res2 < 0) && (Res2 < 0xffff8000))
+ {
+ Res2 = 0x00008000;
+ Res0 = 0x00000000;
+ }
+ else if (((int32_t) 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_t m, uint32_t n)
+{
+ int32_t tempm, tempn, dest, src, ans;
+ uint32_t templ;
+
+ tempn = (int32_t) RW( m_sh2_state->r[n] );
+ m_sh2_state->r[n] += 2;
+ tempm = (int32_t) RW( m_sh2_state->r[m] );
+ m_sh2_state->r[m] += 2;
+ templ = m_sh2_state->macl;
+ tempm = ((int32_t) (short) tempn * (int32_t) (short) tempm);
+ if ((int32_t) m_sh2_state->macl >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) tempm >= 0)
+ {
+ src = 0;
+ tempn = 0;
+ }
+ else
+ {
+ src = 1;
+ tempn = 0xffffffff;
+ }
+ src += dest;
+ m_sh2_state->macl += tempm;
+ if ((int32_t) 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_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->r[m];
+}
+
+/* MOV.B Rm,@Rn */
+void sh2_device::MOVBS(uint32_t m, uint32_t 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_t m, uint32_t 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_t m, uint32_t 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_t m, uint32_t n)
+{
+ m_sh2_state->ea = m_sh2_state->r[m];
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_sh2_state->ea );
+}
+
+/* MOV.W @Rm,Rn */
+void sh2_device::MOVWL(uint32_t m, uint32_t n)
+{
+ m_sh2_state->ea = m_sh2_state->r[m];
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t) RW( m_sh2_state->ea );
+}
+
+/* MOV.L @Rm,Rn */
+void sh2_device::MOVLL(uint32_t m, uint32_t 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_t m, uint32_t n)
+{
+ /* SMG : bug fix, was reading m_sh2_state->r[n] */
+ uint32_t 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_t m, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_sh2_state->r[m] );
+ if (n != m)
+ m_sh2_state->r[m] += 1;
+}
+
+/* MOV.W @Rm+,Rn */
+void sh2_device::MOVWP(uint32_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t) RW( m_sh2_state->r[m] );
+ if (n != m)
+ m_sh2_state->r[m] += 2;
+}
+
+/* MOV.L @Rm+,Rn */
+void sh2_device::MOVLP(uint32_t m, uint32_t 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_t m, uint32_t 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_t m, uint32_t 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_t m, uint32_t 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_t m, uint32_t n)
+{
+ m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0];
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_sh2_state->ea );
+}
+
+/* MOV.W @(R0,Rm),Rn */
+void sh2_device::MOVWL0(uint32_t m, uint32_t n)
+{
+ m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0];
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t) RW( m_sh2_state->ea );
+}
+
+/* MOV.L @(R0,Rm),Rn */
+void sh2_device::MOVLL0(uint32_t m, uint32_t 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_t i, uint32_t n)
+{
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t)(int8_t) i;
+}
+
+/* MOV.W @(disp8,PC),Rn */
+void sh2_device::MOVWI(uint32_t d, uint32_t n)
+{
+ uint32_t disp = d & 0xff;
+ m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2;
+ m_sh2_state->r[n] = (uint32_t)(int32_t)(int16_t) RW( m_sh2_state->ea );
+}
+
+/* MOV.L @(disp8,PC),Rn */
+void sh2_device::MOVLI(uint32_t d, uint32_t n)
+{
+ uint32_t 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_t d)
+{
+ uint32_t disp = d & 0xff;
+ m_sh2_state->ea = m_sh2_state->gbr + disp;
+ m_sh2_state->r[0] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_sh2_state->ea );
+}
+
+/* MOV.W @(disp8,GBR),R0 */
+void sh2_device::MOVWLG(uint32_t d)
+{
+ uint32_t disp = d & 0xff;
+ m_sh2_state->ea = m_sh2_state->gbr + disp * 2;
+ m_sh2_state->r[0] = (int32_t)(int16_t) RW( m_sh2_state->ea );
+}
+
+/* MOV.L @(disp8,GBR),R0 */
+void sh2_device::MOVLLG(uint32_t d)
+{
+ uint32_t 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_t d)
+{
+ uint32_t 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_t d)
+{
+ uint32_t 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_t d)
+{
+ uint32_t 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_t d, uint32_t n)
+{
+ uint32_t 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_t d, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t d, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t d)
+{
+ uint32_t disp = d & 0x0f;
+ m_sh2_state->ea = m_sh2_state->r[m] + disp;
+ m_sh2_state->r[0] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_sh2_state->ea );
+}
+
+/* MOV.W @(disp4,Rm),R0 */
+void sh2_device::MOVWL4(uint32_t m, uint32_t d)
+{
+ uint32_t disp = d & 0x0f;
+ m_sh2_state->ea = m_sh2_state->r[m] + disp * 2;
+ m_sh2_state->r[0] = (uint32_t)(int32_t)(int16_t) RW( m_sh2_state->ea );
+}
+
+/* MOV.L @(disp4,Rm),Rn */
+void sh2_device::MOVLL4(uint32_t m, uint32_t d, uint32_t n)
+{
+ uint32_t 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_t d)
+{
+ uint32_t 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_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->sr & T;
+}
+
+/* MUL.L Rm,Rn */
+void sh2_device::MULL(uint32_t m, uint32_t 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_t m, uint32_t n)
+{
+ m_sh2_state->macl = (int16_t) m_sh2_state->r[n] * (int16_t) m_sh2_state->r[m];
+}
+
+/* MULU Rm,Rn */
+void sh2_device::MULU(uint32_t m, uint32_t n)
+{
+ m_sh2_state->macl = (uint16_t) m_sh2_state->r[n] * (uint16_t) m_sh2_state->r[m];
+}
+
+/* NEG Rm,Rn */
+void sh2_device::NEG(uint32_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = 0 - m_sh2_state->r[m];
+}
+
+/* NEGC Rm,Rn */
+void sh2_device::NEGC(uint32_t m, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ m_sh2_state->r[n] = ~m_sh2_state->r[m];
+}
+
+/* OR Rm,Rn */
+void sh2_device::OR(uint32_t m, uint32_t n)
+{
+ m_sh2_state->r[n] |= m_sh2_state->r[m];
+}
+
+/* OR #imm,R0 */
+void sh2_device::ORI(uint32_t i)
+{
+ m_sh2_state->r[0] |= i;
+}
+
+/* OR.B #imm,@(R0,GBR) */
+void sh2_device::ORM(uint32_t i)
+{
+ uint32_t 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_t n)
+{
+ uint32_t 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_t n)
+{
+ uint32_t 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_t 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_t 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 = 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->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_t 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_t n)
+{
+ m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T);
+ m_sh2_state->r[n] = (uint32_t)((int32_t)m_sh2_state->r[n] >> 1);
+}
+
+/* SHLL Rn (same as SHAL) */
+void sh2_device::SHLL(uint32_t 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_t n)
+{
+ m_sh2_state->r[n] <<= 2;
+}
+
+/* SHLL8 Rn */
+void sh2_device::SHLL8(uint32_t n)
+{
+ m_sh2_state->r[n] <<= 8;
+}
+
+/* SHLL16 Rn */
+void sh2_device::SHLL16(uint32_t n)
+{
+ m_sh2_state->r[n] <<= 16;
+}
+
+/* SHLR Rn */
+void sh2_device::SHLR(uint32_t 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_t n)
+{
+ m_sh2_state->r[n] >>= 2;
+}
+
+/* SHLR8 Rn */
+void sh2_device::SHLR8(uint32_t n)
+{
+ m_sh2_state->r[n] >>= 8;
+}
+
+/* SHLR16 Rn */
+void sh2_device::SHLR16(uint32_t 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_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->sr;
+}
+
+/* STC GBR,Rn */
+void sh2_device::STCGBR(uint32_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->gbr;
+}
+
+/* STC VBR,Rn */
+void sh2_device::STCVBR(uint32_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->vbr;
+}
+
+/* STC.L SR,@-Rn */
+void sh2_device::STCMSR(uint32_t 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_t 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_t 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_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->mach;
+}
+
+/* STS MACL,Rn */
+void sh2_device::STSMACL(uint32_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->macl;
+}
+
+/* STS PR,Rn */
+void sh2_device::STSPR(uint32_t n)
+{
+ m_sh2_state->r[n] = m_sh2_state->pr;
+}
+
+/* STS.L MACH,@-Rn */
+void sh2_device::STSMMACH(uint32_t 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_t 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_t 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_t m, uint32_t n)
+{
+ m_sh2_state->r[n] -= m_sh2_state->r[m];
+}
+
+/* SUBC Rm,Rn */
+void sh2_device::SUBC(uint32_t m, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ int32_t dest, src, ans;
+
+ if ((int32_t) m_sh2_state->r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) 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_t) 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_t m, uint32_t n)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ uint32_t 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_t n)
+{
+ uint32_t 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_t i)
+{
+ uint32_t 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_t m, uint32_t 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_t i)
+{
+ uint32_t 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_t i)
+{
+ uint32_t 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_t m, uint32_t n)
+{
+ m_sh2_state->r[n] ^= m_sh2_state->r[m];
+}
+
+/* XOR #imm,R0 */
+void sh2_device::XORI(uint32_t i)
+{
+ uint32_t imm = i & 0xff;
+ m_sh2_state->r[0] ^= imm;
+}
+
+/* XOR.B #imm,@(R0,GBR) */
+void sh2_device::XORM(uint32_t i)
+{
+ uint32_t imm = i & 0xff;
+ uint32_t 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_t m, uint32_t n)
+{
+ uint32_t 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_t 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_t opcode)
+{
+ MOVLS4(Rm, opcode & 0x0f, Rn);
+}
+
+void sh2_device::op0010(uint16_t 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_t 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_t 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_t opcode)
+{
+ MOVLL4(Rm, opcode & 0x0f, Rn);
+}
+
+void sh2_device::op0110(uint16_t 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_t opcode)
+{
+ ADDI(opcode & 0xff, Rn);
+}
+
+void sh2_device::op1000(uint16_t 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_t opcode)
+{
+ MOVWI(opcode & 0xff, Rn);
+}
+
+void sh2_device::op1010(uint16_t opcode)
+{
+ BRA(opcode & 0xfff);
+}
+
+void sh2_device::op1011(uint16_t opcode)
+{
+ BSR(opcode & 0xfff);
+}
+
+void sh2_device::op1100(uint16_t 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_t opcode)
+{
+ MOVLI(opcode & 0xff, Rn);
+}
+
+void sh2_device::op1110(uint16_t opcode)
+{
+ MOVI(opcode & 0xff, Rn);
+}
+
+void sh2_device::op1111(uint16_t opcode)
+{
+ ILLEGAL();
+}
+
+/*****************************************************************************
+ * MAME CPU INTERFACE
+ *****************************************************************************/
+
+void sh2_device::device_reset()
+{
+ 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_t opcode;
+
+ debugger_instruction_hook(this, m_sh2_state->pc);
+
+ opcode = m_program->read_word(m_sh2_state->pc & AM);
+
+ if (m_delay)
+ {
+ m_sh2_state->pc = m_delay;
+ m_delay = 0;
+ }
+ else
+ m_sh2_state->pc += 2;
+
+ 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_OPCODES) ? &space(AS_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( STATE_GENPC, "PC", m_sh2_state->pc).mask(AM).callimport();
+ 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_GENPCBASE, "CURPC", m_sh2_state->pc ).callimport().noshow();
+ state_add( STATE_GENSP, "GENSP", m_sh2_state->r[15] ).noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_sh2_state->sr ).formatstr("%6s").noshow();
+
+ m_icountptr = &m_sh2_state->icount;
+
+ // Clear state
+ 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_t flags = 0;
+ m_drcuml = std::make_unique<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 = std::make_unique<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) const
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = string_format("%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 STATE_GENPC:
+ case STATE_GENPCBASE:
+ m_delay = 0;
+ break;
+
+ case SH2_SR:
+ CHECK_PENDING_IRQ("sh2_set_reg");
+ 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 cleared nmi\n");
+ }
+ else
+ {
+ LOG("SH-2 asserted nmi\n");
+
+ 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 cleared irq #%d\n", irqline);
+ m_sh2_state->pending_irq &= ~(1 << irqline);
+ }
+ else
+ {
+ LOG("SH-2 asserted irq #%d\n", 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");
+ }
+ }
+ }
+}
+
+void sh2_device::sh2_exception(const char *message, int irqline)
+{
+ int vector;
+
+ if (irqline != 16)
+ {
+ if (irqline <= ((m_sh2_state->sr >> 4) & 15)) /* If the cpu forbids this interrupt */
+ return;
+
+ // if this is an sh2 internal irq, use its vector
+ if (m_sh2_state->internal_irq_level == irqline)
+ {
+ vector = m_internal_irq_vector;
+ /* avoid spurious irqs with this (TODO: needs a better fix) */
+ m_sh2_state->internal_irq_level = -1;
+ LOG("SH-2 exception #%d (internal vector: $%x) after [%s]\n", irqline, vector, message);
+ }
+ else
+ {
+ if(m_m[0x38] & 0x00010000)
+ {
+ vector = standard_irq_callback(irqline);
+ LOG("SH-2 exception #%d (external vector: $%x) after [%s]\n", irqline, vector, message);
+ }
+ else
+ {
+ standard_irq_callback(irqline);
+ vector = 64 + irqline/2;
+ LOG("SH-2 exception #%d (autovector: $%x) after [%s]\n", irqline, vector, message);
+ }
+ }
+ }
+ else
+ {
+ vector = 11;
+ LOG("SH-2 nmi exception (autovector: $%x) after [%s]\n", vector, message);
+ }
+
+ if (m_isdrc)
+ {
+ m_sh2_state->evec = RL( m_sh2_state->vbr + vector * 4 );
+ m_sh2_state->evec &= AM;
+ m_sh2_state->irqsr = m_sh2_state->sr;
+
+ /* set I flags in SR */
+ if (irqline > SH2_INT_15)
+ m_sh2_state->sr = m_sh2_state->sr | I;
+ else
+ m_sh2_state->sr = (m_sh2_state->sr & ~I) | (irqline << 4);
+
+// printf("sh2_exception [%s] irqline %x evec %x save SR %x new SR %x\n", message, irqline, m_sh2_state->evec, m_sh2_state->irqsr, m_sh2_state->sr);
+ } else {
+ 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 ); /* push PC onto stack */
+
+ /* set I flags in SR */
+ if (irqline > SH2_INT_15)
+ m_sh2_state->sr = m_sh2_state->sr | I;
+ else
+ m_sh2_state->sr = (m_sh2_state->sr & ~I) | (irqline << 4);
+
+ /* fetch PC */
+ m_sh2_state->pc = RL( m_sh2_state->vbr + vector * 4 );
+ }
+
+ if(m_sh2_state->sleep_mode == 1) { m_sh2_state->sleep_mode = 2; }
+}
+
+#include "sh2drc.cpp"
diff --git a/src/devices/cpu/sh/sh2.h b/src/devices/cpu/sh/sh2.h
new file mode 100644
index 00000000000..50ecf680c88
--- /dev/null
+++ b/src/devices/cpu/sh/sh2.h
@@ -0,0 +1,557 @@
+// license:BSD-3-Clause
+// copyright-holders:Juergen Buchmueller
+/*****************************************************************************
+ *
+ * sh2.h
+ * Portable Hitachi SH-2 (SH7600 family) emulator interface
+ *
+ * This work is based on <tiraniddo@hotmail.com> C/C++ implementation of
+ * the SH-2 CPU core and was heavily changed to the MAME CPU requirements.
+ * Thanks also go to Chuck Mason <chukjr@sundail.net> and Olivier Galibert
+ * <galibert@pobox.com> for letting me peek into their SEMU code :-)
+ *
+ *****************************************************************************/
+
+#ifndef MAME_CPU_SH2_SH2_H
+#define MAME_CPU_SH2_SH2_H
+
+#pragma once
+
+#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+
+
+#define SH2_INT_NONE -1
+#define SH2_INT_VBLIN 0
+#define SH2_INT_VBLOUT 1
+#define SH2_INT_HBLIN 2
+#define SH2_INT_TIMER0 3
+#define SH2_INT_TIMER1 4
+#define SH2_INT_DSP 5
+#define SH2_INT_SOUND 6
+#define SH2_INT_SMPC 7
+#define SH2_INT_PAD 8
+#define SH2_INT_DMA2 9
+#define SH2_INT_DMA1 10
+#define SH2_INT_DMA0 11
+#define SH2_INT_DMAILL 12
+#define SH2_INT_SPRITE 13
+#define SH2_INT_14 14
+#define SH2_INT_15 15
+#define SH2_INT_ABUS 16
+
+enum
+{
+ SH2_PC = STATE_GENPC, SH2_SR=1, SH2_PR, SH2_GBR, SH2_VBR, SH2_MACH, SH2_MACL,
+ SH2_R0, SH2_R1, SH2_R2, SH2_R3, SH2_R4, SH2_R5, SH2_R6, SH2_R7,
+ SH2_R8, SH2_R9, SH2_R10, SH2_R11, SH2_R12, SH2_R13, SH2_R14, SH2_R15, SH2_EA
+};
+
+
+#define SH2_DMA_KLUDGE_CB(name) int name(uint32_t src, uint32_t dst, uint32_t data, int size)
+
+#define SH2_DMA_FIFO_DATA_AVAILABLE_CB(name) int name(uint32_t src, uint32_t dst, uint32_t data, int size)
+
+#define SH2_FTCSR_READ_CB(name) void name(uint32_t data)
+
+
+#define MCFG_SH2_IS_SLAVE(_slave) \
+ sh2_device::set_is_slave(*device, _slave);
+
+#define MCFG_SH2_DMA_KLUDGE_CB(_class, _method) \
+ sh2_device::set_dma_kludge_callback(*device, sh2_device::dma_kludge_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
+
+#define MCFG_SH2_FIFO_DATA_AVAIL_CB(_class, _method) \
+ sh2_device::set_dma_fifo_data_available_callback(*device, sh2_device::dma_fifo_data_available_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
+
+#define MCFG_SH2_FTCSR_READ_CB(_class, _method) \
+ sh2_device::set_ftcsr_read_callback(*device, sh2_device::ftcsr_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
+
+
+/***************************************************************************
+ COMPILER-SPECIFIC OPTIONS
+***************************************************************************/
+
+#define SH2DRC_STRICT_VERIFY 0x0001 /* verify all instructions */
+#define SH2DRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */
+#define SH2DRC_STRICT_PCREL 0x0004 /* do actual loads on MOVLI/MOVWI instead of collapsing to immediates */
+
+#define SH2DRC_COMPATIBLE_OPTIONS (SH2DRC_STRICT_VERIFY | SH2DRC_FLUSH_PC | SH2DRC_STRICT_PCREL)
+#define SH2DRC_FASTEST_OPTIONS (0)
+
+#define SH2_MAX_FASTRAM 4
+
+class sh2_frontend;
+
+class sh2_device : public cpu_device
+{
+ friend class sh2_frontend;
+
+public:
+ typedef device_delegate<int (uint32_t src, uint32_t dst, uint32_t data, int size)> dma_kludge_delegate;
+ typedef device_delegate<int (uint32_t src, uint32_t dst, uint32_t data, int size)> dma_fifo_data_available_delegate;
+ typedef device_delegate<void (uint32_t data)> ftcsr_read_delegate;
+
+ // construction/destruction
+ sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ static void set_is_slave(device_t &device, int slave) { downcast<sh2_device &>(device).m_is_slave = slave; }
+ static void set_dma_kludge_callback(device_t &device, dma_kludge_delegate callback) { downcast<sh2_device &>(device).m_dma_kludge_cb = callback; }
+ static void set_dma_fifo_data_available_callback(device_t &device, dma_fifo_data_available_delegate callback) { downcast<sh2_device &>(device).m_dma_fifo_data_available_cb = callback; }
+ static void set_ftcsr_read_callback(device_t &device, ftcsr_read_delegate callback) { downcast<sh2_device &>(device).m_ftcsr_read_cb = callback; }
+
+ DECLARE_WRITE32_MEMBER( sh7604_w );
+ DECLARE_READ32_MEMBER( sh7604_r );
+ DECLARE_READ32_MEMBER(sh2_internal_a5);
+
+ void sh2_set_frt_input(int state);
+ void sh2drc_set_options(uint32_t options);
+ void sh2drc_add_pcflush(offs_t address);
+ void sh2drc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
+
+ void sh2_notify_dma_data_available();
+
+protected:
+ sh2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int cpu_type,address_map_constructor internal_map, int addrlines);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_stop() override;
+
+ // device_execute_interface overrides
+ virtual uint32_t execute_min_cycles() const override { return 1; }
+ virtual uint32_t execute_max_cycles() const override { return 4; }
+ virtual uint32_t execute_input_lines() const override { return 16; }
+ virtual uint32_t execute_default_irq_vector() const override { return 0; }
+ virtual void execute_run() override;
+ virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_state_interface overrides
+ virtual void state_import(const device_state_entry &entry) override;
+ virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+ // device_disasm_interface overrides
+ virtual uint32_t disasm_min_opcode_bytes() const override { return 2; }
+ virtual uint32_t disasm_max_opcode_bytes() const override { return 2; }
+ virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
+ address_space *m_program, *m_decrypted_program;
+
+private:
+ address_space_config m_program_config, m_decrypted_program_config;
+
+ // Data that needs to be stored close to the generated DRC code
+ struct internal_sh2_state
+ {
+ uint32_t pc;
+ uint32_t pr;
+ uint32_t sr;
+ uint32_t gbr;
+ uint32_t vbr;
+ uint32_t mach;
+ uint32_t macl;
+ uint32_t r[16];
+ uint32_t ea;
+ uint32_t pending_irq;
+ uint32_t pending_nmi;
+ int32_t irqline;
+ uint32_t evec; // exception vector for DRC
+ uint32_t irqsr; // IRQ-time old SR for DRC
+ uint32_t target; // target for jmp/jsr/etc so the delay slot can't kill it
+ int internal_irq_level;
+ int icount;
+ uint8_t sleep_mode;
+ uint32_t arg0; /* print_debug argument 1 */
+ };
+
+ uint32_t m_delay;
+ uint32_t m_cpu_off;
+ uint32_t m_dvsr, m_dvdnth, m_dvdntl, m_dvcr;
+ uint32_t m_test_irq;
+ struct
+ {
+ int irq_vector;
+ int irq_priority;
+ } m_irq_queue[16];
+
+ bool m_isdrc;
+
+ int m_pcfsel; // last pcflush entry set
+ int m_maxpcfsel; // highest valid pcflush entry
+ uint32_t m_pcflushes[16]; // pcflush entries
+
+ int8_t m_irq_line_state[17];
+protected:
+ direct_read_data *m_direct;
+private:
+ address_space *m_internal;
+ uint32_t m_m[0x200/4];
+ int8_t m_nmi_line_state;
+
+ uint16_t m_frc;
+ uint16_t m_ocra, m_ocrb, m_icr;
+ uint64_t m_frc_base;
+
+ int m_frt_input;
+ int m_internal_irq_vector;
+
+ emu_timer *m_timer;
+ emu_timer *m_dma_current_active_timer[2];
+ int m_dma_timer_active[2];
+ uint8_t m_dma_irq[2];
+
+ int m_active_dma_incs[2];
+ int m_active_dma_incd[2];
+ int m_active_dma_size[2];
+ int m_active_dma_steal[2];
+ uint32_t m_active_dma_src[2];
+ uint32_t m_active_dma_dst[2];
+ uint32_t m_active_dma_count[2];
+ uint16_t m_wtcnt;
+ uint8_t m_wtcsr;
+
+ int m_is_slave, m_cpu_type;
+ dma_kludge_delegate m_dma_kludge_cb;
+ dma_fifo_data_available_delegate m_dma_fifo_data_available_cb;
+ ftcsr_read_delegate m_ftcsr_read_cb;
+
+ drc_cache m_cache; /* pointer to the DRC code cache */
+ std::unique_ptr<drcuml_state> m_drcuml; /* DRC UML generator state */
+ std::unique_ptr<sh2_frontend> m_drcfe; /* pointer to the DRC front-end state */
+ uint32_t m_drcoptions; /* configurable DRC options */
+
+ internal_sh2_state *m_sh2_state;
+
+ /* internal stuff */
+ uint8_t m_cache_dirty; /* true if we need to flush the cache */
+
+ /* parameters for subroutines */
+ uint64_t m_numcycles; /* return value from gettotalcycles */
+ uint32_t m_arg1; /* print_debug argument 2 */
+ uint32_t m_irq; /* irq we're taking */
+
+ /* register mappings */
+ uml::parameter m_regmap[16]; /* parameter to register mappings for all 16 integer registers */
+
+ uml::code_handle * m_entry; /* entry point */
+ uml::code_handle * m_read8; /* read byte */
+ uml::code_handle * m_write8; /* write byte */
+ uml::code_handle * m_read16; /* read half */
+ uml::code_handle * m_write16; /* write half */
+ uml::code_handle * m_read32; /* read word */
+ uml::code_handle * m_write32; /* write word */
+
+ uml::code_handle * m_interrupt; /* interrupt */
+ uml::code_handle * m_nocode; /* nocode */
+ uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */
+
+ /* fast RAM */
+ uint32_t m_fastram_select;
+ struct
+ {
+ offs_t start; /* start of the RAM block */
+ offs_t end; /* end of the RAM block */
+ bool readonly; /* true if read-only */
+ void * base; /* base in memory where the RAM lives */
+ } m_fastram[SH2_MAX_FASTRAM];
+
+ uint32_t m_debugger_temp;
+
+ inline uint8_t RB(offs_t A);
+ inline uint16_t RW(offs_t A);
+ inline uint32_t RL(offs_t A);
+ inline void WB(offs_t A, uint8_t V);
+ inline void WW(offs_t A, uint16_t V);
+ inline void WL(offs_t A, uint32_t V);
+ inline void ADD(uint32_t m, uint32_t n);
+ inline void ADDI(uint32_t i, uint32_t n);
+ inline void ADDC(uint32_t m, uint32_t n);
+ inline void ADDV(uint32_t m, uint32_t n);
+ inline void AND(uint32_t m, uint32_t n);
+ inline void ANDI(uint32_t i);
+ inline void ANDM(uint32_t i);
+ inline void BF(uint32_t d);
+ inline void BFS(uint32_t d);
+ inline void BRA(uint32_t d);
+ inline void BRAF(uint32_t m);
+ inline void BSR(uint32_t d);
+ inline void BSRF(uint32_t m);
+ inline void BT(uint32_t d);
+ inline void BTS(uint32_t d);
+ inline void CLRMAC();
+ inline void CLRT();
+ inline void CMPEQ(uint32_t m, uint32_t n);
+ inline void CMPGE(uint32_t m, uint32_t n);
+ inline void CMPGT(uint32_t m, uint32_t n);
+ inline void CMPHI(uint32_t m, uint32_t n);
+ inline void CMPHS(uint32_t m, uint32_t n);
+ inline void CMPPL(uint32_t n);
+ inline void CMPPZ(uint32_t n);
+ inline void CMPSTR(uint32_t m, uint32_t n);
+ inline void CMPIM(uint32_t i);
+ inline void DIV0S(uint32_t m, uint32_t n);
+ inline void DIV0U();
+ inline void DIV1(uint32_t m, uint32_t n);
+ inline void DMULS(uint32_t m, uint32_t n);
+ inline void DMULU(uint32_t m, uint32_t n);
+ inline void DT(uint32_t n);
+ inline void EXTSB(uint32_t m, uint32_t n);
+ inline void EXTSW(uint32_t m, uint32_t n);
+ inline void EXTUB(uint32_t m, uint32_t n);
+ inline void EXTUW(uint32_t m, uint32_t n);
+ inline void ILLEGAL();
+ inline void JMP(uint32_t m);
+ inline void JSR(uint32_t m);
+ inline void LDCSR(uint32_t m);
+ inline void LDCGBR(uint32_t m);
+ inline void LDCVBR(uint32_t m);
+ inline void LDCMSR(uint32_t m);
+ inline void LDCMGBR(uint32_t m);
+ inline void LDCMVBR(uint32_t m);
+ inline void LDSMACH(uint32_t m);
+ inline void LDSMACL(uint32_t m);
+ inline void LDSPR(uint32_t m);
+ inline void LDSMMACH(uint32_t m);
+ inline void LDSMMACL(uint32_t m);
+ inline void LDSMPR(uint32_t m);
+ inline void MAC_L(uint32_t m, uint32_t n);
+ inline void MAC_W(uint32_t m, uint32_t n);
+ inline void MOV(uint32_t m, uint32_t n);
+ inline void MOVBS(uint32_t m, uint32_t n);
+ inline void MOVWS(uint32_t m, uint32_t n);
+ inline void MOVLS(uint32_t m, uint32_t n);
+ inline void MOVBL(uint32_t m, uint32_t n);
+ inline void MOVWL(uint32_t m, uint32_t n);
+ inline void MOVLL(uint32_t m, uint32_t n);
+ inline void MOVBM(uint32_t m, uint32_t n);
+ inline void MOVWM(uint32_t m, uint32_t n);
+ inline void MOVLM(uint32_t m, uint32_t n);
+ inline void MOVBP(uint32_t m, uint32_t n);
+ inline void MOVWP(uint32_t m, uint32_t n);
+ inline void MOVLP(uint32_t m, uint32_t n);
+ inline void MOVBS0(uint32_t m, uint32_t n);
+ inline void MOVWS0(uint32_t m, uint32_t n);
+ inline void MOVLS0(uint32_t m, uint32_t n);
+ inline void MOVBL0(uint32_t m, uint32_t n);
+ inline void MOVWL0(uint32_t m, uint32_t n);
+ inline void MOVLL0(uint32_t m, uint32_t n);
+ inline void MOVI(uint32_t i, uint32_t n);
+ inline void MOVWI(uint32_t d, uint32_t n);
+ inline void MOVLI(uint32_t d, uint32_t n);
+ inline void MOVBLG(uint32_t d);
+ inline void MOVWLG(uint32_t d);
+ inline void MOVLLG(uint32_t d);
+ inline void MOVBSG(uint32_t d);
+ inline void MOVWSG(uint32_t d);
+ inline void MOVLSG(uint32_t d);
+ inline void MOVBS4(uint32_t d, uint32_t n);
+ inline void MOVWS4(uint32_t d, uint32_t n);
+ inline void MOVLS4(uint32_t m, uint32_t d, uint32_t n);
+ inline void MOVBL4(uint32_t m, uint32_t d);
+ inline void MOVWL4(uint32_t m, uint32_t d);
+ inline void MOVLL4(uint32_t m, uint32_t d, uint32_t n);
+ inline void MOVA(uint32_t d);
+ inline void MOVT(uint32_t n);
+ inline void MULL(uint32_t m, uint32_t n);
+ inline void MULS(uint32_t m, uint32_t n);
+ inline void MULU(uint32_t m, uint32_t n);
+ inline void NEG(uint32_t m, uint32_t n);
+ inline void NEGC(uint32_t m, uint32_t n);
+ inline void NOP(void);
+ inline void NOT(uint32_t m, uint32_t n);
+ inline void OR(uint32_t m, uint32_t n);
+ inline void ORI(uint32_t i);
+ inline void ORM(uint32_t i);
+ inline void ROTCL(uint32_t n);
+ inline void ROTCR(uint32_t n);
+ inline void ROTL(uint32_t n);
+ inline void ROTR(uint32_t n);
+ inline void RTE();
+ inline void RTS();
+ inline void SETT();
+ inline void SHAL(uint32_t n);
+ inline void SHAR(uint32_t n);
+ inline void SHLL(uint32_t n);
+ inline void SHLL2(uint32_t n);
+ inline void SHLL8(uint32_t n);
+ inline void SHLL16(uint32_t n);
+ inline void SHLR(uint32_t n);
+ inline void SHLR2(uint32_t n);
+ inline void SHLR8(uint32_t n);
+ inline void SHLR16(uint32_t n);
+ inline void SLEEP();
+ inline void STCSR(uint32_t n);
+ inline void STCGBR(uint32_t n);
+ inline void STCVBR(uint32_t n);
+ inline void STCMSR(uint32_t n);
+ inline void STCMGBR(uint32_t n);
+ inline void STCMVBR(uint32_t n);
+ inline void STSMACH(uint32_t n);
+ inline void STSMACL(uint32_t n);
+ inline void STSPR(uint32_t n);
+ inline void STSMMACH(uint32_t n);
+ inline void STSMMACL(uint32_t n);
+ inline void STSMPR(uint32_t n);
+ inline void SUB(uint32_t m, uint32_t n);
+ inline void SUBC(uint32_t m, uint32_t n);
+ inline void SUBV(uint32_t m, uint32_t n);
+ inline void SWAPB(uint32_t m, uint32_t n);
+ inline void SWAPW(uint32_t m, uint32_t n);
+ inline void TAS(uint32_t n);
+ inline void TRAPA(uint32_t i);
+ inline void TST(uint32_t m, uint32_t n);
+ inline void TSTI(uint32_t i);
+ inline void TSTM(uint32_t i);
+ inline void XOR(uint32_t m, uint32_t n);
+ inline void XORI(uint32_t i);
+ inline void XORM(uint32_t i);
+ inline void XTRCT(uint32_t m, uint32_t n);
+ inline void op0000(uint16_t opcode);
+ inline void op0001(uint16_t opcode);
+ inline void op0010(uint16_t opcode);
+ inline void op0011(uint16_t opcode);
+ inline void op0100(uint16_t opcode);
+ inline void op0101(uint16_t opcode);
+ inline void op0110(uint16_t opcode);
+ inline void op0111(uint16_t opcode);
+ inline void op1000(uint16_t opcode);
+ inline void op1001(uint16_t opcode);
+ inline void op1010(uint16_t opcode);
+ inline void op1011(uint16_t opcode);
+ inline void op1100(uint16_t opcode);
+ inline void op1101(uint16_t opcode);
+ inline void op1110(uint16_t opcode);
+ inline void op1111(uint16_t opcode);
+ TIMER_CALLBACK_MEMBER( sh2_timer_callback );
+ TIMER_CALLBACK_MEMBER( sh2_dma_current_active_callback );
+ void sh2_timer_resync();
+ void sh2_timer_activate();
+ void sh2_do_dma(int dma);
+ void sh2_exception(const char *message, int irqline);
+ void sh2_dmac_check(int dma);
+ void sh2_recalc_irq();
+
+ /* internal compiler state */
+ struct compiler_state
+ {
+ uint32_t cycles; /* accumulated cycles */
+ uint8_t checkints; /* need to check interrupts before next instruction */
+ uml::code_label labelnum; /* index for local labels */
+ };
+
+ inline uint32_t epc(const opcode_desc *desc);
+ inline void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name);
+ inline void load_fast_iregs(drcuml_block *block);
+ inline void save_fast_iregs(drcuml_block *block);
+
+ void code_flush_cache();
+ void execute_run_drc();
+ void code_compile_block(uint8_t mode, offs_t pc);
+ void static_generate_entry_point();
+ void static_generate_nocode_handler();
+ void static_generate_out_of_cycles();
+ void static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle **handleptr);
+ const char *log_desc_flags_to_string(uint32_t flags);
+ void log_register_list(drcuml_state *drcuml, const char *string, const uint32_t *reglist, const uint32_t *regnostarlist);
+ void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent);
+ void log_add_disasm_comment(drcuml_block *block, uint32_t pc, uint32_t op);
+ void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, bool allow_exception);
+ void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
+ void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc);
+ void generate_delay_slot(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc);
+ bool generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc);
+ bool generate_group_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
+ bool generate_group_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
+ bool generate_group_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, uint32_t ovrpc);
+ bool generate_group_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
+ bool generate_group_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
+ bool generate_group_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
+ bool generate_group_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
+
+public:
+ void func_printf_probe();
+ void func_unimplemented();
+ void func_fastirq();
+ void func_MAC_W();
+ void func_MAC_L();
+ void func_DIV1();
+ void func_ADDV();
+ void func_SUBV();
+};
+
+class sh2a_device : public sh2_device
+{
+public:
+ // construction/destruction
+ sh2a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_READ32_MEMBER(dma_sar0_r);
+ DECLARE_WRITE32_MEMBER(dma_sar0_w);
+ DECLARE_READ32_MEMBER(dma_dar0_r);
+ DECLARE_WRITE32_MEMBER(dma_dar0_w);
+ DECLARE_READ16_MEMBER(dmaor_r);
+ DECLARE_WRITE16_MEMBER(dmaor_w);
+ DECLARE_READ16_MEMBER(dma_tcr0_r);
+ DECLARE_WRITE16_MEMBER(dma_tcr0_w);
+ DECLARE_READ16_MEMBER(dma_chcr0_r);
+ DECLARE_WRITE16_MEMBER(dma_chcr0_w);
+ DECLARE_READ16_MEMBER(sh7021_r);
+ DECLARE_WRITE16_MEMBER(sh7021_w);
+ void sh7032_dma_exec(int ch);
+
+private:
+ uint16_t m_sh7021_regs[0x200];
+ struct
+ {
+ uint32_t sar; /**< Source Address Register */
+ uint32_t dar; /**< Destination Address Register */
+ uint16_t tcr; /**< Transfer Count Register */
+ uint16_t chcr; /**< Channel Control Register */
+ } m_dma[4];
+ uint16_t m_dmaor; /**< DMA Operation Register (status flags) */
+
+};
+
+class sh1_device : public sh2_device
+{
+public:
+ // construction/destruction
+ sh1_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t _clock);
+
+ DECLARE_READ16_MEMBER(sh7032_r);
+ DECLARE_WRITE16_MEMBER(sh7032_w);
+private:
+ uint16_t m_sh7032_regs[0x200];
+};
+
+
+class sh2_frontend : public drc_frontend
+{
+public:
+ sh2_frontend(sh2_device *device, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
+
+protected:
+ virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override;
+
+private:
+ bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+
+ sh2_device *m_sh2;
+};
+
+
+DECLARE_DEVICE_TYPE(SH1, sh1_device)
+DECLARE_DEVICE_TYPE(SH2, sh2_device)
+DECLARE_DEVICE_TYPE(SH2A, sh2a_device)
+
+
+#endif // MAME_CPU_SH2_SH2_H
diff --git a/src/devices/cpu/sh/sh2comn.cpp b/src/devices/cpu/sh/sh2comn.cpp
new file mode 100644
index 00000000000..b6ac0e1cc65
--- /dev/null
+++ b/src/devices/cpu/sh/sh2comn.cpp
@@ -0,0 +1,946 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*****************************************************************************
+ *
+ * sh2common.c
+ *
+ * SH-2 non-specific components
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "sh2.h"
+#include "sh2comn.h"
+
+#include "debugger.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+static const int div_tab[4] = { 3, 5, 7, 0 };
+
+
+void sh2_device::sh2_timer_resync()
+{
+ int divider = div_tab[(m_m[5] >> 8) & 3];
+ uint64_t cur_time = total_cycles();
+ uint64_t add = (cur_time - m_frc_base) >> divider;
+
+ if (add > 0)
+ {
+ if(divider)
+ m_frc += add;
+
+ m_frc_base = cur_time;
+ }
+}
+
+void sh2_device::sh2_timer_activate()
+{
+ int max_delta = 0xfffff;
+ uint16_t frc;
+
+ m_timer->adjust(attotime::never);
+
+ frc = m_frc;
+ if(!(m_m[4] & OCFA)) {
+ uint16_t delta = m_ocra - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(!(m_m[4] & OCFB) && (m_ocra <= m_ocrb || !(m_m[4] & 0x010000))) {
+ uint16_t delta = m_ocrb - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(!(m_m[4] & OVF) && !(m_m[4] & 0x010000)) {
+ int delta = 0x10000 - frc;
+ if(delta < max_delta)
+ max_delta = delta;
+ }
+
+ if(max_delta != 0xfffff) {
+ int divider = div_tab[(m_m[5] >> 8) & 3];
+ if(divider) {
+ max_delta <<= divider;
+ m_frc_base = total_cycles();
+ m_timer->adjust(cycles_to_attotime(max_delta));
+ } else {
+ logerror("SH2.%s: Timer event in %d cycles of external clock", tag(), max_delta);
+ }
+ }
+}
+
+TIMER_CALLBACK_MEMBER( sh2_device::sh2_timer_callback )
+{
+ uint16_t frc;
+
+ sh2_timer_resync();
+
+ frc = m_frc;
+
+ if(frc == m_ocrb)
+ m_m[4] |= OCFB;
+
+ if(frc == 0x0000)
+ m_m[4] |= OVF;
+
+ if(frc == m_ocra)
+ {
+ m_m[4] |= OCFA;
+
+ if(m_m[4] & 0x010000)
+ m_frc = 0;
+ }
+
+ sh2_recalc_irq();
+ sh2_timer_activate();
+}
+
+
+/*
+ We have to do DMA on a timer (or at least, in chunks) due to the way some systems use it.
+ The 32x is a difficult case, they set the SOURCE of the DMA to a FIFO buffer, which at most
+ can have 8 words in it. Attempting to do an 'instant DMA' in this scenario is impossible
+ because the game is expecting the 68k of the system to feed data into the FIFO at the same
+ time as the SH2 is transfering it out via DMA
+
+ There are two ways we can do this
+
+ a) with a high frequency timer (more accurate, but a large performance hit)
+
+ or
+
+ b) in the CPU_EXECUTE loop
+
+
+ we're currently doing a)
+
+ b) causes problems with ST-V games
+
+*/
+
+
+
+void sh2_device::sh2_notify_dma_data_available()
+{
+ //printf("call notify\n");
+
+ for (int dma=0;dma<2;dma++)
+ {
+ //printf("m_dma_timer_active[dma] %04x\n",m_dma_timer_active[dma]);
+
+ if (m_dma_timer_active[dma]==2) // 2 = stalled
+ {
+ // printf("resuming stalled dma\n");
+ m_dma_timer_active[dma]=1;
+ m_dma_current_active_timer[dma]->adjust(attotime::zero, dma);
+ }
+ }
+
+}
+
+void sh2_device::sh2_do_dma(int dma)
+{
+ uint32_t dmadata;
+
+ uint32_t tempsrc, tempdst;
+
+ if (m_active_dma_count[dma] > 0)
+ {
+ // process current DMA
+ switch(m_active_dma_size[dma])
+ {
+ case 0:
+ {
+ // we need to know the src / dest ahead of time without changing them
+ // to allow for the callback to check if we can process the DMA at this
+ // time (we need to know where we're reading / writing to/from)
+
+ if(m_active_dma_incs[dma] == 2)
+ tempsrc = m_active_dma_src[dma] - 1;
+ else
+ tempsrc = m_active_dma_src[dma];
+
+ if(m_active_dma_incd[dma] == 2)
+ tempdst = m_active_dma_dst[dma] - 1;
+ else
+ tempdst = m_active_dma_dst[dma];
+
+ if (!m_dma_fifo_data_available_cb.isnull())
+ {
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+
+ if (!available)
+ {
+ //printf("dma stalled\n");
+ m_dma_timer_active[dma]=2;// mark as stalled
+ return;
+ }
+ }
+
+ #ifdef USE_TIMER_FOR_DMA
+ //schedule next DMA callback
+ m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ #endif
+
+
+ dmadata = m_program->read_byte(tempsrc);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_byte(tempdst, dmadata);
+
+ if(m_active_dma_incs[dma] == 2)
+ m_active_dma_src[dma] --;
+ if(m_active_dma_incd[dma] == 2)
+ m_active_dma_dst[dma] --;
+
+
+ if(m_active_dma_incs[dma] == 1)
+ m_active_dma_src[dma] ++;
+ if(m_active_dma_incd[dma] == 1)
+ m_active_dma_dst[dma] ++;
+
+ m_active_dma_count[dma] --;
+ }
+ break;
+ case 1:
+ {
+ if(m_active_dma_incs[dma] == 2)
+ tempsrc = m_active_dma_src[dma] - 2;
+ else
+ tempsrc = m_active_dma_src[dma];
+
+ if(m_active_dma_incd[dma] == 2)
+ tempdst = m_active_dma_dst[dma] - 2;
+ else
+ tempdst = m_active_dma_dst[dma];
+
+ if (!m_dma_fifo_data_available_cb.isnull())
+ {
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+
+ if (!available)
+ {
+ //printf("dma stalled\n");
+ m_dma_timer_active[dma]=2;// mark as stalled
+ return;
+ }
+ }
+
+ #ifdef USE_TIMER_FOR_DMA
+ //schedule next DMA callback
+ m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ #endif
+
+ // check: should this really be using read_word_32 / write_word_32?
+ dmadata = m_program->read_word(tempsrc);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_word(tempdst, dmadata);
+
+ if(m_active_dma_incs[dma] == 2)
+ m_active_dma_src[dma] -= 2;
+ if(m_active_dma_incd[dma] == 2)
+ m_active_dma_dst[dma] -= 2;
+
+ if(m_active_dma_incs[dma] == 1)
+ m_active_dma_src[dma] += 2;
+ if(m_active_dma_incd[dma] == 1)
+ m_active_dma_dst[dma] += 2;
+
+ m_active_dma_count[dma] --;
+ }
+ break;
+ case 2:
+ {
+ if(m_active_dma_incs[dma] == 2)
+ tempsrc = m_active_dma_src[dma] - 4;
+ else
+ tempsrc = m_active_dma_src[dma];
+
+ if(m_active_dma_incd[dma] == 2)
+ tempdst = m_active_dma_dst[dma] - 4;
+ else
+ tempdst = m_active_dma_dst[dma];
+
+ if (!m_dma_fifo_data_available_cb.isnull())
+ {
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+
+ if (!available)
+ {
+ //printf("dma stalled\n");
+ m_dma_timer_active[dma]=2;// mark as stalled
+ return;
+ }
+ }
+
+ #ifdef USE_TIMER_FOR_DMA
+ //schedule next DMA callback
+ m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ #endif
+
+ dmadata = m_program->read_dword(tempsrc);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_dword(tempdst, dmadata);
+
+ if(m_active_dma_incs[dma] == 2)
+ m_active_dma_src[dma] -= 4;
+ if(m_active_dma_incd[dma] == 2)
+ m_active_dma_dst[dma] -= 4;
+
+ if(m_active_dma_incs[dma] == 1)
+ m_active_dma_src[dma] += 4;
+ if(m_active_dma_incd[dma] == 1)
+ m_active_dma_dst[dma] += 4;
+
+ m_active_dma_count[dma] --;
+ }
+ break;
+ case 3:
+ {
+ // shouldn't this really be 4 calls here instead?
+
+ tempsrc = m_active_dma_src[dma];
+
+ if(m_active_dma_incd[dma] == 2)
+ tempdst = m_active_dma_dst[dma] - 16;
+ else
+ tempdst = m_active_dma_dst[dma];
+
+ if (!m_dma_fifo_data_available_cb.isnull())
+ {
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+
+ if (!available)
+ {
+ //printf("dma stalled\n");
+ m_dma_timer_active[dma]=2;// mark as stalled
+ fatalerror("SH2 dma_callback_fifo_data_available == 0 in unsupported mode\n");
+ }
+ }
+
+ #ifdef USE_TIMER_FOR_DMA
+ //schedule next DMA callback
+ m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ #endif
+
+ dmadata = m_program->read_dword(tempsrc);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_dword(tempdst, dmadata);
+
+ dmadata = m_program->read_dword(tempsrc+4);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_dword(tempdst+4, dmadata);
+
+ dmadata = m_program->read_dword(tempsrc+8);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_dword(tempdst+8, dmadata);
+
+ dmadata = m_program->read_dword(tempsrc+12);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ m_program->write_dword(tempdst+12, dmadata);
+
+ if(m_active_dma_incd[dma] == 2)
+ m_active_dma_dst[dma] -= 16;
+
+ m_active_dma_src[dma] += 16;
+ if(m_active_dma_incd[dma] == 1)
+ m_active_dma_dst[dma] += 16;
+
+ m_active_dma_count[dma]-=4;
+ }
+ break;
+ }
+ }
+ else // the dma is complete
+ {
+ // int dma = param & 1;
+
+ // fever soccer uses cycle-stealing mode, resume the CPU now DMA has finished
+ if (m_active_dma_steal[dma])
+ {
+ resume(SUSPEND_REASON_HALT );
+ }
+
+
+ LOG("SH2: DMA %d complete\n", dma);
+ m_m[0x62+4*dma] = 0;
+ m_m[0x63+4*dma] |= 2;
+ m_dma_timer_active[dma] = 0;
+ m_dma_irq[dma] |= 1;
+ sh2_recalc_irq();
+
+ }
+}
+
+TIMER_CALLBACK_MEMBER( sh2_device::sh2_dma_current_active_callback )
+{
+ int dma = param & 1;
+
+ sh2_do_dma(dma);
+}
+
+
+void sh2_device::sh2_dmac_check(int dma)
+{
+ if(m_m[0x63+4*dma] & m_m[0x6c] & 1)
+ {
+ if(!m_dma_timer_active[dma] && !(m_m[0x63+4*dma] & 2))
+ {
+ m_active_dma_incd[dma] = (m_m[0x63+4*dma] >> 14) & 3;
+ m_active_dma_incs[dma] = (m_m[0x63+4*dma] >> 12) & 3;
+ m_active_dma_size[dma] = (m_m[0x63+4*dma] >> 10) & 3;
+ m_active_dma_steal[dma] = (m_m[0x63+4*dma] &0x10);
+
+ if(m_active_dma_incd[dma] == 3 || m_active_dma_incs[dma] == 3)
+ {
+ logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", m_active_dma_incd[dma], m_active_dma_incs[dma], m_active_dma_size[dma], m_m[0x63+4*dma]);
+ return;
+ }
+ m_active_dma_src[dma] = m_m[0x60+4*dma];
+ m_active_dma_dst[dma] = m_m[0x61+4*dma];
+ m_active_dma_count[dma] = m_m[0x62+4*dma];
+ if(!m_active_dma_count[dma])
+ m_active_dma_count[dma] = 0x1000000;
+
+ LOG("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, m_active_dma_src[dma], m_active_dma_dst[dma], m_active_dma_count[dma], m_m[0x63+4*dma], m_active_dma_incs[dma], m_active_dma_incd[dma], m_active_dma_size[dma]);
+
+ m_dma_timer_active[dma] = 1;
+
+ m_active_dma_src[dma] &= AM;
+ m_active_dma_dst[dma] &= AM;
+
+ switch(m_active_dma_size[dma])
+ {
+ case 0:
+ break;
+ case 1:
+ m_active_dma_src[dma] &= ~1;
+ m_active_dma_dst[dma] &= ~1;
+ break;
+ case 2:
+ m_active_dma_src[dma] &= ~3;
+ m_active_dma_dst[dma] &= ~3;
+ break;
+ case 3:
+ m_active_dma_src[dma] &= ~3;
+ m_active_dma_dst[dma] &= ~3;
+ m_active_dma_count[dma] &= ~3;
+ break;
+ }
+
+
+
+
+#ifdef USE_TIMER_FOR_DMA
+ // start DMA timer
+
+ // fever soccer uses cycle-stealing mode, requiring the CPU to be halted
+ if (m_active_dma_steal[dma])
+ {
+ //printf("cycle stealing DMA\n");
+ suspend(SUSPEND_REASON_HALT, 1 );
+ }
+
+ m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+#endif
+
+ }
+ }
+ else
+ {
+ if(m_dma_timer_active[dma])
+ {
+ logerror("SH2: DMA %d cancelled in-flight\n", dma);
+ //m_dma_complete_timer[dma]->adjust(attotime::never);
+ m_dma_current_active_timer[dma]->adjust(attotime::never);
+
+ m_dma_timer_active[dma] = 0;
+ }
+ }
+}
+
+
+WRITE32_MEMBER( sh2_device::sh7604_w )
+{
+ uint32_t old;
+
+ old = m_m[offset];
+ COMBINE_DATA(m_m+offset);
+
+ // if(offset != 0x20)
+ // logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask);
+
+// if(offset != 0x20)
+// printf("sh2_internal_w: Write %08x (%x), %08x @ %08x (PC %x)\n", 0xfffffe00+offset*4, offset, data, mem_mask, space.device().safe_pc());
+
+ switch( offset )
+ {
+ case 0x00:
+ //if(mem_mask == 0xff)
+ // printf("%c",data & 0xff);
+ break;
+ case 0x01:
+ //printf("%08x %02x %02x\n",mem_mask,offset,data);
+ break;
+ // Timers
+ case 0x04: // TIER, FTCSR, FRC
+ if((mem_mask & 0x00ffffff) != 0)
+ {
+ sh2_timer_resync();
+ }
+// printf("SH2.%s: TIER write %04x @ %04x\n", m_device->tag(), data >> 16, mem_mask>>16);
+ m_m[4] = (m_m[4] & ~(ICF|OCFA|OCFB|OVF)) | (old & m_m[4] & (ICF|OCFA|OCFB|OVF));
+ COMBINE_DATA(&m_frc);
+ if((mem_mask & 0x00ffffff) != 0)
+ sh2_timer_activate();
+ sh2_recalc_irq();
+ break;
+ case 0x05: // OCRx, TCR, TOCR
+// printf("SH2.%s: TCR write %08x @ %08x\n", m_device->tag(), data, mem_mask);
+ sh2_timer_resync();
+ if(m_m[5] & 0x10)
+ m_ocrb = (m_ocrb & (~mem_mask >> 16)) | ((data & mem_mask) >> 16);
+ else
+ m_ocra = (m_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
+ if((m_m[0x20] & 0xff000000) == 0x5a000000)
+ m_wtcnt = (m_m[0x20] >> 16) & 0xff;
+
+ if((m_m[0x20] & 0xff000000) == 0xa5000000)
+ {
+ /*
+ WTCSR
+ x--- ---- Overflow in IT mode
+ -x-- ---- Timer mode (0: IT 1: watchdog)
+ --x- ---- Timer enable
+ ---1 1---
+ ---- -xxx Clock select
+ */
+
+ m_wtcsr = (m_m[0x20] >> 16) & 0xff;
+ }
+
+ if((m_m[0x20] & 0x0000ff00) == 0x00005a00)
+ {
+ // -x-- ---- RSTE (1: resets wtcnt when overflows 0: no reset)
+ // --x- ---- RSTS (0: power-on reset 1: Manual reset)
+ // ...
+ }
+
+ if((m_m[0x20] & 0x0000ff00) == 0x0000a500)
+ {
+ // clear WOVF
+ // ...
+ }
+
+
+
+ break;
+
+ // Standby and cache
+ case 0x24: // SBYCR, CCR
+ /*
+ CCR
+ xx-- ---- ---- ---- Way 0/1
+ ---x ---- ---- ---- Cache Purge (CP)
+ ---- x--- ---- ---- Two-Way Mode (TW)
+ ---- -x-- ---- ---- Data Replacement Disable (OD)
+ ---- --x- ---- ---- Instruction Replacement Disable (ID)
+ ---- ---x ---- ---- Cache Enable (CE)
+ */
+ break;
+
+ // Interrupt vectors cont.
+ case 0x38: // ICR, IRPA
+ break;
+ case 0x39: // VCRWDT
+ break;
+
+ // Division box
+ case 0x40: // DVSR
+ break;
+ case 0x41: // DVDNT
+ {
+ int32_t a = m_m[0x41];
+ int32_t b = m_m[0x40];
+ LOG("SH2 div+mod %d/%d\n", a, b);
+ if (b)
+ {
+ m_m[0x45] = a / b;
+ m_m[0x44] = a % b;
+ }
+ else
+ {
+ m_m[0x42] |= 0x00010000;
+ m_m[0x45] = 0x7fffffff;
+ m_m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ break;
+ }
+ case 0x42: // DVCR
+ m_m[0x42] = (m_m[0x42] & ~0x00001000) | (old & m_m[0x42] & 0x00010000);
+ sh2_recalc_irq();
+ break;
+ case 0x43: // VCRDIV
+ sh2_recalc_irq();
+ break;
+ case 0x44: // DVDNTH
+ break;
+ case 0x45: // DVDNTL
+ {
+ int64_t a = m_m[0x45] | ((uint64_t)(m_m[0x44]) << 32);
+ int64_t b = (int32_t)m_m[0x40];
+ LOG("SH2 div+mod %d/%d\n", a, b);
+ if (b)
+ {
+ int64_t q = a / b;
+ if (q != (int32_t)q)
+ {
+ m_m[0x42] |= 0x00010000;
+ m_m[0x45] = 0x7fffffff;
+ m_m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ else
+ {
+ m_m[0x45] = q;
+ m_m[0x44] = a % b;
+ }
+ }
+ else
+ {
+ m_m[0x42] |= 0x00010000;
+ m_m[0x45] = 0x7fffffff;
+ m_m[0x44] = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ break;
+ }
+
+ // DMA controller
+ case 0x60: // SAR0
+ case 0x61: // DAR0
+ break;
+ case 0x62: // DTCR0
+ m_m[0x62] &= 0xffffff;
+ break;
+ case 0x63: // CHCR0
+ m_m[0x63] = (m_m[0x63] & ~2) | (old & m_m[0x63] & 2);
+ sh2_dmac_check(0);
+ break;
+ case 0x64: // SAR1
+ case 0x65: // DAR1
+ break;
+ case 0x66: // DTCR1
+ m_m[0x66] &= 0xffffff;
+ break;
+ case 0x67: // CHCR1
+ m_m[0x67] = (m_m[0x67] & ~2) | (old & m_m[0x67] & 2);
+ sh2_dmac_check(1);
+ break;
+ case 0x68: // VCRDMA0
+ case 0x6a: // VCRDMA1
+ sh2_recalc_irq();
+ break;
+ case 0x6c: // DMAOR
+ m_m[0x6c] = (m_m[0x6c] & ~6) | (old & m_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_MEMBER( sh2_device::sh7604_r )
+{
+// logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask);
+ switch( offset )
+ {
+ case 0x00:
+ break;
+ case 0x01:
+// return m_m[1] | 0; // bit31 is TDRE: Trasmit Data Register Empty. Forcing it to be '1' breaks Saturn ...
+ return m_m[1] | (0x84 << 24); // ... but this is actually needed to make EGWord on SS to boot?
+
+ case 0x04: // TIER, FTCSR, FRC
+ if ( mem_mask == 0x00ff0000 )
+ {
+ if (!m_ftcsr_read_cb.isnull())
+ {
+ m_ftcsr_read_cb((m_m[4] & 0xffff0000) | m_frc);
+ }
+ }
+ sh2_timer_resync();
+ return (m_m[4] & 0xffff0000) | m_frc;
+ case 0x05: // OCRx, TCR, TOCR
+ if(m_m[5] & 0x10)
+ return (m_ocrb << 16) | (m_m[5] & 0xffff);
+ else
+ return (m_ocra << 16) | (m_m[5] & 0xffff);
+ case 0x06: // ICR
+ return m_icr << 16;
+
+ case 0x20:
+ return (((m_wtcsr | 0x18) & 0xff) << 24) | ((m_wtcnt & 0xff) << 16);
+
+ case 0x24: // SBYCR, CCR
+ return m_m[0x24] & ~0x3000; /* bit 4-5 of CCR are always zero */
+
+ case 0x38: // ICR, IPRA
+ return (m_m[0x38] & 0x7fffffff) | (m_nmi_line_state == ASSERT_LINE ? 0 : 0x80000000);
+
+ case 0x78: // BCR1
+ return (m_is_slave ? 0x00008000 : 0) | (m_m[0x78] & 0x7fff);
+
+ case 0x41: // dvdntl mirrors
+ case 0x47:
+ return m_m[0x45];
+
+ case 0x46: // dvdnth mirror
+ return m_m[0x44];
+ }
+ return m_m[offset];
+}
+
+void sh2_device::sh2_set_frt_input(int state)
+{
+ if(state == PULSE_LINE)
+ {
+ sh2_set_frt_input(ASSERT_LINE);
+ sh2_set_frt_input(CLEAR_LINE);
+ return;
+ }
+
+ if(m_frt_input == state) {
+ return;
+ }
+
+ m_frt_input = state;
+
+ if(m_m[5] & 0x8000) {
+ if(state == CLEAR_LINE) {
+ return;
+ }
+ } else {
+ if(state == ASSERT_LINE) {
+ return;
+ }
+ }
+
+ sh2_timer_resync();
+ m_icr = m_frc;
+ m_m[4] |= ICF;
+ //logerror("SH2.%s: ICF activated (%x)\n", tag(), m_sh2_state->pc & AM);
+ sh2_recalc_irq();
+}
+
+void sh2_device::sh2_recalc_irq()
+{
+ int irq = 0, vector = -1;
+ int level;
+
+ // Timer irqs
+ if((m_m[4]>>8) & m_m[4] & (ICF|OCFA|OCFB|OVF))
+ {
+ level = (m_m[0x18] >> 24) & 15;
+ if(level > irq)
+ {
+ int mask = (m_m[4]>>8) & m_m[4];
+ irq = level;
+ if(mask & ICF)
+ vector = (m_m[0x19] >> 8) & 0x7f;
+ else if(mask & (OCFA|OCFB))
+ vector = m_m[0x19] & 0x7f;
+ else
+ vector = (m_m[0x1a] >> 24) & 0x7f;
+ }
+ }
+
+ // DMA irqs
+ if((m_m[0x63] & 6) == 6 && m_dma_irq[0]) {
+ level = (m_m[0x38] >> 8) & 15;
+ if(level > irq) {
+ irq = level;
+ m_dma_irq[0] &= ~1;
+ vector = (m_m[0x68]) & 0x7f;
+ }
+ }
+ else if((m_m[0x67] & 6) == 6 && m_dma_irq[1]) {
+ level = (m_m[0x38] >> 8) & 15;
+ if(level > irq) {
+ irq = level;
+ m_dma_irq[1] &= ~1;
+ vector = (m_m[0x6a]) & 0x7f;
+ }
+ }
+
+ m_sh2_state->internal_irq_level = irq;
+ m_internal_irq_vector = vector;
+ m_test_irq = 1;
+}
+
+/*
+ SH-7021 on-chip device
+ */
+
+void sh2a_device::sh7032_dma_exec(int ch)
+{
+ const short dma_word_size[4] = { 0, +1, -1, 0 };
+ uint8_t rs = (m_dma[ch].chcr >> 8) & 0xf; /**< Resource Select bits */
+ if(rs != 0xc) // Auto-Request
+ {
+ logerror("Warning: SH7032 DMA enables non auto-request transfer\n");
+ return;
+ }
+
+ // channel enable & master enable
+ if((m_dma[ch].chcr & 1) == 0 || (m_dmaor & 1) == 0)
+ return;
+
+ printf("%08x %08x %04x\n",m_dma[ch].sar,m_dma[ch].dar,m_dma[ch].chcr);
+ uint8_t dm = (m_dma[ch].chcr >> 14) & 3; /**< Destination Address Mode bits */
+ uint8_t sm = (m_dma[ch].chcr >> 12) & 3; /**< Source Address Mode bits */
+ bool ts = (m_dma[ch].chcr & 8); /**< Transfer Size bit */
+ int src_word_size = dma_word_size[sm] * ((ts == true) ? 2 : 1);
+ int dst_word_size = dma_word_size[dm] * ((ts == true) ? 2 : 1);
+ uint32_t src_addr = m_dma[ch].sar;
+ uint32_t dst_addr = m_dma[ch].dar;
+ uint32_t size_index = m_dma[ch].tcr;
+ if(size_index == 0)
+ size_index = 0x10000;
+
+ if(ts == false)
+ logerror("SH7032: DMA byte mode check\n");
+
+ for(int index = size_index;index>-1;index--)
+ {
+ if(ts == true)
+ m_program->write_word(dst_addr,m_program->read_word(src_addr));
+ else
+ m_program->write_byte(dst_addr,m_program->read_byte(src_addr));
+
+ src_addr += src_word_size;
+ dst_addr += dst_word_size;
+ }
+
+ m_dma[ch].chcr &= ~1; /**< @todo non-instant DMA */
+ printf("%02x %02x %02x %1d\n",sm,dm,rs,ts);
+}
+
+READ32_MEMBER(sh2a_device::dma_sar0_r)
+{
+ return m_dma[0].sar;
+}
+
+WRITE32_MEMBER(sh2a_device::dma_sar0_w)
+{
+ COMBINE_DATA(&m_dma[0].sar);
+}
+
+READ32_MEMBER(sh2a_device::dma_dar0_r)
+{
+ return m_dma[0].dar;
+}
+
+WRITE32_MEMBER(sh2a_device::dma_dar0_w)
+{
+ COMBINE_DATA(&m_dma[0].dar);
+}
+
+READ16_MEMBER(sh2a_device::dma_tcr0_r)
+{
+ return m_dma[0].tcr;
+}
+
+WRITE16_MEMBER(sh2a_device::dma_tcr0_w)
+{
+ //printf("%04x\n",data);
+ COMBINE_DATA(&m_dma[0].tcr);
+}
+
+READ16_MEMBER(sh2a_device::dma_chcr0_r)
+{
+ return m_dma[0].chcr;
+}
+
+WRITE16_MEMBER(sh2a_device::dma_chcr0_w)
+{
+ //printf("%04x CHCR0\n",data);
+ COMBINE_DATA(&m_dma[0].chcr);
+ sh7032_dma_exec(0);
+}
+
+READ16_MEMBER(sh2a_device::dmaor_r)
+{
+ return m_dmaor;
+}
+
+WRITE16_MEMBER(sh2a_device::dmaor_w)
+{
+ COMBINE_DATA(&m_dmaor);
+ sh7032_dma_exec(0);
+}
+
+/*!
+ @brief Dummy debug interface
+ */
+READ16_MEMBER(sh1_device::sh7032_r)
+{
+ return m_sh7032_regs[offset];
+}
+
+/*!
+ @brief Dummy debug interface
+ */
+WRITE16_MEMBER(sh1_device::sh7032_w)
+{
+ COMBINE_DATA(&m_sh7032_regs[offset]);
+}
+
+READ16_MEMBER(sh2a_device::sh7021_r)
+{
+ return m_sh7021_regs[offset];
+}
+
+/*!
+ @brief Dummy debug interface
+ */
+WRITE16_MEMBER(sh2a_device::sh7021_w)
+{
+ COMBINE_DATA(&m_sh7021_regs[offset]);
+}
diff --git a/src/devices/cpu/sh/sh2comn.h b/src/devices/cpu/sh/sh2comn.h
new file mode 100644
index 00000000000..1c859e227d6
--- /dev/null
+++ b/src/devices/cpu/sh/sh2comn.h
@@ -0,0 +1,85 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*****************************************************************************
+ *
+ * sh2common.h
+ *
+ * SH-2 non-specific components
+ *
+ *****************************************************************************/
+
+#ifndef MAME_CPU_SH2_SH2COMN_H
+#define MAME_CPU_SH2_SH2COMN_H
+
+#pragma once
+
+
+
+// do we use a timer for the DMA, or have it in CPU_EXECUTE
+#define USE_TIMER_FOR_DMA
+
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
+
+#define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0))
+
+enum
+{
+ ICF = 0x00800000,
+ OCFA = 0x00080000,
+ OCFB = 0x00040000,
+ OVF = 0x00020000
+};
+
+#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)
+
+#define CPU_TYPE_SH1 (0)
+#define CPU_TYPE_SH2 (1)
+
+#define REGFLAG_R(n) (1 << (n))
+
+/* register flags 1 */
+#define REGFLAG_PR (1 << 0)
+#define REGFLAG_MACL (1 << 1)
+#define REGFLAG_MACH (1 << 2)
+#define REGFLAG_GBR (1 << 3)
+#define REGFLAG_VBR (1 << 4)
+#define REGFLAG_SR (1 << 5)
+
+#define CHECK_PENDING_IRQ(message) \
+do { \
+ int irq = -1; \
+ if (m_sh2_state->pending_irq & (1 << 0)) irq = 0; \
+ if (m_sh2_state->pending_irq & (1 << 1)) irq = 1; \
+ if (m_sh2_state->pending_irq & (1 << 2)) irq = 2; \
+ if (m_sh2_state->pending_irq & (1 << 3)) irq = 3; \
+ if (m_sh2_state->pending_irq & (1 << 4)) irq = 4; \
+ if (m_sh2_state->pending_irq & (1 << 5)) irq = 5; \
+ if (m_sh2_state->pending_irq & (1 << 6)) irq = 6; \
+ if (m_sh2_state->pending_irq & (1 << 7)) irq = 7; \
+ if (m_sh2_state->pending_irq & (1 << 8)) irq = 8; \
+ if (m_sh2_state->pending_irq & (1 << 9)) irq = 9; \
+ if (m_sh2_state->pending_irq & (1 << 10)) irq = 10; \
+ if (m_sh2_state->pending_irq & (1 << 11)) irq = 11; \
+ if (m_sh2_state->pending_irq & (1 << 12)) irq = 12; \
+ if (m_sh2_state->pending_irq & (1 << 13)) irq = 13; \
+ if (m_sh2_state->pending_irq & (1 << 14)) irq = 14; \
+ if (m_sh2_state->pending_irq & (1 << 15)) irq = 15; \
+ if ((m_sh2_state->internal_irq_level != -1) && (m_sh2_state->internal_irq_level > irq)) irq = m_sh2_state->internal_irq_level; \
+ if (irq >= 0) \
+ sh2_exception(message,irq); \
+} while(0)
+
+
+#endif // MAME_CPU_SH2_SH2COMN_H
diff --git a/src/devices/cpu/sh/sh2dasm.cpp b/src/devices/cpu/sh/sh2dasm.cpp
new file mode 100644
index 00000000000..ef823ee28a5
--- /dev/null
+++ b/src/devices/cpu/sh/sh2dasm.cpp
@@ -0,0 +1,610 @@
+// license:BSD-3-Clause
+// copyright-holders:Juergen Buchmueller
+#include "emu.h"
+#include "debugger.h"
+#include "sh2.h"
+
+#define SIGNX8(x) (((int32_t)(x) << 24) >> 24)
+#define SIGNX12(x) (((int32_t)(x) << 20) >> 20)
+
+#define Rn ((opcode >> 8) & 15)
+#define Rm ((opcode >> 4) & 15)
+
+static const char *const regname[16] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10","R11","R12","R13","R14","SP"
+};
+
+static uint32_t op0000(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ uint32_t flags = 0;
+ switch(opcode & 0x3f)
+ {
+ case 0x02:
+ util::stream_format(stream, "STC SR,%s", regname[Rn]);
+ break;
+ case 0x03:
+ util::stream_format(stream, "BSRF %s", regname[Rn]);
+ break;
+ case 0x08:
+ stream << "CLRT";
+ break;
+ case 0x09:
+ stream << "NOP";
+ break;
+ case 0x0A:
+ util::stream_format(stream, "STS MACH,%s", regname[Rn]);
+ break;
+ case 0x0B:
+ stream << "RTS";
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x12:
+ util::stream_format(stream, "STS GBR,%s", regname[Rn]);
+ break;
+ case 0x18:
+ stream << "SETT";
+ break;
+ case 0x19:
+ stream << "DIV0U";
+ break;
+ case 0x1A:
+ util::stream_format(stream, "STS MACL,%s", regname[Rn]);
+ break;
+ case 0x1B:
+ stream << "SLEEP";
+ break;
+ case 0x22:
+ util::stream_format(stream, "STC VBR,%s", regname[Rn]);
+ break;
+ case 0x23:
+ util::stream_format(stream, "BRAF %s", regname[Rn]);
+ break;
+ case 0x28:
+ stream << "CLRMAC";
+ break;
+ case 0x29:
+ util::stream_format(stream, "MOVT %s", regname[Rn]);
+ break;
+ case 0x2A:
+ util::stream_format(stream, "STS PR,%s", regname[Rn]);
+ break;
+ case 0x2B:
+ stream << "RTE";
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ default:
+ switch(opcode & 15)
+ {
+ case 0:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 1:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 2:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 3:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ util::stream_format(stream, "MOV.L %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ util::stream_format(stream, "MUL.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 9:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 10:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 11:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 12:
+ util::stream_format(stream, "MOV.B @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ util::stream_format(stream, "MOV.W @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ util::stream_format(stream, "MOV.L @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ util::stream_format(stream, "MAC.L @%s+,@%s+", regname[Rn], regname[Rm]);
+ break;
+ }
+ }
+ return flags;
+}
+
+static uint32_t op0001(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV.L %s,@($%02X,%s)", regname[Rm], (opcode & 15) * 4, regname[Rn]);
+ return 0;
+}
+
+static uint32_t op0010(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ util::stream_format(stream, "MOV.B %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ util::stream_format(stream, "MOV.W %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ util::stream_format(stream, "MOV.L %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ util::stream_format(stream, "MOV.L %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ util::stream_format(stream, "DIV0S %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ util::stream_format(stream, "TST %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ util::stream_format(stream, "AND %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ util::stream_format(stream, "XOR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ util::stream_format(stream, "OR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ util::stream_format(stream, "CMP/STR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ util::stream_format(stream, "XTRCT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ util::stream_format(stream, "MULU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ util::stream_format(stream, "MULS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static uint32_t op0011(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ util::stream_format(stream, "CMP/EQ %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ util::stream_format(stream, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ util::stream_format(stream, "CMP/HS %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ util::stream_format(stream, "CMP/GE %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 4:
+ util::stream_format(stream, "DIV1 %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ util::stream_format(stream, "DMULU.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ util::stream_format(stream, "CMP/HI %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ util::stream_format(stream, "CMP/GT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ util::stream_format(stream, "SUB %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ util::stream_format(stream, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ util::stream_format(stream, "SUBC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ util::stream_format(stream, "SUBV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ util::stream_format(stream, "ADD %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ util::stream_format(stream, "DMULS.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ util::stream_format(stream, "ADDC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ util::stream_format(stream, "ADDV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static uint32_t op0100(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ uint32_t flags = 0;
+ switch(opcode & 0x3F)
+ {
+ case 0x00:
+ util::stream_format(stream, "SHLL %s", regname[Rn]);
+ break;
+ case 0x01:
+ util::stream_format(stream, "SHLR %s", regname[Rn]);
+ break;
+ case 0x02:
+ util::stream_format(stream, "STS.L MACH,@-%s", regname[Rn]);
+ break;
+ case 0x03:
+ util::stream_format(stream, "STC.L SR,@-%s", regname[Rn]);
+ break;
+ case 0x04:
+ util::stream_format(stream, "ROTL %s", regname[Rn]);
+ break;
+ case 0x05:
+ util::stream_format(stream, "ROTR %s", regname[Rn]);
+ break;
+ case 0x06:
+ util::stream_format(stream, "LDS.L @%s+,MACH", regname[Rn]);
+ break;
+ case 0x07:
+ util::stream_format(stream, "LDC.L @%s+,SR", regname[Rn]);
+ break;
+ case 0x08:
+ util::stream_format(stream, "SHLL2 %s", regname[Rn]);
+ break;
+ case 0x09:
+ util::stream_format(stream, "SHLR2 %s", regname[Rn]);
+ break;
+ case 0x0a:
+ util::stream_format(stream, "LDS %s,MACH", regname[Rn]);
+ break;
+ case 0x0b:
+ util::stream_format(stream, "JSR %s", regname[Rn]);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ case 0x0e:
+ util::stream_format(stream, "LDC %s,SR", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "DT %s", regname[Rn]);
+ break;
+ case 0x11:
+ util::stream_format(stream, "CMP/PZ %s", regname[Rn]);
+ break;
+ case 0x12:
+ util::stream_format(stream, "STS.L MACL,@-%s", regname[Rn]);
+ break;
+ case 0x13:
+ util::stream_format(stream, "STC.L GBR,@-%s", regname[Rn]);
+ break;
+ case 0x15:
+ util::stream_format(stream, "CMP/PL %s", regname[Rn]);
+ break;
+ case 0x16:
+ util::stream_format(stream, "LDS.L @%s+,MACL", regname[Rn]);
+ break;
+ case 0x17:
+ util::stream_format(stream, "LDC.L @%s+,GBR", regname[Rn]);
+ break;
+ case 0x18:
+ util::stream_format(stream, "SHLL8 %s", regname[Rn]);
+ break;
+ case 0x19:
+ util::stream_format(stream, "SHLR8 %s", regname[Rn]);
+ break;
+ case 0x1a:
+ util::stream_format(stream, "LDS %s,MACL", regname[Rn]);
+ break;
+ case 0x1b:
+ util::stream_format(stream, "TAS %s", regname[Rn]);
+ break;
+ case 0x1e:
+ util::stream_format(stream, "LDC %s,GBR", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "SHAL %s", regname[Rn]);
+ break;
+ case 0x21:
+ util::stream_format(stream, "SHAR %s", regname[Rn]);
+ break;
+ case 0x22:
+ util::stream_format(stream, "STS.L PR,@-%s", regname[Rn]);
+ break;
+ case 0x23:
+ util::stream_format(stream, "STC.L VBR,@-%s", regname[Rn]);
+ break;
+ case 0x24:
+ util::stream_format(stream, "ROTCL %s", regname[Rn]);
+ break;
+ case 0x25:
+ util::stream_format(stream, "ROTCR %s", regname[Rn]);
+ break;
+ case 0x26:
+ util::stream_format(stream, "LDS.L @%s+,PR", regname[Rn]);
+ break;
+ case 0x27:
+ util::stream_format(stream, "LDC.L @%s+,VBR", regname[Rn]);
+ break;
+ case 0x28:
+ util::stream_format(stream, "SHLL16 %s", regname[Rn]);
+ break;
+ case 0x29:
+ util::stream_format(stream, "SHLR16 %s", regname[Rn]);
+ break;
+ case 0x2a:
+ util::stream_format(stream, "LDS %s,PR", regname[Rn]);
+ break;
+ case 0x2b:
+ util::stream_format(stream, "JMP %s", regname[Rn]);
+ break;
+ case 0x2e:
+ util::stream_format(stream, "LDC %s,VBR", regname[Rn]);
+ break;
+ default:
+ if ((opcode & 15) == 15)
+ util::stream_format(stream, "MAC.W @%s+,@%s+", regname[Rm], regname[Rn]);
+ else
+ util::stream_format(stream, "?????? $%04X", opcode);
+ }
+ return flags;
+}
+
+static uint32_t op0101(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV.L @($%02X,%s),%s", (opcode & 15) * 4, regname[Rm], regname[Rn]);
+ return 0;
+}
+
+static uint32_t op0110(std::ostream &stream, uint32_t pc, uint16_t opcode)
+
+{
+ switch(opcode & 0xF)
+ {
+ case 0x00:
+ util::stream_format(stream, "MOV.B @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x01:
+ util::stream_format(stream, "MOV.W @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x02:
+ util::stream_format(stream, "MOV.L @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x03:
+ util::stream_format(stream, "MOV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x04:
+ util::stream_format(stream, "MOV.B @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x05:
+ util::stream_format(stream, "MOV.W @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x06:
+ util::stream_format(stream, "MOV.L @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x07:
+ util::stream_format(stream, "NOT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x08:
+ util::stream_format(stream, "SWAP.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x09:
+ util::stream_format(stream, "SWAP.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0a:
+ util::stream_format(stream, "NEGC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0b:
+ util::stream_format(stream, "NEG %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0c:
+ util::stream_format(stream, "EXTU.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0d:
+ util::stream_format(stream, "EXTU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0e:
+ util::stream_format(stream, "EXTS.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0f:
+ util::stream_format(stream, "EXTS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static uint32_t op0111(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "ADD #$%02X,%s", opcode & 0xff, regname[Rn]);
+ return 0;
+}
+
+static uint32_t op1000(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ util::stream_format(stream, "MOV.B R0,@($%02X,%s)", (opcode & 15), regname[Rm]);
+ break;
+ case 1:
+ util::stream_format(stream, "MOV.W R0,@($%02X,%s)", (opcode & 15) * 2, regname[Rm]);
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 8:
+ util::stream_format(stream, "CMP/EQ #$%02X,R0", (opcode & 0xff));
+ break;
+ case 9:
+ util::stream_format(stream, "BT $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 11:
+ util::stream_format(stream, "BF $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 13:
+ util::stream_format(stream, "BTS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 15:
+ util::stream_format(stream, "BFS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ default :
+ util::stream_format(stream, "invalid $%04X", opcode);
+ }
+ return 0;
+}
+
+static uint32_t op1001(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV.W @($%04X,PC),%s [%08X]", (opcode & 0xff) * 2, regname[Rn], pc+((opcode & 0xff) * 2)+2);
+ return 0;
+}
+
+static uint32_t op1010(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "BRA $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return 0;
+}
+
+static uint32_t op1011(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "BSR $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+}
+
+static uint32_t op1100(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ uint32_t flags = 0;
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ util::stream_format(stream, "MOV.B R0,@($%02X,GBR)", opcode & 0xff);
+ break;
+ case 1:
+ util::stream_format(stream, "MOV.W R0,@($%04X,GBR)", (opcode & 0xff) * 2);
+ break;
+ case 2:
+ util::stream_format(stream, "MOV.L R0,@($%04X,GBR)", (opcode & 0xff) * 4);
+ break;
+ case 3:
+ util::stream_format(stream, "TRAPA #$%02X", opcode & 0xff);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B @($%02X,GBR),R0", opcode & 0xff);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W @($%04X,GBR),R0", (opcode & 0xff) * 2);
+ break;
+ case 6:
+ util::stream_format(stream, "MOV.L @($%04X,GBR),R0", (opcode & 0xff) * 4);
+ break;
+ case 7:
+ util::stream_format(stream, "MOVA @($%04X,PC),R0 [%08X]", (opcode & 0xff) * 4, ((pc + 2) & ~3) + (opcode & 0xff) * 4);
+ break;
+ case 8:
+ util::stream_format(stream, "TST #$%02X,R0", opcode & 0xff);
+ break;
+ case 9:
+ util::stream_format(stream, "AND #$%02X,R0", opcode & 0xff);
+ break;
+ case 10:
+ util::stream_format(stream, "XOR #$%02X,R0", opcode & 0xff);
+ break;
+ case 11:
+ util::stream_format(stream, "OR #$%02X,R0", opcode & 0xff);
+ break;
+ case 12:
+ util::stream_format(stream, "TST.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 13:
+ util::stream_format(stream, "AND.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 14:
+ util::stream_format(stream, "XOR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 15:
+ util::stream_format(stream, "OR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ }
+ return flags;
+}
+
+static uint32_t op1101(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV.L @($%02X,PC),%s [%08X]", (opcode * 4) & 0xff, regname[Rn], ((pc + 2) & ~3) + (opcode & 0xff) * 4);
+ return 0;
+}
+
+static uint32_t op1110(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV #$%02X,%s", (opcode & 0xff), regname[Rn]);
+ return 0;
+}
+
+static uint32_t op1111(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "unknown $%04X", opcode);
+ return 0;
+}
+
+unsigned DasmSH2(std::ostream &stream, unsigned pc, uint16_t opcode)
+{
+ uint32_t flags;
+
+ pc += 2;
+
+ switch ((opcode >> 12) & 15)
+ {
+ case 0: flags = op0000(stream, pc, opcode); break;
+ case 1: flags = op0001(stream, pc, opcode); break;
+ case 2: flags = op0010(stream, pc, opcode); break;
+ case 3: flags = op0011(stream, pc, opcode); break;
+ case 4: flags = op0100(stream, pc, opcode); break;
+ case 5: flags = op0101(stream, pc, opcode); break;
+ case 6: flags = op0110(stream, pc, opcode); break;
+ case 7: flags = op0111(stream, pc, opcode); break;
+ case 8: flags = op1000(stream, pc, opcode); break;
+ case 9: flags = op1001(stream, pc, opcode); break;
+ case 10: flags = op1010(stream, pc, opcode); break;
+ case 11: flags = op1011(stream, pc, opcode); break;
+ case 12: flags = op1100(stream, pc, opcode); break;
+ case 13: flags = op1101(stream, pc, opcode); break;
+ case 14: flags = op1110(stream, pc, opcode); break;
+ default: flags = op1111(stream, pc, opcode); break;
+ }
+ return 2 | flags | DASMFLAG_SUPPORTED;
+}
+
+CPU_DISASSEMBLE(sh2)
+{
+ return DasmSH2(stream, pc, (oprom[0] << 8) | oprom[1]);
+}
diff --git a/src/devices/cpu/sh/sh2drc.cpp b/src/devices/cpu/sh/sh2drc.cpp
new file mode 100644
index 00000000000..1003463b97a
--- /dev/null
+++ b/src/devices/cpu/sh/sh2drc.cpp
@@ -0,0 +1,2982 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ sh2drc.c
+ Universal machine language-based SH-2 emulator.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "sh2.h"
+#include "sh2comn.h"
+
+extern unsigned DasmSH2(std::ostream &stream, unsigned pc, uint16_t opcode);
+
+using namespace uml;
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define SET_EA (0) // makes slower but "shows work" in the EA fake register like the interpreter
+
+#define ADDSUBV_DIRECT (0)
+
+#if SET_EA
+#define SETEA(x) UML_MOV(block, mem(&m_sh2_state->ea), ireg(x))
+#else
+#define SETEA(x)
+#endif
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* map variables */
+#define MAPVAR_PC M0
+#define MAPVAR_CYCLES M1
+
+/* exit codes */
+#define EXECUTE_OUT_OF_CYCLES 0
+#define EXECUTE_MISSING_CODE 1
+#define EXECUTE_UNMAPPED_CODE 2
+#define EXECUTE_RESET_CACHE 3
+
+#define PROBE_ADDRESS ~0
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define R32(reg) m_regmap[reg]
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ epc - compute the exception PC from a
+ descriptor
+-------------------------------------------------*/
+
+uint32_t sh2_device::epc(const opcode_desc *desc)
+{
+ return (desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 1) : desc->pc;
+}
+
+/*-------------------------------------------------
+ alloc_handle - allocate a handle if not
+ already allocated
+-------------------------------------------------*/
+
+void sh2_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name)
+{
+ if (*handleptr == nullptr)
+ *handleptr = drcuml->handle_alloc(name);
+}
+
+/*-------------------------------------------------
+ load_fast_iregs - load any fast integer
+ registers
+-------------------------------------------------*/
+
+void sh2_device::load_fast_iregs(drcuml_block *block)
+{
+ int regnum;
+
+ for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ {
+ if (m_regmap[regnum].is_int_register())
+ {
+ UML_MOV(block, uml::parameter::make_ireg(m_regmap[regnum].ireg()), mem(&m_sh2_state->r[regnum]));
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ save_fast_iregs - save any fast integer
+ registers
+-------------------------------------------------*/
+
+void sh2_device::save_fast_iregs(drcuml_block *block)
+{
+ int regnum;
+
+ for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ {
+ if (m_regmap[regnum].is_int_register())
+ {
+ UML_MOV(block, mem(&m_sh2_state->r[regnum]), uml::parameter::make_ireg(m_regmap[regnum].ireg()));
+ }
+ }
+}
+
+/*-------------------------------------------------
+ cfunc_printf_probe - print the current CPU
+ state and return
+-------------------------------------------------*/
+
+static void cfunc_printf_probe(void *param)
+{
+ ((sh2_device *)param)->func_printf_probe();
+}
+
+void sh2_device::func_printf_probe()
+{
+ uint32_t pc = m_sh2_state->pc;
+
+ printf(" PC=%08X r0=%08X r1=%08X r2=%08X\n",
+ pc,
+ (uint32_t)m_sh2_state->r[0],
+ (uint32_t)m_sh2_state->r[1],
+ (uint32_t)m_sh2_state->r[2]);
+ printf(" r3=%08X r4=%08X r5=%08X r6=%08X\n",
+ (uint32_t)m_sh2_state->r[3],
+ (uint32_t)m_sh2_state->r[4],
+ (uint32_t)m_sh2_state->r[5],
+ (uint32_t)m_sh2_state->r[6]);
+ printf(" r7=%08X r8=%08X r9=%08X r10=%08X\n",
+ (uint32_t)m_sh2_state->r[7],
+ (uint32_t)m_sh2_state->r[8],
+ (uint32_t)m_sh2_state->r[9],
+ (uint32_t)m_sh2_state->r[10]);
+ printf(" r11=%08X r12=%08X r13=%08X r14=%08X\n",
+ (uint32_t)m_sh2_state->r[11],
+ (uint32_t)m_sh2_state->r[12],
+ (uint32_t)m_sh2_state->r[13],
+ (uint32_t)m_sh2_state->r[14]);
+ printf(" r15=%08X macl=%08X mach=%08X gbr=%08X\n",
+ (uint32_t)m_sh2_state->r[15],
+ (uint32_t)m_sh2_state->macl,
+ (uint32_t)m_sh2_state->mach,
+ (uint32_t)m_sh2_state->gbr);
+ printf(" evec %x irqsr %x pc=%08x\n",
+ (uint32_t)m_sh2_state->evec,
+ (uint32_t)m_sh2_state->irqsr, (uint32_t)m_sh2_state->pc);
+}
+
+/*-------------------------------------------------
+ cfunc_unimplemented - handler for
+ unimplemented opcdes
+-------------------------------------------------*/
+
+static void cfunc_unimplemented(void *param)
+{
+ ((sh2_device *)param)->func_unimplemented();
+}
+
+void sh2_device::func_unimplemented()
+{
+ // set up an invalid opcode exception
+ m_sh2_state->evec = RL( m_sh2_state->vbr + 4 * 4 );
+ m_sh2_state->evec &= AM;
+ m_sh2_state->irqsr = m_sh2_state->sr;
+ // claim it's an NMI, because it pretty much is
+ m_sh2_state->pending_nmi = 1;
+}
+
+/*-------------------------------------------------
+ cfunc_fastirq - checks for pending IRQs
+-------------------------------------------------*/
+static void cfunc_fastirq(void *param)
+{
+ ((sh2_device *)param)->func_fastirq();
+}
+
+void sh2_device::func_fastirq()
+{
+ sh2_exception("fastirq",m_sh2_state->irqline);
+}
+
+/*-------------------------------------------------
+ cfunc_MAC_W - implementation of MAC_W Rm,Rn
+-------------------------------------------------*/
+static void cfunc_MAC_W(void *param)
+{
+ ((sh2_device *)param)->func_MAC_W();
+}
+
+void sh2_device::func_MAC_W()
+{
+ int32_t tempm, tempn, dest, src, ans;
+ uint32_t templ;
+ uint16_t opcode;
+ int n, m;
+
+ // recover the opcode
+ opcode = m_sh2_state->arg0;
+
+ // extract the operands
+ n = Rn;
+ m = Rm;
+
+ tempn = (int32_t) RW( m_sh2_state->r[n] );
+ m_sh2_state->r[n] += 2;
+ tempm = (int32_t) RW( m_sh2_state->r[m] );
+ m_sh2_state->r[m] += 2;
+ templ = m_sh2_state->macl;
+ tempm = ((int32_t) (short) tempn * (int32_t) (short) tempm);
+ if ((int32_t) m_sh2_state->macl >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) tempm >= 0)
+ {
+ src = 0;
+ tempn = 0;
+ }
+ else
+ {
+ src = 1;
+ tempn = 0xffffffff;
+ }
+ src += dest;
+ m_sh2_state->macl += tempm;
+ if ((int32_t) m_sh2_state->macl >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (m_sh2_state->sr & S)
+ {
+ if (ans == 1)
+ {
+ if ((m_cpu_type == CPU_TYPE_SH1) && ((src == 0) || (src == 2)))
+ {
+ m_sh2_state->mach |= 0x00000001;
+ }
+
+ 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;
+
+ // SH-1 has limited precision
+ if (m_cpu_type == CPU_TYPE_SH1)
+ {
+ if ((m_sh2_state->mach & 0x200) == 0)
+ {
+ m_sh2_state->mach &= 0x3ff;
+ }
+ else
+ {
+ m_sh2_state->mach |= 0xfffffc00;
+ }
+ }
+
+
+ }
+}
+
+/*-------------------------------------------------
+ cfunc_MAC_L - implementation of MAC_L Rm,Rn
+-------------------------------------------------*/
+static void cfunc_MAC_L(void *param)
+{
+ ((sh2_device *)param)->func_MAC_L();
+}
+
+void sh2_device::func_MAC_L()
+{
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t temp0, temp1, temp2, temp3;
+ int32_t tempm, tempn, fnLmL;
+ uint16_t opcode;
+ int n, m;
+
+ // recover the opcode
+ opcode = m_sh2_state->arg0;
+
+ // extract the operands
+ n = Rn;
+ m = Rm;
+
+ tempn = (int32_t) RL( m_sh2_state->r[n] );
+ m_sh2_state->r[n] += 4;
+ tempm = (int32_t) RL( m_sh2_state->r[m] );
+ m_sh2_state->r[m] += 4;
+ if ((int32_t) (tempn ^ tempm) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ temp1 = (uint32_t) tempn;
+ temp2 = (uint32_t) 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_t) Res2 < 0) && (Res2 < 0xffff8000))
+ {
+ Res2 = 0x00008000;
+ Res0 = 0x00000000;
+ }
+ else if (((int32_t) 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;
+ }
+}
+
+/*-------------------------------------------------
+ cfunc_DIV1 - implementation of DIV1 Rm,Rn
+-------------------------------------------------*/
+static void cfunc_DIV1(void *param)
+{
+ ((sh2_device *)param)->func_DIV1();
+}
+
+void sh2_device::func_DIV1()
+{
+ uint32_t tmp0;
+ uint32_t old_q;
+ uint16_t opcode;
+ int n, m;
+
+ // recover the opcode
+ opcode = m_sh2_state->arg0;
+
+ // extract the operands
+ n = Rn;
+ m = Rm;
+
+ 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;
+}
+
+#if (!ADDSUBV_DIRECT)
+/*-------------------------------------------------
+ cfunc_ADDV - implementation of ADDV Rm,Rn
+-------------------------------------------------*/
+static void cfunc_ADDV(void *param)
+{
+ ((sh2_device *)param)->func_ADDV();
+}
+
+void sh2_device::func_ADDV()
+{
+ int32_t dest, src, ans;
+ uint16_t opcode;
+ int n, m;
+
+ // recover the opcode
+ opcode = m_sh2_state->arg0;
+
+ // extract the operands
+ n = Rn;
+ m = Rm;
+
+ if ((int32_t) m_sh2_state->r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) 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_t) 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;
+}
+
+/*-------------------------------------------------
+ cfunc_SUBV - implementation of SUBV Rm,Rn
+-------------------------------------------------*/
+static void cfunc_SUBV(void *param)
+{
+ ((sh2_device *)param)->func_SUBV();
+}
+
+void sh2_device::func_SUBV()
+{
+ int32_t dest, src, ans;
+ uint16_t opcode;
+ int n, m;
+
+ // recover the opcode
+ opcode = m_sh2_state->arg0;
+
+ // extract the operands
+ n = Rn;
+ m = Rm;
+
+ if ((int32_t) m_sh2_state->r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) 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_t) 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;
+}
+#else
+void sh2_device::func_ADDV() {}
+void sh2_device::func_SUBV() {}
+#endif
+
+/*-------------------------------------------------
+ code_flush_cache - flush the cache and
+ regenerate static code
+-------------------------------------------------*/
+
+void sh2_device::code_flush_cache()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+
+ /* empty the transient cache contents */
+ drcuml->reset();
+
+ try
+ {
+ /* generate the entry point and out-of-cycles handlers */
+ static_generate_nocode_handler();
+ static_generate_out_of_cycles();
+ static_generate_entry_point();
+
+ /* add subroutines for memory accesses */
+ static_generate_memory_accessor(1, false, "read8", &m_read8);
+ static_generate_memory_accessor(1, true, "write8", &m_write8);
+ static_generate_memory_accessor(2, false, "read16", &m_read16);
+ static_generate_memory_accessor(2, true, "write16", &m_write16);
+ static_generate_memory_accessor(4, false, "read32", &m_read32);
+ static_generate_memory_accessor(4, true, "write32", &m_write32);
+ }
+ catch (drcuml_block::abort_compilation &)
+ {
+ fatalerror("Unable to generate SH2 static code\n");
+ }
+
+ m_cache_dirty = false;
+}
+
+/* Execute cycles - returns number of cycles actually run */
+void sh2_device::execute_run_drc()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ int execute_result;
+
+ // 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
+
+ /* reset the cache if dirty */
+ if (m_cache_dirty)
+ code_flush_cache();
+
+ /* execute */
+ do
+ {
+ /* run as much as we can */
+ execute_result = drcuml->execute(*m_entry);
+
+ /* if we need to recompile, do it */
+ if (execute_result == EXECUTE_MISSING_CODE)
+ {
+ code_compile_block(0, m_sh2_state->pc);
+ }
+ else if (execute_result == EXECUTE_UNMAPPED_CODE)
+ {
+ fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_sh2_state->pc);
+ }
+ else if (execute_result == EXECUTE_RESET_CACHE)
+ {
+ code_flush_cache();
+ }
+ } while (execute_result != EXECUTE_OUT_OF_CYCLES);
+}
+
+/*-------------------------------------------------
+ code_compile_block - compile a block of the
+ given mode at the specified pc
+-------------------------------------------------*/
+
+void sh2_device::code_compile_block(uint8_t mode, offs_t pc)
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ compiler_state compiler = { 0 };
+ const opcode_desc *seqhead, *seqlast;
+ const opcode_desc *desclist;
+ bool override = false;
+ drcuml_block *block;
+
+ g_profiler.start(PROFILER_DRC_COMPILE);
+
+ /* get a description of this sequence */
+ desclist = m_drcfe->describe_code(pc);
+ if (drcuml->logging() || drcuml->logging_native())
+ log_opcode_desc(drcuml, desclist, 0);
+
+ bool succeeded = false;
+ while (!succeeded)
+ {
+ try
+ {
+ /* start the block */
+ block = drcuml->begin_block(4096);
+
+ /* loop until we get through all instruction sequences */
+ for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next())
+ {
+ const opcode_desc *curdesc;
+ uint32_t nextpc;
+
+ /* add a code log entry */
+ if (drcuml->logging())
+ block->append_comment("-------------------------"); // comment
+
+ /* determine the last instruction in this sequence */
+ for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next())
+ if (seqlast->flags & OPFLAG_END_SEQUENCE)
+ break;
+ assert(seqlast != nullptr);
+
+ /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
+ if (override || !drcuml->hash_exists(mode, seqhead->pc))
+ UML_HASH(block, mode, seqhead->pc); // hash mode,pc
+
+ /* if we already have a hash, and this is the first sequence, assume that we */
+ /* are recompiling due to being out of sync and allow future overrides */
+ else if (seqhead == desclist)
+ {
+ override = true;
+ UML_HASH(block, mode, seqhead->pc); // hash mode,pc
+ }
+
+ /* otherwise, redispatch to that fixed PC and skip the rest of the processing */
+ else
+ {
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
+ UML_HASHJMP(block, 0, seqhead->pc, *m_nocode);
+ // hashjmp <mode>,seqhead->pc,nocode
+ continue;
+ }
+
+ /* validate this code block if we're not pointing into ROM */
+ if (m_program->get_write_ptr(seqhead->physpc) != nullptr)
+ generate_checksum_block(block, &compiler, seqhead, seqlast);
+
+ /* label this instruction, if it may be jumped to locally */
+ if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
+ {
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
+ }
+
+ /* iterate over instructions in the sequence and compile them */
+ for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
+ {
+ generate_sequence_instruction(block, &compiler, curdesc, 0xffffffff);
+ }
+
+ /* if we need to return to the start, do it */
+ if (seqlast->flags & OPFLAG_RETURN_TO_START)
+ {
+ nextpc = pc;
+ }
+ /* otherwise we just go to the next instruction */
+ else
+ {
+ nextpc = seqlast->pc + (seqlast->skipslots + 1) * 2;
+ }
+
+ /* count off cycles and go there */
+ generate_update_cycles(block, &compiler, nextpc, true); // <subtract cycles>
+
+ /* SH2 has no modes */
+ if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc)
+ {
+ UML_HASHJMP(block, 0, nextpc, *m_nocode);
+ }
+ // hashjmp <mode>,nextpc,nocode
+ }
+
+ /* end the sequence */
+ block->end();
+ g_profiler.stop();
+ succeeded = true;
+ }
+ catch (drcuml_block::abort_compilation &)
+ {
+ code_flush_cache();
+ }
+ }
+}
+
+/*-------------------------------------------------
+ static_generate_entry_point - generate a
+ static entry point
+-------------------------------------------------*/
+
+void sh2_device::static_generate_entry_point()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ code_label skip = 1;
+ drcuml_block *block;
+
+ /* begin generating */
+ block = drcuml->begin_block(200);
+
+ /* forward references */
+ alloc_handle(drcuml, &m_nocode, "nocode");
+ alloc_handle(drcuml, &m_write32, "write32"); // necessary?
+ alloc_handle(drcuml, &m_entry, "entry");
+ UML_HANDLE(block, *m_entry); // handle entry
+
+ /* load fast integer registers */
+ load_fast_iregs(block);
+
+ /* check for interrupts */
+ UML_MOV(block, mem(&m_sh2_state->irqline), 0xffffffff); // mov irqline, #-1
+ UML_CMP(block, mem(&m_sh2_state->pending_nmi), 0); // cmp pending_nmi, #0
+ UML_JMPc(block, COND_Z, skip+2); // jz skip+2
+
+ UML_MOV(block, mem(&m_sh2_state->pending_nmi), 0); // zap pending_nmi
+ UML_JMP(block, skip+1); // and then go take it (evec is already set)
+
+ UML_LABEL(block, skip+2); // skip+2:
+ UML_MOV(block, mem(&m_sh2_state->evec), 0xffffffff); // mov evec, -1
+ UML_MOV(block, I0, 0xffffffff); // mov r0, -1 (r0 = irq)
+ UML_AND(block, I1, I0, 0xffff); // and r1, 0xffff
+
+ UML_LZCNT(block, I1, mem(&m_sh2_state->pending_irq)); // lzcnt r1, r1
+ UML_CMP(block, I1, 32); // cmp r1, #32
+ UML_JMPc(block, COND_Z, skip+4); // jz skip+4
+
+ UML_SUB(block, mem(&m_sh2_state->irqline), 31, I1); // sub irqline, #31, r1
+
+ UML_LABEL(block, skip+4); // skip+4:
+ UML_CMP(block, mem(&m_sh2_state->internal_irq_level), 0xffffffff); // cmp internal_irq_level, #-1
+ UML_JMPc(block, COND_Z, skip+3); // jz skip+3
+ UML_CMP(block, mem(&m_sh2_state->internal_irq_level), mem(&m_sh2_state->irqline)); // cmp internal_irq_level, irqline
+ UML_JMPc(block, COND_LE, skip+3); // jle skip+3
+
+ UML_MOV(block, mem(&m_sh2_state->irqline), mem(&m_sh2_state->internal_irq_level)); // mov r0, internal_irq_level
+
+ UML_LABEL(block, skip+3); // skip+3:
+ UML_CMP(block, mem(&m_sh2_state->irqline), 0xffffffff); // cmp irqline, #-1
+ UML_JMPc(block, COND_Z, skip+1); // jz skip+1
+ UML_CALLC(block, cfunc_fastirq, this); // callc fastirq
+
+ UML_LABEL(block, skip+1); // skip+1:
+
+ UML_CMP(block, mem(&m_sh2_state->evec), 0xffffffff); // cmp evec, 0xffffffff
+ UML_JMPc(block, COND_Z, skip); // jz skip
+
+ UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_MOV(block, I1, mem(&m_sh2_state->irqsr)); // mov r1, irqsr
+ UML_CALLH(block, *m_write32); // call write32
+
+ UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_MOV(block, I1, mem(&m_sh2_state->pc)); // mov r1, pc
+ UML_CALLH(block, *m_write32); // call write32
+
+ UML_MOV(block, mem(&m_sh2_state->pc), mem(&m_sh2_state->evec)); // mov pc, evec
+
+ UML_LABEL(block, skip); // skip:
+
+ /* generate a hash jump via the current mode and PC */
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
+
+ block->end();
+}
+
+/*-------------------------------------------------
+ static_generate_nocode_handler - generate an
+ exception handler for "out of code"
+-------------------------------------------------*/
+
+void sh2_device::static_generate_nocode_handler()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ drcuml_block *block;
+
+ /* begin generating */
+ block = drcuml->begin_block(10);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(drcuml, &m_nocode, "nocode");
+ UML_HANDLE(block, *m_nocode); // handle nocode
+ UML_GETEXP(block, I0); // getexp i0
+ UML_MOV(block, mem(&m_sh2_state->pc), I0); // mov [pc],i0
+ save_fast_iregs(block);
+ UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
+
+ block->end();
+}
+
+
+/*-------------------------------------------------
+ static_generate_out_of_cycles - generate an
+ out of cycles exception handler
+-------------------------------------------------*/
+
+void sh2_device::static_generate_out_of_cycles()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ drcuml_block *block;
+
+ /* begin generating */
+ block = drcuml->begin_block(10);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(drcuml, &m_out_of_cycles, "out_of_cycles");
+ UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles
+ UML_GETEXP(block, I0); // getexp i0
+ UML_MOV(block, mem(&m_sh2_state->pc), I0); // mov <pc>,i0
+ save_fast_iregs(block);
+ UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES
+
+ block->end();
+}
+
+/*------------------------------------------------------------------
+ static_generate_memory_accessor
+------------------------------------------------------------------*/
+
+void sh2_device::static_generate_memory_accessor(int size, int iswrite, const char *name, code_handle **handleptr)
+{
+ /* on entry, address is in I0; data for writes is in I1 */
+ /* on exit, read result is in I0 */
+ /* routine trashes I0 */
+ drcuml_state *drcuml = m_drcuml.get();
+ drcuml_block *block;
+ int label = 1;
+
+ /* begin generating */
+ block = drcuml->begin_block(1024);
+
+ /* add a global entry for this */
+ alloc_handle(drcuml, handleptr, name);
+ UML_HANDLE(block, **handleptr); // handle *handleptr
+
+ // with internal handlers this becomes easier.
+ // if addr < 0x40000000 AND it with AM and do the read/write, else just do the read/write
+ UML_TEST(block, I0, 0x80000000); // test r0, #0x80000000
+ UML_JMPc(block, COND_NZ, label); // if high bit is set, don't mask
+
+ UML_CMP(block, I0, 0x40000000); // cmp #0x40000000, r0
+ UML_JMPc(block, COND_AE, label); // bae label
+
+ UML_AND(block, I0, I0, AM); // and r0, r0, #AM (0xc7ffffff)
+
+ UML_LABEL(block, label++); // label:
+
+ for (auto & elem : m_fastram)
+ {
+ if (elem.base != nullptr && (!iswrite || !elem.readonly))
+ {
+ void *fastbase = (uint8_t *)elem.base - elem.start;
+ uint32_t skip = label++;
+ if (elem.end != 0xffffffff)
+ {
+ UML_CMP(block, I0, elem.end); // cmp i0,end
+ UML_JMPc(block, COND_A, skip); // ja skip
+ }
+ if (elem.start != 0x00000000)
+ {
+ UML_CMP(block, I0, elem.start);// cmp i0,fastram_start
+ UML_JMPc(block, COND_B, skip); // jb skip
+ }
+
+ if (!iswrite)
+ {
+ if (size == 1)
+ {
+ UML_XOR(block, I0, I0, BYTE4_XOR_BE(0));
+ UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte
+ }
+ else if (size == 2)
+ {
+ UML_XOR(block, I0, I0, WORD_XOR_BE(0));
+ UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1
+ }
+ else if (size == 4)
+ {
+ UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1
+ }
+ UML_RET(block); // ret
+ }
+ else
+ {
+ if (size == 1)
+ {
+ UML_XOR(block, I0, I0, BYTE4_XOR_BE(0));
+ UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1);// store fastbase,i0,i1,byte
+ }
+ else if (size == 2)
+ {
+ UML_XOR(block, I0, I0, WORD_XOR_BE(0));
+ UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1);// store fastbase,i0,i1,word_x1
+ }
+ else if (size == 4)
+ {
+ UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1
+ }
+ UML_RET(block); // ret
+ }
+
+ UML_LABEL(block, skip); // skip:
+ }
+ }
+
+ if (iswrite)
+ {
+ switch (size)
+ {
+ case 1:
+ UML_WRITE(block, I0, I1, SIZE_BYTE, SPACE_PROGRAM); // write r0, r1, program_byte
+ break;
+
+ case 2:
+ UML_WRITE(block, I0, I1, SIZE_WORD, SPACE_PROGRAM); // write r0, r1, program_word
+ break;
+
+ case 4:
+ UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write r0, r1, program_dword
+ break;
+ }
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ UML_READ(block, I0, I0, SIZE_BYTE, SPACE_PROGRAM); // read r0, program_byte
+ break;
+
+ case 2:
+ UML_READ(block, I0, I0, SIZE_WORD, SPACE_PROGRAM); // read r0, program_word
+ break;
+
+ case 4:
+ UML_READ(block, I0, I0, SIZE_DWORD, SPACE_PROGRAM); // read r0, program_dword
+ break;
+ }
+ }
+
+ UML_RET(block); // ret
+
+ block->end();
+}
+
+/*-------------------------------------------------
+ log_desc_flags_to_string - generate a string
+ representing the instruction description
+ flags
+-------------------------------------------------*/
+
+const char *sh2_device::log_desc_flags_to_string(uint32_t flags)
+{
+ static char tempbuf[30];
+ char *dest = tempbuf;
+
+ /* branches */
+ if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH)
+ *dest++ = 'U';
+ else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH)
+ *dest++ = 'C';
+ else
+ *dest++ = '.';
+
+ /* intrablock branches */
+ *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.';
+
+ /* branch targets */
+ *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.';
+
+ /* delay slots */
+ *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.';
+
+ /* exceptions */
+ if (flags & OPFLAG_WILL_CAUSE_EXCEPTION)
+ *dest++ = 'E';
+ else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION)
+ *dest++ = 'e';
+ else
+ *dest++ = '.';
+
+ /* read/write */
+ if (flags & OPFLAG_READS_MEMORY)
+ *dest++ = 'R';
+ else if (flags & OPFLAG_WRITES_MEMORY)
+ *dest++ = 'W';
+ else
+ *dest++ = '.';
+
+ /* TLB validation */
+ *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.';
+
+ /* TLB modification */
+ *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.';
+
+ /* redispatch */
+ *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.';
+ return tempbuf;
+}
+
+
+/*-------------------------------------------------
+ log_register_list - log a list of GPR registers
+-------------------------------------------------*/
+
+void sh2_device::log_register_list(drcuml_state *drcuml, const char *string, const uint32_t *reglist, const uint32_t *regnostarlist)
+{
+ int count = 0;
+ int regnum;
+
+ /* skip if nothing */
+ if (reglist[0] == 0 && reglist[1] == 0 && reglist[2] == 0)
+ return;
+
+ drcuml->log_printf("[%s:", string);
+
+ for (regnum = 0; regnum < 16; regnum++)
+ {
+ if (reglist[0] & REGFLAG_R(regnum))
+ {
+ drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum);
+ if (regnostarlist != nullptr && !(regnostarlist[0] & REGFLAG_R(regnum)))
+ drcuml->log_printf("*");
+ }
+ }
+
+ if (reglist[1] & REGFLAG_PR)
+ {
+ drcuml->log_printf("%spr", (count++ == 0) ? "" : ",");
+ if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_PR))
+ drcuml->log_printf("*");
+ }
+
+ if (reglist[1] & REGFLAG_SR)
+ {
+ drcuml->log_printf("%ssr", (count++ == 0) ? "" : ",");
+ if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_SR))
+ drcuml->log_printf("*");
+ }
+
+ if (reglist[1] & REGFLAG_MACL)
+ {
+ drcuml->log_printf("%smacl", (count++ == 0) ? "" : ",");
+ if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_MACL))
+ drcuml->log_printf("*");
+ }
+
+ if (reglist[1] & REGFLAG_MACH)
+ {
+ drcuml->log_printf("%smach", (count++ == 0) ? "" : ",");
+ if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_MACH))
+ drcuml->log_printf("*");
+ }
+
+ if (reglist[1] & REGFLAG_GBR)
+ {
+ drcuml->log_printf("%sgbr", (count++ == 0) ? "" : ",");
+ if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_GBR))
+ drcuml->log_printf("*");
+ }
+
+ if (reglist[1] & REGFLAG_VBR)
+ {
+ drcuml->log_printf("%svbr", (count++ == 0) ? "" : ",");
+ if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_VBR))
+ drcuml->log_printf("*");
+ }
+
+ drcuml->log_printf("] ");
+}
+
+/*-------------------------------------------------
+ log_opcode_desc - log a list of descriptions
+-------------------------------------------------*/
+
+void sh2_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent)
+{
+ /* open the file, creating it if necessary */
+ if (indent == 0)
+ drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc);
+
+ /* output each descriptor */
+ for ( ; desclist != nullptr; desclist = desclist->next())
+ {
+ std::ostringstream stream;
+
+ /* disassemle the current instruction and output it to the log */
+ if (drcuml->logging() || drcuml->logging_native())
+ {
+ if (desclist->flags & OPFLAG_VIRTUAL_NOOP)
+ stream << "<virtual nop>";
+ else
+ DasmSH2(stream, desclist->pc, desclist->opptr.w[0]);
+ }
+ else
+ stream << "???";
+ drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), stream.str().c_str());
+
+ /* output register states */
+ log_register_list(drcuml, "use", desclist->regin, nullptr);
+ log_register_list(drcuml, "mod", desclist->regout, desclist->regreq);
+ drcuml->log_printf("\n");
+
+ /* if we have a delay slot, output it recursively */
+ if (desclist->delay.first() != nullptr)
+ log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
+
+ /* at the end of a sequence add a dividing line */
+ if (desclist->flags & OPFLAG_END_SEQUENCE)
+ drcuml->log_printf("-----\n");
+ }
+}
+
+/*-------------------------------------------------
+ log_add_disasm_comment - add a comment
+ including disassembly of an SH2 instruction
+-------------------------------------------------*/
+
+void sh2_device::log_add_disasm_comment(drcuml_block *block, uint32_t pc, uint32_t op)
+{
+ if (m_drcuml->logging())
+ {
+ std::ostringstream stream;
+ DasmSH2(stream, pc, op);
+ block->append_comment("%08X: %s", pc, stream.str().c_str());
+ }
+}
+
+/*-------------------------------------------------
+ generate_update_cycles - generate code to
+ subtract cycles from the icount and generate
+ an exception if out
+-------------------------------------------------*/
+void sh2_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, bool allow_exception)
+{
+ /* check full interrupts if pending */
+ if (compiler->checkints)
+ {
+ code_label skip = compiler->labelnum++;
+
+ compiler->checkints = false;
+ compiler->labelnum += 4;
+
+ /* check for interrupts */
+ UML_MOV(block, mem(&m_sh2_state->irqline), 0xffffffff); // mov irqline, #-1
+ UML_CMP(block, mem(&m_sh2_state->pending_nmi), 0); // cmp pending_nmi, #0
+ UML_JMPc(block, COND_Z, skip+2); // jz skip+2
+
+ UML_MOV(block, mem(&m_sh2_state->pending_nmi), 0); // zap pending_nmi
+ UML_JMP(block, skip+1); // and then go take it (evec is already set)
+
+ UML_LABEL(block, skip+2); // skip+2:
+ UML_MOV(block, mem(&m_sh2_state->evec), 0xffffffff); // mov evec, -1
+ UML_MOV(block, I0, 0xffffffff); // mov r0, -1 (r0 = irq)
+ UML_AND(block, I1, I0, 0xffff); // and r1, r0, 0xffff
+
+ UML_LZCNT(block, I1, mem(&m_sh2_state->pending_irq)); // lzcnt r1, pending_irq
+ UML_CMP(block, I1, 32); // cmp r1, #32
+ UML_JMPc(block, COND_Z, skip+4); // jz skip+4
+
+ UML_SUB(block, mem(&m_sh2_state->irqline), 31, I1); // sub irqline, #31, r1
+
+ UML_LABEL(block, skip+4); // skip+4:
+ UML_CMP(block, mem(&m_sh2_state->internal_irq_level), 0xffffffff); // cmp internal_irq_level, #-1
+ UML_JMPc(block, COND_Z, skip+3); // jz skip+3
+ UML_CMP(block, mem(&m_sh2_state->internal_irq_level), mem(&m_sh2_state->irqline)); // cmp internal_irq_level, irqline
+ UML_JMPc(block, COND_LE, skip+3); // jle skip+3
+
+ UML_MOV(block, mem(&m_sh2_state->irqline), mem(&m_sh2_state->internal_irq_level)); // mov r0, internal_irq_level
+
+ UML_LABEL(block, skip+3); // skip+3:
+ UML_CMP(block, mem(&m_sh2_state->irqline), 0xffffffff); // cmp irqline, #-1
+ UML_JMPc(block, COND_Z, skip+1); // jz skip+1
+ UML_CALLC(block, cfunc_fastirq, this); // callc fastirq
+
+ UML_LABEL(block, skip+1); // skip+1:
+ UML_CMP(block, mem(&m_sh2_state->evec), 0xffffffff); // cmp evec, 0xffffffff
+ UML_JMPc(block, COND_Z, skip); // jz skip
+
+ UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_MOV(block, I1, mem(&m_sh2_state->irqsr)); // mov r1, irqsr
+ UML_CALLH(block, *m_write32); // call write32
+
+ UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_MOV(block, I1, param); // mov r1, nextpc
+ UML_CALLH(block, *m_write32); // call write32
+
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->evec), *m_nocode); // hashjmp m_sh2_state->evec
+
+ UML_LABEL(block, skip); // skip:
+ }
+
+ /* account for cycles */
+ if (compiler->cycles > 0)
+ {
+ UML_SUB(block, mem(&m_sh2_state->icount), mem(&m_sh2_state->icount), MAPVAR_CYCLES); // sub icount,icount,cycles
+ UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0
+ if (allow_exception)
+ UML_EXHc(block, COND_S, *m_out_of_cycles, param);
+ // exh out_of_cycles,nextpc
+ }
+ compiler->cycles = 0;
+}
+
+/*-------------------------------------------------
+ generate_checksum_block - generate code to
+ validate a sequence of opcodes
+-------------------------------------------------*/
+
+void sh2_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
+{
+ const opcode_desc *curdesc;
+ if (m_drcuml->logging())
+ block->append_comment("[Validation for %08X]", seqhead->pc); // comment
+
+ /* loose verify or single instruction: just compare and fail */
+ if (!(m_drcoptions & SH2DRC_STRICT_VERIFY) || seqhead->next() == nullptr)
+ {
+ if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ void *base = m_direct->read_ptr(seqhead->physpc, SH2_CODE_XOR(0));
+ UML_LOAD(block, I0, base, 0, SIZE_WORD, SCALE_x2); // load i0,base,word
+ UML_CMP(block, I0, seqhead->opptr.w[0]); // cmp i0,*opptr
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ }
+ }
+
+ /* full verification; sum up everything */
+ else
+ {
+#if 0
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ base = m_direct->read_ptr(curdesc->physpc, SH2_CODE_XOR(0));
+ UML_LOAD(block, I0, curdesc->opptr.w, 0, SIZE_WORD, SCALE_x2); // load i0,*opptr,0,word
+ UML_CMP(block, I0, curdesc->opptr.w[0]); // cmp i0,*opptr
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ }
+#else
+ uint32_t sum = 0;
+ void *base = m_direct->read_ptr(seqhead->physpc, SH2_CODE_XOR(0));
+ UML_LOAD(block, I0, base, 0, SIZE_WORD, SCALE_x4); // load i0,base,word
+ sum += seqhead->opptr.w[0];
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ base = m_direct->read_ptr(curdesc->physpc, SH2_CODE_XOR(0));
+ UML_LOAD(block, I1, base, 0, SIZE_WORD, SCALE_x2); // load i1,*opptr,word
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->opptr.w[0];
+ }
+ UML_CMP(block, I0, sum); // cmp i0,sum
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+#endif
+ }
+}
+
+
+/*-------------------------------------------------
+ generate_sequence_instruction - generate code
+ for a single instruction in a sequence
+-------------------------------------------------*/
+
+void sh2_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc)
+{
+ offs_t expc;
+
+ /* add an entry for the log */
+ if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
+ log_add_disasm_comment(block, desc->pc, desc->opptr.w[0]);
+
+ /* set the PC map variable */
+ expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 1 : desc->pc;
+ UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc
+
+ /* accumulate total cycles */
+ compiler->cycles += desc->cycles;
+
+ /* update the icount map variable */
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+
+ /* if we want a probe, add it here */
+ if (desc->pc == PROBE_ADDRESS)
+ {
+ UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc
+ UML_CALLC(block, cfunc_printf_probe, this); // callc cfunc_printf_probe,sh2
+ }
+
+ /* if we are debugging, call the debugger */
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ {
+ UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc
+ save_fast_iregs(block);
+ UML_DEBUG(block, desc->pc); // debug desc->pc
+ }
+ else // not debug, see what other reasons there are for flushing the PC
+ {
+ if (m_drcoptions & SH2DRC_FLUSH_PC) // always flush?
+ {
+ UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov m_sh2_state->pc, desc->pc
+ }
+ else // check for driver-selected flushes
+ {
+ int pcflush;
+
+ for (pcflush = 0; pcflush < m_pcfsel; pcflush++)
+ {
+ if (desc->pc == m_pcflushes[pcflush])
+ {
+ UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov m_sh2_state->pc, desc->pc
+ }
+ }
+ }
+ }
+
+
+ /* if we hit an unmapped address, fatal error */
+ if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
+ {
+ UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc
+ save_fast_iregs(block);
+ UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE
+ }
+
+ /* if this is an invalid opcode, die */
+ if (desc->flags & OPFLAG_INVALID_OPCODE)
+ {
+ fatalerror("SH2DRC: invalid opcode!\n");
+ }
+
+ /* otherwise, unless this is a virtual no-op, it's a regular instruction */
+ else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ /* compile the instruction */
+ if (!generate_opcode(block, compiler, desc, ovrpc))
+ {
+ // handle an illegal op
+ UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc
+ UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); // mov [arg0],opcode
+ UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ generate_delay_slot
+------------------------------------------------------------------*/
+
+void sh2_device::generate_delay_slot(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc)
+{
+ compiler_state compiler_temp = *compiler;
+
+ /* compile the delay slot using temporary compiler state */
+ assert(desc->delay.first() != nullptr);
+ generate_sequence_instruction(block, &compiler_temp, desc->delay.first(), ovrpc); // <next instruction>
+
+ /* update the label */
+ compiler->labelnum = compiler_temp.labelnum;
+}
+
+/*-------------------------------------------------
+ generate_opcode - generate code for a specific
+ opcode
+-------------------------------------------------*/
+
+bool sh2_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc)
+{
+ uint32_t scratch, scratch2;
+ int32_t disp;
+ uint16_t opcode = desc->opptr.w[0];
+ uint8_t opswitch = opcode >> 12;
+ int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
+
+ switch (opswitch)
+ {
+ case 0:
+ return generate_group_0(block, compiler, desc, opcode, in_delay_slot, ovrpc);
+
+ case 1: // MOVLS4
+ scratch = (opcode & 0x0f) * 4;
+ UML_ADD(block, I0, R32(Rn), scratch); // add r0, Rn, scratch
+ UML_MOV(block, I1, R32(Rm)); // mov r1, Rm
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_write32);
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 2:
+ return generate_group_2(block, compiler, desc, opcode, in_delay_slot, ovrpc);
+ case 3:
+ return generate_group_3(block, compiler, desc, opcode, ovrpc);
+ case 4:
+ return generate_group_4(block, compiler, desc, opcode, in_delay_slot, ovrpc);
+
+ case 5: // MOVLL4
+ scratch = (opcode & 0x0f) * 4;
+ UML_ADD(block, I0, R32(Rm), scratch); // add r0, Rm, scratch
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, R32(Rn), I0); // mov Rn, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 6:
+ return generate_group_6(block, compiler, desc, opcode, in_delay_slot, ovrpc);
+
+ case 7: // ADDI
+ scratch = opcode & 0xff;
+ scratch2 = (uint32_t)(int32_t)(int16_t)(int8_t)scratch;
+ UML_ADD(block, R32(Rn), R32(Rn), scratch2); // add Rn, Rn, scratch2
+ return true;
+
+ case 8:
+ return generate_group_8(block, compiler, desc, opcode, in_delay_slot, ovrpc);
+
+ case 9: // MOVWI
+ if (ovrpc == 0xffffffff)
+ {
+ scratch = (desc->pc + 2) + ((opcode & 0xff) * 2) + 2;
+ }
+ else
+ {
+ scratch = (ovrpc + 2) + ((opcode & 0xff) * 2) + 2;
+ }
+
+ if (m_drcoptions & SH2DRC_STRICT_PCREL)
+ {
+ UML_MOV(block, I0, scratch); // mov r0, scratch
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_read16); // read16(r0, r1)
+ UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD
+ }
+ else
+ {
+ scratch2 = (uint32_t)(int32_t)(int16_t) RW(scratch);
+ UML_MOV(block, R32(Rn), scratch2); // mov Rn, scratch2
+ }
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 10: // BRA
+ disp = ((int32_t)opcode << 20) >> 20;
+ m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = pc+4 + disp*2 + 2
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2);
+
+ generate_update_cycles(block, compiler, m_sh2_state->ea, true); // <subtract cycles>
+ UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // hashjmp m_sh2_state->ea
+ return true;
+
+ case 11: // BSR
+ // panicstr @ 403da22 relies on the delay slot clobbering the PR set by a BSR, so
+ // do this before running the delay slot
+ UML_ADD(block, mem(&m_sh2_state->pr), desc->pc, 4); // add m_pr, desc->pc, #4 (skip the current insn & delay slot)
+
+ disp = ((int32_t)opcode << 20) >> 20;
+ m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = pc+4 + disp*2 + 2
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2);
+
+ generate_update_cycles(block, compiler, m_sh2_state->ea, true); // <subtract cycles>
+ UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // hashjmp m_sh2_state->ea
+ return true;
+
+ case 12:
+ return generate_group_12(block, compiler, desc, opcode, in_delay_slot, ovrpc);
+
+ case 13: // MOVLI
+ if (ovrpc == 0xffffffff)
+ {
+ scratch = ((desc->pc + 4) & ~3) + ((opcode & 0xff) * 4);
+ }
+ else
+ {
+ scratch = ((ovrpc + 4) & ~3) + ((opcode & 0xff) * 4);
+ }
+
+ if (m_drcoptions & SH2DRC_STRICT_PCREL)
+ {
+ UML_MOV(block, I0, scratch); // mov r0, scratch
+ UML_CALLH(block, *m_read32); // read32(r0, r1)
+ UML_MOV(block, R32(Rn), I0); // mov Rn, r0
+ }
+ else
+ {
+ scratch2 = RL(scratch);
+ UML_MOV(block, R32(Rn), scratch2); // mov Rn, scratch2
+ }
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 14: // MOVI
+ scratch = opcode & 0xff;
+ scratch2 = (uint32_t)(int32_t)(int16_t)(int8_t)scratch;
+ UML_MOV(block, R32(Rn), scratch2);
+ return true;
+
+ case 15:
+ return false;
+ }
+
+ return false;
+}
+
+bool sh2_device::generate_group_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: // these are all illegal
+ case 0x01:
+ case 0x10:
+ case 0x11:
+ case 0x13:
+ case 0x20:
+ case 0x21:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ return false;
+
+ case 0x09: // NOP();
+ return true;
+
+ case 0x02: // STCSR(Rn);
+ UML_MOV(block, R32(Rn), mem(&m_sh2_state->sr));
+ return true;
+
+ case 0x03: // BSRF(Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_ADD(block, mem(&m_sh2_state->target), R32(Rn), 4); // add target, Rm, #4
+ UML_ADD(block, mem(&m_sh2_state->target), mem(&m_sh2_state->target), desc->pc); // add target, target, pc
+
+ // 32x Cosmic Carnage @ 6002cb0 relies on the delay slot
+ // clobbering the calculated PR, so do it first
+ UML_ADD(block, mem(&m_sh2_state->pr), desc->pc, 4); // add m_pr, desc->pc, #4 (skip the current insn & delay slot)
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->target);
+
+ generate_update_cycles(block, compiler, mem(&m_sh2_state->target), true); // <subtract cycles>
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // jmp target
+ return true;
+ }
+ break;
+
+ case 0x04: // MOVBS0(Rm, Rn);
+ case 0x14: // MOVBS0(Rm, Rn);
+ case 0x24: // MOVBS0(Rm, Rn);
+ case 0x34: // MOVBS0(Rm, Rn);
+ UML_ADD(block, I0, R32(0), R32(Rn)); // add r0, R0, Rn
+ UML_AND(block, I1, R32(Rm), 0x000000ff); // and r1, Rm, 0xff
+ UML_CALLH(block, *m_write8); // call write8
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x05: // MOVWS0(Rm, Rn);
+ case 0x15: // MOVWS0(Rm, Rn);
+ case 0x25: // MOVWS0(Rm, Rn);
+ case 0x35: // MOVWS0(Rm, Rn);
+ UML_ADD(block, I0, R32(0), R32(Rn)); // add r0, R0, Rn
+ UML_AND(block, I1, R32(Rm), 0x0000ffff); // and r1, Rm, 0xffff
+ UML_CALLH(block, *m_write16); // call write16
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x06: // MOVLS0(Rm, Rn);
+ case 0x16: // MOVLS0(Rm, Rn);
+ case 0x26: // MOVLS0(Rm, Rn);
+ case 0x36: // MOVLS0(Rm, Rn);
+ UML_ADD(block, I0, R32(0), R32(Rn)); // add r0, R0, Rn
+ UML_MOV(block, I1, R32(Rm)); // mov r1, Rm
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x07: // MULL(Rm, Rn);
+ case 0x17: // MULL(Rm, Rn);
+ case 0x27: // MULL(Rm, Rn);
+ case 0x37: // MULL(Rm, Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_MULU(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->ea), R32(Rn), R32(Rm)); // mulu macl, ea, Rn, Rm
+ return true;
+ }
+ break;
+
+ case 0x08: // CLRT();
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit)
+ return true;
+
+ case 0x0a: // STSMACH(Rn);
+ UML_MOV(block, R32(Rn), mem(&m_sh2_state->mach)); // mov Rn, mach
+ return true;
+
+ case 0x0b: // RTS();
+ UML_MOV(block, mem(&m_sh2_state->target), mem(&m_sh2_state->pr)); // mov target, pr (in case of d-slot shenanigans)
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->target);
+
+ generate_update_cycles(block, compiler, mem(&m_sh2_state->target), true); // <subtract cycles>
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode);
+ return true;
+
+ case 0x0c: // MOVBL0(Rm, Rn);
+ case 0x1c: // MOVBL0(Rm, Rn);
+ case 0x2c: // MOVBL0(Rm, Rn);
+ case 0x3c: // MOVBL0(Rm, Rn);
+ UML_ADD(block, I0, R32(0), R32(Rm)); // add r0, R0, Rm
+ UML_CALLH(block, *m_read8); // call read8
+ UML_SEXT(block, R32(Rn), I0, SIZE_BYTE); // sext Rn, r0, BYTE
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x0d: // MOVWL0(Rm, Rn);
+ case 0x1d: // MOVWL0(Rm, Rn);
+ case 0x2d: // MOVWL0(Rm, Rn);
+ case 0x3d: // MOVWL0(Rm, Rn);
+ UML_ADD(block, I0, R32(0), R32(Rm)); // add r0, R0, Rm
+ UML_CALLH(block, *m_read16); // call read16
+ UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x0e: // MOVLL0(Rm, Rn);
+ case 0x1e: // MOVLL0(Rm, Rn);
+ case 0x2e: // MOVLL0(Rm, Rn);
+ case 0x3e: // MOVLL0(Rm, Rn);
+ UML_ADD(block, I0, R32(0), R32(Rm)); // add r0, R0, Rm
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, R32(Rn), I0); // mov Rn, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x0f: // MAC_L(Rm, Rn);
+ case 0x1f: // MAC_L(Rm, Rn);
+ case 0x2f: // MAC_L(Rm, Rn);
+ case 0x3f: // MAC_L(Rm, Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ save_fast_iregs(block);
+ UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]);
+ UML_CALLC(block, cfunc_MAC_L, this);
+ load_fast_iregs(block);
+ return true;
+ }
+ break;
+
+ case 0x12: // STCGBR(Rn);
+ UML_MOV(block, R32(Rn), mem(&m_sh2_state->gbr)); // mov Rn, gbr
+ return true;
+
+ case 0x18: // SETT();
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T
+ return true;
+
+ case 0x19: // DIV0U();
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~(M|Q|T)); // and sr, sr, ~(M|Q|T)
+ return true;
+
+ case 0x1a: // STSMACL(Rn);
+ UML_MOV(block, R32(Rn), mem(&m_sh2_state->macl)); // mov Rn, macl
+ return true;
+
+ case 0x1b: // SLEEP();
+ UML_MOV(block, I0, mem(&m_sh2_state->sleep_mode)); // mov i0, sleep_mode
+ UML_CMP(block, I0, 0x2); // cmp i0, #2
+ UML_JMPc(block, COND_E, compiler->labelnum); // beq labelnum
+ // sleep mode != 2
+ UML_MOV(block, mem(&m_sh2_state->sleep_mode), 0x1); // mov sleep_mode, #1
+ generate_update_cycles(block, compiler, desc->pc, true); // repeat this insn
+ UML_JMP(block, compiler->labelnum+1); // jmp labelnum+1
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ // sleep_mode == 2
+ UML_MOV(block, mem(&m_sh2_state->sleep_mode), 0x0); // sleep_mode = 0
+ generate_update_cycles(block, compiler, desc->pc+2, true); // go to next insn
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum+1:
+ return true;
+
+ case 0x22: // STCVBR(Rn);
+ UML_MOV(block, R32(Rn), mem(&m_sh2_state->vbr)); // mov Rn, vbr
+ return true;
+
+ case 0x23: // BRAF(Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_ADD(block, mem(&m_sh2_state->target), R32(Rn), desc->pc+4); // add target, Rn, pc+4
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->target);
+
+ generate_update_cycles(block, compiler, mem(&m_sh2_state->target), true); // <subtract cycles>
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // jmp target
+ return true;
+ }
+ break;
+
+ case 0x28: // CLRMAC();
+ UML_MOV(block, mem(&m_sh2_state->macl), 0); // mov macl, #0
+ UML_MOV(block, mem(&m_sh2_state->mach), 0); // mov mach, #0
+ return true;
+
+ case 0x29: // MOVT(Rn);
+ UML_AND(block, R32(Rn), mem(&m_sh2_state->sr), T); // and Rn, sr, T
+ return true;
+
+ case 0x2a: // STSPR(Rn);
+ UML_MOV(block, R32(Rn), mem(&m_sh2_state->pr)); // mov Rn, pr
+ return true;
+
+ case 0x2b: // RTE();
+ generate_delay_slot(block, compiler, desc, 0xffffffff);
+
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, mem(&m_sh2_state->pc), I0); // mov pc, r0
+ UML_ADD(block, R32(15), R32(15), 4); // add R15, R15, #4
+
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov sr, r0
+ UML_ADD(block, R32(15), R32(15), 4); // add R15, R15, #4
+
+ compiler->checkints = true;
+ UML_MOV(block, mem(&m_sh2_state->ea), mem(&m_sh2_state->pc)); // mov ea, pc
+ generate_update_cycles(block, compiler, mem(&m_sh2_state->ea), true); // <subtract cycles>
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->pc), *m_nocode); // and jump to the "resume PC"
+
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_device::generate_group_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc)
+{
+ switch (opcode & 15)
+ {
+ case 0: // MOVBS(Rm, Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_AND(block, I1, R32(Rm), 0xff); // and r1, Rm, 0xff
+ UML_CALLH(block, *m_write8);
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 1: // MOVWS(Rm, Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_AND(block, I1, R32(Rm), 0xffff); // and r1, Rm, 0xffff
+ UML_CALLH(block, *m_write16);
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 2: // MOVLS(Rm, Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_MOV(block, I1, R32(Rm)); // mov r1, Rm
+ UML_CALLH(block, *m_write32);
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 3:
+ return false;
+
+ case 4: // MOVBM(Rm, Rn);
+ UML_MOV(block, I1, R32(Rm)); // mov r1, Rm
+ UML_SUB(block, R32(Rn), R32(Rn), 1); // sub Rn, Rn, 1
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_CALLH(block, *m_write8); // call write8
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 5: // MOVWM(Rm, Rn);
+ UML_MOV(block, I1, R32(Rm)); // mov r1, Rm
+ UML_SUB(block, R32(Rn), R32(Rn), 2); // sub Rn, Rn, 2
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_CALLH(block, *m_write16); // call write16
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 6: // MOVLM(Rm, Rn);
+ UML_MOV(block, I1, R32(Rm)); // mov r1, Rm
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, 4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 13: // XTRCT(Rm, Rn);
+ UML_SHL(block, I0, R32(Rm), 16); // shl r0, Rm, #16
+ UML_AND(block, I0, I0, 0xffff0000); // and r0, r0, #0xffff0000
+
+ UML_SHR(block, I1, R32(Rn), 16); // shr, r1, Rn, #16
+ UML_AND(block, I1, I1, 0xffff); // and r1, r1, #0x0000ffff
+
+ UML_OR(block, R32(Rn), I0, I1); // or Rn, r0, r1
+ return true;
+
+ case 7: // DIV0S(Rm, Rn);
+ UML_MOV(block, I0, mem(&m_sh2_state->sr)); // move r0, sr
+ UML_AND(block, I0, I0, ~(Q|M|T)); // and r0, r0, ~(Q|M|T) (clear the Q,M, and T bits)
+
+ UML_TEST(block, R32(Rn), 0x80000000); // test Rn, #0x80000000
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jz labelnum
+
+ UML_OR(block, I0, I0, Q); // or r0, r0, Q
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+
+ UML_TEST(block, R32(Rm), 0x80000000); // test Rm, #0x80000000
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jz labelnum
+
+ UML_OR(block, I0, I0, M); // or r0, r0, M
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+
+ UML_XOR(block, I1, R32(Rn), R32(Rm)); // xor r1, Rn, Rm
+ UML_TEST(block, I1, 0x80000000); // test r1, #0x80000000
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jz labelnum
+
+ UML_OR(block, I0, I0, T); // or r0, r0, T
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov sr, r0
+ return true;
+
+ case 8: // TST(Rm, Rn);
+ UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit)
+ UML_TEST(block, R32(Rm), R32(Rn)); // test Rm, Rn
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum
+
+ UML_OR(block, I0, I0, T); // or r0, r0, T
+ UML_LABEL(block, compiler->labelnum++); // desc->pc:
+
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0
+ return true;
+
+ case 12: // CMPSTR(Rm, Rn);
+ UML_XOR(block, I0, R32(Rn), R32(Rm)); // xor r0, Rn, Rm (temp)
+
+ UML_SHR(block, I1, I0, 24); // shr r1, r0, #24 (HH)
+ UML_AND(block, I1, I1, 0xff); // and r1, r1, #0xff
+
+ UML_SHR(block, I2, I0, 16); // shr r2, r0, #16 (HL)
+ UML_AND(block, I2, I2, 0xff); // and r2, r2, #0xff
+
+ UML_SHR(block, I3, I0, 8); // shr r3, r0, #8 (LH)
+ UML_AND(block, I3, I3, 0xff); // and r3, r3, #0xff
+
+ UML_AND(block, I7, I0, 0xff); // and r7, r0, #0xff (LL)
+
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit)
+
+ UML_CMP(block, I1, 0); // cmp r1, #0
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jnz labelnum
+ UML_CMP(block, I2, 0); // cmp r2, #0
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jnz labelnum
+ UML_CMP(block, I3, 0); // cmp r3, #0
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jnz labelnum
+ UML_CMP(block, I7, 0); // cmp r7, #0
+ UML_JMPc(block, COND_NZ, compiler->labelnum+1); // jnz labelnum
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum+1:
+ return true;
+
+ case 9: // AND(Rm, Rn);
+ UML_AND(block, R32(Rn), R32(Rn), R32(Rm)); // and Rn, Rn, Rm
+ return true;
+
+ case 10: // XOR(Rm, Rn);
+ UML_XOR(block, R32(Rn), R32(Rn), R32(Rm)); // xor Rn, Rn, Rm
+ return true;
+
+ case 11: // OR(Rm, Rn);
+ UML_OR(block, R32(Rn), R32(Rn), R32(Rm)); // or Rn, Rn, Rm
+ return true;
+
+ case 14: // MULU(Rm, Rn);
+ UML_AND(block, I0, R32(Rm), 0xffff); // and r0, Rm, 0xffff
+ UML_AND(block, I1, R32(Rn), 0xffff); // and r1, Rn, 0xffff
+ UML_MULU(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->ea), I0, I1); // mulu macl, ea, r0, r1
+ return true;
+
+ case 15: // MULS(Rm, Rn);
+ UML_SEXT(block, I0, R32(Rm), SIZE_WORD); // sext r0, Rm
+ UML_SEXT(block, I1, R32(Rn), SIZE_WORD); // sext r1, Rn
+ UML_MULS(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->ea), I0, I1); // muls macl, ea, r0, r1
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_device::generate_group_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, uint32_t ovrpc)
+{
+ switch (opcode & 15)
+ {
+ case 0: // CMPEQ(Rm, Rn); (equality)
+ UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm
+ UML_SETc(block, COND_E, I0); // set E, r0
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1
+ return true;
+
+ case 2: // CMPHS(Rm, Rn); (unsigned greater than or equal)
+ UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm
+ UML_SETc(block, COND_AE, I0); // set AE, r0
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1
+ return true;
+
+ case 3: // CMPGE(Rm, Rn); (signed greater than or equal)
+ UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm
+ UML_SETc(block, COND_GE, I0); // set GE, r0
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1
+ return true;
+
+ case 6: // CMPHI(Rm, Rn); (unsigned greater than)
+ UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm
+ UML_SETc(block, COND_A, I0); // set A, r0
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1
+ return true;
+
+ case 7: // CMPGT(Rm, Rn); (signed greater than)
+ UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm
+ UML_SETc(block, COND_G, I0); // set G, r0
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1
+ return true;
+
+ case 1:
+ case 9:
+ return false;
+
+ case 4: // DIV1(Rm, Rn);
+ save_fast_iregs(block);
+ UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]);
+ UML_CALLC(block, cfunc_DIV1, this);
+ load_fast_iregs(block);
+ return true;
+
+ case 5: // DMULU(Rm, Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_MULU(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->mach), R32(Rn), R32(Rm));
+ return true;
+ }
+ break;
+
+ case 13: // DMULS(Rm, Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_MULS(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->mach), R32(Rn), R32(Rm));
+ return true;
+ }
+ break;
+
+ case 8: // SUB(Rm, Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), R32(Rm)); // sub Rn, Rn, Rm
+ return true;
+
+ case 12: // ADD(Rm, Rn);
+ UML_ADD(block, R32(Rn), R32(Rn), R32(Rm)); // add Rn, Rn, Rm
+ return true;
+
+ case 10: // SUBC(Rm, Rn);
+ UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry = T (T is bit 0 of SR)
+ UML_SUBB(block, R32(Rn), R32(Rn), R32(Rm)); // addc Rn, Rn, Rm
+ UML_SETc(block, COND_C, I0); // setc i0, C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T
+ return true;
+
+ case 11: // SUBV(Rm, Rn);
+#if ADDSUBV_DIRECT
+ UML_SUB(block, R32(Rn), R32(Rn), R32(Rm)); // sub Rn, Rn, Rm
+ UML_SETc(block, COND_V, I0); // setc i0, V
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T
+#else
+ save_fast_iregs(block);
+ UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]);
+ UML_CALLC(block, cfunc_SUBV, this);
+ load_fast_iregs(block);
+#endif
+ return true;
+
+ case 14: // ADDC(Rm, Rn);
+ UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry = T (T is bit 0 of SR)
+ UML_ADDC(block, R32(Rn), R32(Rn), R32(Rm)); // addc Rn, Rn, Rm
+ UML_SETc(block, COND_C, I0); // setc i0, C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T
+ return true;
+
+ case 15: // ADDV(Rm, Rn);
+#if ADDSUBV_DIRECT
+ UML_ADD(block, R32(Rn), R32(Rn), R32(Rm)); // add Rn, Rn, Rm
+ UML_SETc(block, COND_V, I0); // setc i0, V
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T
+#else
+ save_fast_iregs(block);
+ UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]);
+ UML_CALLC(block, cfunc_ADDV, this);
+ load_fast_iregs(block);
+#endif
+ return true;
+ }
+ return false;
+}
+
+bool sh2_device::generate_group_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: // SHLL(Rn);
+ UML_SHL(block, R32(Rn), R32(Rn), 1); // shl Rn, Rn, 1
+ UML_SETc(block, COND_C, I0); // set i0,C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T
+ return true;
+
+ case 0x01: // SHLR(Rn);
+ UML_SHR(block, R32(Rn), R32(Rn), 1); // shr Rn, Rn, 1
+ UML_SETc(block, COND_C, I0); // set i0,C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T
+ return true;
+
+ case 0x04: // ROTL(Rn);
+ UML_ROL(block, R32(Rn), R32(Rn), 1); // rol Rn, Rn, 1
+ UML_SETc(block, COND_C, I0); // set i0,C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T
+ return true;
+
+ case 0x05: // ROTR(Rn);
+ UML_ROR(block, R32(Rn), R32(Rn), 1); // ror Rn, Rn, 1
+ UML_SETc(block, COND_C, I0); // set i0,C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T
+ return true;
+
+ case 0x02: // STSMMACH(Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_MOV(block, I1, mem(&m_sh2_state->mach)); // mov r1, mach
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x03: // STCMSR(Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_MOV(block, I1, mem(&m_sh2_state->sr)); // mov r1, sr
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x06: // LDSMMACH(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read32); // call read32
+ UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4
+ UML_MOV(block, mem(&m_sh2_state->mach), I0); // mov mach, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x07: // LDCMSR(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read32); // call read32
+ UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov sr, r0
+
+ compiler->checkints = true;
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+
+ case 0x08: // SHLL2(Rn);
+ UML_SHL(block, R32(Rn), R32(Rn), 2);
+ return true;
+
+ case 0x09: // SHLR2(Rn);
+ UML_SHR(block, R32(Rn), R32(Rn), 2);
+ return true;
+
+ case 0x18: // SHLL8(Rn);
+ UML_SHL(block, R32(Rn), R32(Rn), 8);
+ return true;
+
+ case 0x19: // SHLR8(Rn);
+ UML_SHR(block, R32(Rn), R32(Rn), 8);
+ return true;
+
+ case 0x28: // SHLL16(Rn);
+ UML_SHL(block, R32(Rn), R32(Rn), 16);
+ return true;
+
+ case 0x29: // SHLR16(Rn);
+ UML_SHR(block, R32(Rn), R32(Rn), 16);
+ return true;
+
+ case 0x0a: // LDSMACH(Rn);
+ UML_MOV(block, mem(&m_sh2_state->mach), R32(Rn)); // mov mach, Rn
+ return true;
+
+ case 0x0b: // JSR(Rn);
+ UML_MOV(block, mem(&m_sh2_state->target), R32(Rn)); // mov target, Rn
+
+ UML_ADD(block, mem(&m_sh2_state->pr), desc->pc, 4); // add m_pr, desc->pc, #4 (skip the current insn & delay slot)
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->target-4);
+
+ generate_update_cycles(block, compiler, mem(&m_sh2_state->target), true); // <subtract cycles>
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // and do the jump
+ return true;
+
+ case 0x0e: // LDCSR(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_AND(block, I0, I0, FLAGS); // and r0, r0, FLAGS
+ UML_MOV(block, mem(&m_sh2_state->sr), I0);
+
+ compiler->checkints = true;
+ return true;
+
+ case 0x0f: // MAC_W(Rm, Rn);
+ case 0x1f: // MAC_W(Rm, Rn);
+ case 0x2f: // MAC_W(Rm, Rn);
+ case 0x3f: // MAC_W(Rm, Rn);
+ save_fast_iregs(block);
+ UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]);
+ UML_CALLC(block, cfunc_MAC_W, this);
+ load_fast_iregs(block);
+ return true;
+
+ case 0x10: // DT(Rn);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit)
+ UML_SUB(block, R32(Rn), R32(Rn), 1); // sub Rn, Rn, 1
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jz compiler->labelnum
+
+ UML_OR(block, I0, I0, T); // or r0, r0, T
+ UML_LABEL(block, compiler->labelnum++); // desc->pc:
+
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0
+ return true;
+ }
+ break;
+
+ case 0x11: // CMPPZ(Rn);
+ UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit)
+
+ UML_CMP(block, R32(Rn), 0); // cmp Rn, 0
+ UML_JMPc(block, COND_S, compiler->labelnum); // js compiler->labelnum (if negative)
+
+ UML_OR(block, I0, I0, T); // or r0, r0, T
+ UML_LABEL(block, compiler->labelnum++); // desc->pc:
+
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0
+ return true;
+
+ case 0x15: // CMPPL(Rn);
+ UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit)
+
+ UML_CMP(block, R32(Rn), 0); // cmp Rn, 0
+
+ UML_JMPc(block, COND_S, compiler->labelnum); // js compiler->labelnum (if negative)
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jz compiler->labelnum (if zero)
+
+ UML_OR(block, I0, I0, T); // or r0, r0, T
+
+ UML_LABEL(block, compiler->labelnum++); // desc->pc:
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0
+ return true;
+
+ case 0x12: // STSMMACL(Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_MOV(block, I1, mem(&m_sh2_state->macl)); // mov r1, macl
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x13: // STCMGBR(Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_MOV(block, I1, mem(&m_sh2_state->gbr)); // mov r1, gbr
+ SETEA(0); // set ea for debug
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x16: // LDSMMACL(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read32); // call read32
+ UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4
+ UML_MOV(block, mem(&m_sh2_state->macl), I0); // mov macl, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x17: // LDCMGBR(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read32); // call read32
+ UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4
+ UML_MOV(block, mem(&m_sh2_state->gbr), I0); // mov gbr, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x1a: // LDSMACL(Rn);
+ UML_MOV(block, mem(&m_sh2_state->macl), R32(Rn)); // mov macl, Rn
+ return true;
+
+ case 0x1b: // TAS(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read8); // call read8
+
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T
+
+ UML_CMP(block, I0, 0); // cmp r0, #0
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz labelnum
+
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+
+ UML_OR(block, I1, I0, 0x80); // or r1, r0, #0x80
+
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ UML_CALLH(block, *m_write8); // write the value back
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x1e: // LDCGBR(Rn);
+ UML_MOV(block, mem(&m_sh2_state->gbr), R32(Rn)); // mov gbr, Rn
+ return true;
+
+ case 0x20: // SHAL(Rn);
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T
+ UML_SHR(block, I0, R32(Rn), 31); // shr r0, Rn, 31
+ UML_AND(block, I0, I0, T); // and r0, r0, T
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), I0); // or sr, sr, r0
+ UML_SHL(block, R32(Rn), R32(Rn), 1); // shl Rn, Rn, 1
+ return true;
+
+ case 0x21: // SHAR(Rn);
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T
+ UML_AND(block, I0, R32(Rn), T); // and r0, Rn, T
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), I0); // or sr, sr, r0
+ UML_SAR(block, R32(Rn), R32(Rn), 1); // sar Rn, Rn, 1
+ return true;
+
+ case 0x22: // STSMPR(Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, 4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_MOV(block, I1, mem(&m_sh2_state->pr)); // mov r1, pr
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x23: // STCMVBR(Rn);
+ UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, 4
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_MOV(block, I1, mem(&m_sh2_state->vbr)); // mov r1, vbr
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x24: // ROTCL(Rn);
+ UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry sr,0
+ UML_ROLC(block, R32(Rn), R32(Rn), 1); // rolc Rn,Rn,1
+ UML_SETc(block, COND_C, I0); // set i0,C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T
+ return true;
+
+ case 0x25: // ROTCR(Rn);
+ UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry sr,0
+ UML_RORC(block, R32(Rn), R32(Rn), 1); // rorc Rn,Rn,1
+ UML_SETc(block, COND_C, I0); // set i0,C
+ UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T
+ return true;
+
+ case 0x26: // LDSMPR(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, mem(&m_sh2_state->pr), I0); // mov m_pr, r0
+ UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, Rn, #4
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x27: // LDCMVBR(Rn);
+ UML_MOV(block, I0, R32(Rn)); // mov r0, Rn
+ SETEA(0);
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, mem(&m_sh2_state->vbr), I0); // mov m_sh2_state->vbr, r0
+ UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, Rn, #4
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 0x2a: // LDSPR(Rn);
+ UML_MOV(block, mem(&m_sh2_state->pr), R32(Rn)); // mov m_pr, Rn
+ return true;
+
+ case 0x2b: // JMP(Rn);
+ UML_MOV(block, mem(&m_sh2_state->target), R32(Rn)); // mov target, Rn
+
+ generate_delay_slot(block, compiler, desc, m_sh2_state->target);
+
+ generate_update_cycles(block, compiler, mem(&m_sh2_state->target), true); // <subtract cycles>
+ UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // jmp (target)
+ return true;
+
+ case 0x2e: // LDCVBR(Rn);
+ UML_MOV(block, mem(&m_sh2_state->vbr), R32(Rn)); // mov vbr, Rn
+ return true;
+
+ case 0x0c:
+ case 0x0d:
+ case 0x14:
+ case 0x1c:
+ case 0x1d:
+ case 0x2c:
+ case 0x2d:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ return false;
+ }
+
+ return false;
+}
+
+bool sh2_device::generate_group_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc)
+{
+ switch (opcode & 15)
+ {
+ case 0: // MOVBL(Rm, Rn);
+ UML_MOV(block, I0, R32(Rm)); // mov r0, Rm
+ SETEA(0); // debug: ea = r0
+ UML_CALLH(block, *m_read8); // call read8
+ UML_SEXT(block, R32(Rn), I0, SIZE_BYTE); // sext Rn, r0, BYTE
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 1: // MOVWL(Rm, Rn);
+ UML_MOV(block, I0, R32(Rm)); // mov r0, Rm
+ SETEA(0); // debug: ea = r0
+ UML_CALLH(block, *m_read16); // call read16
+ UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 2: // MOVLL(Rm, Rn);
+ UML_MOV(block, I0, R32(Rm)); // mov r0, Rm
+ SETEA(0); // debug: ea = r0
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, R32(Rn), I0); // mov Rn, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 3: // MOV(Rm, Rn);
+ UML_MOV(block, R32(Rn), R32(Rm)); // mov Rn, Rm
+ return true;
+
+ case 7: // NOT(Rm, Rn);
+ UML_XOR(block, R32(Rn), R32(Rm), 0xffffffff); // xor Rn, Rm, 0xffffffff
+ return true;
+
+ case 9: // SWAPW(Rm, Rn);
+ UML_ROL(block, R32(Rn), R32(Rm), 16); // rol Rn, Rm, 16
+ return true;
+
+ case 11: // NEG(Rm, Rn);
+ UML_SUB(block, R32(Rn), 0, R32(Rm)); // sub Rn, 0, Rm
+ return true;
+
+ case 12: // EXTUB(Rm, Rn);
+ UML_AND(block, R32(Rn), R32(Rm), 0x000000ff); // and Rn, Rm, 0xff
+ return true;
+
+ case 13: // EXTUW(Rm, Rn);
+ UML_AND(block, R32(Rn), R32(Rm), 0x0000ffff); // and Rn, Rm, 0xffff
+ return true;
+
+ case 14: // EXTSB(Rm, Rn);
+ UML_SEXT(block, R32(Rn), R32(Rm), SIZE_BYTE); // sext Rn, Rm, BYTE
+ return true;
+
+ case 15: // EXTSW(Rm, Rn);
+ UML_SEXT(block, R32(Rn), R32(Rm), SIZE_WORD); // sext Rn, Rm, WORD
+ return true;
+
+ case 4: // MOVBP(Rm, Rn);
+ UML_MOV(block, I0, R32(Rm)); // mov r0, Rm
+ UML_CALLH(block, *m_read8); // call read8
+ UML_SEXT(block, R32(Rn), I0, SIZE_BYTE); // sext Rn, r0, BYTE
+
+ if (Rm != Rn)
+ UML_ADD(block, R32(Rm), R32(Rm), 1); // add Rm, Rm, #1
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 5: // MOVWP(Rm, Rn);
+ UML_MOV(block, I0, R32(Rm)); // mov r0, Rm
+ UML_CALLH(block, *m_read16); // call read16
+ UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD
+
+ if (Rm != Rn)
+ UML_ADD(block, R32(Rm), R32(Rm), 2); // add Rm, Rm, #2
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 6: // MOVLP(Rm, Rn);
+ UML_MOV(block, I0, R32(Rm)); // mov r0, Rm
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, R32(Rn), I0); // mov Rn, r0
+
+ if (Rm != Rn)
+ UML_ADD(block, R32(Rm), R32(Rm), 4); // add Rm, Rm, #4
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 8: // SWAPB(Rm, Rn);
+ UML_AND(block, I0, R32(Rm), 0xffff0000); // and r0, Rm, #0xffff0000
+ UML_AND(block, I1, R32(Rm), 0x000000ff); // and r0, Rm, #0x000000ff
+ UML_AND(block, I2, R32(Rm), 0x0000ff00); // and r0, Rm, #0x0000ff00
+ UML_SHL(block, I1, I1, 8); // shl r1, r1, #8
+ UML_SHR(block, I2, I2, 8); // shr r2, r2, #8
+ UML_OR(block, I0, I0, I1); // or r0, r0, r1
+ UML_OR(block, R32(Rn), I0, I2); // or Rn, r0, r2
+ return true;
+
+ case 10: // NEGC(Rm, Rn);
+ UML_MOV(block, I0, mem(&m_sh2_state->sr)); // mov r0, sr (save SR)
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit)
+ UML_CARRY(block, I0, 0); // carry = T (T is bit 0 of SR)
+ UML_SUBB(block, R32(Rn), 0, R32(Rm)); // subb Rn, #0, Rm
+
+ UML_JMPc(block, COND_NC, compiler->labelnum); // jnc labelnum
+
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_device::generate_group_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc)
+{
+ int32_t disp;
+ uint32_t udisp;
+ code_label templabel;
+
+ switch ( opcode & (15<<8) )
+ {
+ case 0 << 8: // MOVBS4(opcode & 0x0f, Rm);
+ udisp = (opcode & 0x0f);
+ UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp
+ UML_MOV(block, I1, R32(0)); // mov r1, R0
+ UML_CALLH(block, *m_write8); // call write8
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 1 << 8: // MOVWS4(opcode & 0x0f, Rm);
+ udisp = (opcode & 0x0f) * 2;
+ UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp
+ UML_MOV(block, I1, R32(0)); // mov r1, R0
+ UML_CALLH(block, *m_write16); // call write16
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 2<< 8:
+ case 3<< 8:
+ case 6<< 8:
+ case 7<< 8:
+ case 10<< 8:
+ case 12<< 8:
+ case 14<< 8:
+ return false;
+
+ case 4<< 8: // MOVBL4(Rm, opcode & 0x0f);
+ udisp = opcode & 0x0f;
+ UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp
+ SETEA(0);
+ UML_CALLH(block, *m_read8); // call read8
+ UML_SEXT(block, R32(0), I0, SIZE_BYTE); // sext R0, r0, BYTE
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 5<< 8: // MOVWL4(Rm, opcode & 0x0f);
+ udisp = (opcode & 0x0f)*2;
+ UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp
+ SETEA(0);
+ UML_CALLH(block, *m_read16); // call read16
+ UML_SEXT(block, R32(0), I0, SIZE_WORD); // sext R0, r0, WORD
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 8<< 8: // CMPIM(opcode & 0xff);
+ UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit)
+
+ UML_SEXT(block, I1, opcode&0xff, SIZE_BYTE); // sext r1, opcode&0xff, BYTE
+ UML_CMP(block, I1, R32(0)); // cmp r1, R0
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum (if negative)
+
+ UML_OR(block, I0, I0, T); // or r0, r0, T
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0
+ return true;
+
+ case 9<< 8: // BT(opcode & 0xff);
+ UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jz compiler->labelnum
+
+ disp = ((int32_t)opcode << 24) >> 24;
+ m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination
+
+ generate_update_cycles(block, compiler, m_sh2_state->ea, true); // <subtract cycles>
+ UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ return true;
+
+ case 11<< 8: // BF(opcode & 0xff);
+ UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum
+
+ disp = ((int32_t)opcode << 24) >> 24;
+ m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination
+
+ generate_update_cycles(block, compiler, m_sh2_state->ea, true); // <subtract cycles>
+ UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ return true;
+
+ case 13<< 8: // BTS(opcode & 0xff);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T
+ UML_JMPc(block, COND_Z, compiler->labelnum); // jz compiler->labelnum
+
+ disp = ((int32_t)opcode << 24) >> 24;
+ m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination
+
+ templabel = compiler->labelnum; // save our label
+ compiler->labelnum++; // make sure the delay slot doesn't use it
+ generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2);
+
+ generate_update_cycles(block, compiler, m_sh2_state->ea, true); // <subtract cycles>
+ UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea
+
+ UML_LABEL(block, templabel); // labelnum:
+ return true;
+ }
+ break;
+
+ case 15<< 8: // BFS(opcode & 0xff);
+ if (m_cpu_type > CPU_TYPE_SH1)
+ {
+ UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum
+
+ disp = ((int32_t)opcode << 24) >> 24;
+ m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination
+
+ templabel = compiler->labelnum; // save our label
+ compiler->labelnum++; // make sure the delay slot doesn't use it
+ generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2); // delay slot only if the branch is taken
+
+ generate_update_cycles(block, compiler, m_sh2_state->ea, true); // <subtract cycles>
+ UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea
+
+ UML_LABEL(block, templabel); // labelnum:
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+bool sh2_device::generate_group_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc)
+{
+ uint32_t scratch;
+
+ switch (opcode & (15<<8))
+ {
+ case 0<<8: // MOVBSG(opcode & 0xff);
+ scratch = (opcode & 0xff);
+ UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch
+ UML_AND(block, I1, R32(0), 0xff); // and r1, R0, 0xff
+ UML_CALLH(block, *m_write8); // call write8
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 1<<8: // MOVWSG(opcode & 0xff);
+ scratch = (opcode & 0xff) * 2;
+ UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch
+ UML_AND(block, I1, R32(0), 0xffff); // and r1, R0, 0xffff
+ UML_CALLH(block, *m_write16); // call write16
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 2<<8: // MOVLSG(opcode & 0xff);
+ scratch = (opcode & 0xff) * 4;
+ UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch
+ UML_MOV(block, I1, R32(0)); // mov r1, R0
+ UML_CALLH(block, *m_write32); // call write32
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 3<<8: // TRAPA(opcode & 0xff);
+ scratch = (opcode & 0xff) * 4;
+ UML_ADD(block, mem(&m_sh2_state->ea), mem(&m_sh2_state->vbr), scratch); // add ea, vbr, scratch
+
+ UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_MOV(block, I1, mem(&m_sh2_state->sr)); // mov r1, sr
+ UML_CALLH(block, *m_write32); // write32
+
+ UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4
+ UML_MOV(block, I0, R32(15)); // mov r0, R15
+ UML_MOV(block, I1, desc->pc+2); // mov r1, pc+2
+ UML_CALLH(block, *m_write32); // write32
+
+ UML_MOV(block, I0, mem(&m_sh2_state->ea)); // mov r0, ea
+ UML_CALLH(block, *m_read32); // read32
+ UML_HASHJMP(block, 0, I0, *m_nocode); // jmp (r0)
+
+ return true;
+
+ case 4<<8: // MOVBLG(opcode & 0xff);
+ scratch = (opcode & 0xff);
+ UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch
+ UML_CALLH(block, *m_read8); // call read16
+ UML_SEXT(block, R32(0), I0, SIZE_BYTE); // sext R0, r0, BYTE
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 5<<8: // MOVWLG(opcode & 0xff);
+ scratch = (opcode & 0xff) * 2;
+ UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch
+ UML_CALLH(block, *m_read16); // call read16
+ UML_SEXT(block, R32(0), I0, SIZE_WORD); // sext R0, r0, WORD
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 6<<8: // MOVLLG(opcode & 0xff);
+ scratch = (opcode & 0xff) * 4;
+ UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch
+ UML_CALLH(block, *m_read32); // call read32
+ UML_MOV(block, R32(0), I0); // mov R0, r0
+
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 2, true);
+ return true;
+
+ case 7<<8: // MOVA(opcode & 0xff);
+ scratch = (opcode & 0xff) * 4;
+ scratch += ((desc->pc + 4) & ~3);
+
+ UML_MOV(block, R32(0), scratch); // mov R0, scratch
+ return true;
+
+ case 8<<8: // TSTI(opcode & 0xff);
+ scratch = opcode & 0xff;
+
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit)
+ UML_AND(block, I0, R32(0), scratch); // and r0, R0, scratch
+ UML_CMP(block, I0, 0); // cmp r0, #0
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz labelnum
+
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ return true;
+
+ case 9<<8: // ANDI(opcode & 0xff);
+ UML_AND(block, R32(0), R32(0), opcode & 0xff); // and r0, r0, opcode & 0xff
+ return true;
+
+ case 10<<8: // XORI(opcode & 0xff);
+ UML_XOR(block, R32(0), R32(0), opcode & 0xff); // xor r0, r0, opcode & 0xff
+ return true;
+
+ case 11<<8: // ORI(opcode & 0xff);
+ UML_OR(block, R32(0), R32(0), opcode & 0xff); // or r0, r0, opcode & 0xff
+ return true;
+
+ case 12<<8: // TSTM(opcode & 0xff);
+ UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit)
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ UML_CALLH(block, *m_read8); // read8
+
+ UML_AND(block, I0, I0, opcode & 0xff);
+ UML_CMP(block, I0, 0); // cmp r0, #0
+ UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz labelnum
+
+ UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T
+
+ UML_LABEL(block, compiler->labelnum++); // labelnum:
+ return true;
+
+ case 13<<8: // ANDM(opcode & 0xff);
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ UML_CALLH(block, *m_read8); // read8
+
+ UML_AND(block, I1, I0, opcode&0xff); // and r1, r0, #opcode&0xff
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ SETEA(0);
+ UML_CALLH(block, *m_write8); // write8
+ return true;
+
+ case 14<<8: // XORM(opcode & 0xff);
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ UML_CALLH(block, *m_read8); // read8
+
+ UML_XOR(block, I1, I0, opcode&0xff); // xor r1, r0, #opcode&0xff
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ SETEA(0);
+ UML_CALLH(block, *m_write8); // write8
+ return true;
+
+ case 15<<8: // ORM(opcode & 0xff);
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ UML_CALLH(block, *m_read8); // read8
+
+ UML_OR(block, I1, I0, opcode&0xff); // or r1, r0, #opcode&0xff
+ UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr
+ SETEA(0);
+ UML_CALLH(block, *m_write8); // write8
+ return true;
+ }
+
+ return false;
+}
+
+/***************************************************************************
+ CORE CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ sh2drc_set_options - configure DRC options
+-------------------------------------------------*/
+
+void sh2_device::sh2drc_set_options(uint32_t options)
+{
+ if (!allow_drc()) return;
+ m_drcoptions = options;
+}
+
+
+/*-------------------------------------------------
+ sh2drc_add_pcflush - add a new address where
+ the PC must be flushed for speedups to work
+-------------------------------------------------*/
+
+void sh2_device::sh2drc_add_pcflush(offs_t address)
+{
+ if (!allow_drc()) return;
+
+ if (m_pcfsel < ARRAY_LENGTH(m_pcflushes))
+ m_pcflushes[m_pcfsel++] = address;
+}
+
+
+/*-------------------------------------------------
+ sh2drc_add_fastram - add a new fastram
+ region
+-------------------------------------------------*/
+
+void sh2_device::sh2drc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base)
+{
+ if (m_fastram_select < ARRAY_LENGTH(m_fastram))
+ {
+ m_fastram[m_fastram_select].start = start;
+ m_fastram[m_fastram_select].end = end;
+ m_fastram[m_fastram_select].readonly = readonly;
+ m_fastram[m_fastram_select].base = base;
+ m_fastram_select++;
+ }
+}
diff --git a/src/devices/cpu/sh/sh2fe.cpp b/src/devices/cpu/sh/sh2fe.cpp
new file mode 100644
index 00000000000..f6b409a0cd5
--- /dev/null
+++ b/src/devices/cpu/sh/sh2fe.cpp
@@ -0,0 +1,762 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ sh2fe.c
+
+ Front end for SH-2 recompiler
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh2.h"
+#include "sh2comn.h"
+#include "cpu/drcfe.h"
+
+
+/***************************************************************************
+ INSTRUCTION PARSERS
+***************************************************************************/
+
+sh2_frontend::sh2_frontend(sh2_device *device, uint32_t window_start, uint32_t window_end, uint32_t max_sequence)
+ : drc_frontend(*device, window_start, window_end, max_sequence)
+ , m_sh2(device)
+{
+}
+
+/*-------------------------------------------------
+ describe_instruction - build a description
+ of a single instruction
+-------------------------------------------------*/
+
+bool sh2_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
+{
+ uint16_t opcode;
+
+ /* fetch the opcode */
+ opcode = desc.opptr.w[0] = m_sh2->m_direct->read_word(desc.physpc, SH2_CODE_XOR(0));
+
+ /* all instructions are 2 bytes and most are a single cycle */
+ desc.length = 2;
+ desc.cycles = 1;
+
+ switch (opcode>>12)
+ {
+ case 0:
+ return describe_group_0(desc, prev, opcode);
+
+ case 1: // MOVLS4
+ desc.regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 2:
+ return describe_group_2(desc, prev, opcode);
+
+ case 3:
+ return describe_group_3(desc, prev, opcode);
+
+ case 4:
+ return describe_group_4(desc, prev, opcode);
+
+ case 5: // MOVLL4
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 6:
+ return describe_group_6(desc, prev, opcode);
+
+ case 7: // ADDI
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 8:
+ return describe_group_8(desc, prev, opcode);
+
+ case 9: // MOVWI
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 11: // BSR
+ desc.regout[1] |= REGFLAG_PR;
+ // (intentional fallthrough - BSR is BRA with the addition of PR = the return address)
+ case 10: // BRA
+ {
+ int32_t disp = ((int32_t)opcode << 20) >> 20;
+
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = (desc.pc + 2) + disp * 2 + 2;
+ desc.delayslots = 1;
+ desc.cycles = 2;
+ return true;
+ }
+
+ case 12:
+ return describe_group_12(desc, prev, opcode);
+
+ case 13: // MOVLI
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 14: // MOVI
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 15: // NOP
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_frontend::describe_group_0(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: // NOP();
+ case 0x01: // NOP();
+ case 0x09: // NOP();
+ case 0x10: // NOP();
+ case 0x11: // NOP();
+ case 0x13: // NOP();
+ case 0x20: // NOP();
+ case 0x21: // NOP();
+ case 0x30: // NOP();
+ case 0x31: // NOP();
+ case 0x32: // NOP();
+ case 0x33: // NOP();
+ case 0x38: // NOP();
+ case 0x39: // NOP();
+ case 0x3a: // NOP();
+ case 0x3b: // NOP();
+ return true;
+
+ case 0x02: // STCSR(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 0x03: // BSRF(Rn);
+ desc.regout[1] |= REGFLAG_PR;
+
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.delayslots = 1;
+
+ return true;
+
+ case 0x04: // MOVBS0(Rm, Rn);
+ case 0x05: // MOVWS0(Rm, Rn);
+ case 0x06: // MOVLS0(Rm, Rn);
+ case 0x14: // MOVBS0(Rm, Rn);
+ case 0x15: // MOVWS0(Rm, Rn);
+ case 0x16: // MOVLS0(Rm, Rn);
+ case 0x24: // MOVBS0(Rm, Rn);
+ case 0x25: // MOVWS0(Rm, Rn);
+ case 0x26: // MOVLS0(Rm, Rn);
+ case 0x34: // MOVBS0(Rm, Rn);
+ case 0x35: // MOVWS0(Rm, Rn);
+ case 0x36: // MOVLS0(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn) | REGFLAG_R(0);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x07: // MULL(Rm, Rn);
+ case 0x17: // MULL(Rm, Rn);
+ case 0x27: // MULL(Rm, Rn);
+ case 0x37: // MULL(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm);
+ desc.regout[1] |= REGFLAG_MACL;
+ desc.cycles = 2;
+ return true;
+
+ case 0x08: // CLRT();
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x0a: // STSMACH(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACH;
+ return true;
+
+ case 0x0b: // RTS();
+ desc.regin[1] |= REGFLAG_PR;
+
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.delayslots = 1;
+ desc.cycles = 2;
+
+ return true;
+
+ case 0x0c: // MOVBL0(Rm, Rn);
+ case 0x0d: // MOVWL0(Rm, Rn);
+ case 0x0e: // MOVLL0(Rm, Rn);
+ case 0x1c: // MOVBL0(Rm, Rn);
+ case 0x1d: // MOVWL0(Rm, Rn);
+ case 0x1e: // MOVLL0(Rm, Rn);
+ case 0x2c: // MOVBL0(Rm, Rn);
+ case 0x2d: // MOVWL0(Rm, Rn);
+ case 0x2e: // MOVLL0(Rm, Rn);
+ case 0x3c: // MOVBL0(Rm, Rn);
+ case 0x3d: // MOVWL0(Rm, Rn);
+ case 0x3e: // MOVLL0(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x0f: // MAC_L(Rm, Rn);
+ case 0x1f: // MAC_L(Rm, Rn);
+ case 0x2f: // MAC_L(Rm, Rn);
+ case 0x3f: // MAC_L(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH;
+ desc.cycles = 3;
+ return true;
+
+ case 0x12: // STCGBR(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_GBR;
+ return true;
+
+ case 0x18: // SETT();
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x19: // DIV0U();
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x1a: // STSMACL(Rn);
+ desc.regin[1] |= REGFLAG_MACL;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 0x1b: // SLEEP();
+ desc.cycles = 3;
+ return true;
+
+ case 0x22: // STCVBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_VBR;
+ return true;
+
+ case 0x23: // BRAF(Rn);
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.delayslots = 1;
+ desc.cycles = 2;
+ return true;
+
+ case 0x28: // CLRMAC();
+ desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH;
+ return true;
+
+ case 0x29: // MOVT(Rn);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 0x2a: // STSPR(Rn);
+ desc.regin[1] |= REGFLAG_PR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 0x2b: // RTE();
+ desc.regin[0] |= REGFLAG_R(15);
+ desc.regout[0] |= REGFLAG_R(15);
+
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_EXPOSE_EXTERNAL_INT;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.delayslots = 1;
+ desc.cycles = 4;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_frontend::describe_group_2(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: // MOVBS(Rm, Rn);
+ case 1: // MOVWS(Rm, Rn);
+ case 2: // MOVLS(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 3: // NOP();
+ return true;
+
+ case 4: // MOVBM(Rm, Rn);
+ case 5: // MOVWM(Rm, Rn);
+ case 6: // MOVLM(Rm, Rn);
+ case 13: // XTRCT(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 7: // DIV0S(Rm, Rn);
+ case 8: // TST(Rm, Rn);
+ case 12: // CMPSTR(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 9: // AND(Rm, Rn);
+ case 10: // XOR(Rm, Rn);
+ case 11: // OR(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 14: // MULU(Rm, Rn);
+ case 15: // MULS(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH;
+ desc.cycles = 2;
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_frontend::describe_group_3(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: // CMPEQ(Rm, Rn);
+ case 2: // CMPHS(Rm, Rn);
+ case 3: // CMPGE(Rm, Rn);
+ case 6: // CMPHI(Rm, Rn);
+ case 7: // CMPGT(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 1: // NOP();
+ case 9: // NOP();
+ return true;
+
+ case 4: // DIV1(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 5: // DMULU(Rm, Rn);
+ case 13: // DMULS(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH;
+ desc.cycles = 2;
+ return true;
+
+ case 8: // SUB(Rm, Rn);
+ case 12: // ADD(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 10: // SUBC(Rm, Rn);
+ case 11: // SUBV(Rm, Rn);
+ case 14: // ADDC(Rm, Rn);
+ case 15: // ADDV(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+ }
+ return false;
+}
+
+bool sh2_frontend::describe_group_4(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ switch (opcode & 0x3F)
+ {
+ case 0x00: // SHLL(Rn);
+ case 0x01: // SHLR(Rn);
+ case 0x04: // ROTL(Rn);
+ case 0x05: // ROTR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x02: // STSMMACH(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_MACH;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x03: // STCMSR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.cycles = 2;
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x06: // LDSMMACH(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACH;
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x07: // LDCMSR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ desc.cycles = 3;
+ desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE;
+ return true;
+
+ case 0x08: // SHLL2(Rn);
+ case 0x09: // SHLR2(Rn);
+ case 0x18: // SHLL8(Rn);
+ case 0x19: // SHLR8(Rn);
+ case 0x28: // SHLL16(Rn);
+ case 0x29: // SHLR16(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 0x0a: // LDSMACH(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACH;
+ return true;
+
+ case 0x0b: // JSR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_PR;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.delayslots = 1;
+ return true;
+
+ case 0x0e: // LDCSR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE;
+ return true;
+
+ case 0x0f: // MAC_W(Rm, Rn);
+ case 0x1f: // MAC_W(Rm, Rn);
+ case 0x2f: // MAC_W(Rm, Rn);
+ case 0x3f: // MAC_W(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_MACL | REGFLAG_MACH;
+ desc.regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH;
+ desc.cycles = 3;
+ return true;
+
+ case 0x10: // DT(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x11: // CMPPZ(Rn);
+ case 0x15: // CMPPL(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x12: // STSMMACL(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_MACL;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x13: // STCMGBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_GBR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x16: // LDSMMACL(Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACL;
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x17: // LDCMGBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_GBR;
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x1a: // LDSMACL(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_MACL;
+ return true;
+
+ case 0x1b: // TAS(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[1] |= REGFLAG_SR;
+ desc.cycles = 4;
+ desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x1e: // LDCGBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_GBR;
+ return true;
+
+ case 0x20: // SHAL(Rn);
+ case 0x21: // SHAR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x22: // STSMPR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_PR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x23: // STCMVBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_VBR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x24: // ROTCL(Rn);
+ case 0x25: // ROTCR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 0x26: // LDSMPR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_PR;
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x27: // LDCMVBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_VBR;
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x2a: // LDSPR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_PR;
+ return true;
+
+ case 0x2b: // JMP(Rm);
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.delayslots = 1;
+ return true;
+
+ case 0x2e: // LDCVBR(Rn);
+ desc.regin[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_VBR;
+ return true;
+
+ case 0x0c: // NOP();
+ case 0x0d: // NOP();
+ case 0x14: // NOP();
+ case 0x1c: // NOP();
+ case 0x1d: // NOP();
+ case 0x2c: // NOP();
+ case 0x2d: // NOP();
+ case 0x30: // NOP();
+ case 0x31: // NOP();
+ case 0x32: // NOP();
+ case 0x33: // NOP();
+ case 0x34: // NOP();
+ case 0x35: // NOP();
+ case 0x36: // NOP();
+ case 0x37: // NOP();
+ case 0x38: // NOP();
+ case 0x39: // NOP();
+ case 0x3a: // NOP();
+ case 0x3b: // NOP();
+ case 0x3c: // NOP();
+ case 0x3d: // NOP();
+ case 0x3e: // NOP();
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_frontend::describe_group_6(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0: // MOVBL(Rm, Rn);
+ case 1: // MOVWL(Rm, Rn);
+ case 2: // MOVLL(Rm, Rn);
+ case 3: // MOV(Rm, Rn);
+ case 7: // NOT(Rm, Rn);
+ case 9: // SWAPW(Rm, Rn);
+ case 11: // NEG(Rm, Rn);
+ case 12: // EXTUB(Rm, Rn);
+ case 13: // EXTUW(Rm, Rn);
+ case 14: // EXTSB(Rm, Rn);
+ case 15: // EXTSW(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 4: // MOVBP(Rm, Rn);
+ case 5: // MOVWP(Rm, Rn);
+ case 6: // MOVLP(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 8: // SWAPB(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ return true;
+
+ case 10: // NEGC(Rm, Rn);
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.regout[0] |= REGFLAG_R(Rn);
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+ }
+ return false;
+}
+
+bool sh2_frontend::describe_group_8(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ int32_t disp;
+
+ switch ( opcode & (15<<8) )
+ {
+ case 0 << 8: // MOVBS4(opcode & 0x0f, Rm);
+ case 1 << 8: // MOVWS4(opcode & 0x0f, Rm);
+ desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 2<< 8: // NOP();
+ case 3<< 8: // NOP();
+ case 6<< 8: // NOP();
+ case 7<< 8: // NOP();
+ case 10<< 8: // NOP();
+ case 12<< 8: // NOP();
+ case 14<< 8: // NOP();
+ return true;
+
+ case 4<< 8: // MOVBL4(Rm, opcode & 0x0f);
+ case 5<< 8: // MOVWL4(Rm, opcode & 0x0f);
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.regout[0] |= REGFLAG_R(0);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 8<< 8: // CMPIM(opcode & 0xff);
+ desc.regin[0] |= REGFLAG_R(Rm);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 9<< 8: // BT(opcode & 0xff);
+ case 11<< 8: // BF(opcode & 0xff);
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.cycles = 3;
+ disp = ((int32_t)opcode << 24) >> 24;
+ desc.targetpc = (desc.pc + 2) + disp * 2 + 2;
+ return true;
+
+ case 13<< 8: // BTS(opcode & 0xff);
+ case 15<< 8: // BFS(opcode & 0xff);
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.cycles = 2;
+ disp = ((int32_t)opcode << 24) >> 24;
+ desc.targetpc = (desc.pc + 2) + disp * 2 + 2;
+ desc.delayslots = 1;
+ return true;
+ }
+
+ return false;
+}
+
+bool sh2_frontend::describe_group_12(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode)
+{
+ switch (opcode & (15<<8))
+ {
+ case 0<<8: // MOVBSG(opcode & 0xff);
+ case 1<<8: // MOVWSG(opcode & 0xff);
+ case 2<<8: // MOVLSG(opcode & 0xff);
+ desc.regin[0] |= REGFLAG_R(0);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 3<<8: // TRAPA(opcode & 0xff);
+ desc.regin[0] |= REGFLAG_R(15);
+ desc.regin[1] |= REGFLAG_VBR;
+ desc.regout[0] |= REGFLAG_R(15);
+ desc.cycles = 8;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ return true;
+
+ case 4<<8: // MOVBLG(opcode & 0xff);
+ case 5<<8: // MOVWLG(opcode & 0xff);
+ case 6<<8: // MOVLLG(opcode & 0xff);
+ case 7<<8: // MOVA(opcode & 0xff);
+ desc.regout[0] |= REGFLAG_R(0);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 8<<8: // TSTI(opcode & 0xff);
+ desc.regin[0] |= REGFLAG_R(0);
+ desc.regin[1] |= REGFLAG_SR;
+ desc.regout[1] |= REGFLAG_SR;
+ return true;
+
+ case 9<<8: // ANDI(opcode & 0xff);
+ case 10<<8: // XORI(opcode & 0xff);
+ case 11<<8: // ORI(opcode & 0xff);
+ desc.regin[0] |= REGFLAG_R(0);
+ desc.regout[0] |= REGFLAG_R(0);
+ return true;
+
+ case 12<<8: // TSTM(opcode & 0xff);
+ case 13<<8: // ANDM(opcode & 0xff);
+ case 14<<8: // XORM(opcode & 0xff);
+ case 15<<8: // ORM(opcode & 0xff);
+ desc.regin[0] |= REGFLAG_R(0);
+ desc.regin[1] |= REGFLAG_SR | REGFLAG_GBR;
+ desc.regout[1] |= REGFLAG_SR;
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/devices/cpu/sh/sh3comn.cpp b/src/devices/cpu/sh/sh3comn.cpp
new file mode 100644
index 00000000000..4a50e748eb9
--- /dev/null
+++ b/src/devices/cpu/sh/sh3comn.cpp
@@ -0,0 +1,681 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/* Handlers for SH3 internals */
+
+#include "emu.h"
+#include "debugger.h"
+#include "sh4.h"
+#include "sh4comn.h"
+#include "sh3comn.h"
+#include "sh4tmu.h"
+#include "sh4dmac.h"
+
+/* High internal area (ffffxxxx) */
+
+WRITE32_MEMBER( sh3_base_device::sh3_internal_high_w )
+{
+ COMBINE_DATA(&m_sh3internal_upper[offset]);
+
+ switch (offset)
+ {
+ case SH3_ICR0_IPRA_ADDR:
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (SH3_ICR0_IPRA_ADDR - ICR0)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (SH3_ICR0_IPRA_ADDR - IPRA)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask);
+ sh4_handler_ipra_w(data&0xffff,mem_mask&0xffff);
+ }
+
+ break;
+
+ case SH3_IPRB_ADDR:
+ logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (SH3_IPRB_ADDR)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask);
+ break;
+
+ case SH3_TOCR_TSTR_ADDR:
+ logerror("'%s' (%08x): TMU internal write to %08x = %08x & %08x (SH3_TOCR_TSTR_ADDR)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask);
+ if (mem_mask&0xff000000)
+ {
+ sh4_handle_tocr_addr_w((data>>24)&0xffff, (mem_mask>>24)&0xff);
+ }
+ if (mem_mask&0x0000ff00)
+ {
+ sh4_handle_tstr_addr_w((data>>8)&0xff, (mem_mask>>8)&0xff);
+ }
+ if (mem_mask&0x00ff00ff)
+ {
+ fatalerror("SH3_TOCR_TSTR_ADDR unused bits accessed (write)\n");
+ }
+ break;
+ case SH3_TCOR0_ADDR: sh4_handle_tcor0_addr_w(data, mem_mask);break;
+ case SH3_TCOR1_ADDR: sh4_handle_tcor1_addr_w(data, mem_mask);break;
+ case SH3_TCOR2_ADDR: sh4_handle_tcor2_addr_w(data, mem_mask);break;
+ case SH3_TCNT0_ADDR: sh4_handle_tcnt0_addr_w(data, mem_mask);break;
+ case SH3_TCNT1_ADDR: sh4_handle_tcnt1_addr_w(data, mem_mask);break;
+ case SH3_TCNT2_ADDR: sh4_handle_tcnt2_addr_w(data, mem_mask);break;
+ case SH3_TCR0_ADDR: sh4_handle_tcr0_addr_w(data>>16, mem_mask>>16);break;
+ case SH3_TCR1_ADDR: sh4_handle_tcr1_addr_w(data>>16, mem_mask>>16);break;
+ case SH3_TCR2_ADDR: sh4_handle_tcr2_addr_w(data>>16, mem_mask>>16);break;
+ case SH3_TCPR2_ADDR: sh4_handle_tcpr2_addr_w(data, mem_mask);break;
+
+ default:
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (unk)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask);
+ break;
+
+ }
+
+
+
+
+}
+
+READ32_MEMBER( sh3_base_device::sh3_internal_high_r )
+{
+ uint32_t ret = 0;
+
+ switch (offset)
+ {
+ case SH3_ICR0_IPRA_ADDR:
+ logerror("'%s' (%08x): INTC internal read from %08x mask %08x (SH3_ICR0_IPRA_ADDR - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]);
+ return (m_sh3internal_upper[offset] & 0xffff0000) | (m_SH4_IPRA & 0xffff);
+
+ case SH3_IPRB_ADDR:
+ logerror("'%s' (%08x): INTC internal read from %08x mask %08x (SH3_IPRB_ADDR - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]);
+ return m_sh3internal_upper[offset];
+
+ case SH3_TOCR_TSTR_ADDR:
+
+ if (mem_mask&0xff00000)
+ {
+ ret |= (sh4_handle_tocr_addr_r(mem_mask)&0xff)<<24;
+ }
+ if (mem_mask&0x0000ff00)
+ {
+ ret |= (sh4_handle_tstr_addr_r(mem_mask)&0xff)<<8;
+ }
+ if (mem_mask&0x00ff00ff)
+ {
+ fatalerror("SH3_TOCR_TSTR_ADDR unused bits accessed (read)\n");
+ }
+ return ret;
+ case SH3_TCOR0_ADDR: return sh4_handle_tcor0_addr_r(mem_mask);
+ case SH3_TCOR1_ADDR: return sh4_handle_tcor1_addr_r(mem_mask);
+ case SH3_TCOR2_ADDR: return sh4_handle_tcor2_addr_r(mem_mask);
+ case SH3_TCNT0_ADDR: return sh4_handle_tcnt0_addr_r(mem_mask);
+ case SH3_TCNT1_ADDR: return sh4_handle_tcnt1_addr_r(mem_mask);
+ case SH3_TCNT2_ADDR: return sh4_handle_tcnt2_addr_r(mem_mask);
+ case SH3_TCR0_ADDR: return sh4_handle_tcr0_addr_r(mem_mask)<<16;
+ case SH3_TCR1_ADDR: return sh4_handle_tcr1_addr_r(mem_mask)<<16;
+ case SH3_TCR2_ADDR: return sh4_handle_tcr2_addr_r(mem_mask)<<16;
+ case SH3_TCPR2_ADDR: return sh4_handle_tcpr2_addr_r(mem_mask);
+
+
+ case SH3_TRA_ADDR:
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SH3 TRA - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]);
+ return m_sh3internal_upper[offset];
+
+ case SH3_EXPEVT_ADDR:
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SH3 EXPEVT - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]);
+ return m_sh3internal_upper[offset];
+
+ case SH3_INTEVT_ADDR:
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SH3 INTEVT - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]);
+ fatalerror("INTEVT unsupported on SH3\n");
+ // never executed
+ //return m_sh3internal_upper[offset];
+
+
+ default:
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask);
+ return m_sh3internal_upper[offset];
+ }
+}
+
+
+READ32_MEMBER( sh3_base_device::sh3_internal_r )
+{
+ if (offset<0x1000)
+ {
+ switch (offset)
+ {
+ case SH3_SAR0_ADDR: return sh4_handle_sar0_addr_r(mem_mask);
+ case SH3_SAR1_ADDR: return sh4_handle_sar1_addr_r(mem_mask);
+ case SH3_SAR2_ADDR: return sh4_handle_sar2_addr_r(mem_mask);
+ case SH3_SAR3_ADDR: return sh4_handle_sar3_addr_r(mem_mask);
+ case SH3_DAR0_ADDR: return sh4_handle_dar0_addr_r(mem_mask);
+ case SH3_DAR1_ADDR: return sh4_handle_dar1_addr_r(mem_mask);
+ case SH3_DAR2_ADDR: return sh4_handle_dar2_addr_r(mem_mask);
+ case SH3_DAR3_ADDR: return sh4_handle_dar3_addr_r(mem_mask);
+ case SH3_DMATCR0_ADDR: return sh4_handle_dmatcr0_addr_r(mem_mask);
+ case SH3_DMATCR1_ADDR: return sh4_handle_dmatcr1_addr_r(mem_mask);
+ case SH3_DMATCR2_ADDR: return sh4_handle_dmatcr2_addr_r(mem_mask);
+ case SH3_DMATCR3_ADDR: return sh4_handle_dmatcr3_addr_r(mem_mask);
+ case SH3_CHCR0_ADDR: return sh4_handle_chcr0_addr_r(mem_mask);
+ case SH3_CHCR1_ADDR: return sh4_handle_chcr1_addr_r(mem_mask);
+ case SH3_CHCR2_ADDR: return sh4_handle_chcr2_addr_r(mem_mask);
+ case SH3_CHCR3_ADDR: return sh4_handle_chcr3_addr_r(mem_mask);
+ case SH3_DMAOR_ADDR: return sh4_handle_dmaor_addr_r(mem_mask)<<16;
+
+
+ case INTEVT2:
+ {
+ // logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (INTEVT2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+
+ case IRR0_IRR1:
+ {
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (IRR0)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (IRR1)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+ fatalerror("'%s' (%08x): unmapped internal read from %08x mask %08x (IRR0/1 unused bits)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ }
+ }
+
+ case PADR_PBDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PADR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_A)<<24;
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PBDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_B)<<8;
+ }
+ }
+ break;
+
+ case PCDR_PDDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PCDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_C)<<24;
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PDDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_D)<<8;
+ }
+ }
+ break;
+
+ case PEDR_PFDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PEDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_E)<<24;
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PFDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_F)<<8;
+ }
+ }
+ break;
+
+ case PGDR_PHDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PGDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_G)<<24;
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PHDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_H)<<8;
+ }
+ }
+ break;
+
+ case PJDR_PKDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PJDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_J)<<24;
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PKDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_K)<<8;
+ }
+ }
+ break;
+
+ case PLDR_SCPDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PLDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_io->read_qword(SH3_PORT_L)<<24;
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SCPDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ //return m_io->read_qword(SH3_PORT_K)<<8;
+ }
+ }
+ break;
+
+
+ case SCSMR2_SCBRR2:
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCSMR2 - Serial Mode Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCBRR2 - Bit Rate Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+ }
+ break;
+
+ case SCSCR2_SCFTDR2:
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCSCR2 - Serial Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFTDR2 - Transmit FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+ }
+ break;
+
+ case SCSSR2_SCFRDR2:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCSSR2 - Serial Status Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFRDR2 - Receive FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+ }
+ break;
+
+ case SCFCR2_SCFDR2:
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFCR2 - Fifo Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFDR2 - Fifo Data Count Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask);
+ return m_sh3internal_lower[offset];
+ }
+ }
+ break;
+
+
+ default:
+ {
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x\n",
+ tag(), m_pc & AM,
+ (offset *4)+0x4000000,
+ mem_mask);
+ }
+ break;
+
+ }
+
+ }
+ else
+ {
+ logerror("'%s' (%08x): unmapped internal read from %08x mask %08x\n",
+ tag(), m_pc & AM,
+ (offset *4)+0x4000000,
+ mem_mask);
+ }
+
+ return 0;
+}
+
+/* Lower internal area */
+
+WRITE32_MEMBER( sh3_base_device::sh3_internal_w )
+{
+ if (offset<0x1000)
+ {
+ //uint32_t old = m_sh3internal_lower[offset];
+ COMBINE_DATA(&m_sh3internal_lower[offset]);
+
+ switch (offset)
+ {
+ case SH3_SAR0_ADDR: sh4_handle_sar0_addr_w(data,mem_mask); break;
+ case SH3_SAR1_ADDR: sh4_handle_sar1_addr_w(data,mem_mask); break;
+ case SH3_SAR2_ADDR: sh4_handle_sar2_addr_w(data,mem_mask); break;
+ case SH3_SAR3_ADDR: sh4_handle_sar3_addr_w(data,mem_mask); break;
+ case SH3_DAR0_ADDR: sh4_handle_dar0_addr_w(data,mem_mask); break;
+ case SH3_DAR1_ADDR: sh4_handle_dar1_addr_w(data,mem_mask); break;
+ case SH3_DAR2_ADDR: sh4_handle_dar2_addr_w(data,mem_mask); break;
+ case SH3_DAR3_ADDR: sh4_handle_dar3_addr_w(data,mem_mask); break;
+ case SH3_DMATCR0_ADDR: sh4_handle_dmatcr0_addr_w(data,mem_mask); break;
+ case SH3_DMATCR1_ADDR: sh4_handle_dmatcr1_addr_w(data,mem_mask); break;
+ case SH3_DMATCR2_ADDR: sh4_handle_dmatcr2_addr_w(data,mem_mask); break;
+ case SH3_DMATCR3_ADDR: sh4_handle_dmatcr3_addr_w(data,mem_mask); break;
+ case SH3_CHCR0_ADDR: sh4_handle_chcr0_addr_w(data,mem_mask); break;
+ case SH3_CHCR1_ADDR: sh4_handle_chcr1_addr_w(data,mem_mask); break;
+ case SH3_CHCR2_ADDR: sh4_handle_chcr2_addr_w(data,mem_mask); break;
+ case SH3_CHCR3_ADDR: sh4_handle_chcr3_addr_w(data,mem_mask); break;
+ case SH3_DMAOR_ADDR: sh4_handle_dmaor_addr_w(data>>16,mem_mask>>16); break;
+
+
+ case IRR0_IRR1:
+ {
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (IRR0)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ // not sure if this is how we should clear lines in this core...
+ if (!(data & 0x01000000)) execute_set_input(0, CLEAR_LINE);
+ if (!(data & 0x02000000)) execute_set_input(1, CLEAR_LINE);
+ if (!(data & 0x04000000)) execute_set_input(2, CLEAR_LINE);
+ if (!(data & 0x08000000)) execute_set_input(3, CLEAR_LINE);
+
+ }
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (IRR1)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ if (mem_mask & 0x00ff00ff)
+ {
+ fatalerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (IRR0/1 unused bits)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ }
+ break;
+
+ case PINTER_IPRC:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PINTER)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ data &= 0xffff; mem_mask &= 0xffff;
+ COMBINE_DATA(&m_SH4_IPRC);
+ logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (IPRC)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ m_exception_priority[SH4_INTC_IRL0] = INTPRI((m_SH4_IPRC & 0x000f)>>0, SH4_INTC_IRL0);
+ m_exception_priority[SH4_INTC_IRL1] = INTPRI((m_SH4_IPRC & 0x00f0)>>4, SH4_INTC_IRL1);
+ m_exception_priority[SH4_INTC_IRL2] = INTPRI((m_SH4_IPRC & 0x0f00)>>8, SH4_INTC_IRL2);
+ m_exception_priority[SH4_INTC_IRL3] = INTPRI((m_SH4_IPRC & 0xf000)>>12,SH4_INTC_IRL3);
+ sh4_exception_recompute();
+ }
+ }
+ break;
+
+ case PCCR_PDCR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PCCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PDCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case PECR_PFCR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PECR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PFCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+
+ case PGCR_PHCR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PGCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PHCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+
+ case PJCR_PKCR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PJCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PKCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+
+ case PLCR_SCPCR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PLCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (SCPCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case PADR_PBDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ m_io->write_qword(SH3_PORT_A, (data>>24)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PADR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ m_io->write_qword(SH3_PORT_B, (data>>8)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PBDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case PCDR_PDDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ m_io->write_qword(SH3_PORT_C, (data>>24)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PADR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ m_io->write_qword(SH3_PORT_D, (data>>8)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PBDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+ case PEDR_PFDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ m_io->write_qword(SH3_PORT_E, (data>>24)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PEDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ m_io->write_qword(SH3_PORT_F, (data>>8)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PFDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case PGDR_PHDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ m_io->write_qword(SH3_PORT_G, (data>>24)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PGDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ m_io->write_qword(SH3_PORT_H, (data>>8)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PHDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+
+ case PJDR_PKDR:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ m_io->write_qword(SH3_PORT_J, (data>>24)&0xff);
+ // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PJDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ m_io->write_qword(SH3_PORT_K, (data>>8)&0xff);
+ //logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PKDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case SCSMR2_SCBRR2:
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCSMR2 - Serial Mode Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCBRR2 - Bit Rate Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case SCSCR2_SCFTDR2:
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCSCR2 - Serial Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFTDR2 - Transmit FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case SCSSR2_SCFRDR2:
+ {
+ if (mem_mask & 0xffff0000)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCSSR2 - Serial Status Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ff00)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFRDR2 - Receive FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ case SCFCR2_SCFDR2:
+ {
+ if (mem_mask & 0xff000000)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFCR2 - Fifo Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+
+ if (mem_mask & 0x0000ffff)
+ {
+ logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFDR2 - Fifo Data Count Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask);
+ }
+ }
+ break;
+
+ default:
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x\n",
+ tag(), m_pc & AM,
+ (offset *4)+0x4000000,
+ data,
+ mem_mask);
+ }
+ break;
+ }
+
+ }
+ else
+ {
+ logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x\n",
+ tag(), m_pc & AM,
+ (offset *4)+0x4000000,
+ data,
+ mem_mask);
+ }
+
+}
diff --git a/src/devices/cpu/sh/sh3comn.h b/src/devices/cpu/sh/sh3comn.h
new file mode 100644
index 00000000000..241035b993e
--- /dev/null
+++ b/src/devices/cpu/sh/sh3comn.h
@@ -0,0 +1,96 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+#pragma once
+
+#ifndef __SH3COMN_H__
+#define __SH3COMN_H__
+
+
+// actual port handling is more complex than this
+// which should be considered a temporary solution
+// just used some arbitrary port numbers
+#define SH3_PORT_A (0x10*8)
+#define SH3_PORT_B (0x11*8)
+#define SH3_PORT_C (0x12*8)
+#define SH3_PORT_D (0x13*8)
+#define SH3_PORT_E (0x14*8)
+#define SH3_PORT_F (0x15*8)
+#define SH3_PORT_G (0x16*8)
+#define SH3_PORT_H (0x17*8)
+/* no I */
+#define SH3_PORT_J (0x18*8)
+#define SH3_PORT_K (0x19*8)
+#define SH3_PORT_L (0x1a*8)
+
+/* SH3 lower area regs */
+
+#define SH3_LOWER_REGBASE (0x04000000)
+#define SH3_LOWER_REGEND (0x07ffffff)
+
+#define INTEVT2 ((0x4000000 - SH3_LOWER_REGBASE)/4)
+#define IRR0_IRR1 ((0x4000004 - SH3_LOWER_REGBASE)/4)
+#define PINTER_IPRC ((0x4000014 - SH3_LOWER_REGBASE)/4)
+
+#define SH3_SAR0_ADDR ((0x4000020 - SH3_LOWER_REGBASE)/4)
+#define SH3_DAR0_ADDR ((0x4000024 - SH3_LOWER_REGBASE)/4)
+#define SH3_DMATCR0_ADDR ((0x4000028 - SH3_LOWER_REGBASE)/4)
+#define SH3_CHCR0_ADDR ((0x400002c - SH3_LOWER_REGBASE)/4)
+#define SH3_SAR1_ADDR ((0x4000030 - SH3_LOWER_REGBASE)/4)
+#define SH3_DAR1_ADDR ((0x4000034 - SH3_LOWER_REGBASE)/4)
+#define SH3_DMATCR1_ADDR ((0x4000038 - SH3_LOWER_REGBASE)/4)
+#define SH3_CHCR1_ADDR ((0x400003c - SH3_LOWER_REGBASE)/4)
+#define SH3_SAR2_ADDR ((0x4000040 - SH3_LOWER_REGBASE)/4)
+#define SH3_DAR2_ADDR ((0x4000044 - SH3_LOWER_REGBASE)/4)
+#define SH3_DMATCR2_ADDR ((0x4000048 - SH3_LOWER_REGBASE)/4)
+#define SH3_CHCR2_ADDR ((0x400004c - SH3_LOWER_REGBASE)/4)
+#define SH3_SAR3_ADDR ((0x4000050 - SH3_LOWER_REGBASE)/4)
+#define SH3_DAR3_ADDR ((0x4000054 - SH3_LOWER_REGBASE)/4)
+#define SH3_DMATCR3_ADDR ((0x4000058 - SH3_LOWER_REGBASE)/4)
+#define SH3_CHCR3_ADDR ((0x400005c - SH3_LOWER_REGBASE)/4)
+#define SH3_DMAOR_ADDR ((0x4000060 - SH3_LOWER_REGBASE)/4)
+
+
+#define PCCR_PDCR ((0x4000104 - SH3_LOWER_REGBASE)/4)
+#define PECR_PFCR ((0x4000108 - SH3_LOWER_REGBASE)/4)
+#define PGCR_PHCR ((0x400010c - SH3_LOWER_REGBASE)/4)
+#define PJCR_PKCR ((0x4000110 - SH3_LOWER_REGBASE)/4)
+#define PLCR_SCPCR ((0x4000114 - SH3_LOWER_REGBASE)/4)
+
+#define PADR_PBDR ((0x4000120 - SH3_LOWER_REGBASE)/4)
+#define PCDR_PDDR ((0x4000124 - SH3_LOWER_REGBASE)/4)
+#define PEDR_PFDR ((0x4000128 - SH3_LOWER_REGBASE)/4)
+#define PGDR_PHDR ((0x400012c - SH3_LOWER_REGBASE)/4)
+#define PJDR_PKDR ((0x4000130 - SH3_LOWER_REGBASE)/4)
+#define PLDR_SCPDR ((0x4000134 - SH3_LOWER_REGBASE)/4)
+
+#define SCSMR2_SCBRR2 ((0x4000150 - SH3_LOWER_REGBASE)/4)
+#define SCSCR2_SCFTDR2 ((0x4000154 - SH3_LOWER_REGBASE)/4)
+#define SCSSR2_SCFRDR2 ((0x4000158 - SH3_LOWER_REGBASE)/4)
+#define SCFCR2_SCFDR2 ((0x400015c - SH3_LOWER_REGBASE)/4)
+
+
+/* SH3 upper area */
+
+
+#define SH3_UPPER_REGBASE (0xffffd000)
+#define SH3_UPPER_REGEND (0xffffffff)
+
+#define SH3_ICR0_IPRA_ADDR ((0xfffffee0 - SH3_UPPER_REGBASE)/4)
+#define SH3_IPRB_ADDR ((0xfffffee4 - SH3_UPPER_REGBASE)/4)
+
+#define SH3_TOCR_TSTR_ADDR ((0xfffffe90 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCOR0_ADDR ((0xfffffe94 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCNT0_ADDR ((0xfffffe98 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCR0_ADDR ((0xfffffe9c - SH3_UPPER_REGBASE)/4)
+#define SH3_TCOR1_ADDR ((0xfffffea0 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCNT1_ADDR ((0xfffffea4 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCR1_ADDR ((0xfffffea8 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCOR2_ADDR ((0xfffffeac - SH3_UPPER_REGBASE)/4)
+#define SH3_TCNT2_ADDR ((0xfffffeb0 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCR2_ADDR ((0xfffffeb4 - SH3_UPPER_REGBASE)/4)
+#define SH3_TCPR2_ADDR ((0xfffffeb8 - SH3_UPPER_REGBASE)/4)
+#define SH3_TRA_ADDR ((0xffffffd0 - SH3_UPPER_REGBASE)/4)
+#define SH3_EXPEVT_ADDR ((0xffffffd4 - SH3_UPPER_REGBASE)/4)
+#define SH3_INTEVT_ADDR ((0xffffffd8 - SH3_UPPER_REGBASE)/4)
+
+#endif /* __SH3COMN_H__ */
diff --git a/src/devices/cpu/sh/sh4.cpp b/src/devices/cpu/sh/sh4.cpp
new file mode 100644
index 00000000000..cc7c333d9cc
--- /dev/null
+++ b/src/devices/cpu/sh/sh4.cpp
@@ -0,0 +1,4743 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*****************************************************************************
+ *
+ * sh4.c
+ * Portable Hitachi SH-4 (SH7750 family) emulator
+ *
+ * By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek,
+ * Olivier Galibert, Sylvain Glaize, and James Forshaw.
+ *
+ *
+ * TODO: FPU
+ * DMA
+ * on-board peripherals
+ *
+ * DONE: boot/reset setup
+ * 64-bit data bus
+ * banked registers
+ * additional registers for supervisor mode
+ * FPU status and data registers
+ * state save for the new registers
+ * interrupts
+ * store queues
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "sh4.h"
+#include "sh4regs.h"
+#include "sh4comn.h"
+#include "sh3comn.h"
+#include "sh4tmu.h"
+
+#include "debugger.h"
+
+
+#if SH4_USE_FASTRAM_OPTIMIZATION
+void sh34_base_device::add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base)
+{
+ if (m_fastram_select < ARRAY_LENGTH(m_fastram))
+ {
+ m_fastram[m_fastram_select].start = start;
+ m_fastram[m_fastram_select].end = end;
+ m_fastram[m_fastram_select].readonly = readonly;
+ m_fastram[m_fastram_select].base = base;
+ m_fastram_select++;
+ }
+}
+#else
+void sh34_base_device::add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base)
+{
+}
+#endif
+
+
+CPU_DISASSEMBLE( sh4 );
+CPU_DISASSEMBLE( sh4be );
+
+
+DEFINE_DEVICE_TYPE(SH3LE, sh3_device, "sh3le", "SH-3 (little)")
+DEFINE_DEVICE_TYPE(SH3BE, sh3be_device, "sh3be", "SH-3 (big)")
+DEFINE_DEVICE_TYPE(SH4LE, sh4_device, "sh4le", "SH-4 (little)")
+DEFINE_DEVICE_TYPE(SH4BE, sh4be_device, "sh4be", "SH-4 (big)")
+
+
+#if 0
+/*When OC index mode is off (CCR.OIX = 0)*/
+static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, sh4_base_device )
+ AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x03FFD000)
+ AM_RANGE(0x1C002000, 0x1C002FFF) AM_RAM AM_MIRROR(0x03FFD000)
+ AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0)
+ADDRESS_MAP_END
+#endif
+
+/*When OC index mode is on (CCR.OIX = 1)*/
+static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, sh4_base_device )
+ AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x01FFF000)
+ AM_RANGE(0x1E000000, 0x1E000FFF) AM_RAM AM_MIRROR(0x01FFF000)
+ AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0) // todo: store queues should be write only on DC's SH4, executing PREFM shouldn't cause an actual memory read access!
+
+ AM_RANGE(0xF6000000, 0xF6FFFFFF) AM_READWRITE(sh4_utlb_address_array_r,sh4_utlb_address_array_w)
+ AM_RANGE(0xF7000000, 0xF77FFFFF) AM_READWRITE(sh4_utlb_data_array1_r,sh4_utlb_data_array1_w)
+ AM_RANGE(0xF7800000, 0xF7FFFFFF) AM_READWRITE(sh4_utlb_data_array2_r,sh4_utlb_data_array2_w)
+
+ AM_RANGE(0xFE000000, 0xFFFFFFFF) AM_READWRITE32(sh4_internal_r, sh4_internal_w, 0xffffffffffffffffU)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( sh3_internal_map, AS_PROGRAM, 64, sh3_base_device )
+ AM_RANGE(SH3_LOWER_REGBASE, SH3_LOWER_REGEND) AM_READWRITE32(sh3_internal_r, sh3_internal_w, 0xffffffffffffffffU)
+ AM_RANGE(SH3_UPPER_REGBASE, SH3_UPPER_REGEND) AM_READWRITE32(sh3_internal_high_r, sh3_internal_high_w, 0xffffffffffffffffU)
+ADDRESS_MAP_END
+
+
+sh34_base_device::sh34_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness, address_map_constructor internal)
+ : cpu_device(mconfig, type, tag, owner, clock)
+ , m_program_config("program", endianness, 64, 32, 0, internal)
+ , m_io_config("io", endianness, 64, 8)
+ , c_md2(0)
+ , c_md1(0)
+ , c_md0(0)
+ , c_md6(0)
+ , c_md4(0)
+ , c_md3(0)
+ , c_md5(0)
+ , c_md7(0)
+ , c_md8(0)
+ , c_clock(0)
+ , m_mmuhack(1)
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ , m_bigendian(endianness == ENDIANNESS_BIG)
+ , m_byte_xor(m_bigendian ? BYTE8_XOR_BE(0) : BYTE8_XOR_LE(0))
+ , m_word_xor(m_bigendian ? WORD2_XOR_BE(0) : WORD2_XOR_LE(0))
+ , m_dword_xor(m_bigendian ? DWORD_XOR_BE(0) : DWORD_XOR_LE(0))
+ , m_fastram_select(0)
+#endif
+{
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ memset(m_fastram, 0, sizeof(m_fastram));
+#endif
+}
+
+device_memory_interface::space_config_vector sh34_base_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_IO, &m_io_config)
+ };
+}
+
+
+sh3_base_device::sh3_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness)
+ : sh34_base_device(mconfig, type, tag, owner, clock, endianness, ADDRESS_MAP_NAME(sh3_internal_map))
+{
+ m_cpu_type = CPU_TYPE_SH3;
+}
+
+
+sh4_base_device::sh4_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness)
+ : sh34_base_device(mconfig, type, tag, owner, clock, endianness, ADDRESS_MAP_NAME(sh4_internal_map))
+{
+ m_cpu_type = CPU_TYPE_SH4;
+}
+
+
+sh3_device::sh3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh3_base_device(mconfig, SH3LE, tag, owner, clock, ENDIANNESS_LITTLE)
+{
+}
+
+
+sh3be_device::sh3be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh3_base_device(mconfig, SH3BE, tag, owner, clock, ENDIANNESS_BIG)
+{
+}
+
+
+sh4_device::sh4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh4_base_device(mconfig, SH4LE, tag, owner, clock, ENDIANNESS_LITTLE)
+{
+}
+
+
+sh4be_device::sh4be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh4_base_device(mconfig, SH4BE, tag, owner, clock, ENDIANNESS_BIG)
+{
+}
+
+
+offs_t sh34_base_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
+{
+ extern CPU_DISASSEMBLE( sh4 );
+
+ return CPU_DISASSEMBLE_NAME(sh4)(this, stream, pc, oprom, opram, options);
+}
+
+
+offs_t sh3be_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
+{
+ extern CPU_DISASSEMBLE( sh4be );
+
+ return CPU_DISASSEMBLE_NAME(sh4be)(this, stream, pc, oprom, opram, options);
+}
+
+
+offs_t sh4be_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
+{
+ extern CPU_DISASSEMBLE( sh4be );
+
+ return CPU_DISASSEMBLE_NAME(sh4be)(this, stream, pc, oprom, opram, options);
+}
+
+
+/* Called for unimplemented opcodes */
+void sh34_base_device::TODO(const uint16_t opcode)
+{
+}
+
+void sh34_base_device::LDTLB(const uint16_t opcode)
+{
+ logerror("unhandled LDTLB for this CPU type\n");
+}
+
+void sh4_base_device::LDTLB(const uint16_t opcode)
+{
+ int replace = (m_m[MMUCR] & 0x0000fc00) >> 10;
+
+ logerror("using LDTLB to replace UTLB entry %02x\n", replace);
+
+ // these come from PTEH
+ m_utlb[replace].VPN = (m_m[PTEH] & 0xfffffc00) >> 10;
+// m_utlb[replace].D = (m_m[PTEH] & 0x00000200) >> 9; // from PTEL
+// m_utlb[replace].V = (m_m[PTEH] & 0x00000100) >> 8; // from PTEL
+ m_utlb[replace].ASID = (m_m[PTEH] & 0x000000ff) >> 0;
+ // these come from PTEL
+ m_utlb[replace].PPN = (m_m[PTEL] & 0x1ffffc00) >> 10;
+ m_utlb[replace].V = (m_m[PTEL] & 0x00000100) >> 8;
+ m_utlb[replace].PSZ = (m_m[PTEL] & 0x00000080) >> 6;
+ m_utlb[replace].PSZ |=(m_m[PTEL] & 0x00000010) >> 4;
+ m_utlb[replace].PPR= (m_m[PTEL] & 0x00000060) >> 5;
+ m_utlb[replace].C = (m_m[PTEL] & 0x00000008) >> 3;
+ m_utlb[replace].D = (m_m[PTEL] & 0x00000004) >> 2;
+ m_utlb[replace].SH = (m_m[PTEL] & 0x00000002) >> 1;
+ m_utlb[replace].WT = (m_m[PTEL] & 0x00000001) >> 0;
+ // these come from PTEA
+ m_utlb[replace].TC = (m_m[PTEA] & 0x00000008) >> 3;
+ m_utlb[replace].SA = (m_m[PTEA] & 0x00000007) >> 0;
+}
+
+#if 0
+int sign_of(int n)
+{
+ return(m_fr[n]>>31);
+}
+
+void zero(int n,int sign)
+{
+if (sign == 0)
+ m_fr[n] = 0x00000000;
+else
+ m_fr[n] = 0x80000000;
+if ((m_fpscr & PR) == 1)
+ m_fr[n+1] = 0x00000000;
+}
+
+int data_type_of(int n)
+{
+uint32_t abs;
+
+ abs = m_fr[n] & 0x7fffffff;
+ if ((m_fpscr & PR) == 0) { /* Single-precision */
+ if (abs < 0x00800000) {
+ if (((m_fpscr & DN) == 1) || (abs == 0x00000000)) {
+ if (sign_of(n) == 0) {
+ zero(n, 0);
+ return(SH4_FPU_PZERO);
+ } else {
+ zero(n, 1);
+ return(SH4_FPU_NZERO);
+ }
+ } else
+ return(SH4_FPU_DENORM);
+ } else
+ if (abs < 0x7f800000)
+ return(SH4_FPU_NORM);
+ else
+ if (abs == 0x7f800000) {
+ if (sign_of(n) == 0)
+ return(SH4_FPU_PINF);
+ else
+ return(SH4_FPU_NINF);
+ } else
+ if (abs < 0x7fc00000)
+ return(SH4_FPU_qNaN);
+ else
+ return(SH4_FPU_sNaN);
+ } else { /* Double-precision */
+ if (abs < 0x00100000) {
+ if (((m_fpscr & DN) == 1) || ((abs == 0x00000000) && (m_fr[n+1] == 0x00000000))) {
+ if(sign_of(n) == 0) {
+ zero(n, 0);
+ return(SH4_FPU_PZERO);
+ } else {
+ zero(n, 1);
+ return(SH4_FPU_NZERO);
+ }
+ } else
+ return(SH4_FPU_DENORM);
+ } else
+ if (abs < 0x7ff00000)
+ return(SH4_FPU_NORM);
+ else
+ if ((abs == 0x7ff00000) && (m_fr[n+1] == 0x00000000)) {
+ if (sign_of(n) == 0)
+ return(SH4_FPU_PINF);
+ else
+ return(SH4_FPU_NINF);
+ } else
+ if (abs < 0x7ff80000)
+ return(SH4_FPU_qNaN);
+ else
+ return(SH4_FPU_sNaN);
+ }
+ return(SH4_FPU_NORM);
+}
+#endif
+
+inline uint8_t sh34_base_device::RB(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return m_program->read_byte(A);
+
+ if (A >= 0x80000000) // P1/P2/P3 region
+ {
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ const offs_t _A = A & AM;
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
+ if (_A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end)
+ {
+ continue;
+ }
+ uint8_t *fastbase = (uint8_t*)m_fastram[ramnum].base - m_fastram[ramnum].start;
+ return fastbase[_A ^ m_byte_xor];
+ }
+ return m_program->read_byte(_A);
+#else
+ return m_program->read_byte(A & AM);
+#endif
+ }
+ else // P0 region
+ {
+ if (!m_sh4_mmu_enabled)
+ {
+ return m_program->read_byte(A & AM);
+ }
+ else
+ {
+ A = get_remap(A & AM);
+ return m_program->read_byte(A);
+ }
+ }
+
+}
+
+inline uint16_t sh34_base_device::RW(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return m_program->read_word(A);
+
+ if (A >= 0x80000000) // P1/P2/P3 region
+ {
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ const offs_t _A = A & AM;
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
+ if (_A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end)
+ {
+ continue;
+ }
+ uint8_t *fastbase = (uint8_t*)m_fastram[ramnum].base - m_fastram[ramnum].start;
+ return ((uint16_t*)fastbase)[(_A ^ m_word_xor) >> 1];
+ }
+ return m_program->read_word(_A);
+#else
+ return m_program->read_word(A & AM);
+#endif
+ }
+ else
+ {
+ if (!m_sh4_mmu_enabled)
+ {
+ return m_program->read_word(A & AM);
+ }
+ else
+ {
+ A = get_remap(A & AM);
+ return m_program->read_word(A);
+ }
+ }
+
+}
+
+inline uint32_t sh34_base_device::RL(offs_t A)
+{
+ if (A >= 0xe0000000)
+ return m_program->read_dword(A);
+
+ if (A >= 0x80000000) // P1/P2/P3 region
+ {
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ const offs_t _A = A & AM;
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
+ if (_A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end)
+ {
+ continue;
+ }
+ uint8_t *fastbase = (uint8_t*)m_fastram[ramnum].base - m_fastram[ramnum].start;
+ return ((uint32_t*)fastbase)[(_A^m_dword_xor) >> 2];
+ }
+ return m_program->read_dword(_A);
+#else
+ return m_program->read_dword(A & AM);
+#endif
+ }
+ else
+ {
+ if (!m_sh4_mmu_enabled)
+ {
+ return m_program->read_dword(A & AM);
+ }
+ else
+ {
+ A = get_remap(A & AM);
+ return m_program->read_dword(A);
+ }
+ }
+
+}
+
+inline void sh34_base_device::WB(offs_t A, uint8_t V)
+{
+ if (A >= 0xe0000000)
+ {
+ m_program->write_byte(A,V);
+ return;
+ }
+
+ if (A >= 0x80000000) // P1/P2/P3 region
+ {
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ const offs_t _A = A & AM;
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
+ if (m_fastram[ramnum].readonly == true || _A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end)
+ {
+ continue;
+ }
+ uint8_t *fastbase = (uint8_t*)m_fastram[ramnum].base - m_fastram[ramnum].start;
+ fastbase[_A ^ m_byte_xor] = V;
+ return;
+ }
+ m_program->write_byte(_A, V);
+#else
+ m_program->write_byte(A & AM, V);
+#endif
+ }
+ else
+ {
+ if (!m_sh4_mmu_enabled)
+ {
+ m_program->write_byte(A & AM, V);
+ }
+ else
+ {
+ A = get_remap(A & AM);
+ m_program->write_byte(A, V);
+ }
+ }
+
+}
+
+inline void sh34_base_device::WW(offs_t A, uint16_t V)
+{
+ if (A >= 0xe0000000)
+ {
+ m_program->write_word(A,V);
+ return;
+ }
+
+ if (A >= 0x80000000) // P1/P2/P3 region
+ {
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ const offs_t _A = A & AM;
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
+ if (m_fastram[ramnum].readonly == true || _A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end)
+ {
+ continue;
+ }
+ void *fastbase = (uint8_t*)m_fastram[ramnum].base - m_fastram[ramnum].start;
+ ((uint16_t*)fastbase)[(_A ^ m_word_xor) >> 1] = V;
+ return;
+ }
+ m_program->write_word(_A, V);
+#else
+ m_program->write_word(A & AM, V);
+#endif
+ }
+ else
+ {
+ if (!m_sh4_mmu_enabled)
+ {
+ m_program->write_word(A & AM, V);
+ }
+ else
+ {
+ A = get_remap(A & AM);
+ m_program->write_word(A, V);
+ }
+ }
+
+}
+
+inline void sh34_base_device::WL(offs_t A, uint32_t V)
+{
+ if (A >= 0xe0000000)
+ {
+ m_program->write_dword(A,V);
+ return;
+ }
+
+ if (A >= 0x80000000) // P1/P2/P3 region
+ {
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ const offs_t _A = A & AM;
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
+ if (m_fastram[ramnum].readonly == true || _A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end)
+ {
+ continue;
+ }
+ void *fastbase = (uint8_t*)m_fastram[ramnum].base - m_fastram[ramnum].start;
+ ((uint32_t*)fastbase)[(_A ^ m_dword_xor) >> 2] = V;
+ return;
+ }
+ m_program->write_dword(_A, V);
+#else
+ m_program->write_dword(A & AM, V);
+#endif
+ }
+ else
+ {
+ if (!m_sh4_mmu_enabled)
+ {
+ m_program->write_dword(A & AM, V);
+ }
+ else
+ {
+ A = get_remap(A & AM);
+ m_program->write_dword(A, V);
+ }
+ }
+
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1100 1 -
+ * ADD Rm,Rn
+ */
+inline void sh34_base_device::ADD(const uint16_t opcode)
+{
+ m_r[Rn] += m_r[Rm];
+}
+
+/* code cycles t-bit
+ * 0111 nnnn iiii iiii 1 -
+ * ADD #imm,Rn
+ */
+inline void sh34_base_device::ADDI(const uint16_t opcode)
+{
+ m_r[Rn] += (int32_t)(int16_t)(int8_t)(opcode&0xff);
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1110 1 carry
+ * ADDC Rm,Rn
+ */
+inline void sh34_base_device::ADDC(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+ uint32_t tmp0, tmp1;
+
+ tmp1 = m_r[n] + m_r[m];
+ tmp0 = m_r[n];
+ m_r[n] = tmp1 + (m_sr & T);
+ if (tmp0 > tmp1)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ if (tmp1 > m_r[n])
+ m_sr |= T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 1111 1 overflow
+ * ADDV Rm,Rn
+ */
+inline void sh34_base_device::ADDV(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+ int32_t dest, src, ans;
+
+ if ((int32_t) m_r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) m_r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ m_r[n] += m_r[m];
+ if ((int32_t) m_r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 0 || src == 2)
+ {
+ if (ans == 1)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ }
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1001 1 -
+ * AND Rm,Rn
+ */
+inline void sh34_base_device::AND(const uint16_t opcode)
+{
+ m_r[Rn] &= m_r[Rm];
+}
+
+
+/* code cycles t-bit
+ * 1100 1001 iiii iiii 1 -
+ * AND #imm,R0
+ */
+inline void sh34_base_device::ANDI(const uint16_t opcode)
+{
+ m_r[0] &= (opcode&0xff);
+}
+
+/* code cycles t-bit
+ * 1100 1101 iiii iiii 1 -
+ * AND.B #imm,@(R0,GBR)
+ */
+inline void sh34_base_device::ANDM(const uint16_t opcode)
+{
+ uint32_t temp;
+
+ m_ea = m_gbr + m_r[0];
+ temp = (opcode&0xff) & RB( m_ea );
+ WB(m_ea, temp );
+ m_sh4_icount -= 2;
+}
+
+/* code cycles t-bit
+ * 1000 1011 dddd dddd 3/1 -
+ * BF disp8
+ */
+inline void sh34_base_device::BF(const uint16_t opcode)
+{
+ if ((m_sr & T) == 0)
+ {
+ int32_t disp = ((int32_t)(opcode&0xff) << 24) >> 24;
+ m_pc = m_ea = m_pc + disp * 2 + 2;
+ m_sh4_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1111 dddd dddd 3/1 -
+ * BFS disp8
+ */
+inline void sh34_base_device::BFS(const uint16_t opcode)
+{
+ if ((m_sr & T) == 0)
+ {
+ int32_t disp = ((int32_t)(opcode&0xff) << 24) >> 24;
+ m_delay = m_ea = m_pc + disp * 2 + 2;
+ m_sh4_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 1010 dddd dddd dddd 2 -
+ * BRA disp12
+ */
+inline void sh34_base_device::BRA(const uint16_t opcode)
+{
+ int32_t disp = ((int32_t)(opcode&0xfff) << 20) >> 20;
+
+#if BUSY_LOOP_HACKS
+ if (disp == -2)
+ {
+ uint32_t next_opcode = RW(m_pc & AM);
+ /* BRA $
+ * NOP
+ */
+ if (next_opcode == 0x0009)
+ m_sh4_icount %= 3; /* cycles for BRA $ and NOP taken (3) */
+ }
+#endif
+ m_delay = m_ea = m_pc + disp * 2 + 2;
+ m_sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0010 0011 2 -
+ * BRAF Rm
+ */
+inline void sh34_base_device::BRAF(const uint16_t opcode)
+{
+ m_delay = m_pc + m_r[Rn] + 2;
+ m_sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 1011 dddd dddd dddd 2 -
+ * BSR disp12
+ */
+inline void sh34_base_device::BSR(const uint16_t opcode)
+{
+ int32_t disp = ((int32_t)(opcode&0xfff) << 20) >> 20;
+
+ m_pr = m_pc + 2;
+ m_delay = m_ea = m_pc + disp * 2 + 2;
+ m_sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 0000 mmmm 0000 0011 2 -
+ * BSRF Rm
+ */
+inline void sh34_base_device::BSRF(const uint16_t opcode)
+{
+ m_pr = m_pc + 2;
+ m_delay = m_pc + m_r[Rn] + 2;
+ m_sh4_icount--;
+}
+
+/* code cycles t-bit
+ * 1000 1001 dddd dddd 3/1 -
+ * BT disp8
+ */
+inline void sh34_base_device::BT(const uint16_t opcode)
+{
+ if ((m_sr & T) != 0)
+ {
+ int32_t disp = ((int32_t)(opcode&0xff) << 24) >> 24;
+ m_pc = m_ea = m_pc + disp * 2 + 2;
+ m_sh4_icount -= 2;
+ }
+}
+
+/* code cycles t-bit
+ * 1000 1101 dddd dddd 2/1 -
+ * BTS disp8
+ */
+inline void sh34_base_device::BTS(const uint16_t opcode)
+{
+ if ((m_sr & T) != 0)
+ {
+ int32_t disp = ((int32_t)(opcode&0xff) << 24) >> 24;
+ m_delay = m_ea = m_pc + disp * 2 + 2;
+ m_sh4_icount--;
+ }
+}
+
+/* code cycles t-bit
+ * 0000 0000 0010 1000 1 -
+ * CLRMAC
+ */
+inline void sh34_base_device::CLRMAC(const uint16_t opcode)
+{
+ m_mach = 0;
+ m_macl = 0;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0000 1000 1 -
+ * CLRT
+ */
+inline void sh34_base_device::CLRT(const uint16_t opcode)
+{
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0000 1 comparison result
+ * CMP_EQ Rm,Rn
+ */
+inline void sh34_base_device::CMPEQ(const uint16_t opcode)
+{
+ if (m_r[Rn] == m_r[Rm])
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0011 1 comparison result
+ * CMP_GE Rm,Rn
+ */
+inline void sh34_base_device::CMPGE(const uint16_t opcode)
+{
+ if ((int32_t) m_r[Rn] >= (int32_t) m_r[Rm])
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0111 1 comparison result
+ * CMP_GT Rm,Rn
+ */
+inline void sh34_base_device::CMPGT(const uint16_t opcode)
+{
+ if ((int32_t) m_r[Rn] > (int32_t) m_r[Rm])
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0110 1 comparison result
+ * CMP_HI Rm,Rn
+ */
+inline void sh34_base_device::CMPHI(const uint16_t opcode)
+{
+ if ((uint32_t) m_r[Rn] > (uint32_t) m_r[Rm])
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0010 1 comparison result
+ * CMP_HS Rm,Rn
+ */
+inline void sh34_base_device::CMPHS(const uint16_t opcode)
+{
+ if ((uint32_t) m_r[Rn] >= (uint32_t) m_r[Rm])
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0101 1 comparison result
+ * CMP_PL Rn
+ */
+inline void sh34_base_device::CMPPL(const uint16_t opcode)
+{
+ if ((int32_t) m_r[Rn] > 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0100 nnnn 0001 0001 1 comparison result
+ * CMP_PZ Rn
+ */
+inline void sh34_base_device::CMPPZ(const uint16_t opcode)
+{
+ if ((int32_t) m_r[Rn] >= 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 1100 1 comparison result
+ * CMP_STR Rm,Rn
+ */
+inline void sh34_base_device::CMPSTR(const uint16_t opcode)
+{
+ uint32_t temp;
+ int32_t HH, HL, LH, LL;
+ temp = m_r[Rn] ^ m_r[Rm];
+ HH = (temp >> 24) & 0xff;
+ HL = (temp >> 16) & 0xff;
+ LH = (temp >> 8) & 0xff;
+ LL = temp & 0xff;
+ if (HH && HL && LH && LL)
+ m_sr &= ~T;
+ else
+ m_sr |= T;
+ }
+
+
+/* code cycles t-bit
+ * 1000 1000 iiii iiii 1 comparison result
+ * CMP/EQ #imm,R0
+ */
+inline void sh34_base_device::CMPIM(const uint16_t opcode)
+{
+ uint32_t imm = (uint32_t)(int32_t)(int16_t)(int8_t)(opcode&0xff);
+
+ if (m_r[0] == imm)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0010 nnnn mmmm 0111 1 calculation result
+ * DIV0S Rm,Rn
+ */
+inline void sh34_base_device::DIV0S(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if ((m_r[n] & 0x80000000) == 0)
+ m_sr &= ~Q;
+ else
+ m_sr |= Q;
+ if ((m_r[m] & 0x80000000) == 0)
+ m_sr &= ~M;
+ else
+ m_sr |= M;
+ if ((m_r[m] ^ m_r[n]) & 0x80000000)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* code cycles t-bit
+ * 0000 0000 0001 1001 1 0
+ * DIV0U
+ */
+inline void sh34_base_device::DIV0U(const uint16_t opcode)
+{
+ m_sr &= ~(M | Q | T);
+}
+
+/* code cycles t-bit
+ * 0011 nnnn mmmm 0100 1 calculation result
+ * DIV1 Rm,Rn
+ */
+inline void sh34_base_device::DIV1(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t tmp0;
+ uint32_t old_q;
+
+ old_q = m_sr & Q;
+ if (0x80000000 & m_r[n])
+ m_sr |= Q;
+ else
+ m_sr &= ~Q;
+
+ m_r[n] = (m_r[n] << 1) | (m_sr & T);
+
+ if (!old_q)
+ {
+ if (!(m_sr & M))
+ {
+ tmp0 = m_r[n];
+ m_r[n] -= m_r[m];
+ if(!(m_sr & Q))
+ if(m_r[n] > tmp0)
+ m_sr |= Q;
+ else
+ m_sr &= ~Q;
+ else
+ if(m_r[n] > tmp0)
+ m_sr &= ~Q;
+ else
+ m_sr |= Q;
+ }
+ else
+ {
+ tmp0 = m_r[n];
+ m_r[n] += m_r[m];
+ if(!(m_sr & Q))
+ {
+ if(m_r[n] < tmp0)
+ m_sr &= ~Q;
+ else
+ m_sr |= Q;
+ }
+ else
+ {
+ if(m_r[n] < tmp0)
+ m_sr |= Q;
+ else
+ m_sr &= ~Q;
+ }
+ }
+ }
+ else
+ {
+ if (!(m_sr & M))
+ {
+ tmp0 = m_r[n];
+ m_r[n] += m_r[m];
+ if(!(m_sr & Q))
+ if(m_r[n] < tmp0)
+ m_sr |= Q;
+ else
+ m_sr &= ~Q;
+ else
+ if(m_r[n] < tmp0)
+ m_sr &= ~Q;
+ else
+ m_sr |= Q;
+ }
+ else
+ {
+ tmp0 = m_r[n];
+ m_r[n] -= m_r[m];
+ if(!(m_sr & Q))
+ if(m_r[n] > tmp0)
+ m_sr &= ~Q;
+ else
+ m_sr |= Q;
+ else
+ if(m_r[n] > tmp0)
+ m_sr |= Q;
+ else
+ m_sr &= ~Q;
+ }
+ }
+
+ tmp0 = (m_sr & (Q | M));
+ if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* DMULS.L Rm,Rn */
+inline void sh34_base_device::DMULS(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t temp0, temp1, temp2, temp3;
+ int32_t tempm, tempn, fnLmL;
+
+ tempn = (int32_t) m_r[n];
+ tempm = (int32_t) m_r[m];
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ if ((int32_t) (m_r[n] ^ m_r[m]) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ temp1 = (uint32_t) tempn;
+ temp2 = (uint32_t) 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_mach = Res2;
+ m_macl = Res0;
+ m_sh4_icount--;
+}
+
+/* DMULU.L Rm,Rn */
+inline void sh34_base_device::DMULU(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t temp0, temp1, temp2, temp3;
+
+ RnL = m_r[n] & 0x0000ffff;
+ RnH = (m_r[n] >> 16) & 0x0000ffff;
+ RmL = m_r[m] & 0x0000ffff;
+ RmH = (m_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_mach = Res2;
+ m_macl = Res0;
+ m_sh4_icount--;
+}
+
+/* DT Rn */
+inline void sh34_base_device::DT(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n]--;
+ if (m_r[n] == 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+#if BUSY_LOOP_HACKS
+ {
+ uint32_t next_opcode = RW(m_pc & AM);
+ /* DT Rn
+ * BF $-2
+ */
+ if (next_opcode == 0x8bfd)
+ {
+ while (m_r[n] > 1 && m_sh4_icount > 4)
+ {
+ m_r[n]--;
+ m_sh4_icount -= 4; /* cycles for DT (1) and BF taken (3) */
+ }
+ }
+ }
+#endif
+}
+
+/* EXTS.B Rm,Rn */
+inline void sh34_base_device::EXTSB(const uint16_t opcode)
+{
+ m_r[Rn] = ((int32_t)m_r[Rm] << 24) >> 24;
+}
+
+/* EXTS.W Rm,Rn */
+inline void sh34_base_device::EXTSW(const uint16_t opcode)
+{
+ m_r[Rn] = ((int32_t)m_r[Rm] << 16) >> 16;
+}
+
+/* EXTU.B Rm,Rn */
+inline void sh34_base_device::EXTUB(const uint16_t opcode)
+{
+ m_r[Rn] = m_r[Rm] & 0x000000ff;
+}
+
+/* EXTU.W Rm,Rn */
+inline void sh34_base_device::EXTUW(const uint16_t opcode)
+{
+ m_r[Rn] = m_r[Rm] & 0x0000ffff;
+}
+
+/* JMP @Rm */
+inline void sh34_base_device::JMP(const uint16_t opcode)
+{
+ m_delay = m_ea = m_r[Rn];
+}
+
+/* JSR @Rm */
+inline void sh34_base_device::JSR(const uint16_t opcode)
+{
+ m_pr = m_pc + 2;
+ m_delay = m_ea = m_r[Rn];
+ m_sh4_icount--;
+}
+
+
+/* LDC Rm,SR */
+inline void sh34_base_device::LDCSR(const uint16_t opcode)
+{
+ uint32_t reg;
+
+ reg = m_r[Rn];
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ sh4_syncronize_register_bank((m_sr & sRB) >> 29);
+ if ((m_r[Rn] & sRB) != (m_sr & sRB))
+ sh4_change_register_bank(m_r[Rn] & sRB ? 1 : 0);
+ m_sr = reg & FLAGS;
+ sh4_exception_recompute();
+}
+
+/* LDC Rm,GBR */
+inline void sh34_base_device::LDCGBR(const uint16_t opcode)
+{
+ m_gbr = m_r[Rn];
+}
+
+/* LDC Rm,VBR */
+inline void sh34_base_device::LDCVBR(const uint16_t opcode)
+{
+ m_vbr = m_r[Rn];
+}
+
+/* LDC.L @Rm+,SR */
+inline void sh34_base_device::LDCMSR(const uint16_t opcode)
+{
+ uint32_t old;
+
+ old = m_sr;
+ m_ea = m_r[Rn];
+ m_sr = RL(m_ea ) & FLAGS;
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ sh4_syncronize_register_bank((old & sRB) >> 29);
+ if ((old & sRB) != (m_sr & sRB))
+ sh4_change_register_bank(m_sr & sRB ? 1 : 0);
+ m_r[Rn] += 4;
+ m_sh4_icount -= 2;
+ sh4_exception_recompute();
+}
+
+/* LDC.L @Rm+,GBR */
+inline void sh34_base_device::LDCMGBR(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_gbr = RL(m_ea );
+ m_r[Rn] += 4;
+ m_sh4_icount -= 2;
+}
+
+/* LDC.L @Rm+,VBR */
+inline void sh34_base_device::LDCMVBR(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_vbr = RL(m_ea );
+ m_r[Rn] += 4;
+ m_sh4_icount -= 2;
+}
+
+/* LDS Rm,MACH */
+inline void sh34_base_device::LDSMACH(const uint16_t opcode)
+{
+ m_mach = m_r[Rn];
+}
+
+/* LDS Rm,MACL */
+inline void sh34_base_device::LDSMACL(const uint16_t opcode)
+{
+ m_macl = m_r[Rn];
+}
+
+/* LDS Rm,PR */
+inline void sh34_base_device::LDSPR(const uint16_t opcode)
+{
+ m_pr = m_r[Rn];
+}
+
+/* LDS.L @Rm+,MACH */
+inline void sh34_base_device::LDSMMACH(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_mach = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* LDS.L @Rm+,MACL */
+inline void sh34_base_device::LDSMMACL(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_macl = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* LDS.L @Rm+,PR */
+inline void sh34_base_device::LDSMPR(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_pr = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* MAC.L @Rm+,@Rn+ */
+inline void sh34_base_device::MAC_L(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t RnL, RnH, RmL, RmH, Res0, Res1, Res2;
+ uint32_t temp0, temp1, temp2, temp3;
+ int32_t tempm, tempn, fnLmL;
+
+ tempn = (int32_t) RL(m_r[n] );
+ m_r[n] += 4;
+ tempm = (int32_t) RL(m_r[m] );
+ m_r[m] += 4;
+ if ((int32_t) (tempn ^ tempm) < 0)
+ fnLmL = -1;
+ else
+ fnLmL = 0;
+ if (tempn < 0)
+ tempn = 0 - tempn;
+ if (tempm < 0)
+ tempm = 0 - tempm;
+ temp1 = (uint32_t) tempn;
+ temp2 = (uint32_t) 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_sr & S)
+ {
+ Res0 = m_macl + Res0;
+ if (m_macl > Res0)
+ Res2++;
+ Res2 += (m_mach & 0x0000ffff);
+ if (((int32_t) Res2 < 0) && (Res2 < 0xffff8000))
+ {
+ Res2 = 0x00008000;
+ Res0 = 0x00000000;
+ }
+ else if (((int32_t) Res2 > 0) && (Res2 > 0x00007fff))
+ {
+ Res2 = 0x00007fff;
+ Res0 = 0xffffffff;
+ }
+ m_mach = Res2;
+ m_macl = Res0;
+ }
+ else
+ {
+ Res0 = m_macl + Res0;
+ if (m_macl > Res0)
+ Res2++;
+ Res2 += m_mach;
+ m_mach = Res2;
+ m_macl = Res0;
+ }
+ m_sh4_icount -= 2;
+}
+
+/* MAC.W @Rm+,@Rn+ */
+inline void sh34_base_device::MAC_W(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ int32_t tempm, tempn, dest, src, ans;
+ uint32_t templ;
+
+ tempn = (int32_t) RW(m_r[n] );
+ m_r[n] += 2;
+ tempm = (int32_t) RW(m_r[m] );
+ m_r[m] += 2;
+ templ = m_macl;
+ tempm = ((int32_t) (short) tempn * (int32_t) (short) tempm);
+ if ((int32_t) m_macl >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) tempm >= 0)
+ {
+ src = 0;
+ tempn = 0;
+ }
+ else
+ {
+ src = 1;
+ tempn = 0xffffffff;
+ }
+ src += dest;
+ m_macl += tempm;
+ if ((int32_t) m_macl >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (m_sr & S)
+ {
+ if (ans == 1)
+ {
+ if (src == 0)
+ m_macl = 0x7fffffff;
+ if (src == 2)
+ m_macl = 0x80000000;
+ }
+ }
+ else
+ {
+ m_mach += tempn;
+ if (templ > m_macl)
+ m_mach += 1;
+ }
+ m_sh4_icount -= 2;
+}
+
+/* MOV Rm,Rn */
+inline void sh34_base_device::MOV(const uint16_t opcode)
+{
+ m_r[Rn] = m_r[Rm];
+}
+
+/* MOV.B Rm,@Rn */
+inline void sh34_base_device::MOVBS(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ WB(m_ea, m_r[Rm] & 0x000000ff);
+}
+
+/* MOV.W Rm,@Rn */
+inline void sh34_base_device::MOVWS(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ WW(m_ea, m_r[Rm] & 0x0000ffff);
+}
+
+/* MOV.L Rm,@Rn */
+inline void sh34_base_device::MOVLS(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ WL(m_ea, m_r[Rm] );
+}
+
+/* MOV.B @Rm,Rn */
+inline void sh34_base_device::MOVBL(const uint16_t opcode)
+{
+ m_ea = m_r[Rm];
+ m_r[Rn] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_ea );
+}
+
+/* MOV.W @Rm,Rn */
+inline void sh34_base_device::MOVWL(const uint16_t opcode)
+{
+ m_ea = m_r[Rm];
+ m_r[Rn] = (uint32_t)(int32_t)(int16_t) RW(m_ea );
+}
+
+/* MOV.L @Rm,Rn */
+inline void sh34_base_device::MOVLL(const uint16_t opcode)
+{
+ m_ea = m_r[Rm];
+ m_r[Rn] = RL(m_ea );
+}
+
+/* MOV.B Rm,@-Rn */
+inline void sh34_base_device::MOVBM(const uint16_t opcode)
+{
+ uint32_t data = m_r[Rm] & 0x000000ff;
+
+ m_r[Rn] -= 1;
+ WB(m_r[Rn], data );
+}
+
+/* MOV.W Rm,@-Rn */
+inline void sh34_base_device::MOVWM(const uint16_t opcode)
+{
+ uint32_t data = m_r[Rm] & 0x0000ffff;
+
+ m_r[Rn] -= 2;
+ WW(m_r[Rn], data );
+}
+
+/* MOV.L Rm,@-Rn */
+inline void sh34_base_device::MOVLM(const uint16_t opcode)
+{
+ uint32_t data = m_r[Rm];
+
+ m_r[Rn] -= 4;
+ WL(m_r[Rn], data );
+}
+
+/* MOV.B @Rm+,Rn */
+inline void sh34_base_device::MOVBP(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ m_r[n] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_r[m] );
+ if (n != m)
+ m_r[m] += 1;
+}
+
+/* MOV.W @Rm+,Rn */
+inline void sh34_base_device::MOVWP(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ m_r[n] = (uint32_t)(int32_t)(int16_t) RW(m_r[m] );
+ if (n != m)
+ m_r[m] += 2;
+}
+
+/* MOV.L @Rm+,Rn */
+inline void sh34_base_device::MOVLP(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ m_r[n] = RL(m_r[m] );
+ if (n != m)
+ m_r[m] += 4;
+}
+
+/* MOV.B Rm,@(R0,Rn) */
+inline void sh34_base_device::MOVBS0(const uint16_t opcode)
+{
+ m_ea = m_r[Rn] + m_r[0];
+ WB(m_ea, m_r[Rm] & 0x000000ff );
+}
+
+/* MOV.W Rm,@(R0,Rn) */
+inline void sh34_base_device::MOVWS0(const uint16_t opcode)
+{
+ m_ea = m_r[Rn] + m_r[0];
+ WW(m_ea, m_r[Rm] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(R0,Rn) */
+inline void sh34_base_device::MOVLS0(const uint16_t opcode)
+{
+ m_ea = m_r[Rn] + m_r[0];
+ WL(m_ea, m_r[Rm] );
+}
+
+/* MOV.B @(R0,Rm),Rn */
+inline void sh34_base_device::MOVBL0(const uint16_t opcode)
+{
+ m_ea = m_r[Rm] + m_r[0];
+ m_r[Rn] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_ea );
+}
+
+/* MOV.W @(R0,Rm),Rn */
+inline void sh34_base_device::MOVWL0(const uint16_t opcode)
+{
+ m_ea = m_r[Rm] + m_r[0];
+ m_r[Rn] = (uint32_t)(int32_t)(int16_t) RW(m_ea );
+}
+
+/* MOV.L @(R0,Rm),Rn */
+inline void sh34_base_device::MOVLL0(const uint16_t opcode)
+{
+ m_ea = m_r[Rm] + m_r[0];
+ m_r[Rn] = RL(m_ea );
+}
+
+/* MOV #imm,Rn */
+inline void sh34_base_device::MOVI(const uint16_t opcode)
+{
+ m_r[Rn] = (uint32_t)(int32_t)(int16_t)(int8_t)(opcode&0xff);
+}
+
+/* MOV.W @(disp8,PC),Rn */
+inline void sh34_base_device::MOVWI(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_pc + disp * 2 + 2;
+ m_r[Rn] = (uint32_t)(int32_t)(int16_t) RW(m_ea );
+}
+
+/* MOV.L @(disp8,PC),Rn */
+inline void sh34_base_device::MOVLI(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = ((m_pc + 2) & ~3) + disp * 4;
+ m_r[Rn] = RL(m_ea );
+}
+
+/* MOV.B @(disp8,GBR),R0 */
+inline void sh34_base_device::MOVBLG(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_gbr + disp;
+ m_r[0] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_ea );
+}
+
+/* MOV.W @(disp8,GBR),R0 */
+inline void sh34_base_device::MOVWLG(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_gbr + disp * 2;
+ m_r[0] = (int32_t)(int16_t) RW(m_ea );
+}
+
+/* MOV.L @(disp8,GBR),R0 */
+inline void sh34_base_device::MOVLLG(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_gbr + disp * 4;
+ m_r[0] = RL(m_ea );
+}
+
+/* MOV.B R0,@(disp8,GBR) */
+inline void sh34_base_device::MOVBSG(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_gbr + disp;
+ WB(m_ea, m_r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp8,GBR) */
+inline void sh34_base_device::MOVWSG(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_gbr + disp * 2;
+ WW(m_ea, m_r[0] & 0x0000ffff );
+}
+
+/* MOV.L R0,@(disp8,GBR) */
+inline void sh34_base_device::MOVLSG(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = m_gbr + disp * 4;
+ WL(m_ea, m_r[0] );
+}
+
+/* MOV.B R0,@(disp4,Rm) */
+inline void sh34_base_device::MOVBS4(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0x0f;
+ m_ea = m_r[Rm] + disp;
+ WB(m_ea, m_r[0] & 0x000000ff );
+}
+
+/* MOV.W R0,@(disp4,Rm) */
+inline void sh34_base_device::MOVWS4(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0x0f;
+ m_ea = m_r[Rm] + disp * 2;
+ WW(m_ea, m_r[0] & 0x0000ffff );
+}
+
+/* MOV.L Rm,@(disp4,Rn) */
+inline void sh34_base_device::MOVLS4(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0x0f;
+ m_ea = m_r[Rn] + disp * 4;
+ WL(m_ea, m_r[Rm] );
+}
+
+/* MOV.B @(disp4,Rm),R0 */
+inline void sh34_base_device::MOVBL4(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0x0f;
+ m_ea = m_r[Rm] + disp;
+ m_r[0] = (uint32_t)(int32_t)(int16_t)(int8_t) RB( m_ea );
+}
+
+/* MOV.W @(disp4,Rm),R0 */
+inline void sh34_base_device::MOVWL4(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0x0f;
+ m_ea = m_r[Rm] + disp * 2;
+ m_r[0] = (uint32_t)(int32_t)(int16_t) RW(m_ea );
+}
+
+/* MOV.L @(disp4,Rm),Rn */
+inline void sh34_base_device::MOVLL4(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0x0f;
+ m_ea = m_r[Rm] + disp * 4;
+ m_r[Rn] = RL(m_ea );
+}
+
+/* MOVA @(disp8,PC),R0 */
+inline void sh34_base_device::MOVA(const uint16_t opcode)
+{
+ uint32_t disp = opcode & 0xff;
+ m_ea = ((m_pc + 2) & ~3) + disp * 4;
+ m_r[0] = m_ea;
+}
+
+/* MOVT Rn */
+void sh34_base_device::MOVT(const uint16_t opcode)
+{
+ m_r[Rn] = m_sr & T;
+}
+
+/* MUL.L Rm,Rn */
+inline void sh34_base_device::MULL(const uint16_t opcode)
+{
+ m_macl = m_r[Rn] * m_r[Rm];
+ m_sh4_icount--;
+}
+
+/* MULS Rm,Rn */
+inline void sh34_base_device::MULS(const uint16_t opcode)
+{
+ m_macl = (int16_t) m_r[Rn] * (int16_t) m_r[Rm];
+}
+
+/* MULU Rm,Rn */
+inline void sh34_base_device::MULU(const uint16_t opcode)
+{
+ m_macl = (uint16_t) m_r[Rn] * (uint16_t) m_r[Rm];
+}
+
+/* NEG Rm,Rn */
+inline void sh34_base_device::NEG(const uint16_t opcode)
+{
+ m_r[Rn] = 0 - m_r[Rm];
+}
+
+/* NEGC Rm,Rn */
+inline void sh34_base_device::NEGC(const uint16_t opcode)
+{
+ uint32_t temp;
+
+ temp = m_r[Rm];
+ m_r[Rn] = -temp - (m_sr & T);
+ if (temp || (m_sr & T))
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* NOP */
+inline void sh34_base_device::NOP(const uint16_t opcode)
+{
+}
+
+/* NOT Rm,Rn */
+inline void sh34_base_device::NOT(const uint16_t opcode)
+{
+ m_r[Rn] = ~m_r[Rm];
+}
+
+/* OR Rm,Rn */
+inline void sh34_base_device::OR(const uint16_t opcode)
+{
+ m_r[Rn] |= m_r[Rm];
+}
+
+/* OR #imm,R0 */
+inline void sh34_base_device::ORI(const uint16_t opcode)
+{
+ m_r[0] |= (opcode&0xff);
+ m_sh4_icount -= 2;
+}
+
+/* OR.B #imm,@(R0,GBR) */
+inline void sh34_base_device::ORM(const uint16_t opcode)
+{
+ uint32_t temp;
+
+ m_ea = m_gbr + m_r[0];
+ temp = RB( m_ea );
+ temp |= (opcode&0xff);
+ WB(m_ea, temp );
+}
+
+/* ROTCL Rn */
+inline void sh34_base_device::ROTCL(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ uint32_t temp;
+
+ temp = (m_r[n] >> 31) & T;
+ m_r[n] = (m_r[n] << 1) | (m_sr & T);
+ m_sr = (m_sr & ~T) | temp;
+}
+
+/* ROTCR Rn */
+inline void sh34_base_device::ROTCR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ uint32_t temp;
+ temp = (m_sr & T) << 31;
+ if (m_r[n] & T)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ m_r[n] = (m_r[n] >> 1) | temp;
+}
+
+/* ROTL Rn */
+inline void sh34_base_device::ROTL(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_sr = (m_sr & ~T) | ((m_r[n] >> 31) & T);
+ m_r[n] = (m_r[n] << 1) | (m_r[n] >> 31);
+}
+
+/* ROTR Rn */
+inline void sh34_base_device::ROTR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_sr = (m_sr & ~T) | (m_r[n] & T);
+ m_r[n] = (m_r[n] >> 1) | (m_r[n] << 31);
+}
+
+/* RTE */
+inline void sh34_base_device::RTE(const uint16_t opcode)
+{
+ m_delay = m_ea = m_spc;
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ sh4_syncronize_register_bank((m_sr & sRB) >> 29);
+ if ((m_ssr & sRB) != (m_sr & sRB))
+ sh4_change_register_bank(m_ssr & sRB ? 1 : 0);
+ m_sr = m_ssr;
+ m_sh4_icount--;
+ sh4_exception_recompute();
+}
+
+/* RTS */
+inline void sh34_base_device::RTS(const uint16_t opcode)
+{
+ m_delay = m_ea = m_pr;
+ m_sh4_icount--;
+}
+
+/* SETT */
+inline void sh34_base_device::SETT(const uint16_t opcode)
+{
+ m_sr |= T;
+}
+
+/* SHAL Rn (same as SHLL) */
+inline void sh34_base_device::SHAL(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_sr = (m_sr & ~T) | ((m_r[n] >> 31) & T);
+ m_r[n] <<= 1;
+}
+
+/* SHAR Rn */
+inline void sh34_base_device::SHAR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_sr = (m_sr & ~T) | (m_r[n] & T);
+ m_r[n] = (uint32_t)((int32_t)m_r[n] >> 1);
+}
+
+/* SHLL Rn (same as SHAL) */
+inline void sh34_base_device::SHLL(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_sr = (m_sr & ~T) | ((m_r[n] >> 31) & T);
+ m_r[n] <<= 1;
+}
+
+/* SHLL2 Rn */
+inline void sh34_base_device::SHLL2(const uint16_t opcode)
+{
+ m_r[Rn] <<= 2;
+}
+
+/* SHLL8 Rn */
+inline void sh34_base_device::SHLL8(const uint16_t opcode)
+{
+ m_r[Rn] <<= 8;
+}
+
+/* SHLL16 Rn */
+inline void sh34_base_device::SHLL16(const uint16_t opcode)
+{
+ m_r[Rn] <<= 16;
+}
+
+/* SHLR Rn */
+inline void sh34_base_device::SHLR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_sr = (m_sr & ~T) | (m_r[n] & T);
+ m_r[n] >>= 1;
+}
+
+/* SHLR2 Rn */
+inline void sh34_base_device::SHLR2(const uint16_t opcode)
+{
+ m_r[Rn] >>= 2;
+}
+
+/* SHLR8 Rn */
+inline void sh34_base_device::SHLR8(const uint16_t opcode)
+{
+ m_r[Rn] >>= 8;
+}
+
+/* SHLR16 Rn */
+inline void sh34_base_device::SHLR16(const uint16_t opcode)
+{
+ m_r[Rn] >>= 16;
+}
+
+/* SLEEP */
+inline void sh34_base_device::SLEEP(const uint16_t opcode)
+{
+ /* 0 = normal mode */
+ /* 1 = enters into power-down mode */
+ /* 2 = go out the power-down mode after an exception */
+ if(m_sleep_mode != 2)
+ m_pc -= 2;
+ m_sh4_icount -= 2;
+ /* Wait_for_exception; */
+ if(m_sleep_mode == 0)
+ m_sleep_mode = 1;
+ else if(m_sleep_mode == 2)
+ m_sleep_mode = 0;
+}
+
+/* STC SR,Rn */
+inline void sh34_base_device::STCSR(const uint16_t opcode)
+{
+ m_r[Rn] = m_sr;
+}
+
+/* STC GBR,Rn */
+inline void sh34_base_device::STCGBR(const uint16_t opcode)
+{
+ m_r[Rn] = m_gbr;
+}
+
+/* STC VBR,Rn */
+inline void sh34_base_device::STCVBR(const uint16_t opcode)
+{
+ m_r[Rn] = m_vbr;
+}
+
+/* STC.L SR,@-Rn */
+inline void sh34_base_device::STCMSR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_sr );
+ m_sh4_icount--;
+}
+
+/* STC.L GBR,@-Rn */
+inline void sh34_base_device::STCMGBR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_gbr );
+ m_sh4_icount--;
+}
+
+/* STC.L VBR,@-Rn */
+inline void sh34_base_device::STCMVBR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_vbr );
+ m_sh4_icount--;
+}
+
+/* STS MACH,Rn */
+inline void sh34_base_device::STSMACH(const uint16_t opcode)
+{
+ m_r[Rn] = m_mach;
+}
+
+/* STS MACL,Rn */
+inline void sh34_base_device::STSMACL(const uint16_t opcode)
+{
+ m_r[Rn] = m_macl;
+}
+
+/* STS PR,Rn */
+inline void sh34_base_device::STSPR(const uint16_t opcode)
+{
+ m_r[Rn] = m_pr;
+}
+
+/* STS.L MACH,@-Rn */
+inline void sh34_base_device::STSMMACH(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_mach );
+}
+
+/* STS.L MACL,@-Rn */
+inline void sh34_base_device::STSMMACL(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_macl );
+}
+
+/* STS.L PR,@-Rn */
+inline void sh34_base_device::STSMPR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_pr );
+}
+
+/* SUB Rm,Rn */
+inline void sh34_base_device::SUB(const uint16_t opcode)
+{
+ m_r[Rn] -= m_r[Rm];
+}
+
+/* SUBC Rm,Rn */
+inline void sh34_base_device::SUBC(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t tmp0, tmp1;
+
+ tmp1 = m_r[n] - m_r[m];
+ tmp0 = m_r[n];
+ m_r[n] = tmp1 - (m_sr & T);
+ if (tmp0 < tmp1)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ if (tmp1 < m_r[n])
+ m_sr |= T;
+}
+
+/* SUBV Rm,Rn */
+inline void sh34_base_device::SUBV(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ int32_t dest, src, ans;
+
+ if ((int32_t) m_r[n] >= 0)
+ dest = 0;
+ else
+ dest = 1;
+ if ((int32_t) m_r[m] >= 0)
+ src = 0;
+ else
+ src = 1;
+ src += dest;
+ m_r[n] -= m_r[m];
+ if ((int32_t) m_r[n] >= 0)
+ ans = 0;
+ else
+ ans = 1;
+ ans += dest;
+ if (src == 1)
+ {
+ if (ans == 1)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ }
+ else
+ m_sr &= ~T;
+}
+
+/* SWAP.B Rm,Rn */
+inline void sh34_base_device::SWAPB(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t temp0, temp1;
+
+ temp0 = m_r[m] & 0xffff0000;
+ temp1 = (m_r[m] & 0x000000ff) << 8;
+ m_r[n] = (m_r[m] >> 8) & 0x000000ff;
+ m_r[n] = m_r[n] | temp1 | temp0;
+}
+
+/* SWAP.W Rm,Rn */
+inline void sh34_base_device::SWAPW(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t temp;
+
+ temp = (m_r[m] >> 16) & 0x0000ffff;
+ m_r[n] = (m_r[m] << 16) | temp;
+}
+
+/* TAS.B @Rn */
+inline void sh34_base_device::TAS(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ uint32_t temp;
+ m_ea = m_r[n];
+ /* Bus Lock enable */
+ temp = RB( m_ea );
+ if (temp == 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ temp |= 0x80;
+ /* Bus Lock disable */
+ WB(m_ea, temp );
+ m_sh4_icount -= 3;
+}
+
+/* TRAPA #imm */
+inline void sh34_base_device::TRAPA(const uint16_t opcode)
+{
+ uint32_t imm = opcode & 0xff;
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ m_m[TRA] = imm << 2;
+ }
+ else /* SH3 */
+ {
+ m_sh3internal_upper[SH3_TRA_ADDR] = imm << 2;
+ }
+
+
+ m_ssr = m_sr;
+ m_spc = m_pc;
+ m_sgr = m_r[15];
+
+ m_sr |= MD;
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ sh4_syncronize_register_bank((m_sr & sRB) >> 29);
+ if (!(m_sr & sRB))
+ sh4_change_register_bank(1);
+ m_sr |= sRB;
+ m_sr |= BL;
+ sh4_exception_recompute();
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ m_m[EXPEVT] = 0x00000160;
+ }
+ else /* SH3 */
+ {
+ m_sh3internal_upper[SH3_EXPEVT_ADDR] = 0x00000160;
+ }
+
+ m_pc = m_vbr + 0x00000100;
+
+ m_sh4_icount -= 7;
+}
+
+/* TST Rm,Rn */
+inline void sh34_base_device::TST(const uint16_t opcode)
+{
+ if ((m_r[Rn] & m_r[Rm]) == 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* TST #imm,R0 */
+inline void sh34_base_device::TSTI(const uint16_t opcode)
+{
+ uint32_t imm = opcode & 0xff;
+
+ if ((imm & m_r[0]) == 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+}
+
+/* TST.B #imm,@(R0,GBR) */
+inline void sh34_base_device::TSTM(const uint16_t opcode)
+{
+ uint32_t imm = opcode & 0xff;
+
+ m_ea = m_gbr + m_r[0];
+ if ((imm & RB( m_ea )) == 0)
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ m_sh4_icount -= 2;
+}
+
+/* XOR Rm,Rn */
+inline void sh34_base_device::XOR(const uint16_t opcode)
+{
+ m_r[Rn] ^= m_r[Rm];
+}
+
+/* XOR #imm,R0 */
+inline void sh34_base_device::XORI(const uint16_t opcode)
+{
+ uint32_t imm = opcode & 0xff;
+ m_r[0] ^= imm;
+}
+
+/* XOR.B #imm,@(R0,GBR) */
+inline void sh34_base_device::XORM(const uint16_t opcode)
+{
+ uint32_t imm = opcode & 0xff;
+ uint32_t temp;
+
+ m_ea = m_gbr + m_r[0];
+ temp = RB( m_ea );
+ temp ^= imm;
+ WB(m_ea, temp );
+ m_sh4_icount -= 2;
+}
+
+/* XTRCT Rm,Rn */
+inline void sh34_base_device::XTRCT(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ uint32_t temp;
+
+ temp = (m_r[m] << 16) & 0xffff0000;
+ m_r[n] = (m_r[n] >> 16) & 0x0000ffff;
+ m_r[n] |= temp;
+}
+
+/* STC SSR,Rn */
+inline void sh34_base_device::STCSSR(const uint16_t opcode)
+{
+ m_r[Rn] = m_ssr;
+}
+
+/* STC SPC,Rn */
+inline void sh34_base_device::STCSPC(const uint16_t opcode)
+{
+ m_r[Rn] = m_spc;
+}
+
+/* STC SGR,Rn */
+inline void sh34_base_device::STCSGR(const uint16_t opcode)
+{
+ m_r[Rn] = m_sgr;
+}
+
+/* STS FPUL,Rn */
+inline void sh34_base_device::STSFPUL(const uint16_t opcode)
+{
+ m_r[Rn] = m_fpul;
+}
+
+/* STS FPSCR,Rn */
+inline void sh34_base_device::STSFPSCR(const uint16_t opcode)
+{
+ m_r[Rn] = m_fpscr & 0x003FFFFF;
+}
+
+/* STC DBR,Rn */
+inline void sh34_base_device::STCDBR(const uint16_t opcode)
+{
+ m_r[Rn] = m_dbr;
+}
+
+/* STCRBANK Rm_BANK,Rn */
+inline void sh34_base_device::STCRBANK(const uint16_t opcode)
+{
+ uint32_t m = Rm;
+
+ m_r[Rn] = m_rbnk[m_sr&sRB ? 0 : 1][m & 7];
+}
+
+/* STCMRBANK Rm_BANK,@-Rn */
+inline void sh34_base_device::STCMRBANK(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_rbnk[m_sr&sRB ? 0 : 1][m & 7]);
+ m_sh4_icount--;
+}
+
+/* MOVCA.L R0,@Rn */
+inline void sh34_base_device::MOVCAL(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ WL(m_ea, m_r[0] );
+}
+
+inline void sh34_base_device::CLRS(const uint16_t opcode)
+{
+ m_sr &= ~S;
+}
+
+inline void sh34_base_device::SETS(const uint16_t opcode)
+{
+ m_sr |= S;
+}
+
+/* STS.L SGR,@-Rn */
+inline void sh34_base_device::STCMSGR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_sgr );
+}
+
+/* STS.L FPUL,@-Rn */
+inline void sh34_base_device::STSMFPUL(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_fpul );
+}
+
+/* STS.L FPSCR,@-Rn */
+inline void sh34_base_device::STSMFPSCR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_fpscr & 0x003FFFFF);
+}
+
+/* STC.L DBR,@-Rn */
+inline void sh34_base_device::STCMDBR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_dbr );
+}
+
+/* STC.L SSR,@-Rn */
+inline void sh34_base_device::STCMSSR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_ssr );
+}
+
+/* STC.L SPC,@-Rn */
+inline void sh34_base_device::STCMSPC(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+ WL(m_ea, m_spc );
+}
+
+/* LDS.L @Rm+,FPUL */
+inline void sh34_base_device::LDSMFPUL(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_fpul = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* LDS.L @Rm+,FPSCR */
+inline void sh34_base_device::LDSMFPSCR(const uint16_t opcode)
+{
+ uint32_t s;
+
+ s = m_fpscr;
+ m_ea = m_r[Rn];
+ m_fpscr = RL(m_ea );
+ m_fpscr &= 0x003FFFFF;
+ m_r[Rn] += 4;
+ if ((s & FR) != (m_fpscr & FR))
+ sh4_swap_fp_registers();
+#ifdef LSB_FIRST
+ if ((s & PR) != (m_fpscr & PR))
+ sh4_swap_fp_couples();
+#endif
+ m_fpu_sz = (m_fpscr & SZ) ? 1 : 0;
+ m_fpu_pr = (m_fpscr & PR) ? 1 : 0;
+}
+
+/* LDC.L @Rm+,DBR */
+inline void sh34_base_device::LDCMDBR(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_dbr = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* LDC.L @Rn+,Rm_BANK */
+inline void sh34_base_device::LDCMRBANK(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ m_ea = m_r[n];
+ m_rbnk[m_sr&sRB ? 0 : 1][m & 7] = RL(m_ea );
+ m_r[n] += 4;
+}
+
+/* LDC.L @Rm+,SSR */
+inline void sh34_base_device::LDCMSSR(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_ssr = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* LDC.L @Rm+,SPC */
+inline void sh34_base_device::LDCMSPC(const uint16_t opcode)
+{
+ m_ea = m_r[Rn];
+ m_spc = RL(m_ea );
+ m_r[Rn] += 4;
+}
+
+/* LDS Rm,FPUL */
+inline void sh34_base_device::LDSFPUL(const uint16_t opcode)
+{
+ m_fpul = m_r[Rn];
+}
+
+/* LDS Rm,FPSCR */
+inline void sh34_base_device::LDSFPSCR(const uint16_t opcode)
+{
+ uint32_t s;
+
+ s = m_fpscr;
+ m_fpscr = m_r[Rn] & 0x003FFFFF;
+ if ((s & FR) != (m_fpscr & FR))
+ sh4_swap_fp_registers();
+#ifdef LSB_FIRST
+ if ((s & PR) != (m_fpscr & PR))
+ sh4_swap_fp_couples();
+#endif
+ m_fpu_sz = (m_fpscr & SZ) ? 1 : 0;
+ m_fpu_pr = (m_fpscr & PR) ? 1 : 0;
+}
+
+/* LDC Rm,DBR */
+inline void sh34_base_device::LDCDBR(const uint16_t opcode)
+{
+ m_dbr = m_r[Rn];
+}
+
+/* SHAD Rm,Rn */
+inline void sh34_base_device::SHAD(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if ((m_r[m] & 0x80000000) == 0)
+ m_r[n] = m_r[n] << (m_r[m] & 0x1F);
+ else if ((m_r[m] & 0x1F) == 0) {
+ if ((m_r[n] & 0x80000000) == 0)
+ m_r[n] = 0;
+ else
+ m_r[n] = 0xFFFFFFFF;
+ } else
+ m_r[n]=(int32_t)m_r[n] >> ((~m_r[m] & 0x1F)+1);
+}
+
+/* SHLD Rm,Rn */
+inline void sh34_base_device::SHLD(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if ((m_r[m] & 0x80000000) == 0)
+ m_r[n] = m_r[n] << (m_r[m] & 0x1F);
+ else if ((m_r[m] & 0x1F) == 0)
+ m_r[n] = 0;
+ else
+ m_r[n] = m_r[n] >> ((~m_r[m] & 0x1F)+1);
+}
+
+/* LDCRBANK Rn,Rm_BANK */
+inline void sh34_base_device::LDCRBANK(const uint16_t opcode)
+{
+ uint32_t m = Rm;
+
+ m_rbnk[m_sr&sRB ? 0 : 1][m & 7] = m_r[Rn];
+}
+
+/* LDC Rm,SSR */
+inline void sh34_base_device::LDCSSR(const uint16_t opcode)
+{
+ m_ssr = m_r[Rn];
+}
+
+/* LDC Rm,SPC */
+inline void sh34_base_device::LDCSPC(const uint16_t opcode)
+{
+ m_spc = m_r[Rn];
+}
+
+/* PREF @Rn */
+inline void sh34_base_device::PREFM(const uint16_t opcode)
+{
+ int a;
+ uint32_t addr,dest,sq;
+
+ addr = m_r[Rn]; // address
+ if ((addr >= 0xE0000000) && (addr <= 0xE3FFFFFF))
+ {
+ if (m_sh4_mmu_enabled)
+ {
+ addr = addr & 0xFFFFFFE0;
+ dest = sh4_getsqremap(addr); // good enough for naomi-gd rom, probably not much else
+
+ }
+ else
+ {
+ sq = (addr & 0x20) >> 5;
+ dest = addr & 0x03FFFFE0;
+ if (sq == 0)
+ {
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ dest |= (m_m[QACR0] & 0x1C) << 24;
+ }
+ else
+ {
+ fatalerror("m_cpu_type != CPU_TYPE_SH4 but access internal regs\n");
+ }
+ }
+ else
+ {
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ dest |= (m_m[QACR1] & 0x1C) << 24;
+ }
+ else
+ {
+ fatalerror("m_cpu_type != CPU_TYPE_SH4 but access internal regs\n");
+ }
+
+ }
+ addr = addr & 0xFFFFFFE0;
+ }
+
+ for (a = 0;a < 4;a++)
+ {
+ // shouldn't be causing a memory read, should store sq writes in registers.
+ m_program->write_qword(dest, m_program->read_qword(addr));
+ addr += 8;
+ dest += 8;
+ }
+ }
+}
+
+/*****************************************************************************
+ * OPCODE DISPATCHERS
+ *****************************************************************************/
+
+// TODO: current SZ=1(64bit) FMOVs correct for SH4 in LE mode only
+
+/* FMOV.S @Rm+,FRn PR=0 SZ=0 1111nnnnmmmm1001 */
+/* FMOV @Rm+,DRn PR=0 SZ=1 1111nnn0mmmm1001 */
+/* FMOV @Rm+,XDn PR=0 SZ=1 1111nnn1mmmm1001 */
+/* FMOV @Rm+,XDn PR=1 1111nnn1mmmm1001 */
+inline void sh34_base_device::FMOVMRIFR(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz) { /* SZ = 1 */
+ if (n & 1) {
+ n &= 14;
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_ea = m_r[m];
+ m_xf[n] = RL(m_ea );
+ m_r[m] += 4;
+ m_xf[n^1] = RL(m_ea+4 );
+ m_r[m] += 4;
+ } else {
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_ea = m_r[m];
+ m_fr[n] = RL(m_ea );
+ m_r[m] += 4;
+ m_fr[n^1] = RL(m_ea+4 );
+ m_r[m] += 4;
+ }
+ } else { /* SZ = 0 */
+ m_ea = m_r[m];
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_fr[n] = RL(m_ea );
+ m_r[m] += 4;
+ }
+}
+
+/* FMOV.S FRm,@Rn PR=0 SZ=0 1111nnnnmmmm1010 */
+/* FMOV DRm,@Rn PR=0 SZ=1 1111nnnnmmm01010 */
+/* FMOV XDm,@Rn PR=0 SZ=1 1111nnnnmmm11010 */
+/* FMOV XDm,@Rn PR=1 1111nnnnmmm11010 */
+inline void sh34_base_device::FMOVFRMR(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz) { /* SZ = 1 */
+ if (m & 1) {
+ m &= 14;
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ m_ea = m_r[n];
+ WL(m_ea,m_xf[m] );
+ WL(m_ea+4,m_xf[m^1] );
+ } else {
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ m_ea = m_r[n];
+ WL(m_ea,m_fr[m] );
+ WL(m_ea+4,m_fr[m^1] );
+ }
+ } else { /* SZ = 0 */
+ m_ea = m_r[n];
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ WL(m_ea,m_fr[m] );
+ }
+}
+
+/* FMOV.S FRm,@-Rn PR=0 SZ=0 1111nnnnmmmm1011 */
+/* FMOV DRm,@-Rn PR=0 SZ=1 1111nnnnmmm01011 */
+/* FMOV XDm,@-Rn PR=0 SZ=1 1111nnnnmmm11011 */
+/* FMOV XDm,@-Rn PR=1 1111nnnnmmm11011 */
+inline void sh34_base_device::FMOVFRMDR(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz) { /* SZ = 1 */
+ if (m & 1) {
+ m &= 14;
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ m_r[n] -= 8;
+ m_ea = m_r[n];
+ WL(m_ea,m_xf[m] );
+ WL(m_ea+4,m_xf[m^1] );
+ } else {
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ m_r[n] -= 8;
+ m_ea = m_r[n];
+ WL(m_ea,m_fr[m] );
+ WL(m_ea+4,m_fr[m^1] );
+ }
+ } else { /* SZ = 0 */
+ m_r[n] -= 4;
+ m_ea = m_r[n];
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ WL(m_ea,m_fr[m] );
+ }
+}
+
+/* FMOV.S FRm,@(R0,Rn) PR=0 SZ=0 1111nnnnmmmm0111 */
+/* FMOV DRm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm00111 */
+/* FMOV XDm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm10111 */
+/* FMOV XDm,@(R0,Rn) PR=1 1111nnnnmmm10111 */
+inline void sh34_base_device::FMOVFRS0(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz) { /* SZ = 1 */
+ if (m & 1) {
+ m &= 14;
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ m_ea = m_r[0] + m_r[n];
+ WL(m_ea,m_xf[m] );
+ WL(m_ea+4,m_xf[m^1] );
+ } else {
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ m_ea = m_r[0] + m_r[n];
+ WL(m_ea,m_fr[m] );
+ WL(m_ea+4,m_fr[m^1] );
+ }
+ } else { /* SZ = 0 */
+ m_ea = m_r[0] + m_r[n];
+#ifdef LSB_FIRST
+ m ^= m_fpu_pr;
+#endif
+ WL(m_ea,m_fr[m] );
+ }
+}
+
+/* FMOV.S @(R0,Rm),FRn PR=0 SZ=0 1111nnnnmmmm0110 */
+/* FMOV @(R0,Rm),DRn PR=0 SZ=1 1111nnn0mmmm0110 */
+/* FMOV @(R0,Rm),XDn PR=0 SZ=1 1111nnn1mmmm0110 */
+/* FMOV @(R0,Rm),XDn PR=1 1111nnn1mmmm0110 */
+inline void sh34_base_device::FMOVS0FR(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz) { /* SZ = 1 */
+ if (n & 1) {
+ n &= 14;
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_ea = m_r[0] + m_r[m];
+ m_xf[n] = RL(m_ea );
+ m_xf[n^1] = RL(m_ea+4 );
+ } else {
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_ea = m_r[0] + m_r[m];
+ m_fr[n] = RL(m_ea );
+ m_fr[n^1] = RL(m_ea+4 );
+ }
+ } else { /* SZ = 0 */
+ m_ea = m_r[0] + m_r[m];
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_fr[n] = RL(m_ea );
+ }
+}
+
+/* FMOV.S @Rm,FRn PR=0 SZ=0 1111nnnnmmmm1000 */
+/* FMOV @Rm,DRn PR=0 SZ=1 1111nnn0mmmm1000 */
+/* FMOV @Rm,XDn PR=0 SZ=1 1111nnn1mmmm1000 */
+/* FMOV @Rm,XDn PR=1 1111nnn1mmmm1000 */
+/* FMOV @Rm,DRn PR=1 1111nnn0mmmm1000 */
+inline void sh34_base_device::FMOVMRFR(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz) { /* SZ = 1 */
+ if (n & 1) {
+ n &= 14;
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_ea = m_r[m];
+ m_xf[n] = RL(m_ea );
+ m_xf[n^1] = RL(m_ea+4 );
+ } else {
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_ea = m_r[m];
+ m_fr[n] = RL(m_ea );
+ m_fr[n^1] = RL(m_ea+4 );
+ }
+ } else { /* SZ = 0 */
+ m_ea = m_r[m];
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+#endif
+ m_fr[n] = RL(m_ea );
+ }
+}
+
+/* FMOV FRm,FRn PR=0 SZ=0 FRm -> FRn 1111nnnnmmmm1100 */
+/* FMOV DRm,DRn PR=0 SZ=1 DRm -> DRn 1111nnn0mmm01100 */
+/* FMOV XDm,DRn PR=1 XDm -> DRn 1111nnn0mmm11100 */
+/* FMOV DRm,XDn PR=1 DRm -> XDn 1111nnn1mmm01100 */
+/* FMOV XDm,XDn PR=1 XDm -> XDn 1111nnn1mmm11100 */
+inline void sh34_base_device::FMOVFR(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_sz == 0) { /* SZ = 0 */
+#ifdef LSB_FIRST
+ n ^= m_fpu_pr;
+ m ^= m_fpu_pr;
+#endif
+ m_fr[n] = m_fr[m];
+ }
+ else { /* SZ = 1 */
+ if (m & 1) {
+ if (n & 1) {
+ m_xf[n & 14] = m_xf[m & 14];
+ m_xf[n | 1] = m_xf[m | 1];
+ } else {
+ m_fr[n] = m_xf[m & 14];
+ m_fr[n | 1] = m_xf[m | 1];
+ }
+ } else {
+ if (n & 1) {
+ m_xf[n & 14] = m_fr[m];
+ m_xf[n | 1] = m_fr[m | 1]; // (a&14)+1 -> a|1
+ } else {
+ m_fr[n] = m_fr[m];
+ m_fr[n | 1] = m_fr[m | 1];
+ }
+ }
+ }
+}
+
+/* FLDI1 FRn 1111nnnn10011101 */
+inline void sh34_base_device::FLDI1(const uint16_t opcode)
+{
+#ifdef LSB_FIRST
+ m_fr[Rn ^ m_fpu_pr] = 0x3F800000;
+#else
+ m_fr[Rn] = 0x3F800000;
+#endif
+}
+
+/* FLDI0 FRn 1111nnnn10001101 */
+inline void sh34_base_device::FLDI0(const uint16_t opcode)
+{
+#ifdef LSB_FIRST
+ m_fr[Rn ^ m_fpu_pr] = 0;
+#else
+ m_fr[Rn] = 0;
+#endif
+}
+
+/* FLDS FRm,FPUL 1111mmmm00011101 */
+inline void sh34_base_device:: FLDS(const uint16_t opcode)
+{
+#ifdef LSB_FIRST
+ m_fpul = m_fr[Rn ^ m_fpu_pr];
+#else
+ m_fpul = m_fr[Rn];
+#endif
+}
+
+/* FSTS FPUL,FRn 1111nnnn00001101 */
+inline void sh34_base_device:: FSTS(const uint16_t opcode)
+{
+#ifdef LSB_FIRST
+ m_fr[Rn ^ m_fpu_pr] = m_fpul;
+#else
+ m_fr[Rn] = m_fpul;
+#endif
+}
+
+/* FRCHG 1111101111111101 */
+void sh34_base_device::FRCHG()
+{
+ m_fpscr ^= FR;
+ sh4_swap_fp_registers();
+}
+
+/* FSCHG 1111001111111101 */
+void sh34_base_device::FSCHG()
+{
+ m_fpscr ^= SZ;
+ m_fpu_sz = (m_fpscr & SZ) ? 1 : 0;
+}
+
+/* FTRC FRm,FPUL PR=0 1111mmmm00111101 */
+/* FTRC DRm,FPUL PR=1 1111mmm000111101 */
+inline void sh34_base_device::FTRC(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ if(n & 1)
+ fatalerror("SH-4: FTRC opcode used with n %d",n);
+
+ n = n & 14;
+ *((int32_t *)&m_fpul) = (int32_t)FP_RFD(n);
+ } else { /* PR = 0 */
+ /* read m_fr[n] as float -> truncate -> fpul(32) */
+ *((int32_t *)&m_fpul) = (int32_t)FP_RFS(n);
+ }
+}
+
+/* FLOAT FPUL,FRn PR=0 1111nnnn00101101 */
+/* FLOAT FPUL,DRn PR=1 1111nnn000101101 */
+inline void sh34_base_device::FLOAT(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ if(n & 1)
+ fatalerror("SH-4: FLOAT opcode used with n %d",n);
+
+ n = n & 14;
+ FP_RFD(n) = (double)*((int32_t *)&m_fpul);
+ } else { /* PR = 0 */
+ FP_RFS(n) = (float)*((int32_t *)&m_fpul);
+ }
+}
+
+/* FNEG FRn PR=0 1111nnnn01001101 */
+/* FNEG DRn PR=1 1111nnn001001101 */
+inline void sh34_base_device::FNEG(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ FP_RFD(n) = -FP_RFD(n);
+ } else { /* PR = 0 */
+ FP_RFS(n) = -FP_RFS(n);
+ }
+}
+
+/* FABS FRn PR=0 1111nnnn01011101 */
+/* FABS DRn PR=1 1111nnn001011101 */
+inline void sh34_base_device::FABS(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+#ifdef LSB_FIRST
+ n = n | 1; // n & 14 + 1
+ m_fr[n] = m_fr[n] & 0x7fffffff;
+#else
+ n = n & 14;
+ m_fr[n] = m_fr[n] & 0x7fffffff;
+#endif
+ } else { /* PR = 0 */
+ m_fr[n] = m_fr[n] & 0x7fffffff;
+ }
+}
+
+/* FCMP/EQ FRm,FRn PR=0 1111nnnnmmmm0100 */
+/* FCMP/EQ DRm,DRn PR=1 1111nnn0mmm00100 */
+inline void sh34_base_device::FCMP_EQ(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ m = m & 14;
+ if (FP_RFD(n) == FP_RFD(m))
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ } else { /* PR = 0 */
+ if (FP_RFS(n) == FP_RFS(m))
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ }
+}
+
+/* FCMP/GT FRm,FRn PR=0 1111nnnnmmmm0101 */
+/* FCMP/GT DRm,DRn PR=1 1111nnn0mmm00101 */
+inline void sh34_base_device::FCMP_GT(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ m = m & 14;
+ if (FP_RFD(n) > FP_RFD(m))
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ } else { /* PR = 0 */
+ if (FP_RFS(n) > FP_RFS(m))
+ m_sr |= T;
+ else
+ m_sr &= ~T;
+ }
+}
+
+/* FCNVDS DRm,FPUL PR=1 1111mmm010111101 */
+inline void sh34_base_device::FCNVDS(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ if (m_fpscr & RM)
+ m_fr[n | NATIVE_ENDIAN_VALUE_LE_BE(0,1)] &= 0xe0000000; /* round toward zero*/
+ *((float *)&m_fpul) = (float)FP_RFD(n);
+ }
+}
+
+/* FCNVSD FPUL, DRn PR=1 1111nnn010101101 */
+inline void sh34_base_device::FCNVSD(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ FP_RFD(n) = (double)*((float *)&m_fpul);
+ }
+}
+
+/* FADD FRm,FRn PR=0 1111nnnnmmmm0000 */
+/* FADD DRm,DRn PR=1 1111nnn0mmm00000 */
+inline void sh34_base_device::FADD(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ m = m & 14;
+ FP_RFD(n) = FP_RFD(n) + FP_RFD(m);
+ } else { /* PR = 0 */
+ FP_RFS(n) = FP_RFS(n) + FP_RFS(m);
+ }
+}
+
+/* FSUB FRm,FRn PR=0 1111nnnnmmmm0001 */
+/* FSUB DRm,DRn PR=1 1111nnn0mmm00001 */
+inline void sh34_base_device::FSUB(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ m = m & 14;
+ FP_RFD(n) = FP_RFD(n) - FP_RFD(m);
+ } else { /* PR = 0 */
+ FP_RFS(n) = FP_RFS(n) - FP_RFS(m);
+ }
+}
+
+
+/* FMUL FRm,FRn PR=0 1111nnnnmmmm0010 */
+/* FMUL DRm,DRn PR=1 1111nnn0mmm00010 */
+inline void sh34_base_device::FMUL(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ m = m & 14;
+ FP_RFD(n) = FP_RFD(n) * FP_RFD(m);
+ } else { /* PR = 0 */
+ FP_RFS(n) = FP_RFS(n) * FP_RFS(m);
+ }
+}
+
+/* FDIV FRm,FRn PR=0 1111nnnnmmmm0011 */
+/* FDIV DRm,DRn PR=1 1111nnn0mmm00011 */
+inline void sh34_base_device::FDIV(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ m = m & 14;
+ if (FP_RFD(m) == 0)
+ return;
+ FP_RFD(n) = FP_RFD(n) / FP_RFD(m);
+ } else { /* PR = 0 */
+ if (FP_RFS(m) == 0)
+ return;
+ FP_RFS(n) = FP_RFS(n) / FP_RFS(m);
+ }
+}
+
+/* FMAC FR0,FRm,FRn PR=0 1111nnnnmmmm1110 */
+inline void sh34_base_device::FMAC(const uint16_t opcode)
+{
+ uint32_t m = Rm; uint32_t n = Rn;
+
+ if (m_fpu_pr == 0) { /* PR = 0 */
+ FP_RFS(n) = (FP_RFS(0) * FP_RFS(m)) + FP_RFS(n);
+ }
+}
+
+/* FSQRT FRn PR=0 1111nnnn01101101 */
+/* FSQRT DRn PR=1 1111nnnn01101101 */
+inline void sh34_base_device::FSQRT(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (m_fpu_pr) { /* PR = 1 */
+ n = n & 14;
+ if (FP_RFD(n) < 0)
+ return;
+ FP_RFD(n) = sqrtf(FP_RFD(n));
+ } else { /* PR = 0 */
+ if (FP_RFS(n) < 0)
+ return;
+ FP_RFS(n) = sqrtf(FP_RFS(n));
+ }
+}
+
+/* FSRRA FRn PR=0 1111nnnn01111101 */
+inline void sh34_base_device::FSRRA(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ if (FP_RFS(n) < 0)
+ return;
+ FP_RFS(n) = 1.0f / sqrtf(FP_RFS(n));
+}
+
+/* FSSCA FPUL,FRn PR=0 1111nnn011111101 */
+void sh34_base_device::FSSCA(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+ float angle;
+
+ angle = (((float)(m_fpul & 0xFFFF)) / 65536.0f) * 2.0f * (float) M_PI;
+ FP_RFS(n) = sinf(angle);
+ FP_RFS(n+1) = cosf(angle);
+}
+
+/* FIPR FVm,FVn PR=0 1111nnmm11101101 */
+inline void sh34_base_device::FIPR(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+uint32_t m;
+float ml[4];
+int a;
+
+ m = (n & 3) << 2;
+ n = n & 12;
+ for (a = 0;a < 4;a++)
+ ml[a] = FP_RFS(n+a) * FP_RFS(m+a);
+ FP_RFS(n+3) = ml[0] + ml[1] + ml[2] + ml[3];
+}
+
+/* FTRV XMTRX,FVn PR=0 1111nn0111111101 */
+void sh34_base_device::FTRV(const uint16_t opcode)
+{
+ uint32_t n = Rn;
+
+int i,j;
+float sum[4];
+
+ n = n & 12;
+ for (i = 0;i < 4;i++) {
+ sum[i] = 0;
+ for (j=0;j < 4;j++)
+ sum[i] += FP_XFS((j << 2) + i)*FP_RFS(n + j);
+ }
+ for (i = 0;i < 4;i++)
+ FP_RFS(n + i) = sum[i];
+}
+
+inline void sh34_base_device::op1111_0xf13(const uint16_t opcode)
+{
+ if (opcode & 0x100) {
+ if (opcode & 0x200) {
+ switch (opcode & 0xC00)
+ {
+ case 0x000:
+ FSCHG();
+ break;
+ case 0x800:
+ FRCHG();
+ break;
+ default:
+ machine().debug_break();
+ break;
+ }
+ } else {
+ FTRV(opcode);
+ }
+ } else {
+ FSSCA(opcode);
+ }
+}
+
+void sh34_base_device::dbreak(const uint16_t opcode)
+{
+ machine().debug_break();
+}
+
+
+inline void sh34_base_device::op1111_0x13(uint16_t opcode)
+{
+ switch((opcode >> 4) & 0x0f)
+ {
+ case 0x00: FSTS(opcode); break;
+ case 0x01: FLDS(opcode); break;
+ case 0x02: FLOAT(opcode); break;
+ case 0x03: FTRC(opcode); break;
+ case 0x04: FNEG(opcode); break;
+ case 0x05: FABS(opcode); break;
+ case 0x06: FSQRT(opcode); break;
+ case 0x07: FSRRA(opcode); break;
+ case 0x08: FLDI0(opcode); break;
+ case 0x09: FLDI1(opcode); break;
+ case 0x0a: FCNVSD(opcode); break;
+ case 0x0b: FCNVDS(opcode); break;
+ case 0x0c: dbreak(opcode); break;
+ case 0x0d: dbreak(opcode); break;
+ case 0x0e: FIPR(opcode); break;
+ case 0x0f: op1111_0xf13(opcode); break;
+ }
+}
+
+
+/*****************************************************************************
+ * MAME CPU INTERFACE
+ *****************************************************************************/
+
+void sh34_base_device::device_reset()
+{
+ m_spc = 0;
+ m_pr = 0;
+ m_sr = 0;
+ m_ssr = 0;
+ m_gbr = 0;
+ m_vbr = 0;
+ m_mach = 0;
+ m_macl = 0;
+ memset(m_r, 0, sizeof(m_r));
+ memset(m_rbnk, 0, sizeof(m_rbnk));
+ m_sgr = 0;
+ memset(m_fr, 0, sizeof(m_fr));
+ memset(m_xf, 0, sizeof(m_xf));
+ m_ea = 0;
+ m_delay = 0;
+ m_cpu_off = 0;
+ m_pending_irq = 0;
+ m_test_irq = 0;
+ memset(m_exception_priority, 0, sizeof(m_exception_priority));
+ memset(m_exception_requesting, 0, sizeof(m_exception_requesting));
+ memset(m_m, 0, sizeof(m_m));
+ memset(m_sh3internal_upper, 0, sizeof(m_sh3internal_upper));
+ memset(m_sh3internal_lower, 0, sizeof(m_sh3internal_lower));
+ memset(m_irq_line_state, 0, sizeof(m_irq_line_state));
+ m_SH4_TSTR = 0;
+ m_SH4_TCNT0 = 0;
+ m_SH4_TCNT1 = 0;
+ m_SH4_TCNT2 = 0;
+ m_SH4_TCR0 = 0;
+ m_SH4_TCR1 = 0;
+ m_SH4_TCR2 = 0;
+ m_SH4_TCOR0 = 0;
+ m_SH4_TCOR1 = 0;
+ m_SH4_TCOR2 = 0;
+ m_SH4_TOCR = 0;
+ m_SH4_TCPR2 = 0;
+ m_SH4_IPRA = 0;
+ m_SH4_IPRC = 0;
+ m_SH4_SAR0 = 0;
+ m_SH4_SAR1 = 0;
+ m_SH4_SAR2 = 0;
+ m_SH4_SAR3 = 0;
+ m_SH4_DAR0 = 0;
+ m_SH4_DAR1 = 0;
+ m_SH4_DAR2 = 0;
+ m_SH4_DAR3 = 0;
+ m_SH4_CHCR0 = 0;
+ m_SH4_CHCR1 = 0;
+ m_SH4_CHCR2 = 0;
+ m_SH4_CHCR3 = 0;
+ m_SH4_DMATCR0 = 0;
+ m_SH4_DMATCR1 = 0;
+ m_SH4_DMATCR2 = 0;
+ m_SH4_DMATCR3 = 0;
+ m_SH4_DMAOR = 0;
+ m_nmi_line_state = 0;
+ m_frt_input = 0;
+ m_internal_irq_vector = 0;
+ m_refresh_timer_base = 0;
+ memset(m_dma_timer_active, 0, sizeof(m_dma_timer_active));
+ memset(m_dma_source, 0, sizeof(m_dma_source));
+ memset(m_dma_destination, 0, sizeof(m_dma_destination));
+ memset(m_dma_count, 0, sizeof(m_dma_count));
+ memset(m_dma_wordsize, 0, sizeof(m_dma_wordsize));
+ memset(m_dma_source_increment, 0, sizeof(m_dma_source_increment));
+ memset(m_dma_destination_increment, 0, sizeof(m_dma_destination_increment));
+ memset(m_dma_mode, 0, sizeof(m_dma_mode));
+ m_ioport16_pullup = 0;
+ m_ioport16_direction = 0;
+ m_ioport4_pullup = 0;
+ m_ioport4_direction = 0;
+
+ sh4_default_exception_priorities();
+
+ m_rtc_timer->adjust(attotime::from_hz(128));
+
+ m_pc = 0xa0000000;
+ m_ppc = m_pc & AM;
+ m_r[15] = RL(4);
+ m_sr = 0x700000f0;
+ m_fpscr = 0x00040001;
+ m_fpu_sz = (m_fpscr & SZ) ? 1 : 0;
+ m_fpu_pr = (m_fpscr & PR) ? 1 : 0;
+ m_fpul = 0;
+ m_dbr = 0;
+
+ m_internal_irq_level = -1;
+ m_irln = 15;
+ m_sleep_mode = 0;
+
+ m_sh4_mmu_enabled = 0;
+}
+
+/*-------------------------------------------------
+ sh3_reset - reset the processor
+-------------------------------------------------*/
+
+void sh3_base_device::device_reset()
+{
+ sh34_base_device::device_reset();
+
+ m_SH4_TCOR0 = 0xffffffff;
+ m_SH4_TCNT0 = 0xffffffff;
+ m_SH4_TCOR1 = 0xffffffff;
+ m_SH4_TCNT1 = 0xffffffff;
+ m_SH4_TCOR2 = 0xffffffff;
+ m_SH4_TCNT2 = 0xffffffff;
+}
+
+void sh4_base_device::device_reset()
+{
+ sh34_base_device::device_reset();
+
+ m_m[RCR2] = 0x09;
+ m_SH4_TCOR0 = 0xffffffff;
+ m_SH4_TCNT0 = 0xffffffff;
+ m_SH4_TCOR1 = 0xffffffff;
+ m_SH4_TCNT1 = 0xffffffff;
+ m_SH4_TCOR2 = 0xffffffff;
+ m_SH4_TCNT2 = 0xffffffff;
+}
+
+inline void sh34_base_device::execute_one_0000(const uint16_t opcode)
+{
+ switch(opcode & 0xff)
+ {
+ // 0x00
+ case 0x00: NOP(opcode); break;
+ case 0x10: NOP(opcode); break;
+ case 0x20: NOP(opcode); break;
+ case 0x30: NOP(opcode); break;
+ case 0x40: NOP(opcode); break;
+ case 0x50: NOP(opcode); break;
+ case 0x60: NOP(opcode); break;
+ case 0x70: NOP(opcode); break;
+ case 0x80: NOP(opcode); break;
+ case 0x90: NOP(opcode); break;
+ case 0xa0: NOP(opcode); break;
+ case 0xb0: NOP(opcode); break;
+ case 0xc0: NOP(opcode); break;
+ case 0xd0: NOP(opcode); break;
+ case 0xe0: NOP(opcode); break;
+ case 0xf0: NOP(opcode); break;
+ // 0x10
+ case 0x01: NOP(opcode); break;
+ case 0x11: NOP(opcode); break;
+ case 0x21: NOP(opcode); break;
+ case 0x31: NOP(opcode); break;
+ case 0x41: NOP(opcode); break;
+ case 0x51: NOP(opcode); break;
+ case 0x61: NOP(opcode); break;
+ case 0x71: NOP(opcode); break;
+ case 0x81: NOP(opcode); break;
+ case 0x91: NOP(opcode); break;
+ case 0xa1: NOP(opcode); break;
+ case 0xb1: NOP(opcode); break;
+ case 0xc1: NOP(opcode); break;
+ case 0xd1: NOP(opcode); break;
+ case 0xe1: NOP(opcode); break;
+ case 0xf1: NOP(opcode); break;
+ // 0x20
+ case 0x02: STCSR(opcode); break;
+ case 0x12: STCGBR(opcode); break;
+ case 0x22: STCVBR(opcode); break;
+ case 0x32: STCSSR(opcode); break;
+ case 0x42: STCSPC(opcode); break;
+ case 0x52: NOP(opcode); break;
+ case 0x62: NOP(opcode); break;
+ case 0x72: NOP(opcode); break;
+ case 0x82: STCRBANK(opcode); break;
+ case 0x92: STCRBANK(opcode); break;
+ case 0xa2: STCRBANK(opcode); break;
+ case 0xb2: STCRBANK(opcode); break;
+ case 0xc2: STCRBANK(opcode); break;
+ case 0xd2: STCRBANK(opcode); break;
+ case 0xe2: STCRBANK(opcode); break;
+ case 0xf2: STCRBANK(opcode); break;
+ // 0x30
+ case 0x03: BSRF(opcode); break;
+ case 0x13: NOP(opcode); break;
+ case 0x23: BRAF(opcode); break;
+ case 0x33: NOP(opcode); break;
+ case 0x43: NOP(opcode); break;
+ case 0x53: NOP(opcode); break;
+ case 0x63: NOP(opcode); break;
+ case 0x73: NOP(opcode); break;
+ case 0x83: PREFM(opcode); break;
+ case 0x93: TODO(opcode); break;
+ case 0xa3: TODO(opcode); break;
+ case 0xb3: TODO(opcode); break;
+ case 0xc3: MOVCAL(opcode); break;
+ case 0xd3: NOP(opcode); break;
+ case 0xe3: NOP(opcode); break;
+ case 0xf3: NOP(opcode); break;
+ // 0x40
+ case 0x04: MOVBS0(opcode); break;
+ case 0x14: MOVBS0(opcode); break;
+ case 0x24: MOVBS0(opcode); break;
+ case 0x34: MOVBS0(opcode); break;
+ case 0x44: MOVBS0(opcode); break;
+ case 0x54: MOVBS0(opcode); break;
+ case 0x64: MOVBS0(opcode); break;
+ case 0x74: MOVBS0(opcode); break;
+ case 0x84: MOVBS0(opcode); break;
+ case 0x94: MOVBS0(opcode); break;
+ case 0xa4: MOVBS0(opcode); break;
+ case 0xb4: MOVBS0(opcode); break;
+ case 0xc4: MOVBS0(opcode); break;
+ case 0xd4: MOVBS0(opcode); break;
+ case 0xe4: MOVBS0(opcode); break;
+ case 0xf4: MOVBS0(opcode); break;
+ // 0x50
+ case 0x05: MOVWS0(opcode); break;
+ case 0x15: MOVWS0(opcode); break;
+ case 0x25: MOVWS0(opcode); break;
+ case 0x35: MOVWS0(opcode); break;
+ case 0x45: MOVWS0(opcode); break;
+ case 0x55: MOVWS0(opcode); break;
+ case 0x65: MOVWS0(opcode); break;
+ case 0x75: MOVWS0(opcode); break;
+ case 0x85: MOVWS0(opcode); break;
+ case 0x95: MOVWS0(opcode); break;
+ case 0xa5: MOVWS0(opcode); break;
+ case 0xb5: MOVWS0(opcode); break;
+ case 0xc5: MOVWS0(opcode); break;
+ case 0xd5: MOVWS0(opcode); break;
+ case 0xe5: MOVWS0(opcode); break;
+ case 0xf5: MOVWS0(opcode); break;
+ // 0x60
+ case 0x06: MOVLS0(opcode); break;
+ case 0x16: MOVLS0(opcode); break;
+ case 0x26: MOVLS0(opcode); break;
+ case 0x36: MOVLS0(opcode); break;
+ case 0x46: MOVLS0(opcode); break;
+ case 0x56: MOVLS0(opcode); break;
+ case 0x66: MOVLS0(opcode); break;
+ case 0x76: MOVLS0(opcode); break;
+ case 0x86: MOVLS0(opcode); break;
+ case 0x96: MOVLS0(opcode); break;
+ case 0xa6: MOVLS0(opcode); break;
+ case 0xb6: MOVLS0(opcode); break;
+ case 0xc6: MOVLS0(opcode); break;
+ case 0xd6: MOVLS0(opcode); break;
+ case 0xe6: MOVLS0(opcode); break;
+ case 0xf6: MOVLS0(opcode); break;
+ // 0x70
+ case 0x07: MULL(opcode); break;
+ case 0x17: MULL(opcode); break;
+ case 0x27: MULL(opcode); break;
+ case 0x37: MULL(opcode); break;
+ case 0x47: MULL(opcode); break;
+ case 0x57: MULL(opcode); break;
+ case 0x67: MULL(opcode); break;
+ case 0x77: MULL(opcode); break;
+ case 0x87: MULL(opcode); break;
+ case 0x97: MULL(opcode); break;
+ case 0xa7: MULL(opcode); break;
+ case 0xb7: MULL(opcode); break;
+ case 0xc7: MULL(opcode); break;
+ case 0xd7: MULL(opcode); break;
+ case 0xe7: MULL(opcode); break;
+ case 0xf7: MULL(opcode); break;
+ // 0x80
+ case 0x08: CLRT(opcode); break;
+ case 0x18: SETT(opcode); break;
+ case 0x28: CLRMAC(opcode); break;
+ case 0x38: LDTLB(opcode); break;
+ case 0x48: CLRS(opcode); break;
+ case 0x58: SETS(opcode); break;
+ case 0x68: NOP(opcode); break;
+ case 0x78: NOP(opcode); break;
+ case 0x88: CLRT(opcode); break;
+ case 0x98: SETT(opcode); break;
+ case 0xa8: CLRMAC(opcode); break;
+ case 0xb8: LDTLB(opcode); break;
+ case 0xc8: CLRS(opcode); break;
+ case 0xd8: SETS(opcode); break;
+ case 0xe8: NOP(opcode); break;
+ case 0xf8: NOP(opcode); break;
+ // 0x90
+ case 0x09: NOP(opcode); break;
+ case 0x19: DIV0U(opcode); break;
+ case 0x29: MOVT(opcode); break;
+ case 0x39: NOP(opcode); break;
+ case 0x49: NOP(opcode); break;
+ case 0x59: DIV0U(opcode); break;
+ case 0x69: MOVT(opcode); break;
+ case 0x79: NOP(opcode); break;
+ case 0x89: NOP(opcode); break;
+ case 0x99: DIV0U(opcode); break;
+ case 0xa9: MOVT(opcode); break;
+ case 0xb9: NOP(opcode); break;
+ case 0xc9: NOP(opcode); break;
+ case 0xd9: DIV0U(opcode); break;
+ case 0xe9: MOVT(opcode); break;
+ case 0xf9: NOP(opcode); break;
+ // 0xa0
+ case 0x0a: STSMACH(opcode); break;
+ case 0x1a: STSMACL(opcode); break;
+ case 0x2a: STSPR(opcode); break;
+ case 0x3a: STCSGR(opcode); break;
+ case 0x4a: NOP(opcode); break;
+ case 0x5a: STSFPUL(opcode); break;
+ case 0x6a: STSFPSCR(opcode); break;
+ case 0x7a: STCDBR(opcode); break;
+ case 0x8a: STSMACH(opcode); break;
+ case 0x9a: STSMACL(opcode); break;
+ case 0xaa: STSPR(opcode); break;
+ case 0xba: STCSGR(opcode); break;
+ case 0xca: NOP(opcode); break;
+ case 0xda: STSFPUL(opcode); break;
+ case 0xea: STSFPSCR(opcode); break;
+ case 0xfa: STCDBR(opcode); break;
+ // 0xb0
+ case 0x0b: RTS(opcode); break;
+ case 0x1b: SLEEP(opcode); break;
+ case 0x2b: RTE(opcode); break;
+ case 0x3b: NOP(opcode); break;
+ case 0x4b: RTS(opcode); break;
+ case 0x5b: SLEEP(opcode); break;
+ case 0x6b: RTE(opcode); break;
+ case 0x7b: NOP(opcode); break;
+ case 0x8b: RTS(opcode); break;
+ case 0x9b: SLEEP(opcode); break;
+ case 0xab: RTE(opcode); break;
+ case 0xbb: NOP(opcode); break;
+ case 0xcb: RTS(opcode); break;
+ case 0xdb: SLEEP(opcode); break;
+ case 0xeb: RTE(opcode); break;
+ case 0xfb: NOP(opcode); break;
+ // 0xc0
+ case 0x0c: MOVBL0(opcode); break;
+ case 0x1c: MOVBL0(opcode); break;
+ case 0x2c: MOVBL0(opcode); break;
+ case 0x3c: MOVBL0(opcode); break;
+ case 0x4c: MOVBL0(opcode); break;
+ case 0x5c: MOVBL0(opcode); break;
+ case 0x6c: MOVBL0(opcode); break;
+ case 0x7c: MOVBL0(opcode); break;
+ case 0x8c: MOVBL0(opcode); break;
+ case 0x9c: MOVBL0(opcode); break;
+ case 0xac: MOVBL0(opcode); break;
+ case 0xbc: MOVBL0(opcode); break;
+ case 0xcc: MOVBL0(opcode); break;
+ case 0xdc: MOVBL0(opcode); break;
+ case 0xec: MOVBL0(opcode); break;
+ case 0xfc: MOVBL0(opcode); break;
+ // 0xd0
+ case 0x0d: MOVWL0(opcode); break;
+ case 0x1d: MOVWL0(opcode); break;
+ case 0x2d: MOVWL0(opcode); break;
+ case 0x3d: MOVWL0(opcode); break;
+ case 0x4d: MOVWL0(opcode); break;
+ case 0x5d: MOVWL0(opcode); break;
+ case 0x6d: MOVWL0(opcode); break;
+ case 0x7d: MOVWL0(opcode); break;
+ case 0x8d: MOVWL0(opcode); break;
+ case 0x9d: MOVWL0(opcode); break;
+ case 0xad: MOVWL0(opcode); break;
+ case 0xbd: MOVWL0(opcode); break;
+ case 0xcd: MOVWL0(opcode); break;
+ case 0xdd: MOVWL0(opcode); break;
+ case 0xed: MOVWL0(opcode); break;
+ case 0xfd: MOVWL0(opcode); break;
+ // 0xe0
+ case 0x0e: MOVLL0(opcode); break;
+ case 0x1e: MOVLL0(opcode); break;
+ case 0x2e: MOVLL0(opcode); break;
+ case 0x3e: MOVLL0(opcode); break;
+ case 0x4e: MOVLL0(opcode); break;
+ case 0x5e: MOVLL0(opcode); break;
+ case 0x6e: MOVLL0(opcode); break;
+ case 0x7e: MOVLL0(opcode); break;
+ case 0x8e: MOVLL0(opcode); break;
+ case 0x9e: MOVLL0(opcode); break;
+ case 0xae: MOVLL0(opcode); break;
+ case 0xbe: MOVLL0(opcode); break;
+ case 0xce: MOVLL0(opcode); break;
+ case 0xde: MOVLL0(opcode); break;
+ case 0xee: MOVLL0(opcode); break;
+ case 0xfe: MOVLL0(opcode); break;
+ // 0xf0
+ case 0x0f: MAC_L(opcode); break;
+ case 0x1f: MAC_L(opcode); break;
+ case 0x2f: MAC_L(opcode); break;
+ case 0x3f: MAC_L(opcode); break;
+ case 0x4f: MAC_L(opcode); break;
+ case 0x5f: MAC_L(opcode); break;
+ case 0x6f: MAC_L(opcode); break;
+ case 0x7f: MAC_L(opcode); break;
+ case 0x8f: MAC_L(opcode); break;
+ case 0x9f: MAC_L(opcode); break;
+ case 0xaf: MAC_L(opcode); break;
+ case 0xbf: MAC_L(opcode); break;
+ case 0xcf: MAC_L(opcode); break;
+ case 0xdf: MAC_L(opcode); break;
+ case 0xef: MAC_L(opcode); break;
+ case 0xff: MAC_L(opcode); break;
+ }
+}
+
+inline void sh34_base_device::execute_one_4000(const uint16_t opcode)
+{
+ switch(opcode & 0xff)
+ {
+ // 0x00
+ case 0x00: SHLL(opcode); break;
+ case 0x10: DT(opcode); break;
+ case 0x20: SHAL(opcode); break;
+ case 0x30: NOP(opcode); break;
+ case 0x40: SHLL(opcode); break;
+ case 0x50: DT(opcode); break;
+ case 0x60: SHAL(opcode); break;
+ case 0x70: NOP(opcode); break;
+ case 0x80: SHLL(opcode); break;
+ case 0x90: DT(opcode); break;
+ case 0xa0: SHAL(opcode); break;
+ case 0xb0: NOP(opcode); break;
+ case 0xc0: SHLL(opcode); break;
+ case 0xd0: DT(opcode); break;
+ case 0xe0: SHAL(opcode); break;
+ case 0xf0: NOP(opcode); break;
+ // 0x10
+ case 0x01: SHLR(opcode); break;
+ case 0x11: CMPPZ(opcode); break;
+ case 0x21: SHAR(opcode); break;
+ case 0x31: NOP(opcode); break;
+ case 0x41: SHLR(opcode); break;
+ case 0x51: CMPPZ(opcode); break;
+ case 0x61: SHAR(opcode); break;
+ case 0x71: NOP(opcode); break;
+ case 0x81: SHLR(opcode); break;
+ case 0x91: CMPPZ(opcode); break;
+ case 0xa1: SHAR(opcode); break;
+ case 0xb1: NOP(opcode); break;
+ case 0xc1: SHLR(opcode); break;
+ case 0xd1: CMPPZ(opcode); break;
+ case 0xe1: SHAR(opcode); break;
+ case 0xf1: NOP(opcode); break;
+ // 0x20
+ case 0x02: STSMMACH(opcode); break;
+ case 0x12: STSMMACL(opcode); break;
+ case 0x22: STSMPR(opcode); break;
+ case 0x32: STCMSGR(opcode); break;
+ case 0x42: NOP(opcode); break;
+ case 0x52: STSMFPUL(opcode); break;
+ case 0x62: STSMFPSCR(opcode); break;
+ case 0x72: NOP(opcode); break;
+ case 0x82: NOP(opcode); break;
+ case 0x92: NOP(opcode); break;
+ case 0xa2: NOP(opcode); break;
+ case 0xb2: NOP(opcode); break;
+ case 0xc2: NOP(opcode); break;
+ case 0xd2: NOP(opcode); break;
+ case 0xe2: NOP(opcode); break;
+ case 0xf2: STCMDBR(opcode); break;
+ // 0x30
+ case 0x03: STCMSR(opcode); break;
+ case 0x13: STCMGBR(opcode); break;
+ case 0x23: STCMVBR(opcode); break;
+ case 0x33: STCMSSR(opcode); break;
+ case 0x43: STCMSPC(opcode); break;
+ case 0x53: NOP(opcode); break;
+ case 0x63: NOP(opcode); break;
+ case 0x73: NOP(opcode); break;
+ case 0x83: STCMRBANK(opcode); break;
+ case 0x93: STCMRBANK(opcode); break;
+ case 0xa3: STCMRBANK(opcode); break;
+ case 0xb3: STCMRBANK(opcode); break;
+ case 0xc3: STCMRBANK(opcode); break;
+ case 0xd3: STCMRBANK(opcode); break;
+ case 0xe3: STCMRBANK(opcode); break;
+ case 0xf3: STCMRBANK(opcode); break;
+ // 0x40
+ case 0x04: ROTL(opcode); break;
+ case 0x14: NOP(opcode); break;
+ case 0x24: ROTCL(opcode); break;
+ case 0x34: NOP(opcode); break;
+ case 0x44: ROTL(opcode); break;
+ case 0x54: NOP(opcode); break;
+ case 0x64: ROTCL(opcode); break;
+ case 0x74: NOP(opcode); break;
+ case 0x84: ROTL(opcode); break;
+ case 0x94: NOP(opcode); break;
+ case 0xa4: ROTCL(opcode); break;
+ case 0xb4: NOP(opcode); break;
+ case 0xc4: ROTL(opcode); break;
+ case 0xd4: NOP(opcode); break;
+ case 0xe4: ROTCL(opcode); break;
+ case 0xf4: NOP(opcode); break;
+ // 0x50
+ case 0x05: ROTR(opcode); break;
+ case 0x15: CMPPL(opcode); break;
+ case 0x25: ROTCR(opcode); break;
+ case 0x35: NOP(opcode); break;
+ case 0x45: ROTR(opcode); break;
+ case 0x55: CMPPL(opcode); break;
+ case 0x65: ROTCR(opcode); break;
+ case 0x75: NOP(opcode); break;
+ case 0x85: ROTR(opcode); break;
+ case 0x95: CMPPL(opcode); break;
+ case 0xa5: ROTCR(opcode); break;
+ case 0xb5: NOP(opcode); break;
+ case 0xc5: ROTR(opcode); break;
+ case 0xd5: CMPPL(opcode); break;
+ case 0xe5: ROTCR(opcode); break;
+ case 0xf5: NOP(opcode); break;
+ // 0x60
+ case 0x06: LDSMMACH(opcode); break;
+ case 0x16: LDSMMACL(opcode); break;
+ case 0x26: LDSMPR(opcode); break;
+ case 0x36: NOP(opcode); break;
+ case 0x46: NOP(opcode); break;
+ case 0x56: LDSMFPUL(opcode); break;
+ case 0x66: LDSMFPSCR(opcode); break;
+ case 0x76: NOP(opcode); break;
+ case 0x86: NOP(opcode); break;
+ case 0x96: NOP(opcode); break;
+ case 0xa6: NOP(opcode); break;
+ case 0xb6: NOP(opcode); break;
+ case 0xc6: NOP(opcode); break;
+ case 0xd6: NOP(opcode); break;
+ case 0xe6: NOP(opcode); break;
+ case 0xf6: LDCMDBR(opcode); break;
+ // 0x70
+ case 0x07: LDCMSR(opcode); break;
+ case 0x17: LDCMGBR(opcode); break;
+ case 0x27: LDCMVBR(opcode); break;
+ case 0x37: LDCMSSR(opcode); break;
+ case 0x47: LDCMSPC(opcode); break;
+ case 0x57: NOP(opcode); break;
+ case 0x67: NOP(opcode); break;
+ case 0x77: NOP(opcode); break;
+ case 0x87: LDCMRBANK(opcode); break;
+ case 0x97: LDCMRBANK(opcode); break;
+ case 0xa7: LDCMRBANK(opcode); break;
+ case 0xb7: LDCMRBANK(opcode); break;
+ case 0xc7: LDCMRBANK(opcode); break;
+ case 0xd7: LDCMRBANK(opcode); break;
+ case 0xe7: LDCMRBANK(opcode); break;
+ case 0xf7: LDCMRBANK(opcode); break;
+ // 0x80
+ case 0x08: SHLL2(opcode); break;
+ case 0x18: SHLL8(opcode); break;
+ case 0x28: SHLL16(opcode); break;
+ case 0x38: NOP(opcode); break;
+ case 0x48: SHLL2(opcode); break;
+ case 0x58: SHLL8(opcode); break;
+ case 0x68: SHLL16(opcode); break;
+ case 0x78: NOP(opcode); break;
+ case 0x88: SHLL2(opcode); break;
+ case 0x98: SHLL8(opcode); break;
+ case 0xa8: SHLL16(opcode); break;
+ case 0xb8: NOP(opcode); break;
+ case 0xc8: SHLL2(opcode); break;
+ case 0xd8: SHLL8(opcode); break;
+ case 0xe8: SHLL16(opcode); break;
+ case 0xf8: NOP(opcode); break;
+ // 0x90
+ case 0x09: SHLR2(opcode); break;
+ case 0x19: SHLR8(opcode); break;
+ case 0x29: SHLR16(opcode); break;
+ case 0x39: NOP(opcode); break;
+ case 0x49: SHLR2(opcode); break;
+ case 0x59: SHLR8(opcode); break;
+ case 0x69: SHLR16(opcode); break;
+ case 0x79: NOP(opcode); break;
+ case 0x89: SHLR2(opcode); break;
+ case 0x99: SHLR8(opcode); break;
+ case 0xa9: SHLR16(opcode); break;
+ case 0xb9: NOP(opcode); break;
+ case 0xc9: SHLR2(opcode); break;
+ case 0xd9: SHLR8(opcode); break;
+ case 0xe9: SHLR16(opcode); break;
+ case 0xf9: NOP(opcode); break;
+ // 0xa0
+ case 0x0a: LDSMACH(opcode); break;
+ case 0x1a: LDSMACL(opcode); break;
+ case 0x2a: LDSPR(opcode); break;
+ case 0x3a: NOP(opcode); break;
+ case 0x4a: NOP(opcode); break;
+ case 0x5a: LDSFPUL(opcode); break;
+ case 0x6a: LDSFPSCR(opcode); break;
+ case 0x7a: NOP(opcode); break;
+ case 0x8a: NOP(opcode); break;
+ case 0x9a: NOP(opcode); break;
+ case 0xaa: NOP(opcode); break;
+ case 0xba: NOP(opcode); break;
+ case 0xca: NOP(opcode); break;
+ case 0xda: NOP(opcode); break;
+ case 0xea: NOP(opcode); break;
+ case 0xfa: LDCDBR(opcode); break;
+ // 0xb0
+ case 0x0b: JSR(opcode); break;
+ case 0x1b: TAS(opcode); break;
+ case 0x2b: JMP(opcode); break;
+ case 0x3b: NOP(opcode); break;
+ case 0x4b: JSR(opcode); break;
+ case 0x5b: TAS(opcode); break;
+ case 0x6b: JMP(opcode); break;
+ case 0x7b: NOP(opcode); break;
+ case 0x8b: JSR(opcode); break;
+ case 0x9b: TAS(opcode); break;
+ case 0xab: JMP(opcode); break;
+ case 0xbb: NOP(opcode); break;
+ case 0xcb: JSR(opcode); break;
+ case 0xdb: TAS(opcode); break;
+ case 0xeb: JMP(opcode); break;
+ case 0xfb: NOP(opcode); break;
+ // 0xc0
+ case 0x0c: SHAD(opcode); break;
+ case 0x1c: SHAD(opcode); break;
+ case 0x2c: SHAD(opcode); break;
+ case 0x3c: SHAD(opcode); break;
+ case 0x4c: SHAD(opcode); break;
+ case 0x5c: SHAD(opcode); break;
+ case 0x6c: SHAD(opcode); break;
+ case 0x7c: SHAD(opcode); break;
+ case 0x8c: SHAD(opcode); break;
+ case 0x9c: SHAD(opcode); break;
+ case 0xac: SHAD(opcode); break;
+ case 0xbc: SHAD(opcode); break;
+ case 0xcc: SHAD(opcode); break;
+ case 0xdc: SHAD(opcode); break;
+ case 0xec: SHAD(opcode); break;
+ case 0xfc: SHAD(opcode); break;
+ // 0xd0
+ case 0x0d: SHLD(opcode); break;
+ case 0x1d: SHLD(opcode); break;
+ case 0x2d: SHLD(opcode); break;
+ case 0x3d: SHLD(opcode); break;
+ case 0x4d: SHLD(opcode); break;
+ case 0x5d: SHLD(opcode); break;
+ case 0x6d: SHLD(opcode); break;
+ case 0x7d: SHLD(opcode); break;
+ case 0x8d: SHLD(opcode); break;
+ case 0x9d: SHLD(opcode); break;
+ case 0xad: SHLD(opcode); break;
+ case 0xbd: SHLD(opcode); break;
+ case 0xcd: SHLD(opcode); break;
+ case 0xdd: SHLD(opcode); break;
+ case 0xed: SHLD(opcode); break;
+ case 0xfd: SHLD(opcode); break;
+ // 0xe0
+ case 0x0e: LDCSR(opcode); break;
+ case 0x1e: LDCGBR(opcode); break;
+ case 0x2e: LDCVBR(opcode); break;
+ case 0x3e: LDCSSR(opcode); break;
+ case 0x4e: LDCSPC(opcode); break;
+ case 0x5e: NOP(opcode); break;
+ case 0x6e: NOP(opcode); break;
+ case 0x7e: NOP(opcode); break;
+ case 0x8e: LDCRBANK(opcode); break;
+ case 0x9e: LDCRBANK(opcode); break;
+ case 0xae: LDCRBANK(opcode); break;
+ case 0xbe: LDCRBANK(opcode); break;
+ case 0xce: LDCRBANK(opcode); break;
+ case 0xde: LDCRBANK(opcode); break;
+ case 0xee: LDCRBANK(opcode); break;
+ case 0xfe: LDCRBANK(opcode); break;
+ // 0xf0
+ case 0x0f: MAC_W(opcode); break;
+ case 0x1f: MAC_W(opcode); break;
+ case 0x2f: MAC_W(opcode); break;
+ case 0x3f: MAC_W(opcode); break;
+ case 0x4f: MAC_W(opcode); break;
+ case 0x5f: MAC_W(opcode); break;
+ case 0x6f: MAC_W(opcode); break;
+ case 0x7f: MAC_W(opcode); break;
+ case 0x8f: MAC_W(opcode); break;
+ case 0x9f: MAC_W(opcode); break;
+ case 0xaf: MAC_W(opcode); break;
+ case 0xbf: MAC_W(opcode); break;
+ case 0xcf: MAC_W(opcode); break;
+ case 0xdf: MAC_W(opcode); break;
+ case 0xef: MAC_W(opcode); break;
+ case 0xff: MAC_W(opcode); break;
+ }
+}
+
+
+inline void sh34_base_device::execute_one(const uint16_t opcode)
+{
+ switch(opcode & 0xf000)
+ {
+ case 0x0000:
+ execute_one_0000(opcode);
+ break;
+
+ case 0x1000:
+ MOVLS4(opcode);
+ break;
+
+ case 0x2000:
+ switch(opcode & 0x0f)
+ {
+ case 0x00: MOVBS(opcode); break;
+ case 0x01: MOVWS(opcode); break;
+ case 0x02: MOVLS(opcode); break;
+ case 0x03: NOP(opcode); break;
+ case 0x04: MOVBM(opcode); break;
+ case 0x05: MOVWM(opcode); break;
+ case 0x06: MOVLM(opcode); break;
+ case 0x07: DIV0S(opcode); break;
+ case 0x08: TST(opcode); break;
+ case 0x09: AND(opcode); break;
+ case 0x0a: XOR(opcode); break;
+ case 0x0b: OR(opcode); break;
+ case 0x0c: CMPSTR(opcode); break;
+ case 0x0d: XTRCT(opcode); break;
+ case 0x0e: MULU(opcode); break;
+ case 0x0f: MULS(opcode); break;
+ }
+ break;
+
+ case 0x3000:
+ switch(opcode & 0x0f)
+ {
+ case 0x00: CMPEQ(opcode); break;
+ case 0x01: NOP(opcode); break;
+ case 0x02: CMPHS(opcode); break;
+ case 0x03: CMPGE(opcode); break;
+ case 0x04: DIV1(opcode); break;
+ case 0x05: DMULU(opcode); break;
+ case 0x06: CMPHI(opcode); break;
+ case 0x07: CMPGT(opcode); break;
+ case 0x08: SUB(opcode); break;
+ case 0x09: NOP(opcode); break;
+ case 0x0a: SUBC(opcode); break;
+ case 0x0b: SUBV(opcode); break;
+ case 0x0c: ADD(opcode); break;
+ case 0x0d: DMULS(opcode); break;
+ case 0x0e: ADDC(opcode); break;
+ case 0x0f: ADDV(opcode); break;
+ }
+ break;
+
+ case 0x4000:
+ execute_one_4000(opcode);
+ break;
+
+ case 0x5000:
+ MOVLL4(opcode);
+ break;
+
+ case 0x6000:
+ switch(opcode & 0x0f)
+ {
+ case 0x00: MOVBL(opcode); break;
+ case 0x01: MOVWL(opcode); break;
+ case 0x02: MOVLL(opcode); break;
+ case 0x03: MOV(opcode); break;
+ case 0x04: MOVBP(opcode); break;
+ case 0x05: MOVWP(opcode); break;
+ case 0x06: MOVLP(opcode); break;
+ case 0x07: NOT(opcode); break;
+ case 0x08: SWAPB(opcode); break;
+ case 0x09: SWAPW(opcode); break;
+ case 0x0a: NEGC(opcode); break;
+ case 0x0b: NEG(opcode); break;
+ case 0x0c: EXTUB(opcode); break;
+ case 0x0d: EXTUW(opcode); break;
+ case 0x0e: EXTSB(opcode); break;
+ case 0x0f: EXTSW(opcode); break;
+ }
+ break;
+
+ case 0x7000:
+ ADDI(opcode);
+ break;
+
+ case 0x8000:
+ switch((opcode >> 8) & 0x0f)
+ {
+ case 0x00: MOVBS4(opcode); break;
+ case 0x01: MOVWS4(opcode); break;
+ case 0x02: NOP(opcode); break;
+ case 0x03: NOP(opcode); break;
+ case 0x04: MOVBL4(opcode); break;
+ case 0x05: MOVWL4(opcode); break;
+ case 0x06: NOP(opcode); break;
+ case 0x07: NOP(opcode); break;
+ case 0x08: CMPIM(opcode); break;
+ case 0x09: BT(opcode); break;
+ case 0x0a: NOP(opcode); break;
+ case 0x0b: BF(opcode); break;
+ case 0x0c: NOP(opcode); break;
+ case 0x0d: BTS(opcode); break;
+ case 0x0e: NOP(opcode); break;
+ case 0x0f: BFS(opcode); break;
+ }
+ break;
+
+ case 0x9000:
+ MOVWI(opcode);
+ break;
+
+ case 0xa000:
+ BRA(opcode);
+ break;
+
+ case 0xb000:
+ BSR(opcode);
+ break;
+
+ case 0xc000:
+ switch((opcode >> 8) & 0x0f)
+ {
+ case 0x00: MOVBSG(opcode); break;
+ case 0x01: MOVWSG(opcode); break;
+ case 0x02: MOVLSG(opcode); break;
+ case 0x03: TRAPA(opcode); break;
+ case 0x04: MOVBLG(opcode); break;
+ case 0x05: MOVWLG(opcode); break;
+ case 0x06: MOVLLG(opcode); break;
+ case 0x07: MOVA(opcode); break;
+ case 0x08: TSTI(opcode); break;
+ case 0x09: ANDI(opcode); break;
+ case 0x0a: XORI(opcode); break;
+ case 0x0b: ORI(opcode); break;
+ case 0x0c: TSTM(opcode); break;
+ case 0x0d: ANDM(opcode); break;
+ case 0x0e: XORM(opcode); break;
+ case 0x0f: ORM(opcode); break;
+ }
+ break;
+
+ case 0xd000:
+ MOVLI(opcode);
+ break;
+
+ case 0xe000:
+ MOVI(opcode);
+ break;
+
+ case 0xf000:
+ switch(opcode & 0x0f)
+ {
+ case 0x00: FADD(opcode); break;
+ case 0x01: FSUB(opcode); break;
+ case 0x02: FMUL(opcode); break;
+ case 0x03: FDIV(opcode); break;
+ case 0x04: FCMP_EQ(opcode); break;
+ case 0x05: FCMP_GT(opcode); break;
+ case 0x06: FMOVS0FR(opcode); break;
+ case 0x07: FMOVFRS0(opcode); break;
+ case 0x08: FMOVMRFR(opcode); break;
+ case 0x09: FMOVMRIFR(opcode); break;
+ case 0x0a: FMOVFRMR(opcode); break;
+ case 0x0b: FMOVFRMDR(opcode); break;
+ case 0x0c: FMOVFR(opcode); break;
+ case 0x0d: op1111_0x13(opcode); break;
+ case 0x0e: FMAC(opcode); break;
+ case 0x0f: dbreak(opcode); break;
+ }
+ break;
+ }
+}
+
+
+/* Execute cycles - returns number of cycles actually run */
+void sh34_base_device::execute_run()
+{
+ if (m_cpu_off)
+ {
+ m_sh4_icount = 0;
+ return;
+ }
+
+ do
+ {
+ m_ppc = m_pc & AM;
+ debugger_instruction_hook(this, m_pc & AM);
+
+ uint16_t opcode;
+
+ if (!m_sh4_mmu_enabled) opcode = m_direct->read_word(m_pc & AM, WORD2_XOR_LE(0));
+ else opcode = RW(m_pc); // should probably use a different function as this needs to go through the ITLB
+
+ if (m_delay)
+ {
+ m_pc = m_delay;
+ m_delay = 0;
+ }
+ else
+ m_pc += 2;
+
+ execute_one(opcode);
+
+ if (m_test_irq && !m_delay)
+ {
+ sh4_check_pending_irq("mame_sh4_execute");
+ }
+
+ m_sh4_icount--;
+ } while( m_sh4_icount > 0 );
+}
+
+void sh3be_device::execute_run()
+{
+ if (m_cpu_off)
+ {
+ m_sh4_icount = 0;
+ return;
+ }
+
+ do
+ {
+ m_ppc = m_pc & AM;
+ debugger_instruction_hook(this, m_pc & AM);
+
+ const uint16_t opcode = m_direct->read_word(m_pc & AM, WORD_XOR_LE(6));
+
+ if (m_delay)
+ {
+ m_pc = m_delay;
+ m_delay = 0;
+ }
+ else
+ m_pc += 2;
+
+ execute_one(opcode);
+
+ if (m_test_irq && !m_delay)
+ {
+ sh4_check_pending_irq("mame_sh4_execute");
+ }
+
+ m_sh4_icount--;
+ } while( m_sh4_icount > 0 );
+}
+
+void sh4be_device::execute_run()
+{
+ if (m_cpu_off)
+ {
+ m_sh4_icount = 0;
+ return;
+ }
+
+ do
+ {
+ m_ppc = m_pc & AM;
+ debugger_instruction_hook(this, m_pc & AM);
+
+ const uint16_t opcode = m_direct->read_word(m_pc & AM, WORD_XOR_LE(6));
+
+ if (m_delay)
+ {
+ m_pc = m_delay;
+ m_delay = 0;
+ }
+ else
+ m_pc += 2;
+
+ execute_one(opcode);
+
+ if (m_test_irq && !m_delay)
+ {
+ sh4_check_pending_irq("mame_sh4_execute");
+ }
+
+ m_sh4_icount--;
+ } while( m_sh4_icount > 0 );
+}
+
+void sh4_base_device::device_start()
+{
+ sh34_base_device::device_start();
+
+ int i;
+ for (i=0;i<64;i++)
+ {
+ m_utlb[i].ASID = 0;
+ m_utlb[i].VPN = 0;
+ m_utlb[i].V = 0;
+ m_utlb[i].PPN = 0;
+ m_utlb[i].PSZ = 0;
+ m_utlb[i].SH = 0;
+ m_utlb[i].C = 0;
+ m_utlb[i].PPR = 0;
+ m_utlb[i].D = 0;
+ m_utlb[i].WT = 0;
+ m_utlb[i].SA = 0;
+ m_utlb[i].TC = 0;
+ }
+
+ for (i=0;i<64;i++)
+ {
+ save_item(NAME(m_utlb[i].ASID), i);
+ save_item(NAME(m_utlb[i].VPN), i);
+ save_item(NAME(m_utlb[i].V), i);
+ save_item(NAME(m_utlb[i].PPN), i);
+ save_item(NAME(m_utlb[i].PSZ), i);
+ save_item(NAME(m_utlb[i].SH), i);
+ save_item(NAME(m_utlb[i].C), i);
+ save_item(NAME(m_utlb[i].PPR), i);
+ save_item(NAME(m_utlb[i].D), i);
+ save_item(NAME(m_utlb[i].WT), i);
+ save_item(NAME(m_utlb[i].SA), i);
+ save_item(NAME(m_utlb[i].TC), i);
+ }
+
+}
+
+
+
+void sh34_base_device::device_start()
+{
+ for (int i=0; i<3; i++)
+ {
+ m_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_timer_callback), this));
+ m_timer[i]->adjust(attotime::never, i);
+ }
+
+ for (int i=0; i<4; i++)
+ {
+ m_dma_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_dmac_callback), this));
+ m_dma_timer[i]->adjust(attotime::never, i);
+ }
+
+ m_refresh_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_refresh_timer_callback), this));
+ m_refresh_timer->adjust(attotime::never);
+ m_refresh_timer_base = 0;
+
+ m_rtc_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_rtc_timer_callback), this));
+ m_rtc_timer->adjust(attotime::never);
+
+ sh4_parse_configuration();
+
+ m_internal = &space(AS_PROGRAM);
+ m_program = &space(AS_PROGRAM);
+ m_io = &space(AS_IO);
+ m_direct = &m_program->direct();
+ sh4_default_exception_priorities();
+ m_irln = 15;
+ m_test_irq = 0;
+
+ save_item(NAME(m_pc));
+ save_item(NAME(m_r));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_pr));
+ save_item(NAME(m_gbr));
+ save_item(NAME(m_vbr));
+ save_item(NAME(m_mach));
+ save_item(NAME(m_macl));
+ save_item(NAME(m_spc));
+ save_item(NAME(m_ssr));
+ save_item(NAME(m_sgr));
+ save_item(NAME(m_fpscr));
+ save_item(NAME(m_rbnk));
+ save_item(NAME(m_fr));
+ save_item(NAME(m_xf));
+ save_item(NAME(m_ea));
+ save_item(NAME(m_delay));
+ save_item(NAME(m_cpu_off));
+ save_item(NAME(m_pending_irq));
+ save_item(NAME(m_test_irq));
+ save_item(NAME(m_fpul));
+ save_item(NAME(m_dbr));
+ save_item(NAME(m_exception_priority));
+ save_item(NAME(m_exception_requesting));
+ save_item(NAME(m_irq_line_state));
+ save_item(NAME(m_m));
+ save_item(NAME(m_SH4_TSTR));
+ save_item(NAME(m_SH4_TCNT0));
+ save_item(NAME(m_SH4_TCNT1));
+ save_item(NAME(m_SH4_TCNT2));
+ save_item(NAME(m_SH4_TCR0));
+ save_item(NAME(m_SH4_TCR1));
+ save_item(NAME(m_SH4_TCR2));
+ save_item(NAME(m_SH4_TCOR0));
+ save_item(NAME(m_SH4_TCOR1));
+ save_item(NAME(m_SH4_TCOR2));
+ save_item(NAME(m_SH4_TOCR));
+ save_item(NAME(m_SH4_TCPR2));
+ save_item(NAME(m_SH4_IPRA));
+ save_item(NAME(m_SH4_IPRC));
+ save_item(NAME(m_SH4_DAR0));
+ save_item(NAME(m_SH4_DAR1));
+ save_item(NAME(m_SH4_DAR2));
+ save_item(NAME(m_SH4_DAR3));
+ save_item(NAME(m_SH4_CHCR0));
+ save_item(NAME(m_SH4_CHCR1));
+ save_item(NAME(m_SH4_CHCR2));
+ save_item(NAME(m_SH4_CHCR3));
+ save_item(NAME(m_SH4_DMATCR0));
+ save_item(NAME(m_SH4_DMATCR1));
+ save_item(NAME(m_SH4_DMATCR2));
+ save_item(NAME(m_SH4_DMATCR3));
+ save_item(NAME(m_SH4_DMAOR));
+ save_item(NAME(m_nmi_line_state));
+ save_item(NAME(m_sleep_mode));
+ save_item(NAME(m_frt_input));
+ save_item(NAME(m_irln));
+ save_item(NAME(m_internal_irq_level));
+ save_item(NAME(m_internal_irq_vector));
+ save_item(NAME(m_refresh_timer_base));
+ save_item(NAME(m_dma_timer_active));
+ save_item(NAME(m_dma_source));
+ save_item(NAME(m_dma_destination));
+ save_item(NAME(m_dma_count));
+ save_item(NAME(m_dma_wordsize));
+ save_item(NAME(m_dma_source_increment));
+ save_item(NAME(m_dma_destination_increment));
+ save_item(NAME(m_dma_mode));
+ save_item(NAME(m_sh4_icount));
+ save_item(NAME(m_fpu_sz));
+ save_item(NAME(m_fpu_pr));
+ save_item(NAME(m_ioport16_pullup));
+ save_item(NAME( m_ioport16_direction));
+ save_item(NAME(m_ioport4_pullup));
+ save_item(NAME(m_ioport4_direction));
+ save_item(NAME(m_sh4_mmu_enabled));
+ save_item(NAME(m_sh3internal_upper));
+ save_item(NAME(m_sh3internal_lower));
+
+ // Debugger state
+
+ state_add(SH4_PC, "PC", m_pc).formatstr("%08X").callimport();
+ state_add(SH4_SR, "SR", m_sr).formatstr("%08X").callimport();
+ state_add(SH4_PR, "PR", m_pr).formatstr("%08X");
+ state_add(SH4_GBR, "GBR", m_gbr).formatstr("%08X");
+ state_add(SH4_VBR, "VBR", m_vbr).formatstr("%08X");
+ state_add(SH4_DBR, "DBR", m_dbr).formatstr("%08X");
+ state_add(SH4_MACH, "MACH", m_mach).formatstr("%08X");
+ state_add(SH4_MACL, "MACL", m_macl).formatstr("%08X");
+ state_add(SH4_R0, "R0", m_r[ 0]).formatstr("%08X");
+ state_add(SH4_R1, "R1", m_r[ 1]).formatstr("%08X");
+ state_add(SH4_R2, "R2", m_r[ 2]).formatstr("%08X");
+ state_add(SH4_R3, "R3", m_r[ 3]).formatstr("%08X");
+ state_add(SH4_R4, "R4", m_r[ 4]).formatstr("%08X");
+ state_add(SH4_R5, "R5", m_r[ 5]).formatstr("%08X");
+ state_add(SH4_R6, "R6", m_r[ 6]).formatstr("%08X");
+ state_add(SH4_R7, "R7", m_r[ 7]).formatstr("%08X");
+ state_add(SH4_R8, "R8", m_r[ 8]).formatstr("%08X");
+ state_add(SH4_R9, "R9", m_r[ 9]).formatstr("%08X");
+ state_add(SH4_R10, "R10", m_r[10]).formatstr("%08X");
+ state_add(SH4_R11, "R11", m_r[11]).formatstr("%08X");
+ state_add(SH4_R12, "R12", m_r[12]).formatstr("%08X");
+ state_add(SH4_R13, "R13", m_r[13]).formatstr("%08X");
+ state_add(SH4_R14, "R14", m_r[14]).formatstr("%08X");
+ state_add(SH4_R15, "R15", m_r[15]).formatstr("%08X");
+ state_add(SH4_EA, "EA", m_ea).formatstr("%08X");
+ state_add(SH4_R0_BK0, "R0 BK 0", m_rbnk[0][0]).formatstr("%08X");
+ state_add(SH4_R1_BK0, "R1 BK 0", m_rbnk[0][1]).formatstr("%08X");
+ state_add(SH4_R2_BK0, "R2 BK 0", m_rbnk[0][2]).formatstr("%08X");
+ state_add(SH4_R3_BK0, "R3 BK 0", m_rbnk[0][3]).formatstr("%08X");
+ state_add(SH4_R4_BK0, "R4 BK 0", m_rbnk[0][4]).formatstr("%08X");
+ state_add(SH4_R5_BK0, "R5 BK 0", m_rbnk[0][5]).formatstr("%08X");
+ state_add(SH4_R6_BK0, "R6 BK 0", m_rbnk[0][6]).formatstr("%08X");
+ state_add(SH4_R7_BK0, "R7 BK 0", m_rbnk[0][7]).formatstr("%08X");
+ state_add(SH4_R0_BK1, "R0 BK 1", m_rbnk[1][0]).formatstr("%08X");
+ state_add(SH4_R1_BK1, "R1 BK 1", m_rbnk[1][1]).formatstr("%08X");
+ state_add(SH4_R2_BK1, "R2 BK 1", m_rbnk[1][2]).formatstr("%08X");
+ state_add(SH4_R3_BK1, "R3 BK 1", m_rbnk[1][3]).formatstr("%08X");
+ state_add(SH4_R4_BK1, "R4 BK 1", m_rbnk[1][4]).formatstr("%08X");
+ state_add(SH4_R5_BK1, "R5 BK 1", m_rbnk[1][5]).formatstr("%08X");
+ state_add(SH4_R6_BK1, "R6 BK 1", m_rbnk[1][6]).formatstr("%08X");
+ state_add(SH4_R7_BK1, "R7 BK 1", m_rbnk[1][7]).formatstr("%08X");
+ state_add(SH4_SPC, "SPC", m_spc).formatstr("%08X");
+ state_add(SH4_SSR, "SSR", m_ssr).formatstr("%08X");
+ state_add(SH4_SGR, "SGR", m_sgr).formatstr("%08X");
+ state_add(SH4_FPSCR, "FPSCR", m_fpscr).formatstr("%08X");
+ state_add(SH4_FPUL, "FPUL", m_fpul).formatstr("%08X");
+
+ state_add(SH4_FR0, "FR0", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR1, "FR1", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR2, "FR2", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR3, "FR3", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR4, "FR4", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR5, "FR5", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR6, "FR6", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR7, "FR7", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR8, "FR8", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR9, "FR9", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR10, "FR10", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR11, "FR11", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR12, "FR12", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR13, "FR13", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR14, "FR14", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_FR15, "FR15", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF0, "XF0", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF1, "XF1", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF2, "XF2", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF3, "XF3", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF4, "XF4", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF5, "XF5", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF6, "XF6", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF7, "XF7", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF8, "XF8", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF9, "XF9", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF10, "XF10", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF11, "XF11", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF12, "XF12", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF13, "XF13", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF14, "XF14", m_debugger_temp).callimport().formatstr("%25s");
+ state_add(SH4_XF15, "XF15", m_debugger_temp).callimport().formatstr("%25s");
+
+ state_add(STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_ppc).noshow();
+ state_add(STATE_GENSP, "GENSP", m_r[15]).noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%20s").noshow();
+
+ m_icountptr = &m_sh4_icount;
+}
+
+void sh34_base_device::state_import(const device_state_entry &entry)
+{
+#ifdef LSB_FIRST
+ uint8_t fpu_xor = m_fpu_pr;
+#else
+ uint8_t fpu_xor = 0;
+#endif
+
+ switch (entry.index())
+ {
+ case STATE_GENPC:
+ m_pc = m_debugger_temp;
+ case SH4_PC:
+ m_delay = 0;
+ break;
+
+ case SH4_SR:
+ sh4_exception_recompute();
+ sh4_check_pending_irq("sh4_set_info");
+ break;
+
+ case SH4_FR0:
+ m_fr[0 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR1:
+ m_fr[1 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR2:
+ m_fr[2 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR3:
+ m_fr[3 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR4:
+ m_fr[4 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR5:
+ m_fr[5 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR6:
+ m_fr[6 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR7:
+ m_fr[7 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR8:
+ m_fr[8 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR9:
+ m_fr[9 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR10:
+ m_fr[10 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR11:
+ m_fr[11 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR12:
+ m_fr[12 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR13:
+ m_fr[13 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR14:
+ m_fr[14 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_FR15:
+ m_fr[15 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF0:
+ m_xf[0 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF1:
+ m_xf[1 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF2:
+ m_xf[2 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF3:
+ m_xf[3 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF4:
+ m_xf[4 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF5:
+ m_xf[5 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF6:
+ m_xf[6 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF7:
+ m_xf[7 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF8:
+ m_xf[8 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF9:
+ m_xf[9 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF10:
+ m_xf[10 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF11:
+ m_xf[11 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF12:
+ m_xf[12 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF13:
+ m_xf[13 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF14:
+ m_xf[14 ^ fpu_xor] = m_debugger_temp;
+ break;
+
+ case SH4_XF15:
+ m_xf[15 ^ fpu_xor] = m_debugger_temp;
+ break;
+ }
+}
+
+void sh34_base_device::state_export(const device_state_entry &entry)
+{
+ switch (entry.index())
+ {
+ case STATE_GENPC:
+ m_debugger_temp = (m_pc & AM);
+ break;
+ }
+}
+
+void sh34_base_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+#ifdef LSB_FIRST
+ uint8_t fpu_xor = m_fpu_pr;
+#else
+ uint8_t fpu_xor = 0;
+#endif
+
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = string_format("%s%s%s%s%c%c%d%c%c",
+ m_sr & MD ? "MD ":" ",
+ m_sr & sRB ? "RB ":" ",
+ m_sr & BL ? "BL ":" ",
+ m_sr & FD ? "FD ":" ",
+ m_sr & M ? 'M':'.',
+ m_sr & Q ? 'Q':'.',
+ (m_sr & I) >> 4,
+ m_sr & S ? 'S':'.',
+ m_sr & T ? 'T':'.');
+ break;
+
+ case SH4_FR0:
+ str = string_format("%08X %f", m_fr[0 ^ fpu_xor], (double)FP_RFS(0 ^ fpu_xor));
+ break;
+
+ case SH4_FR1:
+ str = string_format("%08X %f", m_fr[1 ^ fpu_xor], (double)FP_RFS(1 ^ fpu_xor));
+ break;
+
+ case SH4_FR2:
+ str = string_format("%08X %f", m_fr[2 ^ fpu_xor], (double)FP_RFS(2 ^ fpu_xor));
+ break;
+
+ case SH4_FR3:
+ str = string_format("%08X %f", m_fr[3 ^ fpu_xor], (double)FP_RFS(3 ^ fpu_xor));
+ break;
+
+ case SH4_FR4:
+ str = string_format("%08X %f", m_fr[4 ^ fpu_xor], (double)FP_RFS(4 ^ fpu_xor));
+ break;
+
+ case SH4_FR5:
+ str = string_format("%08X %f", m_fr[5 ^ fpu_xor], (double)FP_RFS(5 ^ fpu_xor));
+ break;
+
+ case SH4_FR6:
+ str = string_format("%08X %f", m_fr[6 ^ fpu_xor], (double)FP_RFS(6 ^ fpu_xor));
+ break;
+
+ case SH4_FR7:
+ str = string_format("%08X %f", m_fr[7 ^ fpu_xor], (double)FP_RFS(7 ^ fpu_xor));
+ break;
+
+ case SH4_FR8:
+ str = string_format("%08X %f", m_fr[8 ^ fpu_xor], (double)FP_RFS(8 ^ fpu_xor));
+ break;
+
+ case SH4_FR9:
+ str = string_format("%08X %f", m_fr[9 ^ fpu_xor], (double)FP_RFS(9 ^ fpu_xor));
+ break;
+
+ case SH4_FR10:
+ str = string_format("%08X %f", m_fr[10 ^ fpu_xor], (double)FP_RFS(10 ^ fpu_xor));
+ break;
+
+ case SH4_FR11:
+ str = string_format("%08X %f", m_fr[11 ^ fpu_xor], (double)FP_RFS(11 ^ fpu_xor));
+ break;
+
+ case SH4_FR12:
+ str = string_format("%08X %f", m_fr[12 ^ fpu_xor], (double)FP_RFS(12 ^ fpu_xor));
+ break;
+
+ case SH4_FR13:
+ str = string_format("%08X %f", m_fr[13 ^ fpu_xor], (double)FP_RFS(13 ^ fpu_xor));
+ break;
+
+ case SH4_FR14:
+ str = string_format("%08X %f", m_fr[14 ^ fpu_xor], (double)FP_RFS(14 ^ fpu_xor));
+ break;
+
+ case SH4_FR15:
+ str = string_format("%08X %f", m_fr[15 ^ fpu_xor], (double)FP_RFS(15 ^ fpu_xor));
+ break;
+
+ case SH4_XF0:
+ str = string_format("%08X %f", m_xf[0 ^ fpu_xor], (double)FP_XFS(0 ^ fpu_xor));
+ break;
+
+ case SH4_XF1:
+ str = string_format("%08X %f", m_xf[1 ^ fpu_xor], (double)FP_XFS(1 ^ fpu_xor));
+ break;
+
+ case SH4_XF2:
+ str = string_format("%08X %f", m_xf[2 ^ fpu_xor], (double)FP_XFS(2 ^ fpu_xor));
+ break;
+
+ case SH4_XF3:
+ str = string_format("%08X %f", m_xf[3 ^ fpu_xor], (double)FP_XFS(3 ^ fpu_xor));
+ break;
+
+ case SH4_XF4:
+ str = string_format("%08X %f", m_xf[4 ^ fpu_xor], (double)FP_XFS(4 ^ fpu_xor));
+ break;
+
+ case SH4_XF5:
+ str = string_format("%08X %f", m_xf[5 ^ fpu_xor], (double)FP_XFS(5 ^ fpu_xor));
+ break;
+
+ case SH4_XF6:
+ str = string_format("%08X %f", m_xf[6 ^ fpu_xor], (double)FP_XFS(6 ^ fpu_xor));
+ break;
+
+ case SH4_XF7:
+ str = string_format("%08X %f", m_xf[7 ^ fpu_xor], (double)FP_XFS(7 ^ fpu_xor));
+ break;
+
+ case SH4_XF8:
+ str = string_format("%08X %f", m_xf[8 ^ fpu_xor], (double)FP_XFS(8 ^ fpu_xor));
+ break;
+
+ case SH4_XF9:
+ str = string_format("%08X %f", m_xf[9 ^ fpu_xor], (double)FP_XFS(9 ^ fpu_xor));
+ break;
+
+ case SH4_XF10:
+ str = string_format("%08X %f", m_xf[10 ^ fpu_xor], (double)FP_XFS(10 ^ fpu_xor));
+ break;
+
+ case SH4_XF11:
+ str = string_format("%08X %f", m_xf[11 ^ fpu_xor], (double)FP_XFS(11 ^ fpu_xor));
+ break;
+
+ case SH4_XF12:
+ str = string_format("%08X %f", m_xf[12 ^ fpu_xor], (double)FP_XFS(12 ^ fpu_xor));
+ break;
+
+ case SH4_XF13:
+ str = string_format("%08X %f", m_xf[13 ^ fpu_xor], (double)FP_XFS(13 ^ fpu_xor));
+ break;
+
+ case SH4_XF14:
+ str = string_format("%08X %f", m_xf[14 ^ fpu_xor], (double)FP_XFS(14 ^ fpu_xor));
+ break;
+
+ case SH4_XF15:
+ str = string_format("%08X %f", m_xf[15 ^ fpu_xor], (double)FP_XFS(15 ^ fpu_xor));
+ break;
+
+ }
+}
+
+
+void sh34_base_device::sh4_set_ftcsr_callback(sh4_ftcsr_callback callback)
+{
+ m_ftcsr_read_callback = callback;
+}
diff --git a/src/devices/cpu/sh/sh4.h b/src/devices/cpu/sh/sh4.h
new file mode 100644
index 00000000000..fad1d326750
--- /dev/null
+++ b/src/devices/cpu/sh/sh4.h
@@ -0,0 +1,844 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*****************************************************************************
+ *
+ * sh4->h
+ * Portable Hitachi SH-4 (SH7750 family) emulator interface
+ *
+ * By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek,
+ * Olivier Galibert, Sylvain Glaize, and James Forshaw.
+ *
+ *****************************************************************************/
+
+#ifndef MAME_CPU_SH4_SH4_H
+#define MAME_CPU_SH4_SH4_H
+
+#pragma once
+
+// doesn't actually seem to improve performance at all
+#define SH4_USE_FASTRAM_OPTIMIZATION 0
+#define SH4_MAX_FASTRAM 3
+
+#define SH4_INT_NONE -1
+enum
+{
+ SH4_IRL0=0, SH4_IRL1, SH4_IRL2, SH4_IRL3, SH4_IRLn
+};
+
+enum
+{
+ SH4_PC=1, SH4_SR, SH4_PR, SH4_GBR, SH4_VBR, SH4_DBR, SH4_MACH, SH4_MACL,
+ SH4_R0, SH4_R1, SH4_R2, SH4_R3, SH4_R4, SH4_R5, SH4_R6, SH4_R7,
+ SH4_R8, SH4_R9, SH4_R10, SH4_R11, SH4_R12, SH4_R13, SH4_R14, SH4_R15, SH4_EA,
+ SH4_R0_BK0, SH4_R1_BK0, SH4_R2_BK0, SH4_R3_BK0, SH4_R4_BK0, SH4_R5_BK0, SH4_R6_BK0, SH4_R7_BK0,
+ SH4_R0_BK1, SH4_R1_BK1, SH4_R2_BK1, SH4_R3_BK1, SH4_R4_BK1, SH4_R5_BK1, SH4_R6_BK1, SH4_R7_BK1,
+ SH4_SPC, SH4_SSR, SH4_SGR, SH4_FPSCR, SH4_FPUL, SH4_FR0, SH4_FR1, SH4_FR2, SH4_FR3, SH4_FR4, SH4_FR5,
+ SH4_FR6, SH4_FR7, SH4_FR8, SH4_FR9, SH4_FR10, SH4_FR11, SH4_FR12, SH4_FR13, SH4_FR14, SH4_FR15,
+ SH4_XF0, SH4_XF1, SH4_XF2, SH4_XF3, SH4_XF4, SH4_XF5, SH4_XF6, SH4_XF7,
+ SH4_XF8, SH4_XF9, SH4_XF10, SH4_XF11, SH4_XF12, SH4_XF13, SH4_XF14, SH4_XF15
+};
+
+enum
+{
+ SH4_INTC_NMI=23,
+ SH4_INTC_IRLn0,
+ SH4_INTC_IRLn1,
+ SH4_INTC_IRLn2,
+ SH4_INTC_IRLn3,
+ SH4_INTC_IRLn4,
+ SH4_INTC_IRLn5,
+ SH4_INTC_IRLn6,
+ SH4_INTC_IRLn7,
+ SH4_INTC_IRLn8,
+ SH4_INTC_IRLn9,
+ SH4_INTC_IRLnA,
+ SH4_INTC_IRLnB,
+ SH4_INTC_IRLnC,
+ SH4_INTC_IRLnD,
+ SH4_INTC_IRLnE,
+
+ SH4_INTC_IRL0,
+ SH4_INTC_IRL1,
+ SH4_INTC_IRL2,
+ SH4_INTC_IRL3,
+
+ SH4_INTC_HUDI,
+ SH4_INTC_GPOI,
+
+ SH4_INTC_DMTE0,
+ SH4_INTC_DMTE1,
+ SH4_INTC_DMTE2,
+ SH4_INTC_DMTE3,
+ SH4_INTC_DMTE4,
+ SH4_INTC_DMTE5,
+ SH4_INTC_DMTE6,
+ SH4_INTC_DMTE7,
+
+ SH4_INTC_DMAE,
+
+ SH4_INTC_TUNI3,
+ SH4_INTC_TUNI4,
+ SH4_INTC_TUNI0,
+ SH4_INTC_TUNI1,
+ SH4_INTC_TUNI2,
+ SH4_INTC_TICPI2,
+ SH4_INTC_ATI,
+ SH4_INTC_PRI,
+ SH4_INTC_CUI,
+ SH4_INTC_SCI1ERI,
+ SH4_INTC_SCI1RXI,
+
+ SH4_INTC_SCI1TXI,
+ SH4_INTC_SCI1TEI,
+ SH4_INTC_SCIFERI,
+ SH4_INTC_SCIFRXI,
+ SH4_INTC_SCIFBRI,
+ SH4_INTC_SCIFTXI,
+ SH4_INTC_ITI,
+ SH4_INTC_RCMI,
+ SH4_INTC_ROVI
+};
+
+#define SH4_FPU_PZERO 0
+#define SH4_FPU_NZERO 1
+#define SH4_FPU_DENORM 2
+#define SH4_FPU_NORM 3
+#define SH4_FPU_PINF 4
+#define SH4_FPU_NINF 5
+#define SH4_FPU_qNaN 6
+#define SH4_FPU_sNaN 7
+
+enum
+{
+ SH4_IOPORT_16=8*0,
+ SH4_IOPORT_4=8*1,
+ SH4_IOPORT_DMA=8*2,
+ // future use
+ SH4_IOPORT_SCI=8*3,
+ SH4_IOPORT_SCIF=8*4
+};
+
+struct sh4_device_dma
+{
+ uint32_t length;
+ uint32_t size;
+ void *buffer;
+ int channel;
+};
+
+struct sh4_ddt_dma
+{
+ uint32_t source;
+ uint32_t length;
+ uint32_t size;
+ uint32_t destination;
+ void *buffer;
+ int direction;
+ int channel;
+ int mode;
+};
+
+
+// ASID [7:0] | VPN [31:10] | V | | PPN [28:10] | SZ[1:0] | SH | C | PR[1:0] | D | WT | SA[2:0] | TC
+
+struct sh4_utlb
+{
+ uint8_t ASID;
+ uint32_t VPN;
+ uint8_t V;
+ uint32_t PPN;
+ uint8_t PSZ;
+ uint8_t SH;
+ uint8_t C;
+ uint8_t PPR;
+ uint8_t D;
+ uint8_t WT;
+ uint8_t SA;
+ uint8_t TC;
+};
+
+
+typedef void (*sh4_ftcsr_callback)(uint32_t);
+
+
+#define MCFG_SH4_MD0(_md0) \
+ sh34_base_device::set_md0(*device, _md0);
+
+#define MCFG_SH4_MD1(_md1) \
+ sh34_base_device::set_md1(*device, _md1);
+
+#define MCFG_SH4_MD2(_md2) \
+ sh34_base_device::set_md2(*device, _md2);
+
+#define MCFG_SH4_MD3(_md3) \
+ sh34_base_device::set_md3(*device, _md3);
+
+#define MCFG_SH4_MD4(_md4) \
+ sh34_base_device::set_md4(*device, _md4);
+
+#define MCFG_SH4_MD5(_md5) \
+ sh34_base_device::set_md5(*device, _md5);
+
+#define MCFG_SH4_MD6(_md6) \
+ sh34_base_device::set_md6(*device, _md6);
+
+#define MCFG_SH4_MD7(_md7) \
+ sh34_base_device::set_md7(*device, _md7);
+
+#define MCFG_SH4_MD8(_md8) \
+ sh34_base_device::set_md8(*device, _md8);
+
+#define MCFG_SH4_CLOCK(_clock) \
+ sh34_base_device::set_sh4_clock(*device, _clock);
+
+
+#define MCFG_MMU_HACK_TYPE(_hacktype) \
+ sh34_base_device::set_mmu_hacktype(*device, _hacktype);
+
+
+class sh34_base_device : public cpu_device
+{
+public:
+//#if SH4_USE_FASTRAM_OPTIMIZATION
+ void add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
+//#endif
+
+ static void set_md0(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md0 = md0; }
+ static void set_md1(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md1 = md0; }
+ static void set_md2(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md2 = md0; }
+ static void set_md3(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md3 = md0; }
+ static void set_md4(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md4 = md0; }
+ static void set_md5(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md5 = md0; }
+ static void set_md6(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md6 = md0; }
+ static void set_md7(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md7 = md0; }
+ static void set_md8(device_t &device, int md0) { downcast<sh34_base_device &>(device).c_md8 = md0; }
+ static void set_sh4_clock(device_t &device, int clock) { downcast<sh34_base_device &>(device).c_clock = clock; }
+
+ static void set_mmu_hacktype(device_t &device, int hacktype) { downcast<sh34_base_device &>(device).m_mmuhack = hacktype; }
+
+ TIMER_CALLBACK_MEMBER( sh4_refresh_timer_callback );
+ TIMER_CALLBACK_MEMBER( sh4_rtc_timer_callback );
+ TIMER_CALLBACK_MEMBER( sh4_timer_callback );
+ TIMER_CALLBACK_MEMBER( sh4_dmac_callback );
+
+ void sh4_set_frt_input(int state);
+ void sh4_set_irln_input(int value);
+ void sh4_set_ftcsr_callback(sh4_ftcsr_callback callback);
+ int sh4_dma_data(struct sh4_device_dma *s);
+ void sh4_dma_ddt(struct sh4_ddt_dma *s);
+
+protected:
+ // construction/destruction
+ sh34_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness, address_map_constructor internal);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_execute_interface overrides
+ virtual uint32_t execute_min_cycles() const override { return 1; }
+ virtual uint32_t execute_max_cycles() const override { return 4; }
+ virtual uint32_t execute_input_lines() const override { return 5; }
+ virtual void execute_run() override;
+ virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_state_interface overrides
+ virtual void state_import(const device_state_entry &entry) override;
+ virtual void state_export(const device_state_entry &entry) override;
+ virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+ // device_disasm_interface overrides
+ virtual uint32_t disasm_min_opcode_bytes() const override { return 2; }
+ virtual uint32_t disasm_max_opcode_bytes() const override { return 2; }
+ virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
+
+ address_space_config m_program_config;
+ address_space_config m_io_config;
+
+ int c_md2;
+ int c_md1;
+ int c_md0;
+ int c_md6;
+ int c_md4;
+ int c_md3;
+ int c_md5;
+ int c_md7;
+ int c_md8;
+ int c_clock;
+
+ // hack 1 = Naomi hack, hack 2 = Work in Progress implementation
+ int m_mmuhack;
+
+ uint32_t m_ppc;
+ uint32_t m_pc;
+ uint32_t m_spc;
+ uint32_t m_pr;
+ uint32_t m_sr;
+ uint32_t m_ssr;
+ uint32_t m_gbr;
+ uint32_t m_vbr;
+ uint32_t m_mach;
+ uint32_t m_macl;
+ uint32_t m_r[16];
+ uint32_t m_rbnk[2][8];
+ uint32_t m_sgr;
+ uint32_t m_fr[16];
+ uint32_t m_xf[16];
+ uint32_t m_ea;
+ uint32_t m_delay;
+ uint32_t m_cpu_off;
+ uint32_t m_pending_irq;
+ uint32_t m_test_irq;
+ uint32_t m_fpscr;
+ uint32_t m_fpul;
+ uint32_t m_dbr;
+
+ uint32_t m_exception_priority[128];
+ int m_exception_requesting[128];
+
+ int8_t m_irq_line_state[17];
+ address_space *m_internal;
+ address_space *m_program;
+ direct_read_data *m_direct;
+ address_space *m_io;
+
+ // sh4 internal
+ uint32_t m_m[16384];
+
+ // timer regs handled manually for reuse
+ uint32_t m_SH4_TSTR;
+ uint32_t m_SH4_TCNT0;
+ uint32_t m_SH4_TCNT1;
+ uint32_t m_SH4_TCNT2;
+ uint32_t m_SH4_TCR0;
+ uint32_t m_SH4_TCR1;
+ uint32_t m_SH4_TCR2;
+ uint32_t m_SH4_TCOR0;
+ uint32_t m_SH4_TCOR1;
+ uint32_t m_SH4_TCOR2;
+ uint32_t m_SH4_TOCR;
+ uint32_t m_SH4_TCPR2;
+
+ // INTC regs
+ uint32_t m_SH4_IPRA;
+
+ uint32_t m_SH4_IPRC;
+
+ // DMAC regs
+ uint32_t m_SH4_SAR0;
+ uint32_t m_SH4_SAR1;
+ uint32_t m_SH4_SAR2;
+ uint32_t m_SH4_SAR3;
+
+ uint32_t m_SH4_DAR0;
+ uint32_t m_SH4_DAR1;
+ uint32_t m_SH4_DAR2;
+ uint32_t m_SH4_DAR3;
+
+ uint32_t m_SH4_CHCR0;
+ uint32_t m_SH4_CHCR1;
+ uint32_t m_SH4_CHCR2;
+ uint32_t m_SH4_CHCR3;
+
+ uint32_t m_SH4_DMATCR0;
+ uint32_t m_SH4_DMATCR1;
+ uint32_t m_SH4_DMATCR2;
+ uint32_t m_SH4_DMATCR3;
+
+ uint32_t m_SH4_DMAOR;
+
+ int8_t m_nmi_line_state;
+
+ uint8_t m_sleep_mode;
+
+ int m_frt_input;
+ int m_irln;
+ int m_internal_irq_level;
+ int m_internal_irq_vector;
+
+ emu_timer *m_dma_timer[4];
+ emu_timer *m_refresh_timer;
+ emu_timer *m_rtc_timer;
+ emu_timer *m_timer[3];
+ uint32_t m_refresh_timer_base;
+ int m_dma_timer_active[4];
+ uint32_t m_dma_source[4];
+ uint32_t m_dma_destination[4];
+ uint32_t m_dma_count[4];
+ int m_dma_wordsize[4];
+ int m_dma_source_increment[4];
+ int m_dma_destination_increment[4];
+ int m_dma_mode[4];
+
+ int m_sh4_icount;
+ int m_is_slave;
+ int m_cpu_clock;
+ int m_bus_clock;
+ int m_pm_clock;
+ int m_fpu_sz;
+ int m_fpu_pr;
+ int m_ioport16_pullup;
+ int m_ioport16_direction;
+ int m_ioport4_pullup;
+ int m_ioport4_direction;
+
+ void (*m_ftcsr_read_callback)(uint32_t data);
+
+ /* This MMU simulation is good for the simple remap used on Naomi GD-ROM SQ access *ONLY* */
+ uint8_t m_sh4_mmu_enabled;
+
+ int m_cpu_type;
+
+ // sh3 internal
+ uint32_t m_sh3internal_upper[0x3000/4];
+ uint32_t m_sh3internal_lower[0x1000];
+
+ uint64_t m_debugger_temp;
+
+
+ void execute_one_0000(const uint16_t opcode);
+ void execute_one_4000(const uint16_t opcode);
+ void execute_one(const uint16_t opcode);
+ inline void sh4_check_pending_irq(const char *message) // look for highest priority active exception and handle it
+ {
+ int a,irq,z;
+
+ irq = 0;
+ z = -1;
+ for (a=0;a <= SH4_INTC_ROVI;a++)
+ {
+ if (m_exception_requesting[a])
+ {
+ if ((int)m_exception_priority[a] > z)
+ {
+ z = m_exception_priority[a];
+ irq = a;
+ }
+ }
+ }
+ if (z >= 0)
+ {
+ sh4_exception(message, irq);
+ }
+ }
+
+ void TODO(const uint16_t opcode);
+ void WB(offs_t A, uint8_t V);
+ void WW(offs_t A, uint16_t V);
+ void WL(offs_t A, uint32_t V);
+ void ADD(const uint16_t opcode);
+ void ADDI(const uint16_t opcode);
+ void ADDC(const uint16_t opcode);
+ void ADDV(const uint16_t opcode);
+ void AND(const uint16_t opcode);
+ void ANDI(const uint16_t opcode);
+ void ANDM(const uint16_t opcode);
+ void BF(const uint16_t opcode);
+ void BFS(const uint16_t opcode);
+ void BRA(const uint16_t opcode);
+ void BRAF(const uint16_t opcode);
+ void BSR(const uint16_t opcode);
+ void BSRF(const uint16_t opcode);
+ void BT(const uint16_t opcode);
+ void BTS(const uint16_t opcode);
+ void CLRMAC(const uint16_t opcode);
+ void CLRT(const uint16_t opcode);
+ void CMPEQ(const uint16_t opcode);
+ void CMPGE(const uint16_t opcode);
+ void CMPGT(const uint16_t opcode);
+ void CMPHI(const uint16_t opcode);
+ void CMPHS(const uint16_t opcode);
+ void CMPPL(const uint16_t opcode);
+ void CMPPZ(const uint16_t opcode);
+ void CMPSTR(const uint16_t opcode);
+ void CMPIM(const uint16_t opcode);
+ void DIV0S(const uint16_t opcode);
+ void DIV0U(const uint16_t opcode);
+ void DIV1(const uint16_t opcode);
+ void DMULS(const uint16_t opcode);
+ void DMULU(const uint16_t opcode);
+ void DT(const uint16_t opcode);
+ void EXTSB(const uint16_t opcode);
+ void EXTSW(const uint16_t opcode);
+ void EXTUB(const uint16_t opcode);
+ void EXTUW(const uint16_t opcode);
+ void JMP(const uint16_t opcode);
+ void JSR(const uint16_t opcode);
+ void LDCSR(const uint16_t opcode);
+ void LDCGBR(const uint16_t opcode);
+ void LDCVBR(const uint16_t opcode);
+ void LDCMSR(const uint16_t opcode);
+ void LDCMGBR(const uint16_t opcode);
+ void LDCMVBR(const uint16_t opcode);
+ void LDSMACH(const uint16_t opcode);
+ void LDSMACL(const uint16_t opcode);
+ void LDSPR(const uint16_t opcode);
+ void LDSMMACH(const uint16_t opcode);
+ void LDSMMACL(const uint16_t opcode);
+ void LDSMPR(const uint16_t opcode);
+ virtual void LDTLB(const uint16_t opcode);
+ void MAC_L(const uint16_t opcode);
+ void MAC_W(const uint16_t opcode);
+ void MOV(const uint16_t opcode);
+ void MOVBS(const uint16_t opcode);
+ void MOVWS(const uint16_t opcode);
+ void MOVLS(const uint16_t opcode);
+ void MOVBL(const uint16_t opcode);
+ void MOVWL(const uint16_t opcode);
+ void MOVLL(const uint16_t opcode);
+ void MOVBM(const uint16_t opcode);
+ void MOVWM(const uint16_t opcode);
+ void MOVLM(const uint16_t opcode);
+ void MOVBP(const uint16_t opcode);
+ void MOVWP(const uint16_t opcode);
+ void MOVLP(const uint16_t opcode);
+ void MOVBS0(const uint16_t opcode);
+ void MOVWS0(const uint16_t opcode);
+ void MOVLS0(const uint16_t opcode);
+ void MOVBL0(const uint16_t opcode);
+ void MOVWL0(const uint16_t opcode);
+ void MOVLL0(const uint16_t opcode);
+ void MOVI(const uint16_t opcode);
+ void MOVWI(const uint16_t opcode);
+ void MOVLI(const uint16_t opcode);
+ void MOVBLG(const uint16_t opcode);
+ void MOVWLG(const uint16_t opcode);
+ void MOVLLG(const uint16_t opcode);
+ void MOVBSG(const uint16_t opcode);
+ void MOVWSG(const uint16_t opcode);
+ void MOVLSG(const uint16_t opcode);
+ void MOVBS4(const uint16_t opcode);
+ void MOVWS4(const uint16_t opcode);
+ void MOVLS4(const uint16_t opcode);
+ void MOVBL4(const uint16_t opcode);
+ void MOVWL4(const uint16_t opcode);
+ void MOVLL4(const uint16_t opcode);
+ void MOVA(const uint16_t opcode);
+ void MOVT(const uint16_t opcode);
+ void MULL(const uint16_t opcode);
+ void MULS(const uint16_t opcode);
+ void MULU(const uint16_t opcode);
+ void NEG(const uint16_t opcode);
+ void NEGC(const uint16_t opcode);
+ void NOP(const uint16_t opcode);
+ void NOT(const uint16_t opcode);
+ void OR(const uint16_t opcode);
+ void ORI(const uint16_t opcode);
+ void ORM(const uint16_t opcode);
+ void ROTCL(const uint16_t opcode);
+ void ROTCR(const uint16_t opcode);
+ void ROTL(const uint16_t opcode);
+ void ROTR(const uint16_t opcode);
+ void RTE(const uint16_t opcode);
+ void RTS(const uint16_t opcode);
+ void SETT(const uint16_t opcode);
+ void SHAL(const uint16_t opcode);
+ void SHAR(const uint16_t opcode);
+ void SHLL(const uint16_t opcode);
+ void SHLL2(const uint16_t opcode);
+ void SHLL8(const uint16_t opcode);
+ void SHLL16(const uint16_t opcode);
+ void SHLR(const uint16_t opcode);
+ void SHLR2(const uint16_t opcode);
+ void SHLR8(const uint16_t opcode);
+ void SHLR16(const uint16_t opcode);
+ void SLEEP(const uint16_t opcode);
+ void STCSR(const uint16_t opcode);
+ void STCGBR(const uint16_t opcode);
+ void STCVBR(const uint16_t opcode);
+ void STCMSR(const uint16_t opcode);
+ void STCMGBR(const uint16_t opcode);
+ void STCMVBR(const uint16_t opcode);
+ void STSMACH(const uint16_t opcode);
+ void STSMACL(const uint16_t opcode);
+ void STSPR(const uint16_t opcode);
+ void STSMMACH(const uint16_t opcode);
+ void STSMMACL(const uint16_t opcode);
+ void STSMPR(const uint16_t opcode);
+ void SUB(const uint16_t opcode);
+ void SUBC(const uint16_t opcode);
+ void SUBV(const uint16_t opcode);
+ void SWAPB(const uint16_t opcode);
+ void SWAPW(const uint16_t opcode);
+ void TAS(const uint16_t opcode);
+ void TRAPA(const uint16_t opcode);
+ void TST(const uint16_t opcode);
+ void TSTI(const uint16_t opcode);
+ void TSTM(const uint16_t opcode);
+ void XOR(const uint16_t opcode);
+ void XORI(const uint16_t opcode);
+ void XORM(const uint16_t opcode);
+ void XTRCT(const uint16_t opcode);
+ void STCSSR(const uint16_t opcode);
+ void STCSPC(const uint16_t opcode);
+ void STCSGR(const uint16_t opcode);
+ void STSFPUL(const uint16_t opcode);
+ void STSFPSCR(const uint16_t opcode);
+ void STCDBR(const uint16_t opcode);
+ void STCRBANK(const uint16_t opcode);
+ void STCMRBANK(const uint16_t opcode);
+ void MOVCAL(const uint16_t opcode);
+ void CLRS(const uint16_t opcode);
+ void SETS(const uint16_t opcode);
+ void STCMSGR(const uint16_t opcode);
+ void STSMFPUL(const uint16_t opcode);
+ void STSMFPSCR(const uint16_t opcode);
+ void STCMDBR(const uint16_t opcode);
+ void STCMSSR(const uint16_t opcode);
+ void STCMSPC(const uint16_t opcode);
+ void LDSMFPUL(const uint16_t opcode);
+ void LDSMFPSCR(const uint16_t opcode);
+ void LDCMDBR(const uint16_t opcode);
+ void LDCMRBANK(const uint16_t opcode);
+ void LDCMSSR(const uint16_t opcode);
+ void LDCMSPC(const uint16_t opcode);
+ void LDSFPUL(const uint16_t opcode);
+ void LDSFPSCR(const uint16_t opcode);
+ void LDCDBR(const uint16_t opcode);
+ void SHAD(const uint16_t opcode);
+ void SHLD(const uint16_t opcode);
+ void LDCRBANK(const uint16_t opcode);
+ void LDCSSR(const uint16_t opcode);
+ void LDCSPC(const uint16_t opcode);
+ void PREFM(const uint16_t opcode);
+ void FMOVMRIFR(const uint16_t opcode);
+ void FMOVFRMR(const uint16_t opcode);
+ void FMOVFRMDR(const uint16_t opcode);
+ void FMOVFRS0(const uint16_t opcode);
+ void FMOVS0FR(const uint16_t opcode);
+ void FMOVMRFR(const uint16_t opcode);
+ void FMOVFR(const uint16_t opcode);
+ void FLDI1(const uint16_t opcode);
+ void FLDI0(const uint16_t opcode);
+ void FLDS(const uint16_t opcode);
+ void FSTS(const uint16_t opcode);
+ void FRCHG();
+ void FSCHG();
+ void FTRC(const uint16_t opcode);
+ void FLOAT(const uint16_t opcode);
+ void FNEG(const uint16_t opcode);
+ void FABS(const uint16_t opcode);
+ void FCMP_EQ(const uint16_t opcode);
+ void FCMP_GT(const uint16_t opcode);
+ void FCNVDS(const uint16_t opcode);
+ void FCNVSD(const uint16_t opcode);
+ void FADD(const uint16_t opcode);
+ void FSUB(const uint16_t opcode);
+ void FMUL(const uint16_t opcode);
+ void FDIV(const uint16_t opcode);
+ void FMAC(const uint16_t opcode);
+ void FSQRT(const uint16_t opcode);
+ void FSRRA(const uint16_t opcode);
+ void FSSCA(const uint16_t opcode);
+ void FIPR(const uint16_t opcode);
+ void FTRV(const uint16_t opcode);
+ void op1111_0xf13(const uint16_t opcode);
+ void dbreak(const uint16_t opcode);
+ void op1111_0x13(uint16_t opcode);
+ uint8_t RB(offs_t A);
+ uint16_t RW(offs_t A);
+ uint32_t RL(offs_t A);
+ void sh4_change_register_bank(int to);
+ void sh4_swap_fp_registers();
+ void sh4_swap_fp_couples();
+ void sh4_syncronize_register_bank(int to);
+ void sh4_default_exception_priorities();
+ void sh4_exception_recompute();
+ void sh4_exception_request(int exception);
+ void sh4_exception_unrequest(int exception);
+ void sh4_exception_checkunrequest(int exception);
+ void sh4_exception(const char *message, int exception);
+ uint32_t compute_ticks_refresh_timer(emu_timer *timer, int hertz, int base, int divisor);
+ void sh4_refresh_timer_recompute();
+ void increment_rtc_time(int mode);
+ void sh4_dmac_nmi();
+ void sh4_handler_ipra_w(uint32_t data, uint32_t mem_mask);
+ virtual uint32_t get_remap(uint32_t address);
+ virtual uint32_t sh4_getsqremap(uint32_t address);
+ void sh4_parse_configuration();
+ void sh4_timer_recompute(int which);
+ uint32_t sh4_handle_tcnt0_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcnt1_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcnt2_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcor0_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcor1_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcor2_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcr0_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcr1_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcr2_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tstr_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tocr_addr_r(uint32_t mem_mask);
+ uint32_t sh4_handle_tcpr2_addr_r(uint32_t mem_mask);
+ void sh4_handle_tstr_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcr0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcr1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcr2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcor0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcor1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcor2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcnt0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcnt1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcnt2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tocr_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_tcpr2_addr_w(uint32_t data, uint32_t mem_mask);
+ int sh4_dma_transfer(int channel, int timermode, uint32_t chcr, uint32_t *sar, uint32_t *dar, uint32_t *dmatcr);
+ int sh4_dma_transfer_device(int channel, uint32_t chcr, uint32_t *sar, uint32_t *dar, uint32_t *dmatcr);
+ void sh4_dmac_check(int channel);
+ void sh4_handle_sar0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_sar1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_sar2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_sar3_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dar0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dar1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dar2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dar3_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dmatcr0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dmatcr1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dmatcr2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dmatcr3_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_chcr0_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_chcr1_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_chcr2_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_chcr3_addr_w(uint32_t data, uint32_t mem_mask);
+ void sh4_handle_dmaor_addr_w(uint32_t data, uint32_t mem_mask);
+ uint32_t sh4_handle_sar0_addr_r(uint32_t mem_mask) { return m_SH4_SAR0; }
+ uint32_t sh4_handle_sar1_addr_r(uint32_t mem_mask) { return m_SH4_SAR1; }
+ uint32_t sh4_handle_sar2_addr_r(uint32_t mem_mask) { return m_SH4_SAR2; }
+ uint32_t sh4_handle_sar3_addr_r(uint32_t mem_mask) { return m_SH4_SAR3; }
+ uint32_t sh4_handle_dar0_addr_r(uint32_t mem_mask) { return m_SH4_DAR0; }
+ uint32_t sh4_handle_dar1_addr_r(uint32_t mem_mask) { return m_SH4_DAR1; }
+ uint32_t sh4_handle_dar2_addr_r(uint32_t mem_mask) { return m_SH4_DAR2; }
+ uint32_t sh4_handle_dar3_addr_r(uint32_t mem_mask) { return m_SH4_DAR3; }
+ uint32_t sh4_handle_dmatcr0_addr_r(uint32_t mem_mask) { return m_SH4_DMATCR0; }
+ uint32_t sh4_handle_dmatcr1_addr_r(uint32_t mem_mask) { return m_SH4_DMATCR1; }
+ uint32_t sh4_handle_dmatcr2_addr_r(uint32_t mem_mask) { return m_SH4_DMATCR2; }
+ uint32_t sh4_handle_dmatcr3_addr_r(uint32_t mem_mask) { return m_SH4_DMATCR3; }
+ uint32_t sh4_handle_chcr0_addr_r(uint32_t mem_mask) { return m_SH4_CHCR0; }
+ uint32_t sh4_handle_chcr1_addr_r(uint32_t mem_mask) { return m_SH4_CHCR1; }
+ uint32_t sh4_handle_chcr2_addr_r(uint32_t mem_mask) { return m_SH4_CHCR2; }
+ uint32_t sh4_handle_chcr3_addr_r(uint32_t mem_mask) { return m_SH4_CHCR3; }
+ uint32_t sh4_handle_dmaor_addr_r(uint32_t mem_mask) { return m_SH4_DMAOR; }
+
+#if SH4_USE_FASTRAM_OPTIMIZATION
+ /* fast RAM */
+ bool m_bigendian;
+ uint32_t m_byte_xor;
+ uint32_t m_word_xor;
+ uint32_t m_dword_xor;
+ uint32_t m_fastram_select;
+ struct
+ {
+ offs_t start; /* start of the RAM block */
+ offs_t end; /* end of the RAM block */
+ bool readonly; /* true if read-only */
+ void * base; /* base in memory where the RAM lives */
+ } m_fastram[SH4_MAX_FASTRAM];
+#endif
+};
+
+
+class sh3_base_device : public sh34_base_device
+{
+public:
+ DECLARE_WRITE32_MEMBER( sh3_internal_w );
+ DECLARE_READ32_MEMBER( sh3_internal_r );
+
+ DECLARE_WRITE32_MEMBER( sh3_internal_high_w );
+ DECLARE_READ32_MEMBER( sh3_internal_high_r );
+
+protected:
+ // construction/destruction
+ sh3_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness);
+
+ virtual void device_reset() override;
+};
+
+
+class sh4_base_device : public sh34_base_device
+{
+public:
+ DECLARE_WRITE32_MEMBER( sh4_internal_w );
+ DECLARE_READ32_MEMBER( sh4_internal_r );
+
+ DECLARE_READ64_MEMBER( sh4_utlb_address_array_r );
+ DECLARE_WRITE64_MEMBER( sh4_utlb_address_array_w );
+ DECLARE_READ64_MEMBER( sh4_utlb_data_array1_r );
+ DECLARE_WRITE64_MEMBER( sh4_utlb_data_array1_w );
+ DECLARE_READ64_MEMBER( sh4_utlb_data_array2_r );
+ DECLARE_WRITE64_MEMBER( sh4_utlb_data_array2_w );
+
+ virtual void LDTLB(const uint16_t opcode) override;
+
+ virtual uint32_t get_remap(uint32_t address) override;
+ virtual uint32_t sh4_getsqremap(uint32_t address) override;
+ sh4_utlb m_utlb[64];
+
+protected:
+ // construction/destruction
+ sh4_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+};
+
+
+class sh3_device : public sh3_base_device
+{
+public:
+ sh3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+
+class sh3be_device : public sh3_base_device
+{
+public:
+ sh3be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void execute_run() override;
+ virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
+};
+
+
+class sh4_device : public sh4_base_device
+{
+public:
+ sh4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+
+class sh4be_device : public sh4_base_device
+{
+public:
+ sh4be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void execute_run() override;
+ virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
+};
+
+
+DECLARE_DEVICE_TYPE(SH3LE, sh3_device)
+DECLARE_DEVICE_TYPE(SH3BE, sh3be_device)
+DECLARE_DEVICE_TYPE(SH4LE, sh4_device)
+DECLARE_DEVICE_TYPE(SH4BE, sh4be_device)
+
+
+/***************************************************************************
+ COMPILER-SPECIFIC OPTIONS
+***************************************************************************/
+
+#define SH4DRC_STRICT_VERIFY 0x0001 /* verify all instructions */
+#define SH4DRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */
+#define SH4DRC_STRICT_PCREL 0x0004 /* do actual loads on MOVLI/MOVWI instead of collapsing to immediates */
+
+#define SH4DRC_COMPATIBLE_OPTIONS (SH4DRC_STRICT_VERIFY | SH4DRC_FLUSH_PC | SH4DRC_STRICT_PCREL)
+#define SH4DRC_FASTEST_OPTIONS (0)
+
+void sh4drc_set_options(device_t *device, uint32_t options);
+void sh4drc_add_pcflush(device_t *device, offs_t address);
+
+#endif // MAME_CPU_SH4_SH4_H
diff --git a/src/devices/cpu/sh/sh4comn.cpp b/src/devices/cpu/sh/sh4comn.cpp
new file mode 100644
index 00000000000..4f7ae411e7d
--- /dev/null
+++ b/src/devices/cpu/sh/sh4comn.cpp
@@ -0,0 +1,1465 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*****************************************************************************
+ *
+ * sh4comn.c
+ *
+ * SH-4 non-specific components
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "sh4.h"
+#include "sh4regs.h"
+#include "sh4comn.h"
+#include "sh3comn.h"
+#include "sh4tmu.h"
+#include "sh4dmac.h"
+
+static const int rtcnt_div[8] = { 0, 4, 16, 64, 256, 1024, 2048, 4096 };
+static const int daysmonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+
+
+static const uint32_t exception_priority_default[] = {
+ EXPPRI(1,1,0,0), /* Power-on Reset */
+ EXPPRI(1,2,0,1), /* Manual Reset */
+ EXPPRI(1,1,0,2), /* H-UDI Reset */
+ EXPPRI(1,3,0,3), /* Inst TLB Multiple Hit */
+ EXPPRI(1,4,0,4), /* Data TLB Multiple Hit */
+
+ EXPPRI(2,0,0,5), /* User break Before Instruction */
+ EXPPRI(2,1,0,6), /* Inst Address Error */
+ EXPPRI(2,2,0,7), /* Inst TLB Miss */
+ EXPPRI(2,3,0,8), /* Inst TLB Protection Violation */
+ EXPPRI(2,4,0,9), /* Illegal Instruction */
+ EXPPRI(2,4,0,10), /* Slot Illegal Instruction */
+ EXPPRI(2,4,0,11), /* FPU Disable */
+ EXPPRI(2,4,0,12), /* Slot FPU Disable */
+ EXPPRI(2,5,0,13), /* Data Address Error (Read) */
+ EXPPRI(2,5,0,14), /* Data Address Error (Write) */
+ EXPPRI(2,6,0,15), /* Data TBL Miss Read */
+ EXPPRI(2,6,0,16), /* Data TBL Miss Write */
+ EXPPRI(2,7,0,17), /* Data TBL Protection Violation Read */
+ EXPPRI(2,7,0,18), /* Data TBL Protection Violation Write */
+ EXPPRI(2,8,0,19), /* FPU Exception */
+ EXPPRI(2,9,0,20), /* Initial Page Write exception */
+
+ EXPPRI(2,4,0,21), /* Unconditional TRAP */
+ EXPPRI(2,10,0,22), /* User break After Instruction */
+
+ EXPPRI(3,0,16,SH4_INTC_NMI) /* NMI */
+ /* This is copied to a table, and the IRQ priorities filled in later */
+};
+
+static const int exception_codes[] =
+
+{ 0x000, /* Power-on Reset */
+ 0x020, /* Manual Reset */
+ 0x000, /* H-UDI Reset */
+ 0x140, /* Inst TLB Multiple Hit */
+ 0x140, /* Data TLB Multiple Hit */
+
+ 0x1E0, /* User break Before Instruction */
+ 0x0E0, /* Inst Address Error */
+ 0x040, /* Inst TLB Miss */
+ 0x0A0, /* Inst TLB Protection Violation */
+ 0x180, /* Illegal Instruction */
+ 0x1A0, /* Slot Illegal Instruction */
+ 0x800, /* FPU Disable */
+ 0x820, /* Slot FPU Disable */
+ 0x0E0, /* Data Address Error (Read) */
+ 0x100, /* Data Address Error (Write) */
+ 0x040, /* Data TBL Miss Read */
+ 0x060, /* Data TBL Miss Write */
+ 0x0A0, /* Data TBL Protection Violation Read */
+ 0x0C0, /* Data TBL Protection Violation Write */
+ 0x120, /* FPU Exception */
+ 0x080, /* Initial Page Write exception */
+
+ 0x160, /* Unconditional TRAP */
+ 0x1E0, /* User break After Instruction */
+
+ 0x1C0, /* NMI */ /* SH4_INTC_NMI=23 represents this location in this list.. */
+
+ 0x200, /* EX Irq 0 */
+ 0x220, /* 1 */
+ 0x240, /* 2 */
+ 0x260, /* 3 */
+ 0x280, /* 4 */
+ 0x2A0, /* 5 */
+ 0x2C0, /* 6 */
+ 0x2E0, /* 7 */
+ 0x300, /* 8 */
+ 0x320, /* 9 */
+ 0x340, /* A */
+ 0x360, /* B */
+ 0x380, /* C */
+ 0x3A0, /* D */
+ 0x3C0, /* E */
+
+ 0x240, /* SH4_INTC_IRL0 */
+ 0x2A0, /* SH4_INTC_IRL1 */
+ 0x300, /* SH4_INTC_IRL2 */
+ 0x360, /* SH4_INTC_IRL3 */
+
+ 0x600, /* HUDI */
+ 0x620, /* SH4_INTC_GPOI */
+ 0x640, /* SH4_INTC_DMTE0 */
+ 0x660, /* SH4_INTC_DMTE1 */
+ 0x680, /* SH4_INTC_DMTE2 */
+ 0x6A0, /* SH4_INTC_DMTE3 */
+
+ 0x780, /* SH4_INTC_DMTE4 */
+ 0x7A0, /* SH4_INTC_DMTE5 */
+ 0x7C0, /* SH4_INTC_DMTE6 */
+ 0x7E0, /* SH4_INTC_DMTE7 */
+
+ 0x6C0, /* SH4_INTC_DMAE */
+
+ 0xB00, /* SH4_INTC_TUNI3 */
+ 0xB80, /* SH4_INTC_TUNI4 */
+ 0x400, /* SH4_INTC_TUNI0 */
+ 0x420, /* SH4_INTC_TUNI1 */
+ 0x440, /* SH4_INTC_TUNI2 */
+ 0x460, /* SH4_INTC_TICPI2 */
+ 0x480, /* SH4_INTC_ATI */
+ 0x4A0, /* SH4_INTC_PRI */
+ 0x4C0, /* SH4_INTC_CUI */
+ 0x4E0, /* SH4_INTC_SCI1ERI */
+ 0x500, /* SH4_INTC_SCI1RXI */
+ 0x520, /* SH4_INTC_SCI1TXI */
+ 0x540, /* SH4_INTC_SCI1TEI */
+
+ 0x700, /* SH4_INTC_SCIFERI */
+ 0x720, /* SH4_INTC_SCIFRXI */
+ 0x740, /* SH4_INTC_SCIFBRI */
+ 0x760, /* SH4_INTC_SCIFTXI */
+ 0x560, /* SH4_INTC_ITI */
+ 0x580, /* SH4_INTC_RCMI */
+ 0x5A0 /* SH4_INTC_ROVI */
+};
+
+/* SH3 INTEVT2 uses a different table - values of -1 aren't filled in yet, some may not exist on the sh3. */
+/* The above table should differ too, some things depend on the interrupt level rather than beign fixed values */
+
+static const int sh3_intevt2_exception_codes[] =
+
+{ 0x000, /* Power-on Reset */
+ -1, /* Manual Reset */
+ -1, /* H-UDI Reset */
+ -1, /* Inst TLB Multiple Hit */
+ -1, /* Data TLB Multiple Hit */
+
+ -1, /* User break Before Instruction */
+ -1, /* Inst Address Error */
+ -1, /* Inst TLB Miss */
+ -1, /* Inst TLB Protection Violation */
+ -1, /* Illegal Instruction */
+ -1, /* Slot Illegal Instruction */
+ -1, /* FPU Disable */
+ -1, /* Slot FPU Disable */
+ -1, /* Data Address Error (Read) */
+ -1, /* Data Address Error (Write) */
+ -1, /* Data TBL Miss Read */
+ -1, /* Data TBL Miss Write */
+ -1, /* Data TBL Protection Violation Read */
+ -1, /* Data TBL Protection Violation Write */
+ -1, /* FPU Exception */
+ -1, /* Initial Page Write exception */
+
+ -1, /* Unconditional TRAP */
+ -1, /* User break After Instruction */
+
+ -1, /* NMI */ /* SH4_INTC_NMI=23 represents this location in this list.. */
+
+ -1, /* EX Irq 0 */
+ -1, /* 1 */
+ -1, /* 2 */
+ -1, /* 3 */
+ -1, /* 4 */
+ -1, /* 5 */
+ -1, /* 6 */
+ -1, /* 7 */
+ -1, /* 8 */
+ -1, /* 9 */
+ -1, /* A */
+ -1, /* B */
+ -1, /* C */
+ -1, /* D */
+ -1, /* E */
+
+ 0x600, /* SH4_INTC_IRL0 */
+ 0x620, /* SH4_INTC_IRL1 */
+ 0x640, /* SH4_INTC_IRL2 */
+ 0x660, /* SH4_INTC_IRL3 */
+ /* todo: SH3 should have lines 4+5 too? */
+
+ -1, /* HUDI */
+ -1, /* SH4_INTC_GPOI */
+ -1, /* SH4_INTC_DMTE0 */
+ -1, /* SH4_INTC_DMTE1 */
+ -1, /* SH4_INTC_DMTE2 */
+ -1, /* SH4_INTC_DMTE3 */
+
+ -1, /* SH4_INTC_DMTE4 */
+ -1, /* SH4_INTC_DMTE5 */
+ -1, /* SH4_INTC_DMTE6 */
+ -1, /* SH4_INTC_DMTE7 */
+
+ -1, /* SH4_INTC_DMAE */
+
+ -1, /* SH4_INTC_TUNI3 */
+ -1, /* SH4_INTC_TUNI4 */
+ 0x400, /* SH4_INTC_TUNI0 */
+ 0x420, /* SH4_INTC_TUNI1 */
+ 0x440, /* SH4_INTC_TUNI2 */
+ 0x460, /* SH4_INTC_TICPI2 */
+ -1, /* SH4_INTC_ATI */
+ -1, /* SH4_INTC_PRI */
+ -1, /* SH4_INTC_CUI */
+ -1, /* SH4_INTC_SCI1ERI */
+ -1, /* SH4_INTC_SCI1RXI */
+ -1, /* SH4_INTC_SCI1TXI */
+ -1, /* SH4_INTC_SCI1TEI */
+
+ -1, /* SH4_INTC_SCIFERI */
+ -1, /* SH4_INTC_SCIFRXI */
+ -1, /* SH4_INTC_SCIFBRI */
+ -1, /* SH4_INTC_SCIFTXI */
+ -1, /* SH4_INTC_ITI */
+ -1, /* SH4_INTC_RCMI */
+ -1 /* SH4_INTC_ROVI */
+};
+
+
+
+void sh34_base_device::sh4_change_register_bank(int to)
+{
+ int s;
+
+ if (to) // 0 -> 1
+ {
+ for (s = 0;s < 8;s++)
+ {
+ m_rbnk[0][s] = m_r[s];
+ m_r[s] = m_rbnk[1][s];
+ }
+ }
+ else // 1 -> 0
+ {
+ for (s = 0;s < 8;s++)
+ {
+ m_rbnk[1][s] = m_r[s];
+ m_r[s] = m_rbnk[0][s];
+ }
+ }
+}
+
+void sh34_base_device::sh4_swap_fp_registers()
+{
+ int s;
+ uint32_t z;
+
+ for (s = 0;s <= 15;s++)
+ {
+ z = m_fr[s];
+ m_fr[s] = m_xf[s];
+ m_xf[s] = z;
+ }
+}
+
+void sh34_base_device::sh4_swap_fp_couples()
+{
+ int s;
+ uint32_t z;
+
+ for (s = 0;s <= 15;s = s+2)
+ {
+ z = m_fr[s];
+ m_fr[s] = m_fr[s + 1];
+ m_fr[s + 1] = z;
+ z = m_xf[s];
+ m_xf[s] = m_xf[s + 1];
+ m_xf[s + 1] = z;
+ }
+}
+
+void sh34_base_device::sh4_syncronize_register_bank(int to)
+{
+ int s;
+
+ for (s = 0;s < 8;s++)
+ {
+ m_rbnk[to][s] = m_r[s];
+ }
+}
+
+void sh34_base_device::sh4_default_exception_priorities() // setup default priorities for exceptions
+{
+ int a;
+
+ for (a=0;a <= SH4_INTC_NMI;a++)
+ m_exception_priority[a] = exception_priority_default[a];
+ for (a=SH4_INTC_IRLn0;a <= SH4_INTC_IRLnE;a++)
+ m_exception_priority[a] = INTPRI(15-(a-SH4_INTC_IRLn0), a);
+ m_exception_priority[SH4_INTC_IRL0] = INTPRI(13, SH4_INTC_IRL0);
+ m_exception_priority[SH4_INTC_IRL1] = INTPRI(10, SH4_INTC_IRL1);
+ m_exception_priority[SH4_INTC_IRL2] = INTPRI(7, SH4_INTC_IRL2);
+ m_exception_priority[SH4_INTC_IRL3] = INTPRI(4, SH4_INTC_IRL3);
+ for (a=SH4_INTC_HUDI;a <= SH4_INTC_ROVI;a++)
+ m_exception_priority[a] = INTPRI(0, a);
+}
+
+void sh34_base_device::sh4_exception_recompute() // checks if there is any interrupt with high enough priority
+{
+ int a,z;
+
+ m_test_irq = 0;
+ if ((!m_pending_irq) || ((m_sr & BL) && (m_exception_requesting[SH4_INTC_NMI] == 0)))
+ return;
+ z = (m_sr >> 4) & 15;
+ for (a=0;a <= SH4_INTC_ROVI;a++)
+ {
+ if (m_exception_requesting[a])
+ {
+ int pri = (((int)m_exception_priority[a] >> 8) & 255);
+ //logerror("pri is %02x z is %02x\n",pri,z);
+ if (pri > z)
+ {
+ //logerror("will test\n");
+ m_test_irq = 1; // will check for exception at end of instructions
+ break;
+ }
+ }
+ }
+}
+
+void sh34_base_device::sh4_exception_request(int exception) // start requesting an exception
+{
+ //logerror("sh4_exception_request a\n");
+ if (!m_exception_requesting[exception])
+ {
+ //logerror("sh4_exception_request b\n");
+ m_exception_requesting[exception] = 1;
+ m_pending_irq++;
+ sh4_exception_recompute();
+ }
+}
+
+void sh34_base_device::sh4_exception_unrequest(int exception) // stop requesting an exception
+{
+ if (m_exception_requesting[exception])
+ {
+ m_exception_requesting[exception] = 0;
+ m_pending_irq--;
+ sh4_exception_recompute();
+ }
+}
+
+void sh34_base_device::sh4_exception_checkunrequest(int exception)
+{
+ if (exception == SH4_INTC_NMI)
+ sh4_exception_unrequest(exception);
+ if ((exception == SH4_INTC_DMTE0) || (exception == SH4_INTC_DMTE1) ||
+ (exception == SH4_INTC_DMTE2) || (exception == SH4_INTC_DMTE3))
+ sh4_exception_unrequest(exception);
+}
+
+void sh34_base_device::sh4_exception(const char *message, int exception) // handle exception
+{
+ uint32_t vector;
+
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ if (exception < SH4_INTC_NMI)
+ return; // Not yet supported
+ if (exception == SH4_INTC_NMI) {
+ if ((m_sr & BL) && (!(m_m[ICR] & 0x200)))
+ return;
+
+ m_m[ICR] &= ~0x200;
+ m_m[INTEVT] = 0x1c0;
+
+
+ vector = 0x600;
+ standard_irq_callback(INPUT_LINE_NMI);
+ LOG(("SH-4 '%s' nmi exception after [%s]\n", tag(), message));
+ } else {
+ // if ((m_m[ICR] & 0x4000) && (m_nmi_line_state == ASSERT_LINE))
+ // return;
+ if (m_sr & BL)
+ return;
+ if (((m_exception_priority[exception] >> 8) & 255) <= ((m_sr >> 4) & 15))
+ return;
+ m_m[INTEVT] = exception_codes[exception];
+ vector = 0x600;
+ if ((exception >= SH4_INTC_IRL0) && (exception <= SH4_INTC_IRL3))
+ standard_irq_callback((exception-SH4_INTC_IRL0)+SH4_IRL0);
+ else
+ standard_irq_callback(SH4_IRL3+1);
+ LOG(("SH-4 '%s' interrupt exception #%d after [%s]\n", tag(), exception, message));
+ }
+ }
+ else /* SH3 exceptions */
+ {
+ /***** ASSUME THIS TO BE WRONG FOR NOW *****/
+
+ if (exception < SH4_INTC_NMI)
+ return; // Not yet supported
+ if (exception == SH4_INTC_NMI)
+ {
+ return;
+ }
+ else
+ {
+ if (m_sr & BL)
+ return;
+ if (((m_exception_priority[exception] >> 8) & 255) <= ((m_sr >> 4) & 15))
+ return;
+
+
+ vector = 0x600;
+
+ if ((exception >= SH4_INTC_IRL0) && (exception <= SH4_INTC_IRL3))
+ standard_irq_callback((exception-SH4_INTC_IRL0)+SH4_IRL0);
+ else
+ standard_irq_callback(SH4_IRL3+1);
+
+ if (sh3_intevt2_exception_codes[exception]==-1)
+ fatalerror("sh3_intevt2_exception_codes unpopulated for exception %02x\n", exception);
+
+ m_sh3internal_lower[INTEVT2] = sh3_intevt2_exception_codes[exception];
+ m_sh3internal_upper[SH3_EXPEVT_ADDR] = exception_codes[exception];
+
+
+ LOG(("SH-3 '%s' interrupt exception #%d after [%s]\n", tag(), exception, message));
+ }
+
+ /***** END ASSUME THIS TO BE WRONG FOR NOW *****/
+ }
+ sh4_exception_checkunrequest(exception);
+
+ m_spc = m_pc;
+ m_ssr = m_sr;
+ m_sgr = m_r[15];
+
+ m_sr |= MD;
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ sh4_syncronize_register_bank((m_sr & sRB) >> 29);
+ if (!(m_sr & sRB))
+ sh4_change_register_bank(1);
+ m_sr |= sRB;
+ m_sr |= BL;
+ sh4_exception_recompute();
+
+ /* fetch PC */
+ m_pc = m_vbr + vector;
+ /* wake up if a sleep opcode is triggered */
+ if(m_sleep_mode == 1) { m_sleep_mode = 2; }
+}
+
+
+uint32_t sh34_base_device::compute_ticks_refresh_timer(emu_timer *timer, int hertz, int base, int divisor)
+{
+ // elapsed:total = x : ticks
+ // x=elapsed*tics/total -> x=elapsed*(double)100000000/rtcnt_div[(m_m[RTCSR] >> 3) & 7]
+ // ticks/total=ticks / ((rtcnt_div[(m_m[RTCSR] >> 3) & 7] * ticks) / 100000000)=1/((rtcnt_div[(m_m[RTCSR] >> 3) & 7] / 100000000)=100000000/rtcnt_div[(m_m[RTCSR] >> 3) & 7]
+ return base + (uint32_t)((timer->elapsed().as_double() * (double)hertz) / (double)divisor);
+}
+
+void sh34_base_device::sh4_refresh_timer_recompute()
+{
+ uint32_t ticks;
+
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("sh4_refresh_timer_recompute uses m_m[] with SH3\n");
+
+
+ //if rtcnt < rtcor then rtcor-rtcnt
+ //if rtcnt >= rtcor then 256-rtcnt+rtcor=256+rtcor-rtcnt
+ ticks = m_m[RTCOR]-m_m[RTCNT];
+ if (ticks <= 0)
+ ticks = 256 + ticks;
+ m_refresh_timer->adjust(attotime::from_hz(m_bus_clock) * rtcnt_div[(m_m[RTCSR] >> 3) & 7] * ticks);
+ m_refresh_timer_base = m_m[RTCNT];
+}
+
+
+TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_refresh_timer_callback )
+{
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("sh4_refresh_timer_callback uses m_m[] with SH3\n");
+
+ m_m[RTCNT] = 0;
+ sh4_refresh_timer_recompute();
+ m_m[RTCSR] |= 128;
+ if ((m_m[MCR] & 4) && !(m_m[MCR] & 2))
+ {
+ m_m[RFCR] = (m_m[RFCR] + 1) & 1023;
+ if (((m_m[RTCSR] & 1) && (m_m[RFCR] == 512)) || (m_m[RFCR] == 0))
+ {
+ m_m[RFCR] = 0;
+ m_m[RTCSR] |= 4;
+ }
+ }
+}
+
+void sh34_base_device::increment_rtc_time(int mode)
+{
+ int carry, year, leap, days;
+
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("increment_rtc_time uses m_m[] with SH3\n");
+
+ if (mode == 0)
+ {
+ carry = 0;
+ m_m[RSECCNT] = m_m[RSECCNT] + 1;
+ if ((m_m[RSECCNT] & 0xf) == 0xa)
+ m_m[RSECCNT] = m_m[RSECCNT] + 6;
+ if (m_m[RSECCNT] == 0x60)
+ {
+ m_m[RSECCNT] = 0;
+ carry=1;
+ }
+ else
+ return;
+ }
+ else
+ carry = 1;
+
+ m_m[RMINCNT] = m_m[RMINCNT] + carry;
+ if ((m_m[RMINCNT] & 0xf) == 0xa)
+ m_m[RMINCNT] = m_m[RMINCNT] + 6;
+ carry=0;
+ if (m_m[RMINCNT] == 0x60)
+ {
+ m_m[RMINCNT] = 0;
+ carry = 1;
+ }
+
+ m_m[RHRCNT] = m_m[RHRCNT] + carry;
+ if ((m_m[RHRCNT] & 0xf) == 0xa)
+ m_m[RHRCNT] = m_m[RHRCNT] + 6;
+ carry = 0;
+ if (m_m[RHRCNT] == 0x24)
+ {
+ m_m[RHRCNT] = 0;
+ carry = 1;
+ }
+
+ m_m[RWKCNT] = m_m[RWKCNT] + carry;
+ if (m_m[RWKCNT] == 0x7)
+ {
+ m_m[RWKCNT] = 0;
+ }
+
+ days = 0;
+ year = (m_m[RYRCNT] & 0xf) + ((m_m[RYRCNT] & 0xf0) >> 4)*10 + ((m_m[RYRCNT] & 0xf00) >> 8)*100 + ((m_m[RYRCNT] & 0xf000) >> 12)*1000;
+ leap = 0;
+ if (!(year%100))
+ {
+ if (!(year%400))
+ leap = 1;
+ }
+ else if (!(year%4))
+ leap = 1;
+ if (m_m[RMONCNT] != 2)
+ leap = 0;
+ if (m_m[RMONCNT])
+ days = daysmonth[(m_m[RMONCNT] & 0xf) + ((m_m[RMONCNT] & 0xf0) >> 4)*10 - 1];
+
+ m_m[RDAYCNT] = m_m[RDAYCNT] + carry;
+ if ((m_m[RDAYCNT] & 0xf) == 0xa)
+ m_m[RDAYCNT] = m_m[RDAYCNT] + 6;
+ carry = 0;
+ if (m_m[RDAYCNT] > (days+leap))
+ {
+ m_m[RDAYCNT] = 1;
+ carry = 1;
+ }
+
+ m_m[RMONCNT] = m_m[RMONCNT] + carry;
+ if ((m_m[RMONCNT] & 0xf) == 0xa)
+ m_m[RMONCNT] = m_m[RMONCNT] + 6;
+ carry=0;
+ if (m_m[RMONCNT] == 0x13)
+ {
+ m_m[RMONCNT] = 1;
+ carry = 1;
+ }
+
+ m_m[RYRCNT] = m_m[RYRCNT] + carry;
+ if ((m_m[RYRCNT] & 0xf) >= 0xa)
+ m_m[RYRCNT] = m_m[RYRCNT] + 6;
+ if ((m_m[RYRCNT] & 0xf0) >= 0xa0)
+ m_m[RYRCNT] = m_m[RYRCNT] + 0x60;
+ if ((m_m[RYRCNT] & 0xf00) >= 0xa00)
+ m_m[RYRCNT] = m_m[RYRCNT] + 0x600;
+ if ((m_m[RYRCNT] & 0xf000) >= 0xa000)
+ m_m[RYRCNT] = 0;
+}
+
+TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_rtc_timer_callback )
+{
+ if (m_cpu_type != CPU_TYPE_SH4)
+ {
+ logerror("sh4_rtc_timer_callback uses m_m[] with SH3\n");
+ return;
+ }
+
+ m_rtc_timer->adjust(attotime::from_hz(128));
+ m_m[R64CNT] = (m_m[R64CNT]+1) & 0x7f;
+ if (m_m[R64CNT] == 64)
+ {
+ m_m[RCR1] |= 0x80;
+ increment_rtc_time(0);
+ //sh4_exception_request(SH4_INTC_NMI); // TEST
+ }
+}
+
+
+void sh34_base_device::sh4_dmac_nmi() // manage dma when nmi gets asserted
+{
+ int s;
+
+ m_SH4_DMAOR |= DMAOR_NMIF;
+ for (s = 0;s < 4;s++)
+ {
+ if (m_dma_timer_active[s])
+ {
+ logerror("SH4: DMA %d cancelled due to NMI but all data transferred", s);
+ m_dma_timer[s]->adjust(attotime::never, s);
+ m_dma_timer_active[s] = 0;
+ }
+ }
+}
+
+void sh34_base_device::sh4_handler_ipra_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_IPRA);
+ /* 15 - 12 TMU0 */
+ /* 11 - 8 TMU1 */
+ /* 7 - 4 TMU2 */
+ /* 3 - 0 RTC */
+ m_exception_priority[SH4_INTC_ATI] = INTPRI(m_SH4_IPRA & 0x000f, SH4_INTC_ATI);
+ m_exception_priority[SH4_INTC_PRI] = INTPRI(m_SH4_IPRA & 0x000f, SH4_INTC_PRI);
+ m_exception_priority[SH4_INTC_CUI] = INTPRI(m_SH4_IPRA & 0x000f, SH4_INTC_CUI);
+
+ m_exception_priority[SH4_INTC_TUNI2] = INTPRI((m_SH4_IPRA & 0x00f0) >> 4, SH4_INTC_TUNI2);
+ m_exception_priority[SH4_INTC_TICPI2] = INTPRI((m_SH4_IPRA & 0x00f0) >> 4, SH4_INTC_TICPI2);
+
+ m_exception_priority[SH4_INTC_TUNI1] = INTPRI((m_SH4_IPRA & 0x0f00) >> 8, SH4_INTC_TUNI1);
+
+ m_exception_priority[SH4_INTC_TUNI0] = INTPRI((m_SH4_IPRA & 0xf000) >> 12, SH4_INTC_TUNI0);
+
+ logerror("setting priorities TMU0 %01x TMU1 %01x TMU2 %01x RTC %01x\n", (m_SH4_IPRA & 0xf000)>>12, (m_SH4_IPRA & 0x0f00)>>8, (m_SH4_IPRA & 0x00f0)>>4, (m_SH4_IPRA & 0x000f)>>0);
+
+ sh4_exception_recompute();
+}
+
+
+WRITE32_MEMBER( sh4_base_device::sh4_internal_w )
+{
+ int a;
+ uint32_t addr = (offset << 2) + 0xfe000000;
+ offset = ((addr & 0xfc) >> 2) | ((addr & 0x1fe0000) >> 11);
+
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("sh4_internal_w uses m_m[] with SH3\n");
+
+ uint32_t old = m_m[offset];
+ COMBINE_DATA(m_m+offset);
+
+// printf("sh4_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), offset, data, mem_mask);
+
+ switch( offset )
+ {
+ case PTEH: // for use with LDTLB opcode
+ m_m[PTEH] &= 0xffffffff;
+ /*
+ NNNN NNNN NNNN NNNN NNNN NN-- AAAA AAAA
+
+ N = VPM = Virtual Page Number
+ A = ASID = Address Space Identifier
+
+ same as the address table part of the utlb but with 2 unused bits (these are sourced from PTEL instead when LDTLB is called)
+ */
+
+
+ break;
+
+ case PTEL:
+ m_m[PTEL] &= 0xffffffff;
+ /*
+ ---P PPPP PPPP PPPP PPPP PP-V zRRz CDHW
+
+ same format as data array 1 of the utlb
+ */
+ break;
+
+ case PTEA:
+ m_m[PTEA] &= 0xffffffff;
+ /*
+ ---- ---- ---- ---- ---- ---- ---- TSSS
+
+ same format as data array 2 of the utlb
+ */
+ break;
+
+ case TTB:
+ m_m[TTB] &= 0xffffffff;
+ logerror("TTB set to %08x\n", data);
+ break;
+
+ case TEA:
+ m_m[TEA] &= 0xffffffff;
+ logerror("TEA set to %08x\n", data);
+ break;
+
+
+ case MMUCR: // MMU Control
+ logerror("%s: MMUCR %08x\n", machine().describe_context(), data);
+ m_m[MMUCR] &= 0xffffffff;
+ /*
+ LLLL LL-- BBBB BB-- CCCC CCQV ---- -T-A
+
+ L = LRUI = Least recently used ITLB
+ B = URB = UTLB replace boundary
+ C = URC = UTLB replace counter
+ Q = SQMD = Store Queue Mode Bit
+ V = SV = Single Virtual Mode Bit
+ T = TI = TLB invaldiate
+ A = AT = Address translation bit (enable)
+ */
+
+
+
+ if (data & MMUCR_AT)
+ {
+ m_sh4_mmu_enabled = 1;
+
+
+ if (m_mmuhack == 1)
+ {
+ printf("SH4 MMU Enabled\n");
+ printf("If you're seeing this, but running something other than a Naomi GD-ROM game then chances are it won't work\n");
+ printf("The MMU emulation is a hack specific to that system\n");
+ }
+
+
+ if (m_mmuhack == 2)
+ {
+ for (int i = 0;i < 64;i++)
+ {
+ if (m_utlb[i].V)
+ {
+ printf("(entry %02x | ASID: %02x VPN: %08x V: %02x PPN: %08x SZ: %02x SH: %02x C: %02x PPR: %02x D: %02x WT %02x: SA: %02x TC: %02x)\n",
+ i,
+ m_utlb[i].ASID,
+ m_utlb[i].VPN << 10,
+ m_utlb[i].V,
+ m_utlb[i].PPN << 10,
+ m_utlb[i].PSZ,
+ m_utlb[i].SH,
+ m_utlb[i].C,
+ m_utlb[i].PPR,
+ m_utlb[i].D,
+ m_utlb[i].WT,
+ m_utlb[i].SA,
+ m_utlb[i].TC);
+ }
+ }
+ }
+
+
+ }
+ else
+ {
+ m_sh4_mmu_enabled = 0;
+ }
+
+ break;
+
+ // Memory refresh
+ case RTCSR:
+ m_m[RTCSR] &= 255;
+ if ((old >> 3) & 7)
+ m_m[RTCNT] = compute_ticks_refresh_timer(m_refresh_timer, m_bus_clock, m_refresh_timer_base, rtcnt_div[(old >> 3) & 7]) & 0xff;
+ if ((m_m[RTCSR] >> 3) & 7)
+ { // activated
+ sh4_refresh_timer_recompute();
+ }
+ else
+ {
+ m_refresh_timer->adjust(attotime::never);
+ }
+ break;
+
+ case RTCNT:
+ m_m[RTCNT] &= 255;
+ if ((m_m[RTCSR] >> 3) & 7)
+ { // active
+ sh4_refresh_timer_recompute();
+ }
+ break;
+
+ case RTCOR:
+ m_m[RTCOR] &= 255;
+ if ((m_m[RTCSR] >> 3) & 7)
+ { // active
+ m_m[RTCNT] = compute_ticks_refresh_timer(m_refresh_timer, m_bus_clock, m_refresh_timer_base, rtcnt_div[(m_m[RTCSR] >> 3) & 7]) & 0xff;
+ sh4_refresh_timer_recompute();
+ }
+ break;
+
+ case RFCR:
+ m_m[RFCR] &= 1023;
+ break;
+
+ // RTC
+ case RCR1:
+ if ((m_m[RCR1] & 8) && (~old & 8)) // 0 -> 1
+ m_m[RCR1] ^= 1;
+ break;
+
+ case RCR2:
+ if (m_m[RCR2] & 2)
+ {
+ m_m[R64CNT] = 0;
+ m_m[RCR2] ^= 2;
+ }
+ if (m_m[RCR2] & 4)
+ {
+ m_m[R64CNT] = 0;
+ if (m_m[RSECCNT] >= 30)
+ increment_rtc_time(1);
+ m_m[RSECCNT] = 0;
+ }
+ if ((m_m[RCR2] & 8) && (~old & 8))
+ { // 0 -> 1
+ m_rtc_timer->adjust(attotime::from_hz(128));
+ }
+ else if (~(m_m[RCR2]) & 8)
+ { // 0
+ m_rtc_timer->adjust(attotime::never);
+ }
+ break;
+
+/*********************************************************************************************************************
+ TMU (Timer Unit)
+*********************************************************************************************************************/
+ case SH4_TSTR_ADDR: sh4_handle_tstr_addr_w(data,mem_mask); break;
+ case SH4_TCR0_ADDR: sh4_handle_tcr0_addr_w(data,mem_mask); break;
+ case SH4_TCR1_ADDR: sh4_handle_tcr1_addr_w(data,mem_mask); break;
+ case SH4_TCR2_ADDR: sh4_handle_tcr2_addr_w(data,mem_mask); break;
+ case SH4_TCOR0_ADDR: sh4_handle_tcor0_addr_w(data,mem_mask); break;
+ case SH4_TCNT0_ADDR: sh4_handle_tcnt0_addr_w(data,mem_mask); break;
+ case SH4_TCOR1_ADDR: sh4_handle_tcor1_addr_w(data,mem_mask); break;
+ case SH4_TCNT1_ADDR: sh4_handle_tcnt1_addr_w(data,mem_mask); break;
+ case SH4_TCOR2_ADDR: sh4_handle_tcor2_addr_w(data,mem_mask); break;
+ case SH4_TCNT2_ADDR: sh4_handle_tcnt2_addr_w(data,mem_mask); break;
+ case SH4_TOCR_ADDR: sh4_handle_tocr_addr_w(data,mem_mask); break; // not supported
+ case SH4_TCPR2_ADDR: sh4_handle_tcpr2_addr_w(data,mem_mask); break; // not supported
+/*********************************************************************************************************************
+ INTC (Interrupt Controller)
+*********************************************************************************************************************/
+ case ICR:
+ m_m[ICR] = (m_m[ICR] & 0x7fff) | (old & 0x8000);
+ break;
+ case IPRA: sh4_handler_ipra_w(data, mem_mask); break;
+ case IPRB:
+ m_exception_priority[SH4_INTC_SCI1ERI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1ERI);
+ m_exception_priority[SH4_INTC_SCI1RXI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1RXI);
+ m_exception_priority[SH4_INTC_SCI1TXI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1TXI);
+ m_exception_priority[SH4_INTC_SCI1TEI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1TEI);
+ m_exception_priority[SH4_INTC_RCMI] = INTPRI((m_m[IPRB] & 0x0f00) >> 8, SH4_INTC_RCMI);
+ m_exception_priority[SH4_INTC_ROVI] = INTPRI((m_m[IPRB] & 0x0f00) >> 8, SH4_INTC_ROVI);
+ m_exception_priority[SH4_INTC_ITI] = INTPRI((m_m[IPRB] & 0xf000) >> 12, SH4_INTC_ITI);
+ sh4_exception_recompute();
+ break;
+ case IPRC:
+ m_exception_priority[SH4_INTC_HUDI] = INTPRI(m_m[IPRC] & 0x000f, SH4_INTC_HUDI);
+ m_exception_priority[SH4_INTC_SCIFERI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFERI);
+ m_exception_priority[SH4_INTC_SCIFRXI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFRXI);
+ m_exception_priority[SH4_INTC_SCIFBRI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFBRI);
+ m_exception_priority[SH4_INTC_SCIFTXI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFTXI);
+ m_exception_priority[SH4_INTC_DMTE0] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE0);
+ m_exception_priority[SH4_INTC_DMTE1] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE1);
+ m_exception_priority[SH4_INTC_DMTE2] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE2);
+ m_exception_priority[SH4_INTC_DMTE3] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE3);
+ m_exception_priority[SH4_INTC_DMAE] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMAE);
+ m_exception_priority[SH4_INTC_GPOI] = INTPRI((m_m[IPRC] & 0xf000) >> 12, SH4_INTC_GPOI);
+ sh4_exception_recompute();
+ break;
+/*********************************************************************************************************************
+ DMAC (DMA Controller)
+*********************************************************************************************************************/
+ case SH4_SAR0_ADDR: sh4_handle_sar0_addr_w(data,mem_mask); break;
+ case SH4_SAR1_ADDR: sh4_handle_sar1_addr_w(data,mem_mask); break;
+ case SH4_SAR2_ADDR: sh4_handle_sar2_addr_w(data,mem_mask); break;
+ case SH4_SAR3_ADDR: sh4_handle_sar3_addr_w(data,mem_mask); break;
+ case SH4_DAR0_ADDR: sh4_handle_dar0_addr_w(data,mem_mask); break;
+ case SH4_DAR1_ADDR: sh4_handle_dar1_addr_w(data,mem_mask); break;
+ case SH4_DAR2_ADDR: sh4_handle_dar2_addr_w(data,mem_mask); break;
+ case SH4_DAR3_ADDR: sh4_handle_dar3_addr_w(data,mem_mask); break;
+ case SH4_DMATCR0_ADDR: sh4_handle_dmatcr0_addr_w(data,mem_mask); break;
+ case SH4_DMATCR1_ADDR: sh4_handle_dmatcr1_addr_w(data,mem_mask); break;
+ case SH4_DMATCR2_ADDR: sh4_handle_dmatcr2_addr_w(data,mem_mask); break;
+ case SH4_DMATCR3_ADDR: sh4_handle_dmatcr3_addr_w(data,mem_mask); break;
+ case SH4_CHCR0_ADDR: sh4_handle_chcr0_addr_w(data,mem_mask); break;
+ case SH4_CHCR1_ADDR: sh4_handle_chcr1_addr_w(data,mem_mask); break;
+ case SH4_CHCR2_ADDR: sh4_handle_chcr2_addr_w(data,mem_mask); break;
+ case SH4_CHCR3_ADDR: sh4_handle_chcr3_addr_w(data,mem_mask); break;
+ case SH4_DMAOR_ADDR: sh4_handle_dmaor_addr_w(data,mem_mask); break;
+/*********************************************************************************************************************
+ Store Queues
+*********************************************************************************************************************/
+ case QACR0:
+ case QACR1:
+ break;
+/*********************************************************************************************************************
+ I/O
+*********************************************************************************************************************/
+ case PCTRA:
+ m_ioport16_pullup = 0;
+ m_ioport16_direction = 0;
+ for (a=0;a < 16;a++) {
+ m_ioport16_direction |= (m_m[PCTRA] & (1 << (a*2))) >> a;
+ m_ioport16_pullup |= (m_m[PCTRA] & (1 << (a*2+1))) >> (a+1);
+ }
+ m_ioport16_direction &= 0xffff;
+ m_ioport16_pullup = (m_ioport16_pullup | m_ioport16_direction) ^ 0xffff;
+ if (m_m[BCR2] & 1)
+ m_io->write_dword(SH4_IOPORT_16, (uint64_t)(m_m[PDTRA] & m_ioport16_direction) | ((uint64_t)m_m[PCTRA] << 16));
+ break;
+ case PDTRA:
+ if (m_m[BCR2] & 1)
+ m_io->write_dword(SH4_IOPORT_16, (uint64_t)(m_m[PDTRA] & m_ioport16_direction) | ((uint64_t)m_m[PCTRA] << 16));
+ break;
+ case PCTRB:
+ m_ioport4_pullup = 0;
+ m_ioport4_direction = 0;
+ for (a=0;a < 4;a++) {
+ m_ioport4_direction |= (m_m[PCTRB] & (1 << (a*2))) >> a;
+ m_ioport4_pullup |= (m_m[PCTRB] & (1 << (a*2+1))) >> (a+1);
+ }
+ m_ioport4_direction &= 0xf;
+ m_ioport4_pullup = (m_ioport4_pullup | m_ioport4_direction) ^ 0xf;
+ if (m_m[BCR2] & 1)
+ m_io->write_dword(SH4_IOPORT_4, (m_m[PDTRB] & m_ioport4_direction) | (m_m[PCTRB] << 16));
+ break;
+ case PDTRB:
+ if (m_m[BCR2] & 1)
+ m_io->write_dword(SH4_IOPORT_4, (m_m[PDTRB] & m_ioport4_direction) | (m_m[PCTRB] << 16));
+ break;
+
+ case SCBRR2:
+ break;
+
+ case SCSPTR2: //trips often in aristocrat mk-6
+ break;
+
+ default:
+ logerror("sh4_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), data, mem_mask);
+ break;
+ }
+}
+
+READ32_MEMBER( sh4_base_device::sh4_internal_r )
+{
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("sh4_internal_r uses m_m[] with SH3\n");
+
+ uint32_t addr = (offset << 2) + 0xfe000000;
+ offset = ((addr & 0xfc) >> 2) | ((addr & 0x1fe0000) >> 11);
+
+// printf("sh4_internal_r: Read %08x (%x) @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), offset, mem_mask);
+
+ switch( offset )
+ {
+ case VERSION:
+ return PVR_SH7091; // 0x040205c1, this is what a real SH7091 in a Dreamcast returns - the later Naomi BIOSes check and care!
+ case PRR:
+ return 0;
+ case IPRD:
+ return 0x00000000; // SH7750 ignores writes here and always returns zero
+ case RTCNT:
+ if ((m_m[RTCSR] >> 3) & 7)
+ { // activated
+ //((double)rtcnt_div[(m_m[RTCSR] >> 3) & 7] / (double)100000000)
+ //return (refresh_timer_base + (m_refresh_timer->elapsed() * (double)100000000) / (double)rtcnt_div[(m_m[RTCSR] >> 3) & 7]) & 0xff;
+ return compute_ticks_refresh_timer(m_refresh_timer, m_bus_clock, m_refresh_timer_base, rtcnt_div[(m_m[RTCSR] >> 3) & 7]) & 0xff;
+ }
+ else
+ return m_m[RTCNT];
+
+/*********************************************************************************************************************
+ INTC (Interrupt Controller)
+*********************************************************************************************************************/
+
+ case IPRA:
+ return m_SH4_IPRA;
+
+/*********************************************************************************************************************
+ TMU (Timer Unit)
+*********************************************************************************************************************/
+ case SH4_TSTR_ADDR: return sh4_handle_tstr_addr_r(mem_mask);
+ case SH4_TCR0_ADDR: return sh4_handle_tcr0_addr_r(mem_mask);
+ case SH4_TCR1_ADDR: return sh4_handle_tcr1_addr_r(mem_mask);
+ case SH4_TCR2_ADDR: return sh4_handle_tcr2_addr_r(mem_mask);
+ case SH4_TCNT0_ADDR: return sh4_handle_tcnt0_addr_r(mem_mask);
+ case SH4_TCNT1_ADDR: return sh4_handle_tcnt1_addr_r(mem_mask);
+ case SH4_TCNT2_ADDR: return sh4_handle_tcnt2_addr_r(mem_mask);
+ case SH4_TCOR0_ADDR: return sh4_handle_tcor0_addr_r(mem_mask);
+ case SH4_TCOR1_ADDR: return sh4_handle_tcor1_addr_r(mem_mask);
+ case SH4_TCOR2_ADDR: return sh4_handle_tcor2_addr_r(mem_mask);
+ case SH4_TOCR_ADDR: return sh4_handle_tocr_addr_r(mem_mask); // not supported
+ case SH4_TCPR2_ADDR: return sh4_handle_tcpr2_addr_r(mem_mask); // not supported
+/*********************************************************************************************************************
+ DMAC (DMA Controller)
+*********************************************************************************************************************/
+ case SH4_SAR0_ADDR: return sh4_handle_sar0_addr_r(mem_mask);
+ case SH4_SAR1_ADDR: return sh4_handle_sar1_addr_r(mem_mask);
+ case SH4_SAR2_ADDR: return sh4_handle_sar2_addr_r(mem_mask);
+ case SH4_SAR3_ADDR: return sh4_handle_sar3_addr_r(mem_mask);
+ case SH4_DAR0_ADDR: return sh4_handle_dar0_addr_r(mem_mask);
+ case SH4_DAR1_ADDR: return sh4_handle_dar1_addr_r(mem_mask);
+ case SH4_DAR2_ADDR: return sh4_handle_dar2_addr_r(mem_mask);
+ case SH4_DAR3_ADDR: return sh4_handle_dar3_addr_r(mem_mask);
+ case SH4_DMATCR0_ADDR: return sh4_handle_dmatcr0_addr_r(mem_mask);
+ case SH4_DMATCR1_ADDR: return sh4_handle_dmatcr1_addr_r(mem_mask);
+ case SH4_DMATCR2_ADDR: return sh4_handle_dmatcr2_addr_r(mem_mask);
+ case SH4_DMATCR3_ADDR: return sh4_handle_dmatcr3_addr_r(mem_mask);
+ case SH4_CHCR0_ADDR: return sh4_handle_chcr0_addr_r(mem_mask);
+ case SH4_CHCR1_ADDR: return sh4_handle_chcr1_addr_r(mem_mask);
+ case SH4_CHCR2_ADDR: return sh4_handle_chcr2_addr_r(mem_mask);
+ case SH4_CHCR3_ADDR: return sh4_handle_chcr3_addr_r(mem_mask);
+ case SH4_DMAOR_ADDR: return sh4_handle_dmaor_addr_r(mem_mask);
+/*********************************************************************************************************************
+ I/O Ports
+*********************************************************************************************************************/
+
+ case PDTRA:
+ if (m_m[BCR2] & 1)
+ return (m_io->read_dword(SH4_IOPORT_16) & ~m_ioport16_direction) | (m_m[PDTRA] & m_ioport16_direction);
+ break;
+ case PDTRB:
+ if (m_m[BCR2] & 1)
+ return (m_io->read_dword(SH4_IOPORT_4) & ~m_ioport4_direction) | (m_m[PDTRB] & m_ioport4_direction);
+ break;
+
+ // SCIF (UART with FIFO)
+ case SCFSR2:
+ return 0x60; //read-only status register
+ }
+ return m_m[offset];
+}
+
+void sh34_base_device::sh4_set_frt_input(int state)
+{
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("sh4_set_frt_input uses m_m[] with SH3\n");
+
+ if(state == PULSE_LINE)
+ {
+ sh4_set_frt_input(ASSERT_LINE);
+ sh4_set_frt_input(CLEAR_LINE);
+ return;
+ }
+
+ if(m_frt_input == state) {
+ return;
+ }
+
+ m_frt_input = state;
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ if(m_m[5] & 0x8000) {
+ if(state == CLEAR_LINE) {
+ return;
+ }
+ } else {
+ if(state == ASSERT_LINE) {
+ return;
+ }
+ }
+ }
+ else
+ {
+ fatalerror("sh4_set_frt_input uses m_m[] with SH3\n");
+ }
+
+#if 0
+ sh4_timer_resync();
+ m_icr = m_frc;
+ m_m[4] |= ICF;
+ logerror("SH4 '%s': ICF activated (%x)\n", tag(), m_pc & AM);
+ sh4_recalc_irq();
+#endif
+}
+
+void sh34_base_device::sh4_set_irln_input(int value)
+{
+ if (m_irln == value)
+ return;
+ m_irln = value;
+ set_input_line(SH4_IRLn, ASSERT_LINE);
+ set_input_line(SH4_IRLn, CLEAR_LINE);
+}
+
+void sh34_base_device::execute_set_input(int irqline, int state) // set state of external interrupt line
+{
+ if (m_cpu_type == CPU_TYPE_SH3)
+ {
+ /***** ASSUME THIS TO BE WRONG FOR NOW *****/
+
+ if (irqline == INPUT_LINE_NMI)
+ {
+ fatalerror("SH3 NMI Unimplemented\n");
+ }
+ else
+ {
+ //if (irqline > SH4_IRL3)
+ // return;
+ if (m_irq_line_state[irqline] == state)
+ return;
+ m_irq_line_state[irqline] = state;
+
+ if( state == CLEAR_LINE )
+ {
+ LOG(("SH-4 '%s' cleared external irq IRL%d\n", tag(), irqline));
+ sh4_exception_unrequest(SH4_INTC_IRL0+irqline-SH4_IRL0);
+ }
+ else
+ {
+ LOG(("SH-4 '%s' assert external irq IRL%d\n", tag(), irqline));
+ sh4_exception_request(SH4_INTC_IRL0+irqline-SH4_IRL0);
+ }
+
+ }
+
+ /***** END ASSUME THIS TO BE WRONG FOR NOW *****/
+ }
+ else
+ {
+ int s;
+
+ if (irqline == INPUT_LINE_NMI)
+ {
+ if (m_nmi_line_state == state)
+ return;
+ if (m_m[ICR] & 0x100)
+ {
+ if ((state == CLEAR_LINE) && (m_nmi_line_state == ASSERT_LINE)) // rising
+ {
+ LOG(("SH-4 '%s' assert nmi\n", tag()));
+ sh4_exception_request(SH4_INTC_NMI);
+ sh4_dmac_nmi();
+ }
+ }
+ else
+ {
+ if ((state == ASSERT_LINE) && (m_nmi_line_state == CLEAR_LINE)) // falling
+ {
+ LOG(("SH-4 '%s' assert nmi\n", tag()));
+ sh4_exception_request(SH4_INTC_NMI);
+ sh4_dmac_nmi();
+ }
+ }
+ if (state == CLEAR_LINE)
+ m_m[ICR] ^= 0x8000;
+ else
+ m_m[ICR] |= 0x8000;
+ m_nmi_line_state = state;
+ }
+ else
+ {
+ if (m_m[ICR] & 0x80) // four independent external interrupt sources
+ {
+ if (irqline > SH4_IRL3)
+ return;
+ if (m_irq_line_state[irqline] == state)
+ return;
+ m_irq_line_state[irqline] = state;
+
+ if( state == CLEAR_LINE )
+ {
+ LOG(("SH-4 '%s' cleared external irq IRL%d\n", tag(), irqline));
+ sh4_exception_unrequest(SH4_INTC_IRL0+irqline-SH4_IRL0);
+ }
+ else
+ {
+ LOG(("SH-4 '%s' assert external irq IRL%d\n", tag(), irqline));
+ sh4_exception_request(SH4_INTC_IRL0+irqline-SH4_IRL0);
+ }
+ }
+ else // level-encoded interrupt
+ {
+ if (irqline != SH4_IRLn)
+ return;
+ if ((m_irln > 15) || (m_irln < 0))
+ return;
+ for (s = 0; s < 15; s++)
+ sh4_exception_unrequest(SH4_INTC_IRLn0+s);
+ if (m_irln < 15)
+ sh4_exception_request(SH4_INTC_IRLn0+m_irln);
+ LOG(("SH-4 '%s' IRLn0-IRLn3 level #%d\n", tag(), m_irln));
+ }
+ }
+ if (m_test_irq && (!m_delay))
+ sh4_check_pending_irq("sh4_set_irq_line");
+ }
+}
+
+void sh34_base_device::sh4_parse_configuration()
+{
+ if(c_clock > 0)
+ {
+ switch((c_md2 << 2) | (c_md1 << 1) | (c_md0))
+ {
+ case 0:
+ m_cpu_clock = c_clock;
+ m_bus_clock = c_clock / 4;
+ m_pm_clock = c_clock / 4;
+ break;
+ case 1:
+ m_cpu_clock = c_clock;
+ m_bus_clock = c_clock / 6;
+ m_pm_clock = c_clock / 6;
+ break;
+ case 2:
+ m_cpu_clock = c_clock;
+ m_bus_clock = c_clock / 3;
+ m_pm_clock = c_clock / 6;
+ break;
+ case 3:
+ m_cpu_clock = c_clock;
+ m_bus_clock = c_clock / 3;
+ m_pm_clock = c_clock / 6;
+ break;
+ case 4:
+ m_cpu_clock = c_clock;
+ m_bus_clock = c_clock / 2;
+ m_pm_clock = c_clock / 4;
+ break;
+ case 5:
+ m_cpu_clock = c_clock;
+ m_bus_clock = c_clock / 2;
+ m_pm_clock = c_clock / 4;
+ break;
+ }
+ m_is_slave = (~(c_md7)) & 1;
+ }
+ else
+ {
+ m_cpu_clock = 200000000;
+ m_bus_clock = 100000000;
+ m_pm_clock = 50000000;
+ m_is_slave = 0;
+ }
+}
+
+uint32_t sh34_base_device::get_remap(uint32_t address)
+{
+ return address;
+}
+
+uint32_t sh4_base_device::get_remap(uint32_t address)
+{
+ if (m_mmuhack != 2)
+ return address;
+
+ // is this the correct way around?
+ int i;
+ uint32_t topaddr = address&0xfff00000;
+
+ for (i=0;i<64;i++)
+ {
+ if (m_utlb[i].V)
+ {
+ uint32_t topcmp = (m_utlb[i].PPN << 10) & 0xfff00000;
+ if (topcmp == topaddr)
+ return (address & 0x000fffff) | ((m_utlb[i].VPN << 10) & 0xfff00000);
+ }
+ }
+
+ //printf("address not in UTLB? %08x\n", address);
+
+
+ return address;
+}
+
+uint32_t sh34_base_device::sh4_getsqremap(uint32_t address)
+{
+ return address;
+}
+
+uint32_t sh4_base_device::sh4_getsqremap(uint32_t address)
+{
+ if (!m_sh4_mmu_enabled || (m_mmuhack != 1))
+ return address;
+ else
+ {
+ int i;
+ uint32_t topaddr = address&0xfff00000;
+
+ for (i=0;i<64;i++)
+ {
+ uint32_t topcmp = (m_utlb[i].VPN<<10)&0xfff00000;
+ if (topcmp==topaddr)
+ return (address&0x000fffff) | ((m_utlb[i].PPN<<10)&0xfff00000);
+ }
+ }
+
+ return address;
+}
+
+
+WRITE64_MEMBER( sh4_base_device::sh4_utlb_address_array_w )
+{
+/* uses bits 13:8 of address to select which UTLB entry we're addressing
+ bit 7 of the address enables 'associative' mode, causing a search
+ operation rather than a direct write.
+
+ NNNN NNNN NNNN NNNN NNNN NNDV AAAA AAAA
+
+ N = VPN = Virtual Page Number
+ D = Dirty Bit
+ V = Validity Bit
+ A = ASID = Address Space Identifier
+*/
+
+ logerror("sh4_utlb_address_array_w %08x %08x\n", offset, data);
+ int offs = offset << 3;
+
+ uint8_t associative = (offs >> 7) & 1;
+
+ if (!associative)
+ {
+ // non-associative mode
+ uint8_t i = (offs >> 8) & 63;
+
+ m_utlb[i].VPN = (data & 0xfffffc00) >> 10;
+ m_utlb[i].D = (data & 0x00000200) >> 9;
+ m_utlb[i].V = (data & 0x00000100) >> 8;
+ m_utlb[i].ASID = (data & 0x000000ff) >> 0;
+ }
+ else
+ {
+ // associative mode
+ fatalerror("SH4MMU: associative mode writes unsupported\n");
+ }
+}
+
+READ64_MEMBER( sh4_base_device::sh4_utlb_address_array_r )
+{
+ // associative bit is ignored for reads
+ int offs = offset*8;
+
+ uint32_t ret = 0;
+
+ uint8_t i = (offs >> 8) & 63;
+
+ ret |= m_utlb[i].VPN << 10;
+ ret |= m_utlb[i].D << 9;
+ ret |= m_utlb[i].V << 8;
+ ret |= m_utlb[i].ASID << 0;
+
+ return ret;
+}
+
+
+WRITE64_MEMBER( sh4_base_device::sh4_utlb_data_array1_w )
+{
+/* uses bits 13:8 of address to select which UTLB entry we're addressing
+
+ ---P PPPP PPPP PPPP PPPP PP-V zRRz CDHW
+
+ P = PPN = Physical page number
+ V = Validity bit
+ z = SZ = Page Size (2 bits, split)
+ D = Dirty Bit
+ R = PR = Protection Key Data
+ C = Cacheable bit
+ H = Share status
+ W = Write through
+ - = unused (should be 0)
+*/
+ logerror("sh4_utlb_data_array1_w %08x %08x\n", offset, data);
+ int offs = offset*8;
+
+ uint8_t i = (offs>>8)&63;
+
+ m_utlb[i].PPN = (data & 0x1ffffc00) >> 10;
+ m_utlb[i].V = (data & 0x00000100) >> 8;
+ m_utlb[i].PSZ = (data & 0x00000080) >> 6;
+ m_utlb[i].PSZ |=(data & 0x00000010) >> 4;
+ m_utlb[i].PPR= (data & 0x00000060) >> 5;
+ m_utlb[i].C = (data & 0x00000008) >> 3;
+ m_utlb[i].D = (data & 0x00000004) >> 2;
+ m_utlb[i].SH = (data & 0x00000002) >> 1;
+ m_utlb[i].WT = (data & 0x00000001) >> 0;
+}
+
+
+READ64_MEMBER(sh4_base_device::sh4_utlb_data_array1_r)
+{
+ uint32_t ret = 0;
+ int offs = offset*8;
+
+ uint8_t i = (offs>>8)&63;
+
+ ret |= m_utlb[i].PPN << 10;
+ ret |= m_utlb[i].V << 8;
+ ret |= (m_utlb[i].PSZ & 2) << 6;
+ ret |= (m_utlb[i].PSZ & 1) << 4;
+ ret |= m_utlb[i].PPR << 5;
+ ret |= m_utlb[i].C << 3;
+ ret |= m_utlb[i].D << 2;
+ ret |= m_utlb[i].SH << 1;
+ ret |= m_utlb[i].WT << 0;
+
+ return ret;
+}
+
+
+
+WRITE64_MEMBER( sh4_base_device::sh4_utlb_data_array2_w )
+{
+/* uses bits 13:8 of address to select which UTLB entry we're addressing
+
+ ---- ---- ---- ---- ---- ---- ---- TSSS
+
+ T = TC = Timing Control
+ S = SA = Space attributes
+ - = unused (should be 0)
+
+*/
+
+ logerror("sh4_utlb_data_array2_w %08x %08x\n", offset, data);
+ int offs = offset*8;
+
+ uint8_t i = (offs>>8)&63;
+
+ m_utlb[i].TC = (data & 0x00000008) >> 3;
+ m_utlb[i].SA = (data & 0x00000007) >> 0;
+}
+
+
+READ64_MEMBER(sh4_base_device::sh4_utlb_data_array2_r)
+{
+ uint32_t ret = 0;
+ int offs = offset*8;
+
+ uint8_t i = (offs>>8)&63;
+
+ ret |= m_utlb[i].TC << 3;
+ ret |= m_utlb[i].SA << 0;
+
+ return ret;
+}
diff --git a/src/devices/cpu/sh/sh4comn.h b/src/devices/cpu/sh/sh4comn.h
new file mode 100644
index 00000000000..230207652d6
--- /dev/null
+++ b/src/devices/cpu/sh/sh4comn.h
@@ -0,0 +1,174 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*****************************************************************************
+ *
+ * sh4comn.h
+ *
+ * SH-4 non-specific components
+ *
+ *****************************************************************************/
+
+#pragma once
+
+#ifndef __SH4COMN_H__
+#define __SH4COMN_H__
+
+//#define USE_SH4DRC
+
+/* speed up delay loops, bail out of tight loops */
+#define BUSY_LOOP_HACKS 0
+
+#define VERBOSE 0
+
+#ifdef USE_SH4DRC
+#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
+
+class sh4_frontend;
+#endif
+
+#define CPU_TYPE_SH3 (2)
+#define CPU_TYPE_SH4 (3)
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#define EXPPRI(pl,po,p,n) (((4-(pl)) << 24) | ((15-(po)) << 16) | ((p) << 8) | (255-(n)))
+#define NMIPRI() EXPPRI(3,0,16,SH4_INTC_NMI)
+#define INTPRI(p,n) EXPPRI(4,2,p,n)
+
+#define FP_RS(r) m_fr[(r)] // binary representation of single precision floating point register r
+#define FP_RFS(r) *( (float *)(m_fr+(r)) ) // single precision floating point register r
+#define FP_RFD(r) *( (double *)(m_fr+(r)) ) // double precision floating point register r
+#define FP_XS(r) m_xf[(r)] // binary representation of extended single precision floating point register r
+#define FP_XFS(r) *( (float *)(m_xf+(r)) ) // single precision extended floating point register r
+#define FP_XFD(r) *( (double *)(m_xf+(r)) ) // double precision extended floating point register r
+#ifdef LSB_FIRST
+#define FP_RS2(r) m_fr[(r) ^ m_fpu_pr]
+#define FP_RFS2(r) *( (float *)(m_fr+((r) ^ m_fpu_pr)) )
+#define FP_XS2(r) m_xf[(r) ^ m_fpu_pr]
+#define FP_XFS2(r) *( (float *)(m_xf+((r) ^ m_fpu_pr)) )
+#endif
+
+
+#ifdef USE_SH4DRC
+struct sh4_state
+{
+ int icount;
+
+ int pcfsel; // last pcflush entry set
+ int maxpcfsel; // highest valid pcflush entry
+ uint32_t pcflushes[16]; // pcflush entries
+
+ drc_cache * cache; /* pointer to the DRC code cache */
+ drcuml_state * drcuml; /* DRC UML generator state */
+ sh4_frontend * drcfe; /* pointer to the DRC front-end class */
+ uint32_t drcoptions; /* configurable DRC options */
+
+ /* internal stuff */
+ uint8_t cache_dirty; /* true if we need to flush the cache */
+
+ /* parameters for subroutines */
+ uint64_t numcycles; /* return value from gettotalcycles */
+ uint32_t arg0; /* print_debug argument 1 */
+ uint32_t arg1; /* print_debug argument 2 */
+ uint32_t irq; /* irq we're taking */
+
+ /* register mappings */
+ uml::parameter regmap[16]; /* parameter to register mappings for all 16 integer registers */
+
+ uml::code_handle * entry; /* entry point */
+ uml::code_handle * read8; /* read byte */
+ uml::code_handle * write8; /* write byte */
+ uml::code_handle * read16; /* read half */
+ uml::code_handle * write16; /* write half */
+ uml::code_handle * read32; /* read word */
+ uml::code_handle * write32; /* write word */
+
+ uml::code_handle * interrupt; /* interrupt */
+ uml::code_handle * nocode; /* nocode */
+ uml::code_handle * out_of_cycles; /* out of cycles exception handler */
+
+ uint32_t prefadr;
+ uint32_t target;
+};
+#endif
+
+#ifdef USE_SH4DRC
+class sh4_frontend : public drc_frontend
+{
+public:
+ sh4_frontend(sh4_state &state, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
+
+protected:
+ virtual bool describe(opcode_desc &desc, const opcode_desc *prev);
+
+private:
+ bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+ bool describe_group_15(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
+
+ sh4_state &m_context;
+};
+#endif
+
+
+enum
+{
+ ICF = 0x00800000,
+ OCFA = 0x00080000,
+ OCFB = 0x00040000,
+ OVF = 0x00020000
+};
+
+/* Bits in SR */
+#define T 0x00000001
+#define S 0x00000002
+#define I 0x000000f0
+#define Q 0x00000100
+#define M 0x00000200
+#define FD 0x00008000
+#define BL 0x10000000
+#define sRB 0x20000000
+#define MD 0x40000000
+
+/* 29 bits */
+#define AM 0x1fffffff
+
+#define FLAGS (MD|sRB|BL|FD|M|Q|I|S|T)
+
+/* Bits in FPSCR */
+#define RM 0x00000003
+#define DN 0x00040000
+#define PR 0x00080000
+#define SZ 0x00100000
+#define FR 0x00200000
+
+#define Rn ((opcode>>8)&15)
+#define Rm ((opcode>>4)&15)
+
+#define REGFLAG_R(n) (1 << (n))
+#define REGFLAG_FR(n) (1 << (n))
+#define REGFLAG_XR(n) (1 << (n))
+
+/* register flags 1 */
+#define REGFLAG_PR (1 << 0)
+#define REGFLAG_MACL (1 << 1)
+#define REGFLAG_MACH (1 << 2)
+#define REGFLAG_GBR (1 << 3)
+#define REGFLAG_VBR (1 << 4)
+#define REGFLAG_SR (1 << 5)
+#define REGFLAG_SGR (1 << 6)
+#define REGFLAG_FPUL (1 << 7)
+#define REGFLAG_FPSCR (1 << 8)
+#define REGFLAG_DBR (1 << 9)
+#define REGFLAG_SSR (1 << 10)
+#define REGFLAG_SPC (1 << 11)
+
+
+#endif /* __SH4COMN_H__ */
diff --git a/src/devices/cpu/sh/sh4dasm.cpp b/src/devices/cpu/sh/sh4dasm.cpp
new file mode 100644
index 00000000000..faff895f3a5
--- /dev/null
+++ b/src/devices/cpu/sh/sh4dasm.cpp
@@ -0,0 +1,905 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+#include "emu.h"
+#include "debugger.h"
+#include "sh4.h"
+
+#define SIGNX8(x) (((int32_t)(x) << 24) >> 24)
+#define SIGNX12(x) (((int32_t)(x) << 20) >> 20)
+
+#define Rn ((opcode >> 8) & 15)
+#define Rm ((opcode >> 4) & 15)
+
+static const char *const regname[16] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10","R11","R12","R13","R14","R15"
+};
+
+static uint32_t op0000(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ uint32_t flags = 0;
+ switch (opcode & 0xF)
+ {
+ case 0x0:
+ case 0x1:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 0x2:
+ if (opcode & 0x80) {
+ util::stream_format(stream, "STC %s_BANK,%s", regname[(Rm) & 7], regname[Rn]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ util::stream_format(stream, "STC SR,%s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "STC GBR,%s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "STC VBR,%s", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "STC SSR,%s", regname[Rn]);
+ break;
+ case 0x40:
+ util::stream_format(stream, "STC SPC,%s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x3:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ util::stream_format(stream, "BSRF %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "BRAF %s", regname[Rn]);
+ break;
+ case 0x80:
+ util::stream_format(stream, "PREF @%s", regname[Rn]);
+ break;
+ case 0x90:
+ util::stream_format(stream, "OCBI @%s", regname[Rn]);
+ break;
+ case 0xA0:
+ util::stream_format(stream, "OCBP @%s", regname[Rn]);
+ break;
+ case 0xB0:
+ util::stream_format(stream, "OCBWB @%s", regname[Rn]);
+ break;
+ case 0xC0:
+ util::stream_format(stream, "MOVCA.L R0,@%s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x4:
+ util::stream_format(stream, "MOV.B %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 0x5:
+ util::stream_format(stream, "MOV.W %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 0x6:
+ util::stream_format(stream, "MOV.L %s,@(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 0x7:
+ util::stream_format(stream, "MUL.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x8:
+ switch (opcode & 0x70)
+ {
+ case 0x00: stream << "CLRT"; break;
+ case 0x10: stream << "SETT"; break;
+ case 0x20: stream << "CLRMAC"; break;
+ case 0x30: stream << "LDTLB"; break;
+ case 0x40: stream << "CLRS"; break;
+ case 0x50: stream << "SETS"; break;
+ }
+ break;
+ case 0x9:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ stream << "NOP";
+ break;
+ case 0x10:
+ stream << "DIV0U";
+ break;
+ case 0x20:
+ util::stream_format(stream, "MOVT %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0xA:
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ util::stream_format(stream, "STS MACH,%s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "STS MACL,%s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "STS PR,%s", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "STC SGR,%s", regname[Rn]);
+ break;
+ case 0x50:
+ util::stream_format(stream, "STS FPUL,%s", regname[Rn]);
+ break;
+ case 0x60:
+ util::stream_format(stream, "STS FPSCR,%s", regname[Rn]);
+ break;
+ case 0x70:
+ util::stream_format(stream, "STC DBR,%s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0xB:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ stream << "RTS";
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ case 0x10:
+ stream << "SLEEP";
+ break;
+ case 0x20:
+ stream << "RTE";
+ flags = DASMFLAG_STEP_OUT;
+ break;
+ }
+ break;
+ case 0xC:
+ util::stream_format(stream, "MOV.B @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 0xD:
+ util::stream_format(stream, "MOV.W @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 0xE:
+ util::stream_format(stream, "MOV.L @(R0,%s),%s", regname[Rm], regname[Rn]);
+ break;
+ case 0xF:
+ util::stream_format(stream, "MAC.L @%s+,@%s+", regname[Rn], regname[Rm]);
+ break;
+ }
+ return flags;
+}
+
+static uint32_t op0001(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV.L %s,@($%02X,%s)", regname[Rm], (opcode & 15) * 4, regname[Rn]);
+ return 0;
+}
+
+static uint32_t op0010(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ util::stream_format(stream, "MOV.B %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ util::stream_format(stream, "MOV.W %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ util::stream_format(stream, "MOV.L %s,@%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ util::stream_format(stream, "?????? $%04X", opcode);
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ util::stream_format(stream, "MOV.L %s,@-%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ util::stream_format(stream, "DIV0S %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ util::stream_format(stream, "TST %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ util::stream_format(stream, "AND %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ util::stream_format(stream, "XOR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ util::stream_format(stream, "OR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ util::stream_format(stream, "CMP/STR %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ util::stream_format(stream, "XTRCT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ util::stream_format(stream, "MULU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ util::stream_format(stream, "MULS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static uint32_t op0011(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch (opcode & 15)
+ {
+ case 0:
+ util::stream_format(stream, "CMP/EQ %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ util::stream_format(stream, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ util::stream_format(stream, "CMP/HS %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ util::stream_format(stream, "CMP/GE %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 4:
+ util::stream_format(stream, "DIV1 %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ util::stream_format(stream, "DMULU.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ util::stream_format(stream, "CMP/HI %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ util::stream_format(stream, "CMP/GT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ util::stream_format(stream, "SUB %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ util::stream_format(stream, "?????? %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ util::stream_format(stream, "SUBC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ util::stream_format(stream, "SUBV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ util::stream_format(stream, "ADD %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ util::stream_format(stream, "DMULS.L %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 14:
+ util::stream_format(stream, "ADDC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 15:
+ util::stream_format(stream, "ADDV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static uint32_t op0100(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ uint32_t flags = 0;
+ switch (opcode & 0xF)
+ {
+ case 0x0:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "SHLL %s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "DT %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "SHAL %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x1:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "SHLR %s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "CMP/PZ %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "SHAR %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x2:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ util::stream_format(stream, "STS.L MACH,@-%s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "STS.L MACL,@-%s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "STS.L PR,@-%s", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "STC.L SGR,@-%s", regname[Rn]);
+ break;
+ case 0x50:
+ util::stream_format(stream, "STS.L FPUL,@-%s", regname[Rn]);
+ break;
+ case 0x60:
+ util::stream_format(stream, "STS.L FPSCR,@-%s", regname[Rn]);
+ break;
+ case 0xF0:
+ util::stream_format(stream, "STC.L DBR,@-%s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x3:
+ if (opcode & 0x80) {
+ util::stream_format(stream, "STC.L %s_BANK,@-%s", regname[(Rm) & 7],regname[Rn]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ util::stream_format(stream, "STC.L SR,@-%s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "STC.L GBR,@-%s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "STC.L VBR,@-%s", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "STC.L SSR,@-%s", regname[Rn]);
+ break;
+ case 0x40:
+ util::stream_format(stream, "STC.L SPC,@-%s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x4:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "ROTL %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "ROTCL %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x5:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "ROTR %s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "CMP/PL %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "ROTCR %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x6:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ util::stream_format(stream, "LDS.L @%s+,MACH", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "LDS.L @%s+,MACL", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "LDS.L @%s+,PR", regname[Rn]);
+ break;
+ case 0x50:
+ util::stream_format(stream, "LDS.L @%s+,FPUL", regname[Rn]);
+ break;
+ case 0x60:
+ util::stream_format(stream, "LDS.L @%s+,FPSCR", regname[Rn]);
+ break;
+ case 0xF0:
+ util::stream_format(stream, "LDC.L @%s+,DBR", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x7:
+ if (opcode & 0x80) {
+ util::stream_format(stream, "LDC.L @%s+,%s_BANK", regname[Rn],regname[(Rm) & 7]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ util::stream_format(stream, "LDC.L @%s+,SR", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "LDC.L @%s+,GBR", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "LDC.L @%s+,VBR", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "LDC.L @%s+,SSR", regname[Rn]);
+ break;
+ case 0x40:
+ util::stream_format(stream, "LDC.L @%s+,SPC", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x8:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "SHLL2 %s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "SHLL8 %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "SHLL16 %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0x9:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "SHLR2 %s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "SHLR8 %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "SHLR16 %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0xA:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ util::stream_format(stream, "LDS %s,MACH", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "LDS %s,MACL", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "LDS %s,PR", regname[Rn]);
+ break;
+ case 0x50:
+ util::stream_format(stream, "LDS %s,FPUL", regname[Rn]);
+ break;
+ case 0x60:
+ util::stream_format(stream, "LDS %s,FPSCR", regname[Rn]);
+ break;
+ case 0xF0:
+ util::stream_format(stream, "LDC %s,DBR", regname[Rn]);
+ break;
+ }
+ break;
+ case 0xB:
+ switch (opcode & 0x30)
+ {
+ case 0x00:
+ util::stream_format(stream, "JSR %s", regname[Rn]);
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ case 0x10:
+ util::stream_format(stream, "TAS %s", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "JMP %s", regname[Rn]);
+ break;
+ }
+ break;
+ case 0xC:
+ util::stream_format(stream, "SHAD %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0xD:
+ util::stream_format(stream, "SHLD %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0xE:
+ if (opcode & 0x80) {
+ util::stream_format(stream, "LDC %s,%s_BANK", regname[Rn],regname[(Rm) & 7]);
+ return flags;
+ }
+ switch (opcode & 0x70)
+ {
+ case 0x00:
+ util::stream_format(stream, "LDC %s,SR", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "LDC %s,GBR", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "LDC %s,VBR", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "LDC %s,SSR", regname[Rn]);
+ break;
+ case 0x40:
+ util::stream_format(stream, "LDC %s,SPC", regname[Rn]);
+ break;
+ }
+ break;
+ case 0xF:
+ util::stream_format(stream, "MAC.W @%s+,@%s+", regname[Rm], regname[Rn]);
+ break;
+ }
+ return flags;
+}
+
+static uint32_t op0101(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV.L @($%02X,%s),%s", (opcode & 15) * 4, regname[Rm], regname[Rn]);
+ return 0;
+}
+
+static uint32_t op0110(std::ostream &stream, uint32_t pc, uint16_t opcode)
+
+{
+ switch(opcode & 0xF)
+ {
+ case 0x00:
+ util::stream_format(stream, "MOV.B @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x01:
+ util::stream_format(stream, "MOV.W @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x02:
+ util::stream_format(stream, "MOV.L @%s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x03:
+ util::stream_format(stream, "MOV %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x04:
+ util::stream_format(stream, "MOV.B @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x05:
+ util::stream_format(stream, "MOV.W @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x06:
+ util::stream_format(stream, "MOV.L @%s+,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x07:
+ util::stream_format(stream, "NOT %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x08:
+ util::stream_format(stream, "SWAP.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x09:
+ util::stream_format(stream, "SWAP.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0a:
+ util::stream_format(stream, "NEGC %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0b:
+ util::stream_format(stream, "NEG %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0c:
+ util::stream_format(stream, "EXTU.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0d:
+ util::stream_format(stream, "EXTU.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0e:
+ util::stream_format(stream, "EXTS.B %s,%s", regname[Rm], regname[Rn]);
+ break;
+ case 0x0f:
+ util::stream_format(stream, "EXTS.W %s,%s", regname[Rm], regname[Rn]);
+ break;
+ }
+ return 0;
+}
+
+static uint32_t op0111(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "ADD #$%02X,%s", opcode & 0xff, regname[Rn]);
+ return 0;
+}
+
+static uint32_t op1000(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ util::stream_format(stream, "MOV.B R0,@($%02X,%s)", (opcode & 15), regname[Rm]);
+ break;
+ case 1:
+ util::stream_format(stream, "MOV.W R0,@($%02X,%s)", (opcode & 15) * 2, regname[Rm]);
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W @($%02X,%s),R0", (opcode & 15) * 2, regname[Rm]);
+ break;
+ case 8:
+ util::stream_format(stream, "CMP/EQ #$%02X,R0", (opcode & 0xff));
+ break;
+ case 9:
+ util::stream_format(stream, "BT $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 11:
+ util::stream_format(stream, "BF $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 13:
+ util::stream_format(stream, "BTS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ case 15:
+ util::stream_format(stream, "BFS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2);
+ break;
+ default :
+ util::stream_format(stream, "invalid $%04X", opcode);
+ }
+ return 0;
+}
+
+static uint32_t op1001(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+uint32_t ea=(pc+((opcode & 0xff) * 2)+2);
+
+ util::stream_format(stream, "MOV.W @($%04X,PC),%s [%08X]", (opcode & 0xff) * 2, regname[Rn], ea);
+ return 0;
+}
+
+static uint32_t op1010(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "BRA $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return 0;
+}
+
+static uint32_t op1011(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "BSR $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2);
+ return DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+}
+
+static uint32_t op1100(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ uint32_t flags = 0;
+ switch((opcode >> 8) & 15)
+ {
+ case 0:
+ util::stream_format(stream, "MOV.B R0,@($%02X,GBR)", opcode & 0xff);
+ break;
+ case 1:
+ util::stream_format(stream, "MOV.W R0,@($%04X,GBR)", (opcode & 0xff) * 2);
+ break;
+ case 2:
+ util::stream_format(stream, "MOV.L R0,@($%04X,GBR)", (opcode & 0xff) * 4);
+ break;
+ case 3:
+ util::stream_format(stream, "TRAPA #$%02X", opcode & 0xff);
+ flags = DASMFLAG_STEP_OVER;
+ break;
+ case 4:
+ util::stream_format(stream, "MOV.B @($%02X,GBR),R0", opcode & 0xff);
+ break;
+ case 5:
+ util::stream_format(stream, "MOV.W @($%04X,GBR),R0", (opcode & 0xff) * 2);
+ break;
+ case 6:
+ util::stream_format(stream, "MOV.L @($%04X,GBR),R0", (opcode & 0xff) * 4);
+ break;
+ case 7:
+ util::stream_format(stream, "MOVA @($%04X,PC),R0 [%08X]", (opcode & 0xff) * 4, ((pc + 2) & ~3) + (opcode & 0xff) * 4);
+ break;
+ case 8:
+ util::stream_format(stream, "TST #$%02X,R0", opcode & 0xff);
+ break;
+ case 9:
+ util::stream_format(stream, "AND #$%02X,R0", opcode & 0xff);
+ break;
+ case 10:
+ util::stream_format(stream, "XOR #$%02X,R0", opcode & 0xff);
+ break;
+ case 11:
+ util::stream_format(stream, "OR #$%02X,R0", opcode & 0xff);
+ break;
+ case 12:
+ util::stream_format(stream, "TST.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 13:
+ util::stream_format(stream, "AND.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 14:
+ util::stream_format(stream, "XOR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ case 15:
+ util::stream_format(stream, "OR.B #$%02X,@(R0,GBR)", opcode & 0xff);
+ break;
+ }
+ return flags;
+}
+
+static uint32_t op1101(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+uint32_t ea=((pc + 2) & ~3) + (opcode & 0xff) * 4;
+
+ util::stream_format(stream, "MOV.L @($%04X,PC),%s [%08X]", (opcode & 0xff) * 4, regname[Rn], ea);
+ return 0;
+}
+
+static uint32_t op1110(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ util::stream_format(stream, "MOV #$%02X,%s", (opcode & 0xff), regname[Rn]);
+ return 0;
+}
+
+static uint32_t op1111(std::ostream &stream, uint32_t pc, uint16_t opcode)
+{
+ switch (opcode & 0xf)
+ {
+ case 0:
+ util::stream_format(stream, "FADD F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 1:
+ util::stream_format(stream, "FSUB F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 2:
+ util::stream_format(stream, "FMUL F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 3:
+ util::stream_format(stream, "FDIV F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 4:
+ util::stream_format(stream, "FCMP/EQ F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 5:
+ util::stream_format(stream, "FCMP/GT F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 6:
+ util::stream_format(stream, "FMOV.S @(R0,%s),F%s", regname[Rm], regname[Rn]);
+ break;
+ case 7:
+ util::stream_format(stream, "FMOV.S F%s, @(R0,%s)", regname[Rm], regname[Rn]);
+ break;
+ case 8:
+ util::stream_format(stream, "FMOV.S @%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 9:
+ util::stream_format(stream, "FMOV.S @%s+, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 10:
+ util::stream_format(stream, "FMOV.S F%s, @%s", regname[Rm], regname[Rn]);
+ break;
+ case 11:
+ util::stream_format(stream, "FMOV.S F%s, @-%s", regname[Rm], regname[Rn]);
+ break;
+ case 12:
+ util::stream_format(stream, "FMOV.S F%s, F%s", regname[Rm], regname[Rn]);
+ break;
+ case 13:
+ switch (opcode & 0xF0)
+ {
+ case 0x00:
+ util::stream_format(stream, "FSTS FPUL, F%s", regname[Rn]);
+ break;
+ case 0x10:
+ util::stream_format(stream, "FLDS F%s, FPUL", regname[Rn]);
+ break;
+ case 0x20:
+ util::stream_format(stream, "FLOAT FPUL, F%s", regname[Rn]);
+ break;
+ case 0x30:
+ util::stream_format(stream, "FTRC F%s, FPUL", regname[Rn]);
+ break;
+ case 0x40:
+ util::stream_format(stream, "FNEG F%s", regname[Rn]);
+ break;
+ case 0x50:
+ util::stream_format(stream, "FABS F%s", regname[Rn]);
+ break;
+ case 0x60:
+ util::stream_format(stream, "FSQRT F%s", regname[Rn]);
+ break;
+ case 0x70:
+ util::stream_format(stream, "FSRRA F%s", regname[Rn]);
+ break;
+ case 0x80:
+ util::stream_format(stream, "FLDI0 F%s", regname[Rn]);
+ break;
+ case 0x90:
+ util::stream_format(stream, "FLDI1 F%s", regname[Rn]);
+ break;
+ case 0xA0:
+ util::stream_format(stream, "FCNVSD FPUL, D%s", regname[Rn]);
+ break;
+ case 0xB0:
+ util::stream_format(stream, "FCNVDS D%s, FPUL", regname[Rn]);
+ break;
+ case 0xE0:
+ util::stream_format(stream, "FIPR FV%d, FV%d", (Rn & 3) << 2, Rn & 12);
+ break;
+ case 0xF0:
+ if (opcode & 0x100) {
+ if (opcode & 0x200) {
+ switch (opcode & 0xC00)
+ {
+ case 0x000:
+ stream << "FSCHG";
+ break;
+ case 0x800:
+ stream << "FRCHG";
+ break;
+ default:
+ util::stream_format(stream, "Funknown $%04X", opcode);
+ break;
+ }
+ } else {
+ util::stream_format(stream, "FTRV XMTRX, FV%d", Rn & 12);
+ }
+ } else {
+ util::stream_format(stream, "FSCA FPUL, F%s", regname[Rn & 14]);
+ }
+ break;
+ default:
+ util::stream_format(stream, "Funknown $%04X", opcode);
+ break;
+ }
+ break;
+ case 14:
+ util::stream_format(stream, "FMAC FR0, F%s,F%s", regname[Rm], regname[Rn]);
+ break;
+ default:
+ util::stream_format(stream, "Funknown $%04X", opcode);
+ break;
+ }
+
+ return 0;
+}
+
+unsigned DasmSH4(std::ostream &stream, unsigned pc, uint16_t opcode)
+{
+ uint32_t flags;
+
+ pc += 2;
+
+ switch ((opcode >> 12) & 15)
+ {
+ case 0: flags = op0000(stream, pc, opcode); break;
+ case 1: flags = op0001(stream, pc, opcode); break;
+ case 2: flags = op0010(stream, pc, opcode); break;
+ case 3: flags = op0011(stream, pc, opcode); break;
+ case 4: flags = op0100(stream, pc, opcode); break;
+ case 5: flags = op0101(stream, pc, opcode); break;
+ case 6: flags = op0110(stream, pc, opcode); break;
+ case 7: flags = op0111(stream, pc, opcode); break;
+ case 8: flags = op1000(stream, pc, opcode); break;
+ case 9: flags = op1001(stream, pc, opcode); break;
+ case 10: flags = op1010(stream, pc, opcode); break;
+ case 11: flags = op1011(stream, pc, opcode); break;
+ case 12: flags = op1100(stream, pc, opcode); break;
+ case 13: flags = op1101(stream, pc, opcode); break;
+ case 14: flags = op1110(stream, pc, opcode); break;
+ default: flags = op1111(stream, pc, opcode); break;
+ }
+ return 2 | flags | DASMFLAG_SUPPORTED;
+}
+
+CPU_DISASSEMBLE(sh4)
+{
+ return DasmSH4(stream, pc, (oprom[1] << 8) | oprom[0]);
+}
+
+CPU_DISASSEMBLE(sh4be)
+{
+ return DasmSH4(stream, pc, (oprom[0] << 8) | oprom[1]);
+}
diff --git a/src/devices/cpu/sh/sh4dmac.cpp b/src/devices/cpu/sh/sh4dmac.cpp
new file mode 100644
index 00000000000..c06ffb034dd
--- /dev/null
+++ b/src/devices/cpu/sh/sh4dmac.cpp
@@ -0,0 +1,666 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/* SHA3/4 DMA Controller */
+
+#include "emu.h"
+#include "debugger.h"
+#include "sh4.h"
+#include "sh4comn.h"
+#include "sh3comn.h"
+#include "sh4dmac.h"
+
+static const int dmasize[8] = { 8, 1, 2, 4, 32, 0, 0, 0 };
+
+static const int sh3_dmasize[4] = { 1, 2, 4, 16 };
+
+TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_dmac_callback )
+{
+ int channel = param;
+
+ LOG(("SH4 '%s': DMA %d complete\n", tag(), channel));
+ m_dma_timer_active[channel] = 0;
+ switch (channel)
+ {
+ case 0:
+ m_SH4_DMATCR0 = 0;
+ m_SH4_CHCR0 |= CHCR_TE;
+ if (m_SH4_CHCR0 & CHCR_IE)
+ sh4_exception_request(SH4_INTC_DMTE0);
+ break;
+ case 1:
+ m_SH4_DMATCR1 = 0;
+ m_SH4_CHCR1 |= CHCR_TE;
+ if (m_SH4_CHCR1 & CHCR_IE)
+ sh4_exception_request(SH4_INTC_DMTE1);
+ break;
+ case 2:
+ m_SH4_DMATCR2 = 0;
+ m_SH4_CHCR2 |= CHCR_TE;
+ if (m_SH4_CHCR2 & CHCR_IE)
+ sh4_exception_request(SH4_INTC_DMTE2);
+ break;
+ case 3:
+ m_SH4_DMATCR3 = 0;
+ m_SH4_CHCR3 |= CHCR_TE;
+ if (m_SH4_CHCR3 & CHCR_IE)
+ sh4_exception_request(SH4_INTC_DMTE3);
+ break;
+ }
+}
+
+int sh34_base_device::sh4_dma_transfer(int channel, int timermode, uint32_t chcr, uint32_t *sar, uint32_t *dar, uint32_t *dmatcr)
+{
+ int incs, incd, size;
+ uint32_t src, dst, count;
+
+ incd = (chcr & CHCR_DM) >> 14;
+ incs = (chcr & CHCR_SM) >> 12;
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ size = dmasize[(chcr & CHCR_TS) >> 4];
+ }
+ else
+ {
+ size = sh3_dmasize[(chcr >> 3) & 3];
+ }
+
+ if(incd == 3 || incs == 3)
+ {
+ logerror("SH4: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, chcr);
+ return 0;
+ }
+ src = *sar;
+ dst = *dar;
+ count = *dmatcr;
+ if (!count)
+ count = 0x1000000;
+
+ LOG(("SH4: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", channel, src, dst, count, chcr, incs, incd, size));
+
+ if (timermode == 1) // timer actvated after a time based on the number of words to transfer
+ {
+ m_dma_timer_active[channel] = 1;
+ m_dma_timer[channel]->adjust(cycles_to_attotime(2*count+1), channel);
+ }
+ else if (timermode == 2) // timer activated immediately
+ {
+ m_dma_timer_active[channel] = 1;
+ m_dma_timer[channel]->adjust(attotime::zero, channel);
+ }
+
+ src &= AM;
+ dst &= AM;
+
+ switch(size)
+ {
+ case 1: // 8 bit
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src --;
+ if(incd == 2)
+ dst --;
+ m_program->write_byte(dst, m_program->read_byte(src));
+ if(incs == 1)
+ src ++;
+ if(incd == 1)
+ dst ++;
+ }
+ break;
+ case 2: // 16 bit
+ src &= ~1;
+ dst &= ~1;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 2;
+ if(incd == 2)
+ dst -= 2;
+ m_program->write_word(dst, m_program->read_word(src));
+ if(incs == 1)
+ src += 2;
+ if(incd == 1)
+ dst += 2;
+ }
+ break;
+ case 8: // 64 bit
+ src &= ~7;
+ dst &= ~7;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 8;
+ if(incd == 2)
+ dst -= 8;
+ m_program->write_qword(dst, m_program->read_qword(src));
+ if(incs == 1)
+ src += 8;
+ if(incd == 1)
+ dst += 8;
+
+ }
+ break;
+ case 4: // 32 bit
+ src &= ~3;
+ dst &= ~3;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 4;
+ if(incd == 2)
+ dst -= 4;
+ m_program->write_dword(dst, m_program->read_dword(src));
+ if(incs == 1)
+ src += 4;
+ if(incd == 1)
+ dst += 4;
+
+ }
+ break;
+ case 32:
+ src &= ~31;
+ dst &= ~31;
+ for(;count > 0; count --)
+ {
+ if(incs == 2)
+ src -= 32;
+ if(incd == 2)
+ dst -= 32;
+ m_program->write_qword(dst, m_program->read_qword(src));
+ m_program->write_qword(dst+8, m_program->read_qword(src+8));
+ m_program->write_qword(dst+16, m_program->read_qword(src+16));
+ m_program->write_qword(dst+24, m_program->read_qword(src+24));
+ if(incs == 1)
+ src += 32;
+ if(incd == 1)
+ dst += 32;
+ }
+ break;
+ }
+ *sar = (*sar & ~AM) | src;
+ *dar = (*dar & ~AM) | dst;
+ *dmatcr = count;
+ return 1;
+}
+
+int sh34_base_device::sh4_dma_transfer_device(int channel, uint32_t chcr, uint32_t *sar, uint32_t *dar, uint32_t *dmatcr)
+{
+ int incs, incd, size, mod;
+ uint32_t src, dst, count;
+
+ incd = (chcr & CHCR_DM) >> 14;
+ incs = (chcr & CHCR_SM) >> 12;
+
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ size = dmasize[(chcr & CHCR_TS) >> 4];
+ }
+ else
+ {
+ size = sh3_dmasize[(chcr >> 3) & 3];
+ }
+
+ mod = ((chcr & CHCR_RS) >> 8);
+ if (incd == 3 || incs == 3)
+ {
+ logerror("SH4: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, chcr);
+ return 0;
+ }
+ src = *sar;
+ dst = *dar;
+ count = *dmatcr;
+ if (!count)
+ count = 0x1000000;
+
+ LOG(("SH4: DMA %d start device<->memory %x, %x, %x, %04x, %d, %d, %d\n", channel, src, dst, count, chcr, incs, incd, size));
+
+ m_dma_timer_active[channel] = 1;
+
+ src &= AM;
+ dst &= AM;
+
+ // remember parameters
+ m_dma_source[channel]=src;
+ m_dma_destination[channel]=dst;
+ m_dma_count[channel]=count;
+ m_dma_wordsize[channel]=size;
+ m_dma_source_increment[channel]=incs;
+ m_dma_destination_increment[channel]=incd;
+ m_dma_mode[channel]=mod;
+
+ // inform device its ready to transfer
+ m_io->write_dword(SH4_IOPORT_DMA, channel | (mod << 16));
+ return 1;
+}
+
+void sh34_base_device::sh4_dmac_check(int channel)
+{
+ uint32_t dmatcr, chcr, sar, dar;
+
+ switch (channel)
+ {
+ case 0:
+ sar = m_SH4_SAR0;
+ dar = m_SH4_DAR0;
+ chcr = m_SH4_CHCR0;
+ dmatcr = m_SH4_DMATCR0;
+ break;
+ case 1:
+ sar = m_SH4_SAR1;
+ dar = m_SH4_DAR1;
+ chcr = m_SH4_CHCR1;
+ dmatcr = m_SH4_DMATCR1;
+ break;
+ case 2:
+ sar = m_SH4_SAR2;
+ dar = m_SH4_DAR2;
+ chcr = m_SH4_CHCR2;
+ dmatcr = m_SH4_DMATCR2;
+ break;
+ case 3:
+ sar = m_SH4_SAR3;
+ dar = m_SH4_DAR3;
+ chcr = m_SH4_CHCR3;
+ dmatcr = m_SH4_DMATCR3;
+ break;
+ default:
+ return;
+ }
+ if (chcr & m_SH4_DMAOR & DMAOR_DME)
+ {
+ if ((((chcr & CHCR_RS) >> 8) < 2) || (((chcr & CHCR_RS) >> 8) > 6))
+ return;
+ if (!m_dma_timer_active[channel] && !(chcr & CHCR_TE) && !(m_SH4_DMAOR & (DMAOR_AE | DMAOR_NMIF)))
+ {
+ if (((chcr & CHCR_RS) >> 8) > 3)
+ sh4_dma_transfer(channel, 1, chcr, &sar, &dar, &dmatcr);
+ else if ((m_SH4_DMAOR & DMAOR_DDT) == 0)
+ sh4_dma_transfer_device(channel, chcr, &sar, &dar, &dmatcr); // tell device we are ready to transfer
+ }
+ }
+ else
+ {
+ if (m_dma_timer_active[channel])
+ {
+ logerror("SH4: DMA %d cancelled in-flight but all data transferred", channel);
+ m_dma_timer[channel]->adjust(attotime::never, channel);
+ m_dma_timer_active[channel] = 0;
+ }
+ }
+}
+
+
+// called by drivers to transfer data in a cpu<->device dma. 'device' must be a SH4 cpu
+int sh34_base_device::sh4_dma_data(struct sh4_device_dma *s)
+{
+ uint32_t pos, len, siz;
+ int channel = s->channel;
+ void *data = s->buffer;
+
+ if (!m_dma_timer_active[channel])
+ return 0;
+
+ if (m_dma_mode[channel] == 2)
+ {
+ // device receives data
+ len = m_dma_count[channel];
+ if (s->length < len)
+ len = s->length;
+ siz = m_dma_wordsize[channel];
+ for (pos = 0;pos < len;pos++) {
+ switch (siz)
+ {
+ case 8:
+ if (m_dma_source_increment[channel] == 2)
+ m_dma_source[channel] -= 8;
+ *(uint64_t *)data = m_program->read_qword(m_dma_source[channel] & ~7);
+ if (m_dma_source_increment[channel] == 1)
+ m_dma_source[channel] += 8;
+ break;
+ case 1:
+ if (m_dma_source_increment[channel] == 2)
+ m_dma_source[channel]--;
+ *(uint8_t *)data = m_program->read_byte(m_dma_source[channel]);
+ if (m_dma_source_increment[channel] == 1)
+ m_dma_source[channel]++;
+ break;
+ case 2:
+ if (m_dma_source_increment[channel] == 2)
+ m_dma_source[channel] -= 2;
+ *(uint16_t *)data = m_program->read_word(m_dma_source[channel] & ~1);
+ if (m_dma_source_increment[channel] == 1)
+ m_dma_source[channel] += 2;
+ break;
+ case 4:
+ if (m_dma_source_increment[channel] == 2)
+ m_dma_source[channel] -= 4;
+ *(uint32_t *)data = m_program->read_dword(m_dma_source[channel] & ~3);
+ if (m_dma_source_increment[channel] == 1)
+ m_dma_source[channel] += 4;
+ break;
+ case 32:
+ if (m_dma_source_increment[channel] == 2)
+ m_dma_source[channel] -= 32;
+ *(uint64_t *)data = m_program->read_qword(m_dma_source[channel] & ~31);
+ *((uint64_t *)data+1) = m_program->read_qword((m_dma_source[channel] & ~31)+8);
+ *((uint64_t *)data+2) = m_program->read_qword((m_dma_source[channel] & ~31)+16);
+ *((uint64_t *)data+3) = m_program->read_qword((m_dma_source[channel] & ~31)+24);
+ if (m_dma_source_increment[channel] == 1)
+ m_dma_source[channel] += 32;
+ break;
+ }
+ m_dma_count[channel]--;
+ }
+ if (m_dma_count[channel] == 0) // all data transferred ?
+ {
+ m_dma_timer[channel]->adjust(attotime::zero, channel);
+ return 2;
+ }
+ return 1;
+ }
+ else if (m_dma_mode[channel] == 3)
+ {
+ // device sends data
+ len = m_dma_count[channel];
+ if (s->length < len)
+ len = s->length;
+ siz = m_dma_wordsize[channel];
+ for (pos = 0;pos < len;pos++) {
+ switch (siz)
+ {
+ case 8:
+ if (m_dma_destination_increment[channel] == 2)
+ m_dma_destination[channel]-=8;
+ m_program->write_qword(m_dma_destination[channel] & ~7, *(uint64_t *)data);
+ if (m_dma_destination_increment[channel] == 1)
+ m_dma_destination[channel]+=8;
+ break;
+ case 1:
+ if (m_dma_destination_increment[channel] == 2)
+ m_dma_destination[channel]--;
+ m_program->write_byte(m_dma_destination[channel], *(uint8_t *)data);
+ if (m_dma_destination_increment[channel] == 1)
+ m_dma_destination[channel]++;
+ break;
+ case 2:
+ if (m_dma_destination_increment[channel] == 2)
+ m_dma_destination[channel]-=2;
+ m_program->write_word(m_dma_destination[channel] & ~1, *(uint16_t *)data);
+ if (m_dma_destination_increment[channel] == 1)
+ m_dma_destination[channel]+=2;
+ break;
+ case 4:
+ if (m_dma_destination_increment[channel] == 2)
+ m_dma_destination[channel]-=4;
+ m_program->write_dword(m_dma_destination[channel] & ~3, *(uint32_t *)data);
+ if (m_dma_destination_increment[channel] == 1)
+ m_dma_destination[channel]+=4;
+ break;
+ case 32:
+ if (m_dma_destination_increment[channel] == 2)
+ m_dma_destination[channel]-=32;
+ m_program->write_qword(m_dma_destination[channel] & ~31, *(uint64_t *)data);
+ m_program->write_qword((m_dma_destination[channel] & ~31)+8, *((uint64_t *)data+1));
+ m_program->write_qword((m_dma_destination[channel] & ~31)+16, *((uint64_t *)data+2));
+ m_program->write_qword((m_dma_destination[channel] & ~31)+24, *((uint64_t *)data+3));
+ if (m_dma_destination_increment[channel] == 1)
+ m_dma_destination[channel]+=32;
+ break;
+ }
+ m_dma_count[channel]--;
+ }
+
+ if (m_dma_count[channel] == 0) // all data transferred ?
+ {
+ m_dma_timer[channel]->adjust(attotime::zero, channel);
+ return 2;
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+// called by drivers to transfer data in a DDT dma.
+void sh34_base_device::sh4_dma_ddt(struct sh4_ddt_dma *s)
+{
+ uint32_t chcr;
+ uint32_t *p32bits;
+ uint64_t *p32bytes;
+ uint32_t pos,len,siz;
+
+ if (m_cpu_type != CPU_TYPE_SH4)
+ fatalerror("sh4_dma_ddt uses m_m[] with SH3\n");
+
+ if (m_dma_timer_active[s->channel])
+ return;
+ if (s->mode >= 0) {
+ switch (s->channel)
+ {
+ case 0:
+ if (s->mode & 1)
+ s->source = m_SH4_SAR0;
+ if (s->mode & 2)
+ m_SH4_SAR0 = s->source;
+ if (s->mode & 4)
+ s->destination = m_SH4_DAR0;
+ if (s->mode & 8)
+ m_SH4_DAR0 = s->destination;
+ break;
+ case 1:
+ if (s->mode & 1)
+ s->source = m_SH4_SAR1;
+ if (s->mode & 2)
+ m_SH4_SAR1 = s->source;
+ if (s->mode & 4)
+ s->destination = m_SH4_DAR1;
+ if (s->mode & 8)
+ m_SH4_DAR1 = s->destination;
+ break;
+ case 2:
+ if (s->mode & 1)
+ s->source = m_SH4_SAR2;
+ if (s->mode & 2)
+ m_SH4_SAR2 = s->source;
+ if (s->mode & 4)
+ s->destination = m_SH4_DAR2;
+ if (s->mode & 8)
+ m_SH4_DAR2 = s->destination;
+ break;
+ case 3:
+ default:
+ if (s->mode & 1)
+ s->source = m_SH4_SAR3;
+ if (s->mode & 2)
+ m_SH4_SAR3 = s->source;
+ if (s->mode & 4)
+ s->destination = m_SH4_DAR3;
+ if (s->mode & 8)
+ m_SH4_DAR3 = s->destination;
+ break;
+ }
+ switch (s->channel)
+ {
+ case 0:
+ chcr = m_SH4_CHCR0;
+ len = m_SH4_DMATCR0;
+ break;
+ case 1:
+ chcr = m_SH4_CHCR1;
+ len = m_SH4_DMATCR1;
+ break;
+ case 2:
+ chcr = m_SH4_CHCR2;
+ len = m_SH4_DMATCR2;
+ break;
+ case 3:
+ default:
+ chcr = m_SH4_CHCR3;
+ len = m_SH4_DMATCR3;
+ break;
+ }
+ if ((s->direction) == 0) {
+ chcr = (chcr & 0xffff3fff) | ((s->mode & 0x30) << 10);
+ } else {
+ chcr = (chcr & 0xffffcfff) | ((s->mode & 0x30) << 8);
+ }
+
+
+ if (m_cpu_type == CPU_TYPE_SH4)
+ {
+ //siz = dmasize[(chcr & CHCR_TS) >> 4];
+ siz = dmasize[(chcr >> 4) & 7];
+ }
+ else
+ {
+ siz = sh3_dmasize[(chcr >> 3) & 3];
+ }
+
+
+ if (siz && (s->size))
+ if ((len * siz) != (s->length * s->size))
+ return;
+ sh4_dma_transfer(s->channel, 0, chcr, &s->source, &s->destination, &len);
+ } else {
+ if (s->size == 4) {
+ if ((s->direction) == 0) {
+ len = s->length;
+ p32bits = (uint32_t *)(s->buffer);
+ for (pos = 0;pos < len;pos++) {
+ *p32bits = m_program->read_dword(s->source);
+ p32bits++;
+ s->source = s->source + 4;
+ }
+ } else {
+ len = s->length;
+ p32bits = (uint32_t *)(s->buffer);
+ for (pos = 0;pos < len;pos++) {
+ m_program->write_dword(s->destination, *p32bits);
+ p32bits++;
+ s->destination = s->destination + 4;
+ }
+ }
+ }
+ if (s->size == 32) {
+ if ((s->direction) == 0) {
+ len = s->length * 4;
+ p32bytes = (uint64_t *)(s->buffer);
+ for (pos = 0;pos < len;pos++) {
+ *p32bytes = m_program->read_qword(s->source);
+ p32bytes++;
+ s->destination = s->destination + 8;
+ }
+ } else {
+ len = s->length * 4;
+ p32bytes = (uint64_t *)(s->buffer);
+ for (pos = 0;pos < len;pos++) {
+ m_program->write_qword(s->destination, *p32bytes);
+ p32bytes++;
+ s->destination = s->destination + 8;
+ }
+ }
+ }
+ }
+}
+
+
+ void sh34_base_device::sh4_handle_sar0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_SAR0);
+}
+
+ void sh34_base_device::sh4_handle_sar1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_SAR1);
+}
+
+ void sh34_base_device::sh4_handle_sar2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_SAR2);
+}
+
+ void sh34_base_device::sh4_handle_sar3_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_SAR3);
+}
+
+ void sh34_base_device::sh4_handle_dar0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DAR0);
+}
+
+ void sh34_base_device::sh4_handle_dar1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DAR1);
+}
+
+ void sh34_base_device::sh4_handle_dar2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DAR2);
+}
+
+ void sh34_base_device::sh4_handle_dar3_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DAR3);
+}
+
+ void sh34_base_device::sh4_handle_dmatcr0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DMATCR0);
+}
+
+ void sh34_base_device::sh4_handle_dmatcr1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DMATCR1);
+}
+
+ void sh34_base_device::sh4_handle_dmatcr2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DMATCR2);
+}
+
+ void sh34_base_device::sh4_handle_dmatcr3_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_DMATCR3);
+}
+
+ void sh34_base_device::sh4_handle_chcr0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_CHCR0);
+ sh4_dmac_check(0);
+}
+
+ void sh34_base_device::sh4_handle_chcr1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_CHCR1);
+ sh4_dmac_check(1);
+}
+
+ void sh34_base_device::sh4_handle_chcr2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_CHCR2);
+ sh4_dmac_check(2);
+}
+
+ void sh34_base_device::sh4_handle_chcr3_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_CHCR3);
+ sh4_dmac_check(3);
+}
+
+ void sh34_base_device::sh4_handle_dmaor_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ uint32_t old = m_SH4_DMAOR;
+ COMBINE_DATA(&m_SH4_DMAOR);
+
+ if ((m_SH4_DMAOR & DMAOR_AE) && (~old & DMAOR_AE))
+ m_SH4_DMAOR &= ~DMAOR_AE;
+ if ((m_SH4_DMAOR & DMAOR_NMIF) && (~old & DMAOR_NMIF))
+ m_SH4_DMAOR &= ~DMAOR_NMIF;
+ sh4_dmac_check(0);
+ sh4_dmac_check(1);
+ sh4_dmac_check(2);
+ sh4_dmac_check(3);
+}
diff --git a/src/devices/cpu/sh/sh4dmac.h b/src/devices/cpu/sh/sh4dmac.h
new file mode 100644
index 00000000000..b7918fac997
--- /dev/null
+++ b/src/devices/cpu/sh/sh4dmac.h
@@ -0,0 +1,63 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/* SHA3/4 DMA Controller */
+
+/* bit definitions */
+#define CHCR_SSA 0xe0000000
+#define CHCR_STC 0x10000000
+#define CHCR_DSA 0x0e000000
+#define CHCR_DTC 0x01000000
+#define CHCR_DS 0x00080000
+#define CHCR_RL 0x00040000
+#define CHCR_AM 0x00020000
+#define CHCR_AL 0x00010000
+#define CHCR_DM 0x0000c000
+#define CHCR_SM 0x00003000
+#define CHCR_RS 0x00000f00
+#define CHCR_TM 0x00000080
+#define CHCR_TS 0x00000070
+#define CHCR_IE 0x00000004
+#define CHCR_TE 0x00000002
+#define CHCR_DE 0x00000001
+
+#define DMAOR_DDT 0x8000
+#define DMAOR_PR 0x0300
+#define DMAOR_COD 0x0010
+#define DMAOR_AE 0x0004
+#define DMAOR_NMIF 0x0002
+#define DMAOR_DME 0x0001
+
+void sh4_handle_sar0_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_sar1_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_sar2_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_sar3_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dar0_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dar1_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dar2_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dar3_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dmatcr0_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dmatcr1_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dmatcr2_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dmatcr3_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_chcr0_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_chcr1_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_chcr2_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_chcr3_addr_w(uint32_t data, uint32_t mem_mask);
+void sh4_handle_dmaor_addr_w(uint32_t data, uint32_t mem_mask);
+uint32_t sh4_handle_sar0_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_sar1_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_sar2_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_sar3_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dar0_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dar1_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dar2_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dar3_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dmatcr0_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dmatcr1_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dmatcr2_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dmatcr3_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_chcr0_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_chcr1_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_chcr2_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_chcr3_addr_r(uint32_t mem_mask);
+uint32_t sh4_handle_dmaor_addr_r(uint32_t mem_mask);
diff --git a/src/devices/cpu/sh/sh4regs.h b/src/devices/cpu/sh/sh4regs.h
new file mode 100644
index 00000000000..384f062858e
--- /dev/null
+++ b/src/devices/cpu/sh/sh4regs.h
@@ -0,0 +1,183 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+#pragma once
+
+#ifndef __SH4REGS_H__
+#define __SH4REGS_H__
+
+/* 00000001111111100000000011111100 */
+#define PTEH 0x2000 /* FF000000 */
+#define PTEL 0x2001 /* FF000004 */
+#define TTB 0x2002 /* FF000008 */
+#define TEA 0x2003 /* FF00000C */
+#define MMUCR 0x2004 /* FF000010 */
+#define BASRA 0x2005 /* FF000014 */
+#define BASRB 0x2006 /* FF000018 */
+#define CCR 0x2007 /* FF00001C */
+#define TRA 0x2008 /* FF000020 */
+#define EXPEVT 0x2009 /* FF000024 */
+#define INTEVT 0x200A /* FF000028 */
+#define VERSION 0x200C /* FF000030 */
+#define PTEA 0x200D /* FF000034 */
+#define QACR0 0x200E /* FF000038 */
+#define QACR1 0x200F /* FF00003C */
+#define PRR 0x2011 /* FF000044 */
+#define BARA 0x2400 /* FF200000 */
+#define BAMRA 0x2401 /* FF200004 */
+#define BBRA 0x2402 /* FF200008 */
+#define BARB 0x2403 /* FF20000C */
+#define BAMRB 0x2404 /* FF200010 */
+#define BBRB 0x2405 /* FF200014 */
+#define BDRB 0x2406 /* FF200018 */
+#define BDMRB 0x2407 /* FF20001C */
+#define BRCR 0x2408 /* FF200020 */
+#define BCR1 0x3000 /* FF800000 */
+#define BCR2 0x3001 /* FF800004 */
+#define BCR3 0x3014 /* FF800050 */
+#define BCR4 0x17C /* FE0A00F0 */
+#define WCR1 0x3002 /* FF800008 */
+#define WCR2 0x3003 /* FF80000C */
+#define WCR3 0x3004 /* FF800010 */
+#define MCR 0x3005 /* FF800014 */
+#define PCR 0x3006 /* FF800018 */
+#define RTCSR 0x3007 /* FF80001C */
+#define RTCNT 0x3008 /* FF800020 */
+#define RTCOR 0x3009 /* FF800024 */
+#define RFCR 0x300A /* FF800028 */
+#define PCTRA 0x300B /* FF80002C */
+#define PDTRA 0x300C /* FF800030 */
+#define PCTRB 0x3010 /* FF800040 */
+#define PDTRB 0x3011 /* FF800044 */
+#define GPIOIC 0x3012 /* FF800048 */
+#define SDMR2 0x3200 /* FF900000 */
+#define SDMR3 0x3280 /* FF940000 */
+#define SH4_SAR0_ADDR 0x3400 /* FFA00000 */
+#define SH4_DAR0_ADDR 0x3401 /* FFA00004 */
+#define SH4_DMATCR0_ADDR 0x3402 /* FFA00008 */
+#define SH4_CHCR0_ADDR 0x3403 /* FFA0000C */
+#define SH4_SAR1_ADDR 0x3404 /* FFA00010 */
+#define SH4_DAR1_ADDR 0x3405 /* FFA00014 */
+#define SH4_DMATCR1_ADDR 0x3406 /* FFA00018 */
+#define SH4_CHCR1_ADDR 0x3407 /* FFA0001C */
+#define SH4_SAR2_ADDR 0x3408 /* FFA00020 */
+#define SH4_DAR2_ADDR 0x3409 /* FFA00024 */
+#define SH4_DMATCR2_ADDR 0x340A /* FFA00028 */
+#define SH4_CHCR2_ADDR 0x340B /* FFA0002C */
+#define SH4_SAR3_ADDR 0x340C /* FFA00030 */
+#define SH4_DAR3_ADDR 0x340D /* FFA00034 */
+#define SH4_DMATCR3_ADDR 0x340E /* FFA00038 */
+#define SH4_CHCR3_ADDR 0x340F /* FFA0003C */
+#define SH4_DMAOR_ADDR 0x3410 /* FFA00040 */
+#define SAR4 0x3414 /* FFA00050 */
+#define DAR4 0x3415 /* FFA00054 */
+#define DMATCR4 0x3416 /* FFA00058 */
+#define CHCR4 0x3417 /* FFA0005C */
+#define SAR5 0x3418 /* FFA00060 */
+#define DAR5 0x3419 /* FFA00064 */
+#define DMATCR5 0x341A /* FFA00068 */
+#define CHCR5 0x341B /* FFA0006C */
+#define SAR6 0x341C /* FFA00070 */
+#define DAR6 0x341D /* FFA00074 */
+#define DMATCR6 0x341E /* FFA00078 */
+#define CHCR6 0x341F /* FFA0007C */
+#define SAR7 0x3420 /* FFA00080 */
+#define DAR7 0x3421 /* FFA00084 */
+#define DMATCR7 0x3422 /* FFA00088 */
+#define CHCR7 0x3423 /* FFA0008C */
+#define FRQCR 0x3800 /* FFC00000 */
+#define STBCR 0x3801 /* FFC00004 */
+#define WTCNT 0x3802 /* FFC00008 */
+#define WTCSR 0x3803 /* FFC0000C */
+#define STBCR2 0x3804 /* FFC00010 */
+#define R64CNT 0x3900 /* FFC80000 */
+#define RSECCNT 0x3901 /* FFC80004 */
+#define RMINCNT 0x3902 /* FFC80008 */
+#define RHRCNT 0x3903 /* FFC8000C */
+#define RWKCNT 0x3904 /* FFC80010 */
+#define RDAYCNT 0x3905 /* FFC80014 */
+#define RMONCNT 0x3906 /* FFC80018 */
+#define RYRCNT 0x3907 /* FFC8001C */
+#define RSECAR 0x3908 /* FFC80020 */
+#define RMINAR 0x3909 /* FFC80024 */
+#define RHRAR 0x390A /* FFC80028 */
+#define RWKAR 0x390B /* FFC8002C */
+#define RDAYAR 0x390C /* FFC80030 */
+#define RMONAR 0x390D /* FFC80034 */
+#define RCR1 0x390E /* FFC80038 */
+#define RCR2 0x390F /* FFC8003C */
+#define RCR3 0x3914 /* FFC80050 */
+#define RYRAR 0x3915 /* FFC80054 */
+#define ICR 0x3A00 /* FFD00000 */
+#define IPRA 0x3A01 /* FFD00004 */
+#define IPRB 0x3A02 /* FFD00008 */
+#define IPRC 0x3A03 /* FFD0000C */
+#define IPRD 0x3A04 /* FFD00010 */
+#define INTPRI00 0x100 /* FE080000 */
+#define INTREQ00 0x108 /* FE080020 */
+#define INTMSK00 0x110 /* FE080040 */
+#define INTMSKCLR00 0x118 /* FE080060 */
+#define CLKSTP00 0x140 /* FE0A0000 */
+#define CLKSTPCLR00 0x142 /* FE0A0008 */
+#define TSTR2 0x201 /* FE100004 */
+#define TCOR3 0x202 /* FE100008 */
+#define TCNT3 0x203 /* FE10000C */
+#define TCR3 0x204 /* FE100010 */
+#define TCOR4 0x205 /* FE100014 */
+#define TCNT4 0x206 /* FE100018 */
+#define TCR4 0x207 /* FE10001C */
+#define SH4_TOCR_ADDR 0x3B00 /* FFD80000 */
+#define SH4_TSTR_ADDR 0x3B01 /* FFD80004 */
+#define SH4_TCOR0_ADDR 0x3B02 /* FFD80008 */
+#define SH4_TCNT0_ADDR 0x3B03 /* FFD8000C */
+#define SH4_TCR0_ADDR 0x3B04 /* FFD80010 */
+#define SH4_TCOR1_ADDR 0x3B05 /* FFD80014 */
+#define SH4_TCNT1_ADDR 0x3B06 /* FFD80018 */
+#define SH4_TCR1_ADDR 0x3B07 /* FFD8001C */
+#define SH4_TCOR2_ADDR 0x3B08 /* FFD80020 */
+#define SH4_TCNT2_ADDR 0x3B09 /* FFD80024 */
+#define SH4_TCR2_ADDR 0x3B0A /* FFD80028 */
+#define SH4_TCPR2_ADDR 0x3B0B /* FFD8002C */
+#define SCSMR1 0x3C00 /* FFE00000 */
+#define SCBRR1 0x3C01 /* FFE00004 */
+#define SCSCR1 0x3C02 /* FFE00008 */
+#define SCTDR1 0x3C03 /* FFE0000C */
+#define SCSSR1 0x3C04 /* FFE00010 */
+#define SCRDR1 0x3C05 /* FFE00014 */
+#define SCSCMR1 0x3C06 /* FFE00018 */
+#define SCSPTR1 0x3C07 /* FFE0001C */
+#define SCSMR2 0x3D00 /* FFE80000 */
+#define SCBRR2 0x3D01 /* FFE80004 */
+#define SCSCR2 0x3D02 /* FFE80008 */
+#define SCFTDR2 0x3D03 /* FFE8000C */
+#define SCFSR2 0x3D04 /* FFE80010 */
+#define SCFRDR2 0x3D05 /* FFE80014 */
+#define SCFCR2 0x3D06 /* FFE80018 */
+#define SCFDR2 0x3D07 /* FFE8001C */
+#define SCSPTR2 0x3D08 /* FFE80020 */
+#define SCLSR2 0x3D09 /* FFE80024 */
+#define SDIR 0x3E00 /* FFF00000 */
+#define SDDR 0x3E02 /* FFF00008 */
+#define SDINT 0x3E05 /* FFF00014 */
+#define SIZEREGS 15878
+
+
+
+#define MMUCR_LRUI 0xfc000000
+#define MMUCR_URB 0x00fc0000
+#define MMUCR_URC 0x0000fc00
+#define MMUCR_SQMD 0x00000200
+#define MMUCR_SV 0x00000100
+#define MMUCR_TI 0x00000004
+#define MMUCR_AT 0x00000001
+
+/* constants */
+#define PVR_SH7091 0x040205c1
+#define PVR_SH7750 0x04020500 // from TN-SH7-361B/E
+#define PVR_SH7750S 0x04020600
+#define PVR_SH7750R 0x04050000
+#define PRR_SH7750R 0x00000100
+#define PVR_SH7751 0x04110000
+#define PVR_SH7751R 0x04050000
+#define PRR_SH7751R 0x00000110
+
+#endif /* __SH4REGS_H__ */
diff --git a/src/devices/cpu/sh/sh4tmu.cpp b/src/devices/cpu/sh/sh4tmu.cpp
new file mode 100644
index 00000000000..4735b8bba67
--- /dev/null
+++ b/src/devices/cpu/sh/sh4tmu.cpp
@@ -0,0 +1,324 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/* SH3/4 Timer Unit */
+
+#include "emu.h"
+#include "debugger.h"
+#include "sh4.h"
+#include "sh4comn.h"
+#include "sh3comn.h"
+#include "sh4tmu.h"
+
+static const int tcnt_div[8] = { 4, 16, 64, 256, 1024, 1, 1, 1 };
+
+/*-------------------------------------------------
+ sh4_scale_up_mame_time - multiply a attotime by
+ a (constant+1) where 0 <= constant < 2^32
+-------------------------------------------------*/
+
+static inline attotime sh4_scale_up_mame_time(const attotime &_time1, uint32_t factor1)
+{
+ return _time1 * factor1 + _time1;
+}
+
+static uint32_t compute_ticks_timer(emu_timer *timer, int hertz, int divisor)
+{
+ double ret;
+
+ ret=((timer->remaining().as_double() * (double)hertz) / (double)divisor) - 1;
+ return (uint32_t)ret;
+}
+
+void sh34_base_device::sh4_timer_recompute(int which)
+{
+ double ticks;
+
+ uint32_t tcnt = 0;
+ uint32_t tcr = 0;
+ switch (which)
+ {
+ case 0:
+ tcr = m_SH4_TCR0;
+ tcnt = m_SH4_TCNT0;
+ break;
+
+ case 1:
+ tcr = m_SH4_TCR1;
+ tcnt = m_SH4_TCNT1;
+ break;
+
+ case 2:
+ tcr = m_SH4_TCR2;
+ tcnt = m_SH4_TCNT2;
+ break;
+ }
+
+ ticks = tcnt;
+ m_timer[which]->adjust(sh4_scale_up_mame_time(attotime::from_hz(m_pm_clock) * tcnt_div[tcr & 7], ticks), which);
+}
+
+
+TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_timer_callback )
+{
+ int which = param;
+
+ switch (which)
+ {
+ case 0:
+ m_SH4_TCNT0 = m_SH4_TCOR0;
+ break;
+
+ case 1:
+ m_SH4_TCNT1 = m_SH4_TCOR1;
+ break;
+
+ case 2:
+ m_SH4_TCNT2 = m_SH4_TCOR2;
+ break;
+
+ }
+
+ sh4_timer_recompute(which);
+
+ switch (which)
+ {
+ case 0:
+ m_SH4_TCR0 |= 0x100;
+ break;
+
+ case 1:
+ m_SH4_TCR1 |= 0x100;
+ break;
+
+ case 2:
+ m_SH4_TCR2 |= 0x100;
+ break;
+
+ }
+
+ switch (which)
+ {
+ case 0:
+ if (m_SH4_TCR0 & 0x20)
+ {
+ sh4_exception_request(SH4_INTC_TUNI0);
+ // logerror("SH4_INTC_TUNI0 requested\n");
+ }
+ break;
+
+ case 1:
+ if (m_SH4_TCR1 & 0x20)
+ {
+ sh4_exception_request(SH4_INTC_TUNI1);
+ // logerror("SH4_INTC_TUNI1 requested\n");
+ }
+ break;
+
+ case 2:
+ if (m_SH4_TCR2 & 0x20)
+ {
+ sh4_exception_request(SH4_INTC_TUNI2);
+ // logerror("SH4_INTC_TUNI2 requested\n");
+ }
+ break;
+
+ }
+}
+
+
+uint32_t sh34_base_device::sh4_handle_tcnt0_addr_r(uint32_t mem_mask)
+{
+ if (m_SH4_TSTR & 1)
+ return compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[m_SH4_TCR0 & 7]);
+ else
+ return m_SH4_TCNT0;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcnt1_addr_r(uint32_t mem_mask)
+{
+ if (m_SH4_TSTR & 2)
+ return compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[m_SH4_TCR1 & 7]);
+ else
+ return m_SH4_TCNT1;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcnt2_addr_r(uint32_t mem_mask)
+{
+ if (m_SH4_TSTR & 4)
+ return compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[m_SH4_TCR2 & 7]);
+ else
+ return m_SH4_TCNT2;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcor0_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCOR0;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcor1_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCOR1;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcor2_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCOR2;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcr0_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCR0;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcr1_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCR1;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcr2_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCR2;
+}
+
+uint32_t sh34_base_device::sh4_handle_tstr_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TSTR;
+}
+
+uint32_t sh34_base_device::sh4_handle_tocr_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TOCR;
+}
+
+uint32_t sh34_base_device::sh4_handle_tcpr2_addr_r(uint32_t mem_mask)
+{
+ return m_SH4_TCPR2;
+}
+
+
+void sh34_base_device::sh4_handle_tstr_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ uint32_t old2 = m_SH4_TSTR;
+ COMBINE_DATA(&m_SH4_TSTR);
+
+ if (old2 & 1)
+ m_SH4_TCNT0 = compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[m_SH4_TCR0 & 7]);
+ if ((m_SH4_TSTR & 1) == 0) {
+ m_timer[0]->adjust(attotime::never);
+ } else
+ sh4_timer_recompute(0);
+
+ if (old2 & 2)
+ m_SH4_TCNT1 = compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[m_SH4_TCR1 & 7]);
+ if ((m_SH4_TSTR & 2) == 0) {
+ m_timer[1]->adjust(attotime::never);
+ } else
+ sh4_timer_recompute(1);
+
+ if (old2 & 4)
+ m_SH4_TCNT2 = compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[m_SH4_TCR2 & 7]);
+ if ((m_SH4_TSTR & 4) == 0) {
+ m_timer[2]->adjust(attotime::never);
+ } else
+ sh4_timer_recompute(2);
+}
+
+void sh34_base_device::sh4_handle_tcr0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ uint32_t old2 = m_SH4_TCR0;
+ COMBINE_DATA(&m_SH4_TCR0);
+ if (m_SH4_TSTR & 1)
+ {
+ m_SH4_TCNT0 = compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[old2 & 7]);
+ sh4_timer_recompute(0);
+ }
+ if (!(m_SH4_TCR0 & 0x20) || !(m_SH4_TCR0 & 0x100))
+ sh4_exception_unrequest(SH4_INTC_TUNI0);
+}
+
+void sh34_base_device::sh4_handle_tcr1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ uint32_t old2 = m_SH4_TCR1;
+ COMBINE_DATA(&m_SH4_TCR1);
+ if (m_SH4_TSTR & 2)
+ {
+ m_SH4_TCNT1 = compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[old2 & 7]);
+ sh4_timer_recompute(1);
+ }
+ if (!(m_SH4_TCR1 & 0x20) || !(m_SH4_TCR1 & 0x100))
+ sh4_exception_unrequest(SH4_INTC_TUNI1);
+}
+
+void sh34_base_device::sh4_handle_tcr2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ uint32_t old2 = m_SH4_TCR2;
+ COMBINE_DATA(&m_SH4_TCR2);
+ if (m_SH4_TSTR & 4)
+ {
+ m_SH4_TCNT2 = compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[old2 & 7]);
+ sh4_timer_recompute(2);
+ }
+ if (!(m_SH4_TCR2 & 0x20) || !(m_SH4_TCR2 & 0x100))
+ sh4_exception_unrequest(SH4_INTC_TUNI2);
+}
+
+void sh34_base_device::sh4_handle_tcor0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCOR0);
+ if (m_SH4_TSTR & 1)
+ {
+ m_SH4_TCNT0 = compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[m_SH4_TCR0 & 7]);
+ sh4_timer_recompute(0);
+ }
+}
+
+void sh34_base_device::sh4_handle_tcor1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCOR1);
+ if (m_SH4_TSTR & 2)
+ {
+ m_SH4_TCNT1 = compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[m_SH4_TCR1 & 7]);
+ sh4_timer_recompute(1);
+ }
+}
+
+void sh34_base_device::sh4_handle_tcor2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCOR2);
+ if (m_SH4_TSTR & 4)
+ {
+ m_SH4_TCNT2 = compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[m_SH4_TCR2 & 7]);
+ sh4_timer_recompute(2);
+ }
+}
+
+void sh34_base_device::sh4_handle_tcnt0_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCNT0);
+ if (m_SH4_TSTR & 1)
+ sh4_timer_recompute(0);
+}
+
+void sh34_base_device::sh4_handle_tcnt1_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCNT1);
+ if (m_SH4_TSTR & 2)
+ sh4_timer_recompute(1);
+}
+
+void sh34_base_device::sh4_handle_tcnt2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCNT2);
+ if (m_SH4_TSTR & 4)
+ sh4_timer_recompute(2);
+}
+
+void sh34_base_device::sh4_handle_tocr_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TOCR);
+}
+
+void sh34_base_device::sh4_handle_tcpr2_addr_w(uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_SH4_TCPR2);
+}
diff --git a/src/devices/cpu/sh/sh4tmu.h b/src/devices/cpu/sh/sh4tmu.h
new file mode 100644
index 00000000000..7bbad37a0c1
--- /dev/null
+++ b/src/devices/cpu/sh/sh4tmu.h
@@ -0,0 +1,3 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/* SH3/4 Timer Unit */
diff --git a/src/devices/cpu/sh/sh7604_bus.cpp b/src/devices/cpu/sh/sh7604_bus.cpp
new file mode 100644
index 00000000000..f4000a46300
--- /dev/null
+++ b/src/devices/cpu/sh/sh7604_bus.cpp
@@ -0,0 +1,162 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+ SH7604 BUS Controller
+
+ Lies at 0xffffffe0-0xffffffff
+
+
+ TODO:
+ - Host CPU setter (is_slave and clock are needed);
+ - timer clock emulation;
+ - fix fatalerrors;
+ - bus control stuff, someday;
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh7604_bus.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(SH7604_BUS, sh7604_bus_device, "sh7604bus", "SH7604 BUS Controller")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+READ16_MEMBER(sh7604_bus_device::bus_control_1_r)
+{
+ return (m_bcr1 & 0x1ff7) | (m_is_slave == true ? 0x8000 : 0);
+}
+
+WRITE16_MEMBER(sh7604_bus_device::bus_control_1_w)
+{
+ COMBINE_DATA(&m_bcr1);
+ if(m_bcr1 & 0x1000) // ENDIAN
+ throw emu_fatalerror("%s: enabled little endian for Area 2\n", tag());
+ if(m_bcr1 & 0x0800) // PSHR
+ throw emu_fatalerror("%s: enabled partial space share mode\n", tag());
+}
+
+READ16_MEMBER(sh7604_bus_device::bus_control_2_r) { return m_bcr2 & 0x00fc; }
+WRITE16_MEMBER(sh7604_bus_device::bus_control_2_w)
+{
+ COMBINE_DATA(&m_bcr2);
+ if(m_bcr2 != 0x00fc)
+ throw emu_fatalerror("%s: unexpected bus size register set %04x\n", tag(),data);
+}
+
+READ16_MEMBER(sh7604_bus_device::wait_control_r) { return m_wcr; }
+WRITE16_MEMBER(sh7604_bus_device::wait_control_w) { COMBINE_DATA(&m_wcr); }
+
+READ16_MEMBER(sh7604_bus_device::memory_control_r) { return m_mcr & 0xfefc; }
+WRITE16_MEMBER(sh7604_bus_device::memory_control_w) { COMBINE_DATA(&m_mcr); }
+
+READ16_MEMBER(sh7604_bus_device::refresh_timer_status_r)
+{
+ return m_rtcsr & 0x00f8;
+}
+
+WRITE16_MEMBER(sh7604_bus_device::refresh_timer_control_w)
+{
+ COMBINE_DATA(&m_rtcsr);
+
+ if(m_rtcsr & 0x40)
+ throw emu_fatalerror("%s: enabled timer irq register with clock setting = %02x\n",tag(),data & 0x38);
+}
+
+READ16_MEMBER(sh7604_bus_device::refresh_timer_counter_r)
+{
+ throw emu_fatalerror("%s: reading timer counter!\n",tag());
+ return 0;
+}
+
+WRITE16_MEMBER(sh7604_bus_device::refresh_timer_counter_w)
+{
+ throw emu_fatalerror("%s: writing timer counter %04x\n",tag(),data);
+ //COMBINE_DATA(&m_rtcnt);
+}
+
+READ16_MEMBER(sh7604_bus_device::refresh_timer_constant_r)
+{
+ return m_rtcor & 0xff;
+}
+
+WRITE16_MEMBER(sh7604_bus_device::refresh_timer_constant_w)
+{
+ COMBINE_DATA(&m_rtcor);
+}
+
+DEVICE_ADDRESS_MAP_START( bus_regs, 16, sh7604_bus_device )
+ AM_RANGE(0x00, 0x01) AM_READWRITE(bus_control_1_r, bus_control_1_w)
+ AM_RANGE(0x02, 0x03) AM_READWRITE(bus_control_2_r, bus_control_2_w)
+ AM_RANGE(0x04, 0x05) AM_READWRITE(wait_control_r, wait_control_w)
+ AM_RANGE(0x06, 0x07) AM_READWRITE(memory_control_r, memory_control_w)
+ AM_RANGE(0x08, 0x09) AM_READWRITE(refresh_timer_status_r, refresh_timer_control_w)
+ AM_RANGE(0x0a, 0x0b) AM_READWRITE(refresh_timer_counter_r, refresh_timer_counter_w)
+ AM_RANGE(0x0c, 0x0d) AM_READWRITE(refresh_timer_constant_r, refresh_timer_constant_w)
+// AM_RANGE(0x0e, 0x0f) unmapped, mirror?
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// sh7604_bus_device - constructor
+//-------------------------------------------------
+
+sh7604_bus_device::sh7604_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SH7604_BUS, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sh7604_bus_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sh7604_bus_device::device_reset()
+{
+ m_bcr1 = 0x03f0;
+ m_bcr2 = 0x00fc;
+ m_wcr = 0xaaff;
+ m_mcr = 0x0000;
+ m_rtcsr = 0x0000;
+ m_rtcor = 0x0000;
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+READ32_MEMBER( sh7604_bus_device::read )
+{
+ // 16 bit access only, TODO
+ return space.read_word(offset) & 0xffff;
+}
+
+WRITE32_MEMBER( sh7604_bus_device::write )
+{
+ // TODO: 8 bit access is invalid
+ // if accessing bits 16-31, one must write ID = 0xa55a
+ if(ACCESSING_BITS_16_31)
+ {
+ // throw fatalerror if something trips it, presumably the write is going to be ignored
+ if((data & 0xffff0000) != 0xa55a0000)
+ throw emu_fatalerror("%s: making bus write with ID signature = %04x!\n", tag(),data >> 16);
+ }
+
+ space.write_word(offset,data & 0xffff);
+}
diff --git a/src/devices/cpu/sh/sh7604_bus.h b/src/devices/cpu/sh/sh7604_bus.h
new file mode 100644
index 00000000000..486ff93558f
--- /dev/null
+++ b/src/devices/cpu/sh/sh7604_bus.h
@@ -0,0 +1,77 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+ SH7604 BUS Controller
+
+***************************************************************************/
+
+#ifndef MAME_CPU_SH2_SH7604_BUS_H
+#define MAME_CPU_SH2_SH7604_BUS_H
+
+#pragma once
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_SH7604_BUS_ADD(_tag,_freq) \
+ MCFG_DEVICE_ADD(_tag, SH7604_BUS, _freq)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> sh7604_bus_device
+
+class sh7604_bus_device : public device_t
+{
+public:
+ // construction/destruction
+ sh7604_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // I/O operations
+ DECLARE_ADDRESS_MAP( bus_regs, 16 );
+
+ DECLARE_WRITE32_MEMBER( write );
+ DECLARE_READ32_MEMBER( read );
+ DECLARE_READ16_MEMBER( bus_control_1_r );
+ DECLARE_WRITE16_MEMBER( bus_control_1_w );
+ DECLARE_READ16_MEMBER( bus_control_2_r );
+ DECLARE_WRITE16_MEMBER( bus_control_2_w );
+ DECLARE_READ16_MEMBER( wait_control_r );
+ DECLARE_WRITE16_MEMBER( wait_control_w );
+ DECLARE_READ16_MEMBER( memory_control_r );
+ DECLARE_WRITE16_MEMBER( memory_control_w );
+ DECLARE_READ16_MEMBER( refresh_timer_status_r );
+ DECLARE_WRITE16_MEMBER( refresh_timer_control_w );
+ DECLARE_READ16_MEMBER( refresh_timer_counter_r );
+ DECLARE_WRITE16_MEMBER( refresh_timer_counter_w );
+ DECLARE_READ16_MEMBER( refresh_timer_constant_r );
+ DECLARE_WRITE16_MEMBER( refresh_timer_constant_w );
+
+protected:
+ // device-level overrides
+ //virtual void device_validity_check(validity_checker &valid) const;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ bool m_is_slave;
+ const address_space_config m_space_config;
+
+ uint16_t m_bcr1;
+ uint16_t m_bcr2;
+ uint16_t m_wcr;
+ uint16_t m_mcr;
+ uint16_t m_rtcsr;
+ uint16_t m_rtcor;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(SH7604_BUS, sh7604_bus_device)
+
+#endif // MAME_CPU_SH2_SH7604_BUS_H
diff --git a/src/devices/cpu/sh/sh7604_sci.cpp b/src/devices/cpu/sh/sh7604_sci.cpp
new file mode 100644
index 00000000000..248e0112622
--- /dev/null
+++ b/src/devices/cpu/sh/sh7604_sci.cpp
@@ -0,0 +1,156 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+ SH7604 SCI Controller
+
+ Lies at 0xfffffe00-0xfffffe0f
+
+ TODO:
+ - diserial;
+ - CPU callbacks for RX and TX;
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh7604_sci.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(SH7604_SCI, sh7604_sci_device, "sh7604sci", "SH7604 SCI Controller")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+READ8_MEMBER(sh7604_sci_device::serial_mode_r)
+{
+ return m_smr;
+}
+
+WRITE8_MEMBER(sh7604_sci_device::serial_mode_w)
+{
+ m_smr = data;
+
+ logerror("%s: serial mode set:\n",tag());
+ logerror("\tCommunication Mode: %s mode\n",data & 0x80 ? "clocked synchronous" : "asynchronous");
+ logerror("\tCharacter Length: %s mode\n",data & 0x40 ? "7-bit" : "8-bit");
+ logerror("\tParity Enable: %s\n",data & 0x20 ? "yes" : "no");
+ logerror("\tParity Mode: %s\n",data & 0x10 ? "Odd" : "Even");
+ logerror("\tStop bits: %s\n",data & 0x08 ? "2" : "1");
+ logerror("\tMultiprocessor mode: %s\n",data & 0x04 ? "yes" : "no");
+ logerror("\tClock select: clock/%d\n",4 << ((data & 0x03)*2));
+}
+
+READ8_MEMBER(sh7604_sci_device::serial_control_r)
+{
+ return m_scr;
+}
+
+WRITE8_MEMBER(sh7604_sci_device::serial_control_w)
+{
+ m_scr = data;
+
+ if(data & 0x30)
+ throw emu_fatalerror("%s: enabled serial control %02x\n", tag(),data);
+}
+
+READ8_MEMBER(sh7604_sci_device::serial_status_r)
+{
+ return m_ssr;
+}
+
+WRITE8_MEMBER(sh7604_sci_device::serial_ack_w)
+{
+ // TODO: verify this
+ m_ssr = (m_ssr & 0x06) | (m_ssr & data & 0xf9);
+}
+
+READ8_MEMBER(sh7604_sci_device::bitrate_r )
+{
+ return m_brr;
+}
+
+WRITE8_MEMBER(sh7604_sci_device::bitrate_w )
+{
+ m_brr = data;
+}
+
+READ8_MEMBER(sh7604_sci_device::transmit_data_r)
+{
+ // ...
+ return 0;
+}
+
+WRITE8_MEMBER(sh7604_sci_device::transmit_data_w)
+{
+ // ...
+}
+
+READ8_MEMBER(sh7604_sci_device::receive_data_r)
+{
+ // ...
+ return 0;
+}
+
+DEVICE_ADDRESS_MAP_START( sci_regs, 8, sh7604_sci_device )
+ AM_RANGE(0x00, 0x00) AM_READWRITE(serial_mode_r, serial_mode_w)
+ AM_RANGE(0x01, 0x01) AM_READWRITE(bitrate_r, bitrate_w)
+ AM_RANGE(0x02, 0x02) AM_READWRITE(serial_control_r,serial_control_w)
+ AM_RANGE(0x03, 0x03) AM_READWRITE(transmit_data_r, transmit_data_w)
+ AM_RANGE(0x04, 0x04) AM_READWRITE(serial_status_r, serial_ack_w)
+ AM_RANGE(0x05, 0x05) AM_READ(receive_data_r)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// sh7604_sci_device - constructor
+//-------------------------------------------------
+
+sh7604_sci_device::sh7604_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SH7604_SCI, tag, owner, clock)
+
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sh7604_sci_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sh7604_sci_device::device_reset()
+{
+ m_smr = 0;
+ m_scr = 0;
+ m_ssr = STATUS_TDRE|STATUS_TEND; //0x84;
+ m_brr = 0xff;
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+READ8_MEMBER( sh7604_sci_device::read )
+{
+ return space.read_byte(offset);
+}
+
+WRITE8_MEMBER( sh7604_sci_device::write )
+{
+ space.write_byte(offset,data);
+}
diff --git a/src/devices/cpu/sh/sh7604_sci.h b/src/devices/cpu/sh/sh7604_sci.h
new file mode 100644
index 00000000000..d7a290f6946
--- /dev/null
+++ b/src/devices/cpu/sh/sh7604_sci.h
@@ -0,0 +1,83 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+ SH7604 SCI Controller
+
+***************************************************************************/
+
+#ifndef MAME_CPU_SH2_SH7604_SCI_H
+#define MAME_CPU_SH2_SH7604_SCI_H
+
+#pragma once
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_SH7604_SCI_ADD(_tag,_freq) \
+ MCFG_DEVICE_ADD(_tag, SH7604_SCI, _freq)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> sh7604_sci_device
+
+class sh7604_sci_device : public device_t
+{
+public:
+ // construction/destruction
+ sh7604_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // I/O operations
+ DECLARE_ADDRESS_MAP( sci_regs, 8 );
+
+ DECLARE_WRITE8_MEMBER( write );
+ DECLARE_READ8_MEMBER( read );
+
+ DECLARE_READ8_MEMBER( serial_mode_r );
+ DECLARE_WRITE8_MEMBER( serial_mode_w );
+ DECLARE_READ8_MEMBER( bitrate_r );
+ DECLARE_WRITE8_MEMBER( bitrate_w );
+ DECLARE_READ8_MEMBER( serial_control_r );
+ DECLARE_WRITE8_MEMBER( serial_control_w );
+
+ DECLARE_READ8_MEMBER( transmit_data_r );
+ DECLARE_WRITE8_MEMBER( transmit_data_w );
+ DECLARE_READ8_MEMBER( serial_status_r );
+ DECLARE_WRITE8_MEMBER( serial_ack_w );
+ DECLARE_READ8_MEMBER( receive_data_r );
+
+protected:
+ enum {
+ STATUS_MPBT = 1 << 0,
+ STATUS_MPB = 1 << 1,
+ STATUS_TEND = 1 << 2,
+ STATUS_PER = 1 << 3,
+ STATUS_FER = 1 << 4,
+ STATUS_ORER = 1 << 5,
+ STATUS_RDRF = 1 << 6,
+ STATUS_TDRE = 1 << 7
+ };
+
+ // device-level overrides
+// virtual void device_validity_check(validity_checker &valid) const;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ const address_space_config m_space_config;
+ uint8_t m_smr;
+ uint8_t m_scr;
+ uint8_t m_ssr;
+ uint8_t m_brr;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(SH7604_SCI, sh7604_sci_device)
+
+#endif // MAME_CPU_SH2_SH7604_SCI_H
diff --git a/src/devices/cpu/sh/sh7604_wdt.cpp b/src/devices/cpu/sh/sh7604_wdt.cpp
new file mode 100644
index 00000000000..16b40f30768
--- /dev/null
+++ b/src/devices/cpu/sh/sh7604_wdt.cpp
@@ -0,0 +1,83 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+ SH7604 Watchdog Timer Controller
+
+ TODO:
+ - Host CPU setter (clock and callback for irq and reset lines);
+ - memory map (needs to verify if ID write is ok);
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sh7604_wdt.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(SH7604_WDT, sh7604_wdt_device, "sh7604wdt", "SH7604 Watchdog Timer")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+DEVICE_ADDRESS_MAP_START( wdt_regs, 8, sh7604_wdt_device )
+// AM_RANGE(0x00, 0x00) timer control/status
+// AM_RANGE(0x01, 0x01) timer counter
+// AM_RANGE(0x02, 0x02) write only, reset control register
+// AM_RANGE(0x03, 0x03) read status register, write reset status register
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// sh7604_wdt_device - constructor
+//-------------------------------------------------
+
+sh7604_wdt_device::sh7604_wdt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SH7604_WDT, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sh7604_wdt_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sh7604_wdt_device::device_reset()
+{
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+READ8_MEMBER( sh7604_wdt_device::read )
+{
+ return space.read_byte(offset);
+}
+
+WRITE16_MEMBER( sh7604_wdt_device::write )
+{
+ uint8_t id_param = data >> 8;
+ switch(id_param)
+ {
+ case 0xa5: space.write_byte(offset*2+0,data & 0xff); break;
+ case 0x5a: space.write_byte(offset*2+1,data & 0xff); break;
+ default: throw emu_fatalerror("%s: invalid id param write = %02x\n",tag(),id_param);
+ }
+}
diff --git a/src/devices/cpu/sh/sh7604_wdt.h b/src/devices/cpu/sh/sh7604_wdt.h
new file mode 100644
index 00000000000..7e014745f19
--- /dev/null
+++ b/src/devices/cpu/sh/sh7604_wdt.h
@@ -0,0 +1,54 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+ SH7604 Watchdog Timer Controller
+
+***************************************************************************/
+
+#ifndef MAME_CPU_SH7604_WDT_H
+#define MAME_CPU_SH7604_WDT_H
+
+#pragma once
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_SH7604_WDT_ADD(_tag,_freq) \
+ MCFG_DEVICE_ADD(_tag, SH7604_WDT, _freq)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> sh7604_wdt_device
+
+class sh7604_wdt_device : public device_t
+{
+public:
+ // construction/destruction
+ sh7604_wdt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // I/O operations
+ DECLARE_ADDRESS_MAP( wdt_regs, 8 );
+
+ DECLARE_WRITE16_MEMBER( write );
+ DECLARE_READ8_MEMBER( read );
+
+protected:
+ // device-level overrides
+// virtual void device_validity_check(validity_checker &valid) const;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+private:
+ const address_space_config m_space_config;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(SH7604_WDT, sh7604_wdt_device)
+
+#endif // MAME_CPU_SH7604_WDT_H