summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mips
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mips')
-rw-r--r--src/devices/cpu/mips/mips1.cpp883
-rw-r--r--src/devices/cpu/mips/mips1.h294
-rw-r--r--src/devices/cpu/mips/mips1dsm.cpp161
-rw-r--r--src/devices/cpu/mips/mips3.cpp786
-rw-r--r--src/devices/cpu/mips/mips3.h161
-rw-r--r--src/devices/cpu/mips/mips3com.cpp18
-rw-r--r--src/devices/cpu/mips/mips3com.h4
-rw-r--r--src/devices/cpu/mips/mips3drc.cpp565
-rw-r--r--src/devices/cpu/mips/mips3dsm.cpp216
-rw-r--r--src/devices/cpu/mips/mips3fe.cpp8
-rw-r--r--src/devices/cpu/mips/o2dprintf.hxx32
-rw-r--r--src/devices/cpu/mips/ps2vif1.cpp12
-rw-r--r--src/devices/cpu/mips/ps2vif1.h12
-rw-r--r--src/devices/cpu/mips/ps2vu.cpp15
-rw-r--r--src/devices/cpu/mips/ps2vu.h35
-rw-r--r--src/devices/cpu/mips/r4000.cpp1416
-rw-r--r--src/devices/cpu/mips/r4000.h152
17 files changed, 3151 insertions, 1619 deletions
diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp
index 6c491cb04ca..2316da4b25d 100644
--- a/src/devices/cpu/mips/mips1.cpp
+++ b/src/devices/cpu/mips/mips1.cpp
@@ -6,26 +6,183 @@
* IDT devices come in two variations: those with an "E" suffix include a TLB,
* while those without have hard-wired address translation.
*
- * TODO
- * - R3041 features
- * - cache emulation
+ * TODO:
+ * - multi-word cache line sizes
+ * - R3041 features
*
*/
#include "emu.h"
#include "mips1.h"
#include "mips1dsm.h"
-#include "debugger.h"
#include "softfloat3/source/include/softfloat.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_TLB (1U << 1)
-#define LOG_IOP (1U << 2)
-#define LOG_RISCOS (1U << 3)
//#define VERBOSE (LOG_GENERAL|LOG_TLB)
#include "logmacro.h"
+enum registers : unsigned
+{
+ MIPS1_R0 = 0,
+ MIPS1_COP0 = 32,
+ MIPS1_F0 = 64,
+
+ MIPS1_PC = 80,
+ MIPS1_HI,
+ MIPS1_LO,
+ MIPS1_FCR30,
+ MIPS1_FCR31,
+};
+
+enum exception : u32
+{
+ EXCEPTION_INTERRUPT = 0x00000000,
+ EXCEPTION_TLBMOD = 0x00000004,
+ EXCEPTION_TLBLOAD = 0x00000008,
+ EXCEPTION_TLBSTORE = 0x0000000c,
+ EXCEPTION_ADDRLOAD = 0x00000010,
+ EXCEPTION_ADDRSTORE = 0x00000014,
+ EXCEPTION_BUSINST = 0x00000018,
+ EXCEPTION_BUSDATA = 0x0000001c,
+ EXCEPTION_SYSCALL = 0x00000020,
+ EXCEPTION_BREAK = 0x00000024,
+ EXCEPTION_INVALIDOP = 0x00000028,
+ EXCEPTION_BADCOP = 0x0000002c,
+ EXCEPTION_OVERFLOW = 0x00000030,
+ EXCEPTION_TRAP = 0x00000034,
+
+ EXCEPTION_BADCOP0 = 0x0000002c,
+ EXCEPTION_BADCOP1 = 0x1000002c,
+ EXCEPTION_BADCOP2 = 0x2000002c,
+ EXCEPTION_BADCOP3 = 0x3000002c,
+};
+
+enum cop0_reg : u8
+{
+ COP0_Index = 0,
+ COP0_Random = 1,
+ COP0_EntryLo = 2,
+ COP0_BusCtrl = 2, // r3041 only
+ COP0_Config = 3, // r3041/r3071/r3081 only
+ COP0_Context = 4,
+ COP0_BadVAddr = 8,
+ COP0_Count = 9, // r3041 only
+ COP0_EntryHi = 10,
+ COP0_PortSize = 10, // r3041 only
+ COP0_Compare = 11, // r3041 only
+ COP0_Status = 12,
+ COP0_Cause = 13,
+ COP0_EPC = 14,
+ COP0_PRId = 15,
+};
+
+enum sr_mask : u32
+{
+ SR_IEc = 0x00000001, // interrupt enable (current)
+ SR_KUc = 0x00000002, // user mode (current)
+ SR_IEp = 0x00000004, // interrupt enable (previous)
+ SR_KUp = 0x00000008, // user mode (previous)
+ SR_IEo = 0x00000010, // interrupt enable (old)
+ SR_KUo = 0x00000020, // user mode (old)
+ SR_IMSW0 = 0x00000100, // software interrupt 0 enable
+ SR_IMSW1 = 0x00000200, // software interrupt 1 enable
+ SR_IMEX0 = 0x00000400, // external interrupt 0 enable
+ SR_IMEX1 = 0x00000800, // external interrupt 1 enable
+ SR_IMEX2 = 0x00001000, // external interrupt 2 enable
+ SR_IMEX3 = 0x00002000, // external interrupt 3 enable
+ SR_IMEX4 = 0x00004000, // external interrupt 4 enable
+ SR_IMEX5 = 0x00008000, // external interrupt 5 enable
+ SR_IsC = 0x00010000, // isolate (data) cache
+ SR_SwC = 0x00020000, // swap caches
+ SR_PZ = 0x00040000, // cache parity zero
+ SR_CM = 0x00080000, // cache miss
+ SR_PE = 0x00100000, // cache parity error
+ SR_TS = 0x00200000, // tlb shutdown
+ SR_BEV = 0x00400000, // boot exception vectors
+ SR_RE = 0x02000000, // reverse endianness in user mode
+ SR_COP0 = 0x10000000, // coprocessor 0 usable
+ SR_COP1 = 0x20000000, // coprocessor 1 usable
+ SR_COP2 = 0x40000000, // coprocessor 2 usable
+ SR_COP3 = 0x80000000, // coprocessor 3 usable
+
+ SR_KUIE = 0x0000003f, // all interrupt enable and user mode bits
+ SR_KUIEpc = 0x0000000f, // previous and current interrupt enable and user mode bits
+ SR_KUIEop = 0x0000003c, // old and previous interrupt enable and user mode bits
+ SR_IM = 0x0000ff00, // all interrupt mask bits
+};
+
+enum cause_mask : u32
+{
+ CAUSE_EXCCODE = 0x0000007c, // exception code
+ CAUSE_IPSW0 = 0x00000100, // software interrupt 0 pending
+ CAUSE_IPSW1 = 0x00000200, // software interrupt 1 pending
+ CAUSE_IPEX0 = 0x00000400, // external interrupt 0 pending
+ CAUSE_IPEX1 = 0x00000800, // external interrupt 1 pending
+ CAUSE_IPEX2 = 0x00001000, // external interrupt 2 pending
+ CAUSE_IPEX3 = 0x00002000, // external interrupt 3 pending
+ CAUSE_IPEX4 = 0x00004000, // external interrupt 4 pending
+ CAUSE_IPEX5 = 0x00008000, // external interrupt 5 pending
+ CAUSE_IP = 0x0000ff00, // interrupt pending
+ CAUSE_CE = 0x30000000, // co-processor error
+ CAUSE_BD = 0x80000000, // branch delay
+
+ CAUSE_IPEX = 0x0000fc00, // external interrupt pending
+};
+
+enum entryhi_mask : u32
+{
+ EH_VPN = 0xfffff000, // virtual page number
+ EH_ASID = 0x00000fc0, // address space identifier
+
+ EH_WM = 0xffffffc0, // write mask
+};
+enum entrylo_mask : u32
+{
+ EL_PFN = 0xfffff000, // physical frame
+ EL_N = 0x00000800, // noncacheable
+ EL_D = 0x00000400, // dirty
+ EL_V = 0x00000200, // valid
+ EL_G = 0x00000100, // global
+
+ EL_WM = 0xffffff00, // write mask
+};
+enum context_mask : u32
+{
+ PTE_BASE = 0xffe00000, // base address of page table
+ BAD_VPN = 0x001ffffc, // virtual address bits 30..12
+};
+
+enum cp1_fcr31_mask : u32
+{
+ FCR31_RM = 0x00000003, // rounding mode
+
+ FCR31_FI = 0x00000004, // inexact operation flag
+ FCR31_FU = 0x00000008, // underflow flag
+ FCR31_FO = 0x00000010, // overflow flag
+ FCR31_FZ = 0x00000020, // divide by zero flag
+ FCR31_FV = 0x00000040, // invalid operation flag
+
+ FCR31_EI = 0x00000080, // inexact operation enable
+ FCR31_EU = 0x00000100, // underflow enable
+ FCR31_EO = 0x00000200, // overflow enable
+ FCR31_EZ = 0x00000400, // divide by zero enable
+ FCR31_EV = 0x00000800, // invalid operation enable
+
+ FCR31_CI = 0x00001000, // inexact operation cause
+ FCR31_CU = 0x00002000, // underflow cause
+ FCR31_CO = 0x00004000, // overflow cause
+ FCR31_CZ = 0x00008000, // divide by zero cause
+ FCR31_CV = 0x00010000, // invalid operation cause
+ FCR31_CE = 0x00020000, // unimplemented operation cause
+
+ FCR31_C = 0x00800000, // condition
+
+ FCR31_FM = 0x0000007c, // flag mask
+ FCR31_EM = 0x00000f80, // enable mask
+ FCR31_CM = 0x0001f000, // cause mask (except unimplemented)
+};
+
#define RSREG ((op >> 21) & 31)
#define RTREG ((op >> 16) & 31)
#define RDREG ((op >> 11) & 31)
@@ -54,106 +211,91 @@ DEFINE_DEVICE_TYPE(R3071, r3071_device, "r3071", "IDT R3071")
DEFINE_DEVICE_TYPE(R3081, r3081_device, "r3081", "IDT R3081")
DEFINE_DEVICE_TYPE(SONYPS2_IOP, iop_device, "sonyiop", "Sony Playstation 2 IOP")
-ALLOW_SAVE_TYPE(mips1core_device_base::branch_state_t);
+ALLOW_SAVE_TYPE(mips1core_device_base::branch_state);
-mips1core_device_base::mips1core_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size)
+mips1core_device_base::mips1core_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size, bool cache_pws)
: cpu_device(mconfig, type, tag, owner, clock)
, m_program_config_be("program", ENDIANNESS_BIG, 32, 32)
, m_program_config_le("program", ENDIANNESS_LITTLE, 32, 32)
- , m_icache_config("icache", ENDIANNESS_BIG, 32, 32)
- , m_dcache_config("dcache", ENDIANNESS_BIG, 32, 32)
, m_cpurev(cpurev)
, m_endianness(ENDIANNESS_BIG)
, m_icount(0)
- , m_icache_size(icache_size)
- , m_dcache_size(dcache_size)
- , m_in_brcond{ *this, *this, *this, *this }
+ , m_icache(icache_size)
+ , m_dcache(dcache_size)
+ , m_cache((icache_size && dcache_size) ? CACHED : UNCACHED)
+ , m_cache_pws(cache_pws)
+ , m_in_brcond(*this, 0)
{
}
-mips1_device_base::mips1_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size)
- : mips1core_device_base(mconfig, type, tag, owner, clock, cpurev, icache_size, dcache_size)
+mips1_device_base::mips1_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size, bool cache_pws)
+ : mips1core_device_base(mconfig, type, tag, owner, clock, cpurev, icache_size, dcache_size, cache_pws)
, m_fcr0(0)
{
}
-r2000_device::r2000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
- : mips1_device_base(mconfig, R2000, tag, owner, clock, 0x0100, icache_size, dcache_size)
+r2000_device::r2000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
+ : mips1_device_base(mconfig, R2000, tag, owner, clock, 0x0120, icache_size, dcache_size, false)
{
}
-r2000a_device::r2000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
- : mips1_device_base(mconfig, R2000A, tag, owner, clock, 0x0210, icache_size, dcache_size)
+r2000a_device::r2000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
+ : mips1_device_base(mconfig, R2000A, tag, owner, clock, 0x0210, icache_size, dcache_size, false)
{
}
-r3000_device::r3000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
- : mips1_device_base(mconfig, R3000, tag, owner, clock, 0x0220, icache_size, dcache_size)
+r3000_device::r3000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
+ : mips1_device_base(mconfig, R3000, tag, owner, clock, 0x0220, icache_size, dcache_size, false)
{
}
-r3000a_device::r3000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
- : mips1_device_base(mconfig, R3000A, tag, owner, clock, 0x0230, icache_size, dcache_size)
+r3000a_device::r3000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
+ : mips1_device_base(mconfig, R3000A, tag, owner, clock, 0x0230, icache_size, dcache_size, false)
{
}
-r3041_device::r3041_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : mips1core_device_base(mconfig, R3041, tag, owner, clock, 0x0700, 2048, 512)
+r3041_device::r3041_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : mips1core_device_base(mconfig, R3041, tag, owner, clock, 0x0700, 2048, 512, true)
{
}
-r3051_device::r3051_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : mips1core_device_base(mconfig, R3051, tag, owner, clock, 0x0200, 4096, 2048)
+r3051_device::r3051_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : mips1core_device_base(mconfig, R3051, tag, owner, clock, 0x0200, 4096, 2048, true)
{
}
-r3052_device::r3052_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : mips1core_device_base(mconfig, R3052, tag, owner, clock, 0x0200, 8192, 2048)
+r3052_device::r3052_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : mips1core_device_base(mconfig, R3052, tag, owner, clock, 0x0200, 8192, 2048, true)
{
}
-r3052e_device::r3052e_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : mips1_device_base(mconfig, R3052E, tag, owner, clock, 0x0200, 8192, 2048)
+r3052e_device::r3052e_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : mips1_device_base(mconfig, R3052E, tag, owner, clock, 0x0200, 8192, 2048, true)
{
}
-r3071_device::r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
- : mips1_device_base(mconfig, R3071, tag, owner, clock, 0x0200, icache_size, dcache_size)
+r3071_device::r3071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
+ : mips1_device_base(mconfig, R3071, tag, owner, clock, 0x0200, icache_size, dcache_size, true)
{
}
-r3081_device::r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
- : mips1_device_base(mconfig, R3081, tag, owner, clock, 0x0200, icache_size, dcache_size)
+r3081_device::r3081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size, size_t dcache_size)
+ : mips1_device_base(mconfig, R3081, tag, owner, clock, 0x0200, icache_size, dcache_size, true)
{
set_fpu(0x0300);
}
-iop_device::iop_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : mips1core_device_base(mconfig, SONYPS2_IOP, tag, owner, clock, 0x001f, 4096, 1024)
+iop_device::iop_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : mips1core_device_base(mconfig, SONYPS2_IOP, tag, owner, clock, 0x001f, 4096, 1024, false)
{
m_endianness = ENDIANNESS_LITTLE;
}
-/*
- * Two additional address spaces are defined to represent the instruction and
- * data caches. These are only used to simulate cache isolation functionality
- * at this point, but could simulate other behaviour as needed in future.
- */
-void mips1core_device_base::device_add_mconfig(machine_config &config)
-{
- set_addrmap(1, &mips1core_device_base::icache_map);
- set_addrmap(2, &mips1core_device_base::dcache_map);
-}
-
void mips1core_device_base::device_start()
{
// set our instruction counter
set_icountptr(m_icount);
- // resolve conditional branch input handlers
- for (devcb_read_line &cb : m_in_brcond)
- cb.resolve_safe(0);
-
// register our state for the debugger
state_add(STATE_GENPC, "GENPC", m_pc).noshow();
state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow();
@@ -161,7 +303,7 @@ void mips1core_device_base::device_start()
state_add(MIPS1_PC, "PC", m_pc);
state_add(MIPS1_COP0 + COP0_Status, "SR", m_cop0[COP0_Status]);
- for (unsigned i = 0; i < ARRAY_LENGTH(m_r); i++)
+ for (unsigned i = 0; i < std::size(m_r); i++)
state_add(MIPS1_R0 + i, util::string_format("R%d", i).c_str(), m_r[i]);
state_add(MIPS1_HI, "HI", m_hi);
@@ -183,6 +325,18 @@ void mips1core_device_base::device_start()
// initialise cpu id register
m_cop0[COP0_PRId] = m_cpurev;
+
+ m_cop0[COP0_Cause] = 0;
+
+ m_r[0] = 0;
+
+ m_icache.start();
+ m_dcache.start();
+
+ save_pointer(STRUCT_MEMBER(m_icache.line, tag), m_icache.lines());
+ save_pointer(STRUCT_MEMBER(m_icache.line, data), m_icache.lines());
+ save_pointer(STRUCT_MEMBER(m_dcache.line, tag), m_dcache.lines());
+ save_pointer(STRUCT_MEMBER(m_dcache.line, data), m_dcache.lines());
}
void r3041_device::device_start()
@@ -195,6 +349,10 @@ void r3041_device::device_start()
state_add(MIPS1_COP0 + COP0_Count, "Count", m_cop0[COP0_Count]);
state_add(MIPS1_COP0 + COP0_PortSize, "PortSize", m_cop0[COP0_PortSize]);
state_add(MIPS1_COP0 + COP0_Compare, "Compare", m_cop0[COP0_Compare]);
+
+ m_cop0[COP0_BusCtrl] = 0x20130b00U;
+ m_cop0[COP0_Config] = 0x40000000U;
+ m_cop0[COP0_PortSize] = 0;
}
void mips1core_device_base::device_reset()
@@ -206,10 +364,17 @@ void mips1core_device_base::device_reset()
// non-tlb devices have tlb shut down
m_cop0[COP0_Status] = SR_BEV | SR_TS;
- m_data_spacenum = 0;
m_bus_error = false;
}
+void r3041_device::device_reset()
+{
+ mips1core_device_base::device_reset();
+
+ m_cop0[COP0_Count] = 0;
+ m_cop0[COP0_Compare] = 0x00ffffffU;
+}
+
void mips1core_device_base::execute_run()
{
// core execution loop
@@ -218,30 +383,21 @@ void mips1core_device_base::execute_run()
// debugging
debugger_instruction_hook(m_pc);
- if (VERBOSE & LOG_IOP)
- {
- if ((m_pc & 0x1fffffff) == 0x00012C48 || (m_pc & 0x1fffffff) == 0x0001420C || (m_pc & 0x1fffffff) == 0x0001430C)
- {
- u32 ptr = m_r[5];
- u32 length = m_r[6];
- if (length >= 4096)
- length = 4095;
- while (length)
- {
- load<u8>(ptr, [](char c) { printf("%c", c); });
- ptr++;
- length--;
- }
- fflush(stdout);
- }
- }
-
// fetch instruction
fetch(m_pc, [this](u32 const op)
{
// check for interrupts
if ((CAUSE & SR & SR_IM) && (SR & SR_IEc))
{
+ // enable debugger interrupt breakpoints
+ for (int irqline = 0; irqline < 6; irqline++)
+ {
+ if (CAUSE & SR & (CAUSE_IPEX0 << irqline))
+ {
+ standard_irq_callback(irqline, m_pc);
+ break;
+ }
+ }
generate_exception(EXCEPTION_INTERRUPT);
return;
}
@@ -605,13 +761,7 @@ void mips1core_device_base::execute_run()
void mips1core_device_base::execute_set_input(int irqline, int state)
{
if (state != CLEAR_LINE)
- {
CAUSE |= CAUSE_IPEX0 << irqline;
-
- // enable debugger interrupt breakpoints
- if ((SR & SR_IEc) && (SR & (SR_IMEX0 << irqline)))
- standard_irq_callback(irqline);
- }
else
CAUSE &= ~(CAUSE_IPEX0 << irqline);
}
@@ -619,26 +769,37 @@ void mips1core_device_base::execute_set_input(int irqline, int state)
device_memory_interface::space_config_vector mips1core_device_base::memory_space_config() const
{
return space_config_vector {
- std::make_pair(AS_PROGRAM, (m_endianness == ENDIANNESS_BIG) ? &m_program_config_be : &m_program_config_le),
- std::make_pair(1, &m_icache_config),
- std::make_pair(2, &m_dcache_config)
+ std::make_pair(AS_PROGRAM, (m_endianness == ENDIANNESS_BIG) ? &m_program_config_be : &m_program_config_le)
};
}
-bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t &address)
+bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
+{
+ target_space = &space(spacenum);
+
+ if (spacenum != AS_PROGRAM)
+ return true;
+
+ return translate(intention, address, true) != ERROR;
+}
+
+mips1core_device_base::translate_result mips1core_device_base::translate(int intention, offs_t &address, bool debug)
{
// check for kernel memory address
if (BIT(address, 31))
{
// check debug or kernel mode
- if ((intention & TRANSLATE_DEBUG_MASK) || !(SR & SR_KUc))
+ if (debug || !(SR & SR_KUc))
{
switch (address & 0xe0000000)
{
case 0x80000000: // kseg0: unmapped, cached, privileged
+ address &= ~0xe0000000;
+ return m_cache;
+
case 0xa0000000: // kseg1: unmapped, uncached, privileged
address &= ~0xe0000000;
- break;
+ return UNCACHED;
case 0xc0000000: // kseg2: mapped, cached, privileged
case 0xe0000000:
@@ -647,21 +808,16 @@ bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t
}
else if (SR & SR_KUc)
{
- if (!machine().side_effects_disabled())
- {
- // exception
- m_cop0[COP0_BadVAddr] = address;
+ address_error(intention, address);
- generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD);
- }
- return false;
+ return ERROR;
}
}
else
// kuseg physical addresses have a 1GB offset
address += 0x40000000;
- return true;
+ return m_cache;
}
std::unique_ptr<util::disasm_interface> mips1core_device_base::create_disassembler()
@@ -669,168 +825,8 @@ std::unique_ptr<util::disasm_interface> mips1core_device_base::create_disassembl
return std::make_unique<mips1_disassembler>();
}
-void mips1core_device_base::icache_map(address_map &map)
-{
- if (m_icache_size)
- map(0, m_icache_size - 1).ram().mirror(~(m_icache_size - 1));
-}
-
-void mips1core_device_base::dcache_map(address_map &map)
-{
- if (m_dcache_size)
- map(0, m_dcache_size - 1).ram().mirror(~(m_dcache_size - 1));
-}
-
void mips1core_device_base::generate_exception(u32 exception, bool refill)
{
- if ((VERBOSE & LOG_RISCOS) && (exception == EXCEPTION_SYSCALL))
- {
- static char const *const sysv_syscalls[] =
- {
- "syscall", "exit", "fork", "read", "write", "open", "close", "wait", "creat", "link",
- "unlink", "execv", "chdir", "time", "mknod", "chmod", "chown", "brk", "stat", "lseek",
- "getpid", "mount", "umount", "setuid", "getuid", "stime", "ptrace", "alarm", "fstat", "pause",
- "utime", "stty", "gtty", "access", "nice", "statfs", "sync", "kill", "fstatfs", "setpgrp",
- nullptr, "dup", "pipe", "times", "profil", "plock", "setgid", "getgid", "signal", "msgsys",
- "sysmips", "acct", "shmsys", "semsys", "ioctl", "uadmin", nullptr, "utssys", nullptr, "execve",
- "umask", "chroot", "ofcntl", "ulimit", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- "advfs", "unadvfs", "rmount", "rumount", "rfstart", nullptr, "rdebug", "rfstop", "rfsys", "rmdir",
- "mkdir", "getdents", nullptr, nullptr, "sysfs", "getmsg", "putmsg", "poll", "sigreturn", "accept",
- "bind", "connect", "gethostid", "getpeername", "getsockname", "getsockopt", "listen", "recv", "recvfrom", "recvmsg",
- "select", "send", "sendmsg", "sendto", "sethostid", "setsockopt", "shutdown", "socket", "gethostname", "sethostname",
- "getdomainname","setdomainname","truncate", "ftruncate", "rename", "symlink", "readlink", "lstat", "nfsmount", "nfssvc",
- "getfh", "async_daemon", "old_exportfs", "mmap", "munmap", "getitimer", "setitimer", nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- "cacheflush", "cachectl", "fchown", "fchmod", "wait3", "mmap", "munmap", "madvise", "getpagesize", "setreuid",
- "setregid", "setpgid", "getgroups", "setgroups", "gettimeofday", "getrusage", "getrlimit", "setrlimit", "exportfs", "fcntl"
- };
-
- static char const *const bsd_syscalls[] =
- {
- "syscall", "exit", "fork", "read", "write", "open", "close", nullptr, "creat", "link",
- "unlink", "execv", "chdir", nullptr, "mknod", "chmod", "chown", "brk", nullptr, "lseek",
- "getpid", "omount", "oumount", nullptr, "getuid", nullptr, "ptrace", nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, "access", nullptr, nullptr, "sync", "kill", "stat", nullptr,
- "lstat", "dup", "pipe", nullptr, "profil", nullptr, nullptr, "getgid", nullptr, nullptr,
- nullptr, "acct", nullptr, nullptr, "ioctl", "reboot", nullptr, "symlink", "readlink", "execve",
- "umask", "chroot", "fstat", nullptr, "getpagesize", "mremap", "vfork", nullptr, nullptr, "sbrk",
- "sstk", "mmap", "vadvise", "munmap", "mprotec", "madvise", "vhangup", nullptr, "mincore", "getgroups",
- "setgroups", "getpgrp", "setpgrp", "setitimer", "wait3", "swapon", "getitimer", "gethostname", "sethostname", "getdtablesize",
- "dup2", "getdopt", "fcntl", "select", "setdopt", "fsync", "setpriority", "socket", "connect", "accept",
- "getpriority", "send", "recv", "sigreturn", "bind", "setsockopt", "listen", nullptr, "sigvec", "sigblock",
- "sigsetmask", "sigpause", "sigstack", "recvmsg", "sendmsg", nullptr, "gettimeofday", "getrusage", "getsockopt", nullptr,
- "readv", "writev", "settimeofday", "fchown", "fchmod", "recvfrom", "setreuid", "setregid", "rename", "truncate",
- "ftruncate", "flock", nullptr, "sendto", "shutdown", "socketpair", "mkdir", "rmdir", "utimes", "sigcleanup",
- "adjtime", "getpeername", "gethostid", "sethostid", "getrlimit", "setrlimit", "killpg", nullptr, "setquota", "quota",
- "getsockname", "sysmips", "cacheflush", "cachectl", "debug", nullptr, nullptr, nullptr, "nfssvc", "getdirentries",
- "statfs", "fstatfs", "unmount", "async_daemon", "getfh", "getdomainname","setdomainname",nullptr, "quotactl", "old_exportfs",
- "mount", "hdwconf", "exportfs", "nfsfh_open", "libattach", "libdetach"
- };
-
- static char const *const msg_syscalls[] = { "msgget", "msgctl", "msgrcv", "msgsnd" };
- static char const *const shm_syscalls[] = { "shmat", "shmctl", "shmdt", "shmget" };
- static char const *const sem_syscalls[] = { "semctl", "semget", "semop" };
- static char const *const mips_syscalls[] = { "mipskopt", "mipshwconf", "mipsgetrusage", "mipswait", "mipscacheflush", "mipscachectl" };
-
- unsigned const asid = (m_cop0[COP0_EntryHi] & EH_ASID) >> 6;
- switch (m_r[2])
- {
- case 1000: // indirect
- switch (m_r[4])
- {
- case 1049: // msgsys
- LOGMASKED(LOG_RISCOS, "asid %d syscall msgsys:%s() (%s)\n",
- asid, (m_r[5] < ARRAY_LENGTH(msg_syscalls)) ? msg_syscalls[m_r[5]] : "unknown", machine().describe_context());
- break;
-
- case 1052: // shmsys
- LOGMASKED(LOG_RISCOS, "asid %d syscall shmsys:%s() (%s)\n",
- asid, (m_r[5] < ARRAY_LENGTH(shm_syscalls)) ? shm_syscalls[m_r[5]] : "unknown", machine().describe_context());
- break;
-
- case 1053: // semsys
- LOGMASKED(LOG_RISCOS, "asid %d syscall semsys:%s() (%s)\n",
- asid, (m_r[5] < ARRAY_LENGTH(sem_syscalls)) ? sem_syscalls[m_r[5]] : "unknown", machine().describe_context());
- break;
-
- case 2151: // bsd_sysmips
- switch (m_r[5])
- {
- case 0x100: // mipskopt
- LOGMASKED(LOG_RISCOS, "asid %d syscall bsd_sysmips:mipskopt(\"%s\") (%s)\n",
- asid, debug_string(m_r[6]), machine().describe_context());
- break;
-
- default:
- if ((m_r[5] > 0x100) && (m_r[5] - 0x100) < ARRAY_LENGTH(mips_syscalls))
- LOGMASKED(LOG_RISCOS, "asid %d syscall bsd_sysmips:%s() (%s)\n",
- asid, mips_syscalls[m_r[5] - 0x100], machine().describe_context());
- else
- LOGMASKED(LOG_RISCOS, "asid %d syscall bsd_sysmips:unknown %d (%s)\n",
- asid, m_r[5], machine().describe_context());
- break;
- }
- break;
-
- default:
- if ((m_r[4] > 2000) && (m_r[4] - 2000 < ARRAY_LENGTH(bsd_syscalls)) && bsd_syscalls[m_r[4] - 2000])
- LOGMASKED(LOG_RISCOS, "asid %d syscall bsd_%s() (%s)\n",
- asid, bsd_syscalls[m_r[4] - 2000], machine().describe_context());
- else
- LOGMASKED(LOG_RISCOS, "asid %d syscall indirect:unknown %d (%s)\n",
- asid, m_r[4], machine().describe_context());
- break;
- }
- break;
-
- case 1003: // read
- case 1006: // close
- case 1054: // ioctl
- case 1169: // fcntl
- LOGMASKED(LOG_RISCOS, "asid %d syscall %s(%d) (%s)\n",
- asid, sysv_syscalls[m_r[2] - 1000], m_r[4], machine().describe_context());
- break;
-
- case 1004: // write
- if (m_r[4] == 1 || m_r[4] == 2)
- LOGMASKED(LOG_RISCOS, "asid %d syscall %s(%d, \"%s\") (%s)\n",
- asid, sysv_syscalls[m_r[2] - 1000], m_r[4], debug_string(m_r[5], m_r[6]), machine().describe_context());
- else
- LOGMASKED(LOG_RISCOS, "asid %d syscall %s(%d) (%s)\n",
- asid, sysv_syscalls[m_r[2] - 1000], m_r[4], machine().describe_context());
- break;
-
- case 1005: // open
- case 1008: // creat
- case 1009: // link
- case 1010: // unlink
- case 1012: // chdir
- case 1018: // stat
- case 1033: // access
- LOGMASKED(LOG_RISCOS, "asid %d syscall %s(\"%s\") (%s)\n",
- asid, sysv_syscalls[m_r[2] - 1000], debug_string(m_r[4]), machine().describe_context());
- break;
-
- case 1059: // execve
- LOGMASKED(LOG_RISCOS, "asid %d syscall execve(\"%s\", [ %s ], [ %s ]) (%s)\n",
- asid, debug_string(m_r[4]), debug_string_array(m_r[5]), debug_string_array(m_r[6]), machine().describe_context());
- break;
-
- case 1060: // umask
- LOGMASKED(LOG_RISCOS, "asid %d syscall umask(%#o) (%s)\n",
- asid, m_r[4] & 0777, machine().describe_context());
- break;
-
- default:
- if ((m_r[2] > 1000) && (m_r[2] - 1000 < ARRAY_LENGTH(sysv_syscalls)) && sysv_syscalls[m_r[2] - 1000])
- LOGMASKED(LOG_RISCOS, "asid %d syscall %s() (%s)\n", asid, sysv_syscalls[m_r[2] - 1000], machine().describe_context());
- else
- LOGMASKED(LOG_RISCOS, "asid %d syscall unknown %d (%s)\n", asid, m_r[2], machine().describe_context());
- break;
- }
- }
-
// set the exception PC
m_cop0[COP0_EPC] = m_pc;
@@ -845,20 +841,36 @@ void mips1core_device_base::generate_exception(u32 exception, bool refill)
}
m_branch_state = EXCEPTION;
- // shift the exception bits
- SR = (SR & ~SR_KUIE) | ((SR << 2) & SR_KUIEop);
-
if (refill)
m_pc = (SR & SR_BEV) ? 0xbfc00100 : 0x80000000;
else
m_pc = (SR & SR_BEV) ? 0xbfc00180 : 0x80000080;
+ // hook exception in caller context enabling debugger access to memory parameters
debugger_exception_hook(exception);
+ // shift the exception bits
+ SR = (SR & ~SR_KUIE) | ((SR << 2) & SR_KUIEop);
+
if (SR & SR_KUp)
debugger_privilege_hook();
}
+void mips1core_device_base::address_error(int intention, u32 const address)
+{
+ if (!machine().side_effects_disabled())
+ {
+ logerror("address_error 0x%08x (%s)\n", address, machine().describe_context());
+
+ m_cop0[COP0_BadVAddr] = address;
+
+ generate_exception((intention == TR_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD);
+
+ // address errors shouldn't typically occur, so a breakpoint is handy
+ machine().debug_break();
+ }
+}
+
void mips1core_device_base::handle_cop0(u32 const op)
{
switch (RSREG)
@@ -923,10 +935,10 @@ void mips1core_device_base::set_cop0_reg(unsigned const reg, u32 const data)
{
u32 const delta = SR ^ data;
- m_cop0[COP0_Status] = data;
+ if ((delta & SR_IsC) && (m_cache == UNCACHED))
+ fatalerror("mips1: cannot isolate non-existent cache (%s)\n", machine().describe_context());
- // handle cache isolation and swap
- m_data_spacenum = (data & SR_IsC) ? ((data & SR_SwC) ? 1 : 2) : 0;
+ m_cop0[COP0_Status] = data;
if ((delta & SR_KUc) && (m_branch_state != EXCEPTION))
debugger_privilege_hook();
@@ -1030,9 +1042,9 @@ void mips1core_device_base::handle_cop3(u32 const op)
void mips1core_device_base::lwl(u32 const op)
{
offs_t const offset = SIMMVAL + m_r[RSREG];
- load<u32>(offset & ~3, [this, op, offset](u32 temp)
+ load<u32, false>(offset, [this, op, offset](u32 temp)
{
- unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3;
+ unsigned const shift = ((offset & 3) ^ (m_endianness == ENDIANNESS_LITTLE ? 3 : 0)) << 3;
m_r[RTREG] = (m_r[RTREG] & ~u32(0xffffffffU << shift)) | (temp << shift);
});
@@ -1041,9 +1053,9 @@ void mips1core_device_base::lwl(u32 const op)
void mips1core_device_base::lwr(u32 const op)
{
offs_t const offset = SIMMVAL + m_r[RSREG];
- load<u32>(offset & ~3, [this, op, offset](u32 temp)
+ load<u32, false>(offset, [this, op, offset](u32 temp)
{
- unsigned const shift = ((offset & 0x3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3;
+ unsigned const shift = ((offset & 3) ^ (m_endianness == ENDIANNESS_LITTLE ? 0 : 3)) << 3;
m_r[RTREG] = (m_r[RTREG] & ~u32(0xffffffffU >> shift)) | (temp >> shift);
});
@@ -1052,128 +1064,263 @@ void mips1core_device_base::lwr(u32 const op)
void mips1core_device_base::swl(u32 const op)
{
offs_t const offset = SIMMVAL + m_r[RSREG];
- unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3;
+ unsigned const shift = ((offset & 3) ^ (m_endianness == ENDIANNESS_LITTLE ? 3 : 0)) << 3;
- store<u32>(offset & ~3, m_r[RTREG] >> shift, 0xffffffffU >> shift);
+ store<u32, false>(offset, m_r[RTREG] >> shift, 0xffffffffU >> shift);
}
void mips1core_device_base::swr(u32 const op)
{
offs_t const offset = SIMMVAL + m_r[RSREG];
- unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3;
+ unsigned const shift = ((offset & 3) ^ (m_endianness == ENDIANNESS_LITTLE ? 0 : 3)) << 3;
- store<u32>(offset & ~3, m_r[RTREG] << shift, 0xffffffffU << shift);
+ store<u32, false>(offset, m_r[RTREG] << shift, 0xffffffffU << shift);
}
-template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> mips1core_device_base::load(u32 address, U &&apply)
+/*
+ * This function determines the active cache (instruction or data) depending on
+ * the icache parameter and the status register SwC (swap caches) flag. A line
+ * within the cache is then selected based upon the low address bits. The upper
+ * address bits are compared with the line tag to identify whether the lookup
+ * is a hit or a miss.
+ *
+ * If the cache lookup misses and the invalidate parameter evaluates to true,
+ * the cache line tag is updated to match the input address and invalidated.
+ *
+ * The function returns the selected line and the miss state.
+ *
+ * TODO: multiple-word cache lines
+ */
+std::tuple<struct mips1core_device_base::cache::line &, bool> mips1core_device_base::cache_lookup(u32 address, bool invalidate, bool icache)
{
- if (memory_translate(m_data_spacenum, TRANSLATE_READ, address))
- {
- T const data
- = (sizeof(T) == 1) ? space(m_data_spacenum).read_byte(address)
- : (sizeof(T) == 2) ? space(m_data_spacenum).read_word(address)
- : space(m_data_spacenum).read_dword(address);
+ // cache line data is word-addressed
+ address &= ~3;
- if (m_bus_error)
- {
- m_bus_error = false;
- generate_exception(EXCEPTION_BUSDATA);
- }
- else
- apply(data);
- }
+ // select instruction or data cache
+ struct cache const &c = (icache ^ bool(SR & SR_SwC)) ? m_icache : m_dcache;
+
+ // select line within cache based on low address bits
+ struct cache::line &l = c.line[(address & (c.size - 1)) >> 2];
+
+ // clear cache parity error
+ SR &= ~SR_PE;
+
+ // compare cache line tag against upper address bits and line valid bit
+ bool const miss = (l.tag ^ address) & (-c.size | cache::line::INV);
+
+ // on cache miss, optionally update the line tag and invalidate (cache
+ // miss is usually followed by line replacement)
+ if (miss && invalidate)
+ l.tag = (address & -c.size) | cache::line::INV;
+
+ return std::tie(l, miss);
}
-template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> mips1core_device_base::store(u32 address, U data, T mem_mask)
+// compute bit position of sub-unit within a word given endianness and address
+template <typename T> unsigned mips1core_device_base::shift_factor(u32 address) const
{
- if (memory_translate(m_data_spacenum, TRANSLATE_WRITE, address))
- {
- switch (sizeof(T))
- {
- case 1: space(m_data_spacenum).write_byte(address, T(data)); break;
- case 2: space(m_data_spacenum).write_word(address, T(data), mem_mask); break;
- case 4: space(m_data_spacenum).write_dword(address, T(data), mem_mask); break;
- }
- }
+ if constexpr (sizeof(T) == 1)
+ return ((m_endianness == ENDIANNESS_BIG) ? (address & 3) ^ 3 : (address & 3)) * 8;
+ else if constexpr (sizeof(T) == 2)
+ return ((m_endianness == ENDIANNESS_BIG) ? (address & 2) ^ 2 : (address & 2)) * 8;
+ else
+ return 0;
}
-bool mips1core_device_base::fetch(u32 address, std::function<void(u32)> &&apply)
+template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> mips1core_device_base::load(u32 address, U &&apply)
{
- if (memory_translate(0, TRANSLATE_FETCH, address))
+ // alignment error
+ if (Aligned && (address & (sizeof(T) - 1)))
{
- u32 const data = space(0).read_dword(address);
+ address_error(TR_READ, address);
+ return;
+ }
- if (m_bus_error)
+ T data;
+ if (!(SR & SR_IsC))
+ {
+ translate_result const t = translate(TR_READ, address, false);
+ if (t == ERROR)
+ return;
+
+ // align address for ld[lr] instructions
+ if (!Aligned)
+ address &= ~(sizeof(T) - 1);
+
+ if (t == CACHED)
{
- m_bus_error = false;
- generate_exception(EXCEPTION_BUSINST);
+ auto [l, miss] = cache_lookup(address, true);
+
+ if (miss)
+ {
+ // load
+ u32 const data = space(AS_PROGRAM).read_dword(address);
+ if (m_bus_error)
+ {
+ m_bus_error = false;
+ generate_exception(EXCEPTION_BUSDATA);
+
+ return;
+ }
+
+ // replace cache line data and mark valid
+ l.update(data);
+ }
- return false;
+ data = l.data >> shift_factor<T>(address);
}
+ else
+ {
+ if constexpr (sizeof(T) == 4)
+ data = space(AS_PROGRAM).read_dword(address);
+ else if constexpr (sizeof(T) == 2)
+ data = space(AS_PROGRAM).read_word(address);
+ else if constexpr (sizeof(T) == 1)
+ data = space(AS_PROGRAM).read_byte(address);
+
+ if (m_bus_error)
+ {
+ m_bus_error = false;
+ generate_exception(EXCEPTION_BUSDATA);
- apply(data);
- return true;
+ return;
+ }
+ }
}
else
- return false;
+ {
+ // when isolated, loads always hit the cache and the status register
+ // CM flag reflects the actual hit/miss state
+ auto [l, miss] = cache_lookup(address & ~0xe000'0000, false);
+
+ if (miss)
+ SR |= SR_CM;
+ else
+ SR &= ~SR_CM;
+
+ data = l.data >> shift_factor<T>(address);
+ }
+
+ apply(data);
}
-std::string mips1core_device_base::debug_string(u32 string_pointer, unsigned const limit)
+template <typename T, bool Aligned> void mips1core_device_base::store(u32 address, T data, T mem_mask)
{
- auto const suppressor(machine().disable_side_effects());
-
- bool done = false;
- bool mapped = false;
- std::string result("");
+ // alignment error
+ if (Aligned && (address & (sizeof(T) - 1)))
+ {
+ address_error(TR_WRITE, address);
+ return;
+ }
- while (!done)
+ if (!(SR & SR_IsC))
{
- done = true;
- load<u8>(string_pointer++, [limit, &done, &mapped, &result](u8 byte)
+ translate_result const t = translate(TR_WRITE, address, false);
+ if (t == ERROR)
+ return;
+
+ // align address for sd[lr] instructions
+ if (!Aligned)
+ address &= ~(sizeof(T) - 1);
+
+ if (t == CACHED)
{
- mapped = true;
- if (byte != 0)
+ auto [l, miss] = cache_lookup(address, sizeof(T) == 4);
+
+ // cached full word stores always update the cache
+ if constexpr (Aligned && sizeof(T) == 4)
+ l.update(data);
+ else if (!miss)
{
- result += byte;
+ if (!m_cache_pws)
+ {
+ // reload the cache line from memory
+ u32 const data = space(AS_PROGRAM).read_dword(address);
+ if (m_bus_error)
+ {
+ m_bus_error = false;
+ generate_exception(EXCEPTION_BUSDATA);
+
+ return;
+ }
- done = result.length() == limit;
+ l.update(data);
+ }
+
+ // merge data into the cache
+ unsigned const shift = shift_factor<T>(address);
+ l.update(u32(data) << shift, u32(mem_mask) << shift);
}
- });
- }
+ }
- if (!mapped)
- result.assign("[unmapped]");
+ // uncached or write-through store
+ if constexpr (sizeof(T) == 4)
+ space(AS_PROGRAM).write_dword(address, T(data), mem_mask);
+ else if constexpr (sizeof(T) == 2)
+ space(AS_PROGRAM).write_word(address, T(data), mem_mask);
+ else if constexpr (sizeof(T) == 1)
+ space(AS_PROGRAM).write_byte(address, T(data));
+ }
+ else
+ {
+ // when isolated, full word stores update the cache, while partial word
+ // stores invalidate the cache line
+ auto [l, miss] = cache_lookup(address & ~0xe000'0000, true);
- return result;
+ if constexpr (Aligned && sizeof(T) == 4)
+ l.update(data, mem_mask);
+ else
+ l.invalidate();
+ }
}
-std::string mips1core_device_base::debug_string_array(u32 array_pointer)
+void mips1core_device_base::fetch(u32 address, std::function<void(u32)> &&apply)
{
- auto const suppressor(machine().disable_side_effects());
+ // alignment error
+ if (address & 3)
+ address_error(TR_FETCH, address);
- bool done = false;
- std::string result("");
+ translate_result const t = translate(TR_FETCH, address, false);
+ if (t == ERROR)
+ return;
- while (!done)
+ u32 data;
+ if (t == CACHED)
{
- done = true;
- load<u32>(array_pointer, [this, &done, &result](u32 string_pointer)
+ auto [l, miss] = cache_lookup(address, true, true);
+
+ if (miss)
{
- if (string_pointer != 0)
+ // fetch
+ u32 const data = space(AS_PROGRAM).read_dword(address);
+ if (m_bus_error)
{
- if (!result.empty())
- result += ", ";
-
- result += '\"' + debug_string(string_pointer) + '\"';
+ m_bus_error = false;
+ generate_exception(EXCEPTION_BUSINST);
- done = false;
+ return;
}
- });
- array_pointer += 4;
+ // replace cache line data and mark valid
+ l.update(data);
+ }
+
+ data = l.data;
+ }
+ else
+ {
+ data = space(AS_PROGRAM).read_dword(address);
+
+ if (m_bus_error)
+ {
+ m_bus_error = false;
+ generate_exception(EXCEPTION_BUSINST);
+
+ return;
+ }
}
- return result;
+ apply(data);
}
void mips1_device_base::device_start()
@@ -1191,7 +1338,7 @@ void mips1_device_base::device_start()
if (m_fcr0)
{
state_add(MIPS1_FCR31, "FCSR", m_fcr31);
- for (unsigned i = 0; i < ARRAY_LENGTH(m_f); i++)
+ for (unsigned i = 0; i < std::size(m_f); i++)
state_add(MIPS1_F0 + i, util::string_format("F%d", i * 2).c_str(), m_f[i]);
}
@@ -1213,11 +1360,11 @@ void mips1_device_base::device_reset()
m_reset_time = total_cycles();
// initialize tlb mru index with identity mapping
- for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++)
+ for (unsigned i = 0; i < std::size(m_tlb); i++)
{
- m_tlb_mru[TRANSLATE_READ][i] = i;
- m_tlb_mru[TRANSLATE_WRITE][i] = i;
- m_tlb_mru[TRANSLATE_FETCH][i] = i;
+ m_tlb_mru[TR_READ][i] = i;
+ m_tlb_mru[TR_WRITE][i] = i;
+ m_tlb_mru[TR_FETCH][i] = i;
}
}
@@ -1475,7 +1622,15 @@ void mips1_device_base::handle_cop1(u32 const op)
set_cop1_reg(FDREG >> 1, f32_to_f64(float32_t{ u32(m_f[FSREG >> 1]) }).v);
break;
case 0x24: // CVT.W.S
- set_cop1_reg(FDREG >> 1, f32_to_i32(float32_t{ u32(m_f[FSREG >> 1]) }, softfloat_roundingMode, true));
+ if (BIT(m_f[FSREG >> 1], 23, 8) == 0xff)
+ {
+ // +/- infinity or NaN
+ m_fcr31 &= ~FCR31_CM;
+ m_fcr31 |= FCR31_CE;
+ execute_set_input(m_fpu_irq, ASSERT_LINE);
+ }
+ else
+ set_cop1_reg(FDREG >> 1, f32_to_i32(float32_t{ u32(m_f[FSREG >> 1]) }, softfloat_roundingMode, true));
break;
case 0x30: // C.F.S (false)
@@ -1659,7 +1814,15 @@ void mips1_device_base::handle_cop1(u32 const op)
set_cop1_reg(FDREG >> 1, f64_to_f32(float64_t{ m_f[FSREG >> 1] }).v);
break;
case 0x24: // CVT.W.D
- set_cop1_reg(FDREG >> 1, f64_to_i32(float64_t{ m_f[FSREG >> 1] }, softfloat_roundingMode, true));
+ if (BIT(m_f[FSREG >> 1], 52, 11) == 0x7ff)
+ {
+ // +/- infinity or NaN
+ m_fcr31 &= ~FCR31_CM;
+ m_fcr31 |= FCR31_CE;
+ execute_set_input(m_fpu_irq, ASSERT_LINE);
+ }
+ else
+ set_cop1_reg(FDREG >> 1, f64_to_i32(float64_t{ m_f[FSREG >> 1] }, softfloat_roundingMode, true));
break;
case 0x30: // C.F.D (false)
@@ -1889,20 +2052,23 @@ template <typename T> void mips1_device_base::set_cop1_reg(unsigned const reg, T
m_f[reg] = data;
}
-bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &address)
+mips1core_device_base::translate_result mips1_device_base::translate(int intention, offs_t &address, bool debug)
{
// check for kernel memory address
if (BIT(address, 31))
{
// check debug or kernel mode
- if ((intention & TRANSLATE_DEBUG_MASK) || !(SR & SR_KUc))
+ if (debug || !(SR & SR_KUc))
{
switch (address & 0xe0000000)
{
case 0x80000000: // kseg0: unmapped, cached, privileged
+ address &= ~0xe0000000;
+ return m_cache;
+
case 0xa0000000: // kseg1: unmapped, uncached, privileged
address &= ~0xe0000000;
- return true;
+ return UNCACHED;
case 0xc0000000: // kseg2: mapped, cached, privileged
case 0xe0000000:
@@ -1911,26 +2077,21 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad
}
else if (SR & SR_KUc)
{
- if (!machine().side_effects_disabled())
- {
- // exception
- m_cop0[COP0_BadVAddr] = address;
+ address_error(intention, address);
- generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD);
- }
- return false;
+ return ERROR;
}
}
// key is a combination of VPN and ASID
u32 const key = (address & EH_VPN) | (m_cop0[COP0_EntryHi] & EH_ASID);
- unsigned *mru = m_tlb_mru[intention & TRANSLATE_TYPE_MASK];
+ unsigned *mru = m_tlb_mru[intention];
bool refill = !BIT(address, 31);
bool modify = false;
- for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++)
+ for (unsigned i = 0; i < std::size(m_tlb); i++)
{
unsigned const index = mru[i];
u32 const *const entry = m_tlb[index];
@@ -1948,7 +2109,7 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad
}
// test dirty
- if ((intention & TRANSLATE_WRITE) && !(entry[1] & EL_D))
+ if ((intention == TR_WRITE) && !(entry[1] & EL_D))
{
refill = false;
modify = true;
@@ -1963,10 +2124,10 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad
if (i > 0)
std::swap(mru[i - 1], mru[i]);
- return true;
+ return (entry[1] & EL_N) ? UNCACHED : m_cache;
}
- if (!machine().side_effects_disabled() && !(intention & TRANSLATE_DEBUG_MASK))
+ if (!machine().side_effects_disabled() && !debug)
{
if (VERBOSE & LOG_TLB)
{
@@ -1975,7 +2136,7 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad
(m_cop0[COP0_EntryHi] & EH_ASID) >> 6, address, machine().describe_context());
else
LOGMASKED(LOG_TLB, "asid %2d tlb miss %c address 0x%08x (%s)\n",
- (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, (intention & TRANSLATE_WRITE) ? 'w' : 'r', address, machine().describe_context());
+ (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, (intention == TR_WRITE) ? 'w' : 'r', address, machine().describe_context());
}
// load tlb exception registers
@@ -1983,8 +2144,8 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad
m_cop0[COP0_EntryHi] = key;
m_cop0[COP0_Context] = (m_cop0[COP0_Context] & PTE_BASE) | ((address >> 10) & BAD_VPN);
- generate_exception(modify ? EXCEPTION_TLBMOD : (intention & TRANSLATE_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill);
+ generate_exception(modify ? EXCEPTION_TLBMOD : (intention == TR_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill);
}
- return false;
+ return ERROR;
}
diff --git a/src/devices/cpu/mips/mips1.h b/src/devices/cpu/mips/mips1.h
index 306944d358f..5de7238281c 100644
--- a/src/devices/cpu/mips/mips1.h
+++ b/src/devices/cpu/mips/mips1.h
@@ -17,163 +17,28 @@ public:
void berr_w(int state) { m_bus_error = bool(state); }
protected:
- mips1core_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
+ mips1core_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size, bool cache_pws);
- enum registers : unsigned
- {
- MIPS1_R0 = 0,
- MIPS1_COP0 = 32,
- MIPS1_F0 = 64,
-
- MIPS1_PC = 80,
- MIPS1_HI,
- MIPS1_LO,
- MIPS1_FCR30,
- MIPS1_FCR31,
- };
-
- enum exception : u32
- {
- EXCEPTION_INTERRUPT = 0x00000000,
- EXCEPTION_TLBMOD = 0x00000004,
- EXCEPTION_TLBLOAD = 0x00000008,
- EXCEPTION_TLBSTORE = 0x0000000c,
- EXCEPTION_ADDRLOAD = 0x00000010,
- EXCEPTION_ADDRSTORE = 0x00000014,
- EXCEPTION_BUSINST = 0x00000018,
- EXCEPTION_BUSDATA = 0x0000001c,
- EXCEPTION_SYSCALL = 0x00000020,
- EXCEPTION_BREAK = 0x00000024,
- EXCEPTION_INVALIDOP = 0x00000028,
- EXCEPTION_BADCOP = 0x0000002c,
- EXCEPTION_OVERFLOW = 0x00000030,
- EXCEPTION_TRAP = 0x00000034,
-
- EXCEPTION_BADCOP0 = 0x0000002c,
- EXCEPTION_BADCOP1 = 0x1000002c,
- EXCEPTION_BADCOP2 = 0x2000002c,
- EXCEPTION_BADCOP3 = 0x3000002c,
- };
-
- enum cop0_reg : u8
- {
- COP0_Index = 0,
- COP0_Random = 1,
- COP0_EntryLo = 2,
- COP0_BusCtrl = 2, // r3041 only
- COP0_Config = 3, // r3041/r3071/r3081 only
- COP0_Context = 4,
- COP0_BadVAddr = 8,
- COP0_Count = 9, // r3041 only
- COP0_EntryHi = 10,
- COP0_PortSize = 10, // r3041 only
- COP0_Compare = 11, // r3041 only
- COP0_Status = 12,
- COP0_Cause = 13,
- COP0_EPC = 14,
- COP0_PRId = 15,
- };
-
- enum sr_mask : u32
- {
- SR_IEc = 0x00000001, // interrupt enable (current)
- SR_KUc = 0x00000002, // user mode (current)
- SR_IEp = 0x00000004, // interrupt enable (previous)
- SR_KUp = 0x00000008, // user mode (previous)
- SR_IEo = 0x00000010, // interrupt enable (old)
- SR_KUo = 0x00000020, // user mode (old)
- SR_IMSW0 = 0x00000100, // software interrupt 0 enable
- SR_IMSW1 = 0x00000200, // software interrupt 1 enable
- SR_IMEX0 = 0x00000400, // external interrupt 0 enable
- SR_IMEX1 = 0x00000800, // external interrupt 1 enable
- SR_IMEX2 = 0x00001000, // external interrupt 2 enable
- SR_IMEX3 = 0x00002000, // external interrupt 3 enable
- SR_IMEX4 = 0x00004000, // external interrupt 4 enable
- SR_IMEX5 = 0x00008000, // external interrupt 5 enable
- SR_IsC = 0x00010000, // isolate (data) cache
- SR_SwC = 0x00020000, // swap caches
- SR_PZ = 0x00040000, // cache parity zero
- SR_CM = 0x00080000, // cache match
- SR_PE = 0x00100000, // cache parity error
- SR_TS = 0x00200000, // tlb shutdown
- SR_BEV = 0x00400000, // boot exception vectors
- SR_RE = 0x02000000, // reverse endianness in user mode
- SR_COP0 = 0x10000000, // coprocessor 0 usable
- SR_COP1 = 0x20000000, // coprocessor 1 usable
- SR_COP2 = 0x40000000, // coprocessor 2 usable
- SR_COP3 = 0x80000000, // coprocessor 3 usable
-
- SR_KUIE = 0x0000003f, // all interrupt enable and user mode bits
- SR_KUIEpc = 0x0000000f, // previous and current interrupt enable and user mode bits
- SR_KUIEop = 0x0000003c, // old and previous interrupt enable and user mode bits
- SR_IM = 0x0000ff00, // all interrupt mask bits
- };
-
- enum cause_mask : u32
- {
- CAUSE_EXCCODE = 0x0000007c, // exception code
- CAUSE_IPSW0 = 0x00000100, // software interrupt 0 pending
- CAUSE_IPSW1 = 0x00000200, // software interrupt 1 pending
- CAUSE_IPEX0 = 0x00000400, // external interrupt 0 pending
- CAUSE_IPEX1 = 0x00000800, // external interrupt 1 pending
- CAUSE_IPEX2 = 0x00001000, // external interrupt 2 pending
- CAUSE_IPEX3 = 0x00002000, // external interrupt 3 pending
- CAUSE_IPEX4 = 0x00004000, // external interrupt 4 pending
- CAUSE_IPEX5 = 0x00008000, // external interrupt 5 pending
- CAUSE_IP = 0x0000ff00, // interrupt pending
- CAUSE_CE = 0x30000000, // co-processor error
- CAUSE_BD = 0x80000000, // branch delay
-
- CAUSE_IPEX = 0x0000fc00, // external interrupt pending
- };
-
- enum entryhi_mask : u32
- {
- EH_VPN = 0xfffff000, // virtual page number
- EH_ASID = 0x00000fc0, // address space identifier
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
- EH_WM = 0xffffffc0, // write mask
- };
- enum entrylo_mask : u32
- {
- EL_PFN = 0xfffff000, // physical frame
- EL_N = 0x00000800, // noncacheable
- EL_D = 0x00000400, // dirty
- EL_V = 0x00000200, // valid
- EL_G = 0x00000100, // global
-
- EL_WM = 0xffffff00, // write mask
- };
- enum context_mask : u32
- {
- PTE_BASE = 0xffe00000, // base address of page table
- BAD_VPN = 0x001ffffc, // virtual address bits 30..12
- };
-
- // device_t overrides
- virtual void device_add_mconfig(machine_config &config) override;
- virtual void device_start() override;
- virtual void device_reset() override;
-
- // device_execute_interface overrides
- virtual u32 execute_min_cycles() const override { return 1; }
- virtual u32 execute_max_cycles() const override { return 40; }
- virtual u32 execute_input_lines() const override { return 6; }
+ // device_execute_interface implementation
+ virtual u32 execute_min_cycles() const noexcept override { return 1; }
+ virtual u32 execute_max_cycles() const noexcept override { return 40; }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
- // device_memory_interface overrides
+ // device_memory_interface implementation
virtual space_config_vector memory_space_config() const override;
- virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
+ virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
- // device_disasm_interface overrides
+ // device_disasm_interface implementation
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
- void icache_map(address_map &map);
- void dcache_map(address_map &map);
-
- // interrupts
+ // exceptions
void generate_exception(u32 exception, bool refill = false);
+ void address_error(int intention, u32 const address);
// cop0
virtual void handle_cop0(u32 const op);
@@ -191,25 +56,54 @@ protected:
void swl(u32 const op);
void swr(u32 const op);
- // memory accessors
- template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply);
- template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u32 address, U data, T mem_mask = ~T(0));
- bool fetch(u32 address, std::function<void(u32)> &&apply);
+ // memory
+ enum translate_result : unsigned { ERROR, UNCACHED, CACHED };
+ virtual translate_result translate(int intention, offs_t &address, bool debug);
+ template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply);
+ template <typename T, bool Aligned = true> void store(u32 address, T data, T mem_mask = ~T(0));
+ void fetch(u32 address, std::function<void(u32)> &&apply);
- // debug helpers
- std::string debug_string(u32 string_pointer, unsigned const limit = 0);
- std::string debug_string_array(u32 array_pointer);
+ // cache
+ template <typename T> unsigned shift_factor(u32 address) const;
+ struct cache
+ {
+ cache(size_t size)
+ : size(size)
+ {
+ }
+
+ struct line
+ {
+ enum tag_mask : u32
+ {
+ INV = 0x0000'0001, // cache line invalid
+ };
+
+ void invalidate() { tag = INV; }
+ void update(u32 data, u32 mask = 0xffff'ffffU)
+ {
+ this->tag &= ~INV;
+ this->data = (this->data & ~mask) | (data & mask);
+ }
+
+ u32 tag;
+ u32 data;
+ };
+
+ size_t lines() const { return size / 4; }
+ void start() { line = std::make_unique<struct line[]>(lines()); }
+
+ size_t const size;
+ std::unique_ptr<struct line[]> line;
+ };
+ std::tuple<struct cache::line &, bool> cache_lookup(u32 address, bool invalidate, bool icache = false);
// address spaces
- const address_space_config m_program_config_be;
- const address_space_config m_program_config_le;
- const address_space_config m_icache_config;
- const address_space_config m_dcache_config;
-
- int m_data_spacenum;
+ address_space_config const m_program_config_be;
+ address_space_config const m_program_config_le;
// configuration
- u32 m_cpurev;
+ u32 const m_cpurev;
endianness_t m_endianness;
// core registers
@@ -223,7 +117,7 @@ protected:
// internal stuff
int m_icount;
- enum branch_state_t : unsigned
+ enum branch_state : unsigned
{
NONE = 0,
DELAY = 1, // delay slot instruction active
@@ -234,11 +128,13 @@ protected:
u32 m_branch_target;
// cache memory
- size_t const m_icache_size;
- size_t const m_dcache_size;
+ struct cache m_icache;
+ struct cache m_dcache;
+ translate_result const m_cache;
+ bool const m_cache_pws; // cache supports partial-word store
// I/O
- devcb_read_line m_in_brcond[4];
+ devcb_read_line::array<4> m_in_brcond;
bool m_bus_error;
};
@@ -246,7 +142,7 @@ class mips1_device_base : public mips1core_device_base
{
public:
// floating point coprocessor revision numbers recognised by RISC/os 4.52 and IRIX
- enum fpu_rev_t : u32
+ enum fpu_rev : u32
{
MIPS_R2360 = 0x0100, // MIPS R2360 Floating Point Board
MIPS_R2010 = 0x0200, // MIPS R2010 VLSI Floating Point Chip
@@ -260,44 +156,13 @@ public:
void set_fpu(u32 revision, unsigned interrupt = 3) { m_fcr0 = revision; m_fpu_irq = interrupt; }
protected:
- mips1_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
-
- enum cp1_fcr31_mask : u32
- {
- FCR31_RM = 0x00000003, // rounding mode
-
- FCR31_FI = 0x00000004, // inexact operation flag
- FCR31_FU = 0x00000008, // underflow flag
- FCR31_FO = 0x00000010, // overflow flag
- FCR31_FZ = 0x00000020, // divide by zero flag
- FCR31_FV = 0x00000040, // invalid operation flag
-
- FCR31_EI = 0x00000080, // inexact operation enable
- FCR31_EU = 0x00000100, // underflow enable
- FCR31_EO = 0x00000200, // overflow enable
- FCR31_EZ = 0x00000400, // divide by zero enable
- FCR31_EV = 0x00000800, // invalid operation enable
-
- FCR31_CI = 0x00001000, // inexact operation cause
- FCR31_CU = 0x00002000, // underflow cause
- FCR31_CO = 0x00004000, // overflow cause
- FCR31_CZ = 0x00008000, // divide by zero cause
- FCR31_CV = 0x00010000, // invalid operation cause
- FCR31_CE = 0x00020000, // unimplemented operation cause
-
- FCR31_C = 0x00800000, // condition
-
- FCR31_FM = 0x0000007c, // flag mask
- FCR31_EM = 0x00000f80, // enable mask
- FCR31_CM = 0x0001f000, // cause mask (except unimplemented)
- };
+ mips1_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size, bool cache_pws);
- // device_t overrides
- virtual void device_start() override;
- virtual void device_reset() override;
+ // device_t implementation
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
- // device_memory_interface overrides
- virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
+ virtual translate_result translate(int intention, offs_t &address, bool debug) override;
virtual void handle_cop0(u32 const op) override;
virtual u32 get_cop0_reg(unsigned const reg) override;
@@ -323,70 +188,71 @@ private:
class r2000_device : public mips1_device_base
{
public:
- r2000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
+ r2000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r2000a_device : public mips1_device_base
{
public:
- r2000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
+ r2000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r3000_device : public mips1_device_base
{
public:
- r3000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
+ r3000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r3000a_device : public mips1_device_base
{
public:
- r3000a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
+ r3000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r3041_device : public mips1core_device_base
{
public:
- r3041_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ r3041_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
protected:
- virtual void device_start() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
};
class r3051_device : public mips1core_device_base
{
public:
- r3051_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ r3051_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
class r3052_device : public mips1core_device_base
{
public:
- r3052_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ r3052_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
class r3052e_device : public mips1_device_base
{
public:
- r3052e_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ r3052e_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
class r3071_device : public mips1_device_base
{
public:
- r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
+ r3071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
};
class r3081_device : public mips1_device_base
{
public:
- r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
+ r3081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
};
class iop_device : public mips1core_device_base
{
public:
- iop_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ iop_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
DECLARE_DEVICE_TYPE(R2000, r2000_device)
diff --git a/src/devices/cpu/mips/mips1dsm.cpp b/src/devices/cpu/mips/mips1dsm.cpp
index 72429ca8c03..563e9e1715a 100644
--- a/src/devices/cpu/mips/mips1dsm.cpp
+++ b/src/devices/cpu/mips/mips1dsm.cpp
@@ -84,10 +84,12 @@ const char *const mips1_disassembler::ccreg[4][32] =
std::string mips1_disassembler::signed_16bit(int16_t val)
{
- if (val < 0)
- return util::string_format("-$%x", -val);
+ if (val >= -9 && val <= 9)
+ return util::string_format("%d", val);
+ else if (val < 0)
+ return util::string_format("-0x%x", -val);
else
- return util::string_format("$%x", val);
+ return util::string_format("0x%x", val);
}
uint32_t mips1_disassembler::dasm_cop(uint32_t pc, int cop, uint32_t op, std::ostream &stream)
@@ -105,11 +107,9 @@ uint32_t mips1_disassembler::dasm_cop(uint32_t pc, int cop, uint32_t op, std::os
case 0x08: /* BC */
switch (rt)
{
- case 0x00: util::stream_format(stream, "bc%df $%08x", cop, pc + 4 + ((int16_t)op << 2)); break;
- case 0x01: util::stream_format(stream, "bc%dt $%08x", cop, pc + 4 + ((int16_t)op << 2)); break;
- case 0x02: util::stream_format(stream, "bc%dfl [invalid]", cop); break;
- case 0x03: util::stream_format(stream, "bc%dtl [invalid]", cop); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ case 0x00: util::stream_format(stream, "bc%df 0x%08x", cop, pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bc%dt 0x%08x", cop, pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
case 0x10:
@@ -137,14 +137,13 @@ uint32_t mips1_disassembler::dasm_cop(uint32_t pc, int cop, uint32_t op, std::os
case 0x06: util::stream_format(stream, "tlbwr"); break;
case 0x08: util::stream_format(stream, "tlbp"); break;
case 0x10: util::stream_format(stream, "rfe"); break;
- case 0x18: util::stream_format(stream, "eret [invalid]"); break;
- default: util::stream_format(stream, "cop%d $%07x", cop, op & 0x01ffffff); break;
+ default: util::stream_format(stream, "cop%d 0x%07x", cop, op & 0x01ffffff); break;
}
}
else
- util::stream_format(stream, "cop%d $%07x", cop, op & 0x01ffffff);
+ util::stream_format(stream, "cop%d 0x%07x", cop, op & 0x01ffffff);
break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return flags;
@@ -176,10 +175,10 @@ uint32_t mips1_disassembler::dasm_cop1(uint32_t pc, uint32_t op, std::ostream &s
case 0x08: /* BC */
switch (rt & 3)
{
- case 0x00: util::stream_format(stream, "bc1f $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); break;
- case 0x01: util::stream_format(stream, "bc1t $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); break;
- case 0x02: util::stream_format(stream, "bc1fl $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_OVER | step_over_extra(1); break;
- case 0x03: util::stream_format(stream, "bc1tl $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_OVER | step_over_extra(1); break;
+ case 0x00: util::stream_format(stream, "bc1f 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bc1t 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
+ case 0x02: util::stream_format(stream, "bc1fl 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
+ case 0x03: util::stream_format(stream, "bc1tl 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
}
break;
default: /* COP */
@@ -226,7 +225,7 @@ uint32_t mips1_disassembler::dasm_cop1(uint32_t pc, uint32_t op, std::ostream &s
case 0x3d: util::stream_format(stream, "c.nge.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
case 0x3e: util::stream_format(stream, "c.le.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
case 0x3f: util::stream_format(stream, "c.ngt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break;
- default: util::stream_format(stream, "cop1 $%07x", op & 0x01ffffff); break;
+ default: util::stream_format(stream, "cop1 0x%07x", op & 0x01ffffff); break;
}
break;
}
@@ -257,7 +256,7 @@ offs_t mips1_disassembler::disassemble(std::ostream &stream, offs_t pc, const da
case 0x04: util::stream_format(stream, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
case 0x06: util::stream_format(stream, "srlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
case 0x07: util::stream_format(stream, "srav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
- case 0x08: util::stream_format(stream, "jr %s", reg[rs]); if (rs == 31) flags = STEP_OUT; break;
+ case 0x08: util::stream_format(stream, "jr %s", reg[rs]); if (rs == 31) flags = STEP_OUT | step_over_extra(1); break;
case 0x09: if (rd == 31)
util::stream_format(stream, "jalr %s", reg[rs]);
else
@@ -266,7 +265,6 @@ offs_t mips1_disassembler::disassemble(std::ostream &stream, offs_t pc, const da
break;
case 0x0c: util::stream_format(stream, "syscall"); flags = STEP_OVER; break;
case 0x0d: util::stream_format(stream, "break"); flags = STEP_OVER; break;
- case 0x0f: util::stream_format(stream, "sync [invalid]"); break;
case 0x10: util::stream_format(stream, "mfhi %s", reg[rd]); break;
case 0x11: util::stream_format(stream, "mthi %s", reg[rs]); break;
case 0x12: util::stream_format(stream, "mflo %s", reg[rd]); break;
@@ -276,72 +274,96 @@ offs_t mips1_disassembler::disassemble(std::ostream &stream, offs_t pc, const da
case 0x1a: util::stream_format(stream, "div %s,%s", reg[rs], reg[rt]); break;
case 0x1b: util::stream_format(stream, "divu %s,%s", reg[rs], reg[rt]); break;
case 0x20: util::stream_format(stream, "add %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x21: util::stream_format(stream, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x22: util::stream_format(stream, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x23: util::stream_format(stream, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x21: if (rs == 0 || rt == 0)
+ util::stream_format(stream, "move %s,%s", reg[rd], reg[rs == 0 ? rt : rs]);
+ else
+ util::stream_format(stream, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
+ case 0x22: if (rs == 0)
+ util::stream_format(stream, "neg %s,%s", reg[rd], reg[rt]);
+ else
+ util::stream_format(stream, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
+ case 0x23: if (rs == 0)
+ util::stream_format(stream, "negu %s,%s", reg[rd], reg[rt]);
+ else
+ util::stream_format(stream, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
case 0x24: util::stream_format(stream, "and %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x25: util::stream_format(stream, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x25: if (rs == 0 || rt == 0)
+ util::stream_format(stream, "move %s,%s", reg[rd], reg[rs == 0 ? rt : rs]);
+ else
+ util::stream_format(stream, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
case 0x26: util::stream_format(stream, "xor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x27: util::stream_format(stream, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x27: if (rs == 0)
+ util::stream_format(stream, "not %s,%s", reg[rd], reg[rt]);
+ else
+ util::stream_format(stream, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
case 0x2a: util::stream_format(stream, "slt %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 0x2b: util::stream_format(stream, "sltu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x30: util::stream_format(stream, "teq [invalid]"); break;
- case 0x31: util::stream_format(stream, "tgeu [invalid]"); break;
- case 0x32: util::stream_format(stream, "tlt [invalid]"); break;
- case 0x33: util::stream_format(stream, "tltu [invalid]"); break;
- case 0x34: util::stream_format(stream, "tge [invalid]"); break;
- case 0x36: util::stream_format(stream, "tne [invalid]"); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
case 0x01: /* REGIMM */
switch ((op >> 16) & 31)
{
- case 0x00: util::stream_format(stream, "bltz %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x01: util::stream_format(stream, "bgez %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x02: util::stream_format(stream, "bltzl [invalid]"); break;
- case 0x03: util::stream_format(stream, "bgezl [invalid]"); break;
- case 0x08: util::stream_format(stream, "tgei [invalid]"); break;
- case 0x09: util::stream_format(stream, "tgeiu [invalid]"); break;
- case 0x0a: util::stream_format(stream, "tlti [invalid]"); break;
- case 0x0b: util::stream_format(stream, "tltiu [invalid]"); break;
- case 0x0c: util::stream_format(stream, "teqi [invalid]"); break;
- case 0x0e: util::stream_format(stream, "tnei [invalid]"); break;
- case 0x10: util::stream_format(stream, "bltzal %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | step_over_extra(1); break;
- case 0x11: util::stream_format(stream, "bgezal %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | step_over_extra(1); break;
- case 0x12: util::stream_format(stream, "bltzall [invalid]"); break;
- case 0x13: util::stream_format(stream, "bgezall [invalid]"); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ case 0x00: util::stream_format(stream, "bltz %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bgez %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x10: util::stream_format(stream, "bltzal %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_OVER | STEP_COND | step_over_extra(1); break;
+ case 0x11: if (rs == 0)
+ util::stream_format(stream, "bal 0x%08x", pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "bgezal %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_OVER | (rs != 0 ? STEP_COND : 0) | step_over_extra(1);
+ break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
- case 0x02: util::stream_format(stream, "j $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); break;
- case 0x03: util::stream_format(stream, "jal $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); flags = STEP_OVER | step_over_extra(1); break;
+ case 0x02: util::stream_format(stream, "j 0x%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); break;
+ case 0x03: util::stream_format(stream, "jal 0x%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); flags = STEP_OVER | step_over_extra(1); break;
case 0x04: if (rs == 0 && rt == 0)
- util::stream_format(stream, "b $%08x", pc + 4 + ((int16_t)op << 2));
+ util::stream_format(stream, "b 0x%08x", pc + 4 + ((int16_t)op << 2));
else
- util::stream_format(stream, "beq %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
- break;
- case 0x05: util::stream_format(stream, "bne %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));break;
- case 0x06: util::stream_format(stream, "blez %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x07: util::stream_format(stream, "bgtz %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
+ {
+ if (rt == 0)
+ util::stream_format(stream, "beqz %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "beq %s,%s,0x%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_COND | step_over_extra(1);
+ }
+ break;
+ case 0x05: if (rt == 0)
+ util::stream_format(stream, "bnez %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "bne %s,%s,0x%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_COND | step_over_extra(1);
+ break;
+ case 0x06: util::stream_format(stream, "blez %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ case 0x07: util::stream_format(stream, "bgtz %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
case 0x08: util::stream_format(stream, "addi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
- case 0x09: util::stream_format(stream, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x09: if (rs == 0)
+ util::stream_format(stream, "li %s,%s", reg[rt], signed_16bit(op));
+ else
+ util::stream_format(stream, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op));
+ break;
case 0x0a: util::stream_format(stream, "slti %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
case 0x0b: util::stream_format(stream, "sltiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
- case 0x0c: util::stream_format(stream, "andi %s,%s,$%04x", reg[rt], reg[rs], (uint16_t)op); break;
- case 0x0d: util::stream_format(stream, "ori %s,%s,$%04x", reg[rt], reg[rs], (uint16_t)op); break;
- case 0x0e: util::stream_format(stream, "xori %s,%s,$%04x", reg[rt], reg[rs], (uint16_t)op); break;
- case 0x0f: util::stream_format(stream, "lui %s,$%04x", reg[rt], (uint16_t)op); break;
+ case 0x0c: util::stream_format(stream, "andi %s,%s,0x%04x", reg[rt], reg[rs], (uint16_t)op); break;
+ case 0x0d: if (rs == 0)
+ util::stream_format(stream, "li %s,0x%04x", reg[rt], (uint16_t)op);
+ else
+ util::stream_format(stream, "ori %s,%s,0x%04x", reg[rt], reg[rs], (uint16_t)op);
+ break;
+ case 0x0e: util::stream_format(stream, "xori %s,%s,0x%04x", reg[rt], reg[rs], (uint16_t)op); break;
+ case 0x0f: util::stream_format(stream, "lui %s,0x%04x", reg[rt], (uint16_t)op); break;
case 0x10: flags = dasm_cop(pc, 0, op, stream); break;
case 0x11: flags = dasm_cop1(pc, op, stream); break;
case 0x12: flags = dasm_cop(pc, 2, op, stream); break;
case 0x13: flags = dasm_cop(pc, 3, op, stream); break;
- case 0x14: util::stream_format(stream, "beql [invalid]"); break;
- case 0x15: util::stream_format(stream, "bnel [invalid]"); break;
- case 0x16: util::stream_format(stream, "blezl [invalid]"); break;
- case 0x17: util::stream_format(stream, "bgtzl [invalid]"); break;
case 0x20: util::stream_format(stream, "lb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x21: util::stream_format(stream, "lh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x22: util::stream_format(stream, "lwl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
@@ -354,24 +376,13 @@ offs_t mips1_disassembler::disassemble(std::ostream &stream, offs_t pc, const da
case 0x2a: util::stream_format(stream, "swl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x2b: util::stream_format(stream, "sw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x2e: util::stream_format(stream, "swr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
- case 0x2f: util::stream_format(stream, "cache [invalid]"); break;
- case 0x30: util::stream_format(stream, "ll [invalid]"); break;
case 0x31: util::stream_format(stream, "lwc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
case 0x32: util::stream_format(stream, "lwc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
case 0x33: util::stream_format(stream, "lwc3 %s,%s(%s)", cpreg[3][rt], signed_16bit(op), reg[rs]); break;
- case 0x34: util::stream_format(stream, "ldc0 [invalid]"); break;
- case 0x35: util::stream_format(stream, "ldc1 [invalid]"); break;
- case 0x36: util::stream_format(stream, "ldc2 [invalid]"); break;
- case 0x37: util::stream_format(stream, "ldc3 [invalid]"); break;
- case 0x38: util::stream_format(stream, "sc [invalid]"); break;
case 0x39: util::stream_format(stream, "swc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
case 0x3a: util::stream_format(stream, "swc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
case 0x3b: util::stream_format(stream, "swc3 %s,%s(%s)", cpreg[3][rt], signed_16bit(op), reg[rs]); break;
- case 0x3c: util::stream_format(stream, "sdc0 [invalid]"); break;
- case 0x3d: util::stream_format(stream, "sdc1 [invalid]"); break;
- case 0x3e: util::stream_format(stream, "sdc2 [invalid]"); break;
- case 0x3f: util::stream_format(stream, "sdc3 [invalid]"); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 4 | flags | SUPPORTED;
}
diff --git a/src/devices/cpu/mips/mips3.cpp b/src/devices/cpu/mips/mips3.cpp
index bd50fb22df7..060c5acfc2f 100644
--- a/src/devices/cpu/mips/mips3.cpp
+++ b/src/devices/cpu/mips/mips3.cpp
@@ -9,7 +9,6 @@
***************************************************************************/
#include "emu.h"
-#include "debugger.h"
#include "mips3.h"
#include "mips3com.h"
#include "mips3dsm.h"
@@ -19,6 +18,9 @@
#define ENABLE_OVERFLOWS (0)
#define ENABLE_EE_ELF_LOADER (0)
#define ENABLE_EE_DECI2 (0)
+#define ENABLE_O2_DPRINTF (0)
+
+#include "o2dprintf.hxx"
/***************************************************************************
HELPER MACROS
@@ -124,7 +126,8 @@ DEFINE_DEVICE_TYPE(R5000BE, r5000be_device, "r5000be", "MIPS R5000 (big)")
DEFINE_DEVICE_TYPE(R5000LE, r5000le_device, "r5000le", "MIPS R5000 (little)")
DEFINE_DEVICE_TYPE(VR5500BE, vr5500be_device, "vr5500be", "NEC VR5500 (big)")
DEFINE_DEVICE_TYPE(VR5500LE, vr5500le_device, "vr5500le", "NEC VR5500 (little)")
-DEFINE_DEVICE_TYPE(R5900LE, r5900le_device, "r5900le", "Emotion Engine Core")
+DEFINE_DEVICE_TYPE(R5900BE, r5900be_device, "r5900be", "Emotion Engine Core (big)")
+DEFINE_DEVICE_TYPE(R5900LE, r5900le_device, "r5900le", "Emotion Engine Core (little)")
DEFINE_DEVICE_TYPE(QED5271BE, qed5271be_device, "qed5271be", "MIPS QED5271 (big)")
DEFINE_DEVICE_TYPE(QED5271LE, qed5271le_device, "qed5271le", "MIPS QED5271 (little)")
DEFINE_DEVICE_TYPE(RM7000BE, rm7000be_device, "rm7000be", "MIPS RM7000 (big)")
@@ -244,7 +247,7 @@ void mips3_device::generate_exception(int exception, int backup)
if (exception != 0)
{
- fprintf(stderr, "Exception: PC=%08X, PPC=%08X\n", m_core->pc, m_ppc);
+ fprintf(stderr, "Exception type %d: PC=%08X, PPC=%08X\n", exception, m_core->pc, m_ppc);
machine().debug_break();
}
*/
@@ -345,11 +348,9 @@ void mips3_device::generate_exception(int exception, int backup)
void mips3_device::generate_tlb_exception(int exception, offs_t address)
{
m_core->cpr[0][COP0_BadVAddr] = address;
- if(exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE || exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL)
- {
- m_core->cpr[0][COP0_Context] = (m_core->cpr[0][COP0_Context] & 0xff800000) | ((address >> 9) & 0x007ffff0);
- m_core->cpr[0][COP0_EntryHi] = (address & 0xffffe000) | (m_core->cpr[0][COP0_EntryHi] & 0xff);
- }
+ m_core->cpr[0][COP0_Context] = (m_core->cpr[0][COP0_Context] & 0xff800000) | ((address >> 9) & 0x007ffff0);
+ m_core->cpr[0][COP0_EntryHi] = (address & 0xffffe000) | (m_core->cpr[0][COP0_EntryHi] & 0xff);
+
generate_exception(exception, 1);
}
@@ -372,7 +373,7 @@ void mips3_device::check_irqs()
generate_exception(EXCEPTION_INTERRUPT, 0);
}
-void r5900le_device::check_irqs()
+void r5900_device::check_irqs()
{
if ((CAUSE & SR & 0xfc00) && (SR & SR_IE) && (SR & SR_EIE) && !(SR & (SR_EXL | SR_ERL)))
generate_exception(EXCEPTION_INTERRUPT, 0);
@@ -401,38 +402,35 @@ void mips3_device::device_start()
{
if (m_data_bits == 32)
{
- auto cache = m_program->cache<2, 0, ENDIANNESS_LITTLE>();
- m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); };
- m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); };
+ m_program->cache(m_cache32le);
+ m_pr32 = delegate<u32 (offs_t)>(&memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache::read_dword, &m_cache32le);
+ m_prptr = [this] (offs_t address) -> const void * { return m_cache32le.read_ptr(address); };
}
else
{
- auto cache = m_program->cache<3, 0, ENDIANNESS_LITTLE>();
- m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); };
- m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); };
+ m_program->cache(m_cache64le);
+ m_pr32 = delegate<u32 (offs_t)>(&memory_access<32, 3, 0, ENDIANNESS_LITTLE>::cache::read_dword, &m_cache64le);
+ m_prptr = [this] (offs_t address) -> const void * { return m_cache64le.read_ptr(address); };
}
}
else
{
if (m_data_bits == 32)
{
- auto cache = m_program->cache<2, 0, ENDIANNESS_BIG>();
- m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); };
- m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); };
+ m_program->cache(m_cache32be);
+ m_pr32 = delegate<u32 (offs_t)>(&memory_access<32, 2, 0, ENDIANNESS_BIG>::cache::read_dword, &m_cache32be);
+ m_prptr = [this] (offs_t address) -> const void * { return m_cache32be.read_ptr(address); };
}
else
{
- auto cache = m_program->cache<3, 0, ENDIANNESS_BIG>();
- m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); };
- m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); };
+ m_program->cache(m_cache64be);
+ m_pr32 = delegate<u32 (offs_t)>(&memory_access<32, 3, 0, ENDIANNESS_BIG>::cache::read_dword, &m_cache64be);
+ m_prptr = [this] (offs_t address) -> const void * { return m_cache64be.read_ptr(address); };
}
}
- /* set up the endianness */
- m_program->accessors(m_memory);
-
/* allocate a timer for the compare interrupt */
- m_compare_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mips3_device::compare_int_callback), this));
+ m_compare_int_timer = timer_alloc(FUNC(mips3_device::compare_int_callback), this);
uint32_t flags = 0;
/* initialize the UML generator */
@@ -444,9 +442,9 @@ void mips3_device::device_start()
for (int regnum = 0; regnum < 32; regnum++)
{
char buf[10];
- sprintf(buf, "r%d", regnum);
+ snprintf(buf, 10, "r%d", regnum);
m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf);
- sprintf(buf, "f%d", regnum);
+ snprintf(buf, 10, "f%d", regnum);
m_drcuml->symbol_add(&m_core->cpr[1][regnum], sizeof(m_core->cpr[1][regnum]), buf);
}
m_drcuml->symbol_add(&m_core->r[REG_LO], sizeof(m_core->r[REG_LO]), "lo");
@@ -474,7 +472,8 @@ void mips3_device::device_start()
m_drcuml->symbol_add(&m_core->cpr[0][COP0_TagLo], sizeof(m_core->cpr[0][COP0_TagLo]), "TagLo");
m_drcuml->symbol_add(&m_core->cpr[0][COP0_TagHi], sizeof(m_core->cpr[0][COP0_TagHi]), "TagHi");
m_drcuml->symbol_add(&m_core->cpr[0][COP0_ErrorPC], sizeof(m_core->cpr[0][COP0_ErrorPC]), "ErrorPC");
- m_drcuml->symbol_add(&m_core->ccr[1][31], sizeof(m_core->cpr[1][31]), "fcr31");
+ m_drcuml->symbol_add(&m_core->ccr[1][0], sizeof(m_core->ccr[1][0]), "fcr0");
+ m_drcuml->symbol_add(&m_core->ccr[1][31], sizeof(m_core->ccr[1][31]), "fcr31");
m_drcuml->symbol_add(&m_core->mode, sizeof(m_core->mode), "mode");
m_drcuml->symbol_add(&m_core->arg0, sizeof(m_core->arg0), "arg0");
m_drcuml->symbol_add(&m_core->arg1, sizeof(m_core->arg1), "arg1");
@@ -545,73 +544,73 @@ void mips3_device::device_start()
#if USE_ABI_REG_NAMES
state_add( MIPS3_R0, "zero", m_core->r[0]).callimport().formatstr("%016X"); // Can't change R0
- state_add( MIPS3_R1, "at", m_core->r[1]).formatstr("%016X");
- state_add( MIPS3_R2, "v0", m_core->r[2]).formatstr("%016X");
- state_add( MIPS3_R3, "v1", m_core->r[3]).formatstr("%016X");
- state_add( MIPS3_R4, "a0", m_core->r[4]).formatstr("%016X");
- state_add( MIPS3_R5, "a1", m_core->r[5]).formatstr("%016X");
- state_add( MIPS3_R6, "a2", m_core->r[6]).formatstr("%016X");
- state_add( MIPS3_R7, "a3", m_core->r[7]).formatstr("%016X");
- state_add( MIPS3_R8, "t0", m_core->r[8]).formatstr("%016X");
- state_add( MIPS3_R9, "t1", m_core->r[9]).formatstr("%016X");
- state_add( MIPS3_R10, "t2", m_core->r[10]).formatstr("%016X");
- state_add( MIPS3_R11, "t3", m_core->r[11]).formatstr("%016X");
- state_add( MIPS3_R12, "t4", m_core->r[12]).formatstr("%016X");
- state_add( MIPS3_R13, "t5", m_core->r[13]).formatstr("%016X");
- state_add( MIPS3_R14, "t6", m_core->r[14]).formatstr("%016X");
- state_add( MIPS3_R15, "t7", m_core->r[15]).formatstr("%016X");
- state_add( MIPS3_R16, "s0", m_core->r[16]).formatstr("%016X");
- state_add( MIPS3_R17, "s1", m_core->r[17]).formatstr("%016X");
- state_add( MIPS3_R18, "s2", m_core->r[18]).formatstr("%016X");
- state_add( MIPS3_R19, "s3", m_core->r[19]).formatstr("%016X");
- state_add( MIPS3_R20, "s4", m_core->r[20]).formatstr("%016X");
- state_add( MIPS3_R21, "s5", m_core->r[21]).formatstr("%016X");
- state_add( MIPS3_R22, "s6", m_core->r[22]).formatstr("%016X");
- state_add( MIPS3_R23, "s7", m_core->r[23]).formatstr("%016X");
- state_add( MIPS3_R24, "t8", m_core->r[24]).formatstr("%016X");
- state_add( MIPS3_R25, "t9", m_core->r[25]).formatstr("%016X");
- state_add( MIPS3_R26, "k0", m_core->r[26]).formatstr("%016X");
- state_add( MIPS3_R27, "k1", m_core->r[27]).formatstr("%016X");
- state_add( MIPS3_R28, "gp", m_core->r[28]).formatstr("%016X");
- state_add( MIPS3_R29, "sp", m_core->r[29]).formatstr("%016X");
- state_add( MIPS3_R30, "fp", m_core->r[30]).formatstr("%016X");
- state_add( MIPS3_R31, "ra", m_core->r[31]).formatstr("%016X");
+ state_add( MIPS3_R1, "at", m_core->r[1]).formatstr("%016X").callimport();
+ state_add( MIPS3_R2, "v0", m_core->r[2]).formatstr("%016X").callimport();
+ state_add( MIPS3_R3, "v1", m_core->r[3]).formatstr("%016X").callimport();
+ state_add( MIPS3_R4, "a0", m_core->r[4]).formatstr("%016X").callimport();
+ state_add( MIPS3_R5, "a1", m_core->r[5]).formatstr("%016X").callimport();
+ state_add( MIPS3_R6, "a2", m_core->r[6]).formatstr("%016X").callimport();
+ state_add( MIPS3_R7, "a3", m_core->r[7]).formatstr("%016X").callimport();
+ state_add( MIPS3_R8, "t0", m_core->r[8]).formatstr("%016X").callimport();
+ state_add( MIPS3_R9, "t1", m_core->r[9]).formatstr("%016X").callimport();
+ state_add( MIPS3_R10, "t2", m_core->r[10]).formatstr("%016X").callimport();
+ state_add( MIPS3_R11, "t3", m_core->r[11]).formatstr("%016X").callimport();
+ state_add( MIPS3_R12, "t4", m_core->r[12]).formatstr("%016X").callimport();
+ state_add( MIPS3_R13, "t5", m_core->r[13]).formatstr("%016X").callimport();
+ state_add( MIPS3_R14, "t6", m_core->r[14]).formatstr("%016X").callimport();
+ state_add( MIPS3_R15, "t7", m_core->r[15]).formatstr("%016X").callimport();
+ state_add( MIPS3_R16, "s0", m_core->r[16]).formatstr("%016X").callimport();
+ state_add( MIPS3_R17, "s1", m_core->r[17]).formatstr("%016X").callimport();
+ state_add( MIPS3_R18, "s2", m_core->r[18]).formatstr("%016X").callimport();
+ state_add( MIPS3_R19, "s3", m_core->r[19]).formatstr("%016X").callimport();
+ state_add( MIPS3_R20, "s4", m_core->r[20]).formatstr("%016X").callimport();
+ state_add( MIPS3_R21, "s5", m_core->r[21]).formatstr("%016X").callimport();
+ state_add( MIPS3_R22, "s6", m_core->r[22]).formatstr("%016X").callimport();
+ state_add( MIPS3_R23, "s7", m_core->r[23]).formatstr("%016X").callimport();
+ state_add( MIPS3_R24, "t8", m_core->r[24]).formatstr("%016X").callimport();
+ state_add( MIPS3_R25, "t9", m_core->r[25]).formatstr("%016X").callimport();
+ state_add( MIPS3_R26, "k0", m_core->r[26]).formatstr("%016X").callimport();
+ state_add( MIPS3_R27, "k1", m_core->r[27]).formatstr("%016X").callimport();
+ state_add( MIPS3_R28, "gp", m_core->r[28]).formatstr("%016X").callimport();
+ state_add( MIPS3_R29, "sp", m_core->r[29]).formatstr("%016X").callimport();
+ state_add( MIPS3_R30, "fp", m_core->r[30]).formatstr("%016X").callimport();
+ state_add( MIPS3_R31, "ra", m_core->r[31]).formatstr("%016X").callimport();
#else
state_add( MIPS3_R0, "R0", m_core->r[0]).callimport().formatstr("%016X"); // Can't change R0
- state_add( MIPS3_R1, "R1", m_core->r[1]).formatstr("%016X");
- state_add( MIPS3_R2, "R2", m_core->r[2]).formatstr("%016X");
- state_add( MIPS3_R3, "R3", m_core->r[3]).formatstr("%016X");
- state_add( MIPS3_R4, "R4", m_core->r[4]).formatstr("%016X");
- state_add( MIPS3_R5, "R5", m_core->r[5]).formatstr("%016X");
- state_add( MIPS3_R6, "R6", m_core->r[6]).formatstr("%016X");
- state_add( MIPS3_R7, "R7", m_core->r[7]).formatstr("%016X");
- state_add( MIPS3_R8, "R8", m_core->r[8]).formatstr("%016X");
- state_add( MIPS3_R9, "R9", m_core->r[9]).formatstr("%016X");
- state_add( MIPS3_R10, "R10", m_core->r[10]).formatstr("%016X");
- state_add( MIPS3_R11, "R11", m_core->r[11]).formatstr("%016X");
- state_add( MIPS3_R12, "R12", m_core->r[12]).formatstr("%016X");
- state_add( MIPS3_R13, "R13", m_core->r[13]).formatstr("%016X");
- state_add( MIPS3_R14, "R14", m_core->r[14]).formatstr("%016X");
- state_add( MIPS3_R15, "R15", m_core->r[15]).formatstr("%016X");
- state_add( MIPS3_R16, "R16", m_core->r[16]).formatstr("%016X");
- state_add( MIPS3_R17, "R17", m_core->r[17]).formatstr("%016X");
- state_add( MIPS3_R18, "R18", m_core->r[18]).formatstr("%016X");
- state_add( MIPS3_R19, "R19", m_core->r[19]).formatstr("%016X");
- state_add( MIPS3_R20, "R20", m_core->r[20]).formatstr("%016X");
- state_add( MIPS3_R21, "R21", m_core->r[21]).formatstr("%016X");
- state_add( MIPS3_R22, "R22", m_core->r[22]).formatstr("%016X");
- state_add( MIPS3_R23, "R23", m_core->r[23]).formatstr("%016X");
- state_add( MIPS3_R24, "R24", m_core->r[24]).formatstr("%016X");
- state_add( MIPS3_R25, "R25", m_core->r[25]).formatstr("%016X");
- state_add( MIPS3_R26, "R26", m_core->r[26]).formatstr("%016X");
- state_add( MIPS3_R27, "R27", m_core->r[27]).formatstr("%016X");
- state_add( MIPS3_R28, "R28", m_core->r[28]).formatstr("%016X");
- state_add( MIPS3_R29, "R29", m_core->r[29]).formatstr("%016X");
- state_add( MIPS3_R30, "R30", m_core->r[30]).formatstr("%016X");
- state_add( MIPS3_R31, "R31", m_core->r[31]).formatstr("%016X");
+ state_add( MIPS3_R1, "R1", m_core->r[1]).formatstr("%016X").callimport();
+ state_add( MIPS3_R2, "R2", m_core->r[2]).formatstr("%016X").callimport();
+ state_add( MIPS3_R3, "R3", m_core->r[3]).formatstr("%016X").callimport();
+ state_add( MIPS3_R4, "R4", m_core->r[4]).formatstr("%016X").callimport();
+ state_add( MIPS3_R5, "R5", m_core->r[5]).formatstr("%016X").callimport();
+ state_add( MIPS3_R6, "R6", m_core->r[6]).formatstr("%016X").callimport();
+ state_add( MIPS3_R7, "R7", m_core->r[7]).formatstr("%016X").callimport();
+ state_add( MIPS3_R8, "R8", m_core->r[8]).formatstr("%016X").callimport();
+ state_add( MIPS3_R9, "R9", m_core->r[9]).formatstr("%016X").callimport();
+ state_add( MIPS3_R10, "R10", m_core->r[10]).formatstr("%016X").callimport();
+ state_add( MIPS3_R11, "R11", m_core->r[11]).formatstr("%016X").callimport();
+ state_add( MIPS3_R12, "R12", m_core->r[12]).formatstr("%016X").callimport();
+ state_add( MIPS3_R13, "R13", m_core->r[13]).formatstr("%016X").callimport();
+ state_add( MIPS3_R14, "R14", m_core->r[14]).formatstr("%016X").callimport();
+ state_add( MIPS3_R15, "R15", m_core->r[15]).formatstr("%016X").callimport();
+ state_add( MIPS3_R16, "R16", m_core->r[16]).formatstr("%016X").callimport();
+ state_add( MIPS3_R17, "R17", m_core->r[17]).formatstr("%016X").callimport();
+ state_add( MIPS3_R18, "R18", m_core->r[18]).formatstr("%016X").callimport();
+ state_add( MIPS3_R19, "R19", m_core->r[19]).formatstr("%016X").callimport();
+ state_add( MIPS3_R20, "R20", m_core->r[20]).formatstr("%016X").callimport();
+ state_add( MIPS3_R21, "R21", m_core->r[21]).formatstr("%016X").callimport();
+ state_add( MIPS3_R22, "R22", m_core->r[22]).formatstr("%016X").callimport();
+ state_add( MIPS3_R23, "R23", m_core->r[23]).formatstr("%016X").callimport();
+ state_add( MIPS3_R24, "R24", m_core->r[24]).formatstr("%016X").callimport();
+ state_add( MIPS3_R25, "R25", m_core->r[25]).formatstr("%016X").callimport();
+ state_add( MIPS3_R26, "R26", m_core->r[26]).formatstr("%016X").callimport();
+ state_add( MIPS3_R27, "R27", m_core->r[27]).formatstr("%016X").callimport();
+ state_add( MIPS3_R28, "R28", m_core->r[28]).formatstr("%016X").callimport();
+ state_add( MIPS3_R29, "R29", m_core->r[29]).formatstr("%016X").callimport();
+ state_add( MIPS3_R30, "R30", m_core->r[30]).formatstr("%016X").callimport();
+ state_add( MIPS3_R31, "R31", m_core->r[31]).formatstr("%016X").callimport();
#endif
- state_add( MIPS3_HI, "HI", m_core->r[REG_HI]).formatstr("%016X");
- state_add( MIPS3_LO, "LO", m_core->r[REG_LO]).formatstr("%016X");
+ state_add( MIPS3_HI, "HI", m_core->r[REG_HI]).formatstr("%016X").callimport();
+ state_add( MIPS3_LO, "LO", m_core->r[REG_LO]).formatstr("%016X").callimport();
state_add( MIPS3_CCR1_31, "CCR31", m_core->ccr[1][31]).formatstr("%08X");
@@ -728,13 +727,12 @@ void mips3_device::device_start()
state_add( MIPS3_LLADDR, "LLAddr", m_core->cpr[0][COP0_LLAddr]).formatstr("%08X");
state_add( STATE_GENPCBASE, "CURPC", m_core->pc).noshow();
- state_add( STATE_GENSP, "CURSP", m_core->r[31]).noshow();
state_add( STATE_GENFLAGS, "CURFLAGS", m_debugger_temp).formatstr("%1s").noshow();
set_icountptr(m_core->icount);
}
-void r5900le_device::device_start()
+void r5900_device::device_start()
{
mips3_device::device_start();
#if USE_ABI_REG_NAMES
@@ -816,6 +814,16 @@ void mips3_device::state_export(const device_state_entry &entry)
}
}
+void mips3_device::state_import(const device_state_entry &entry)
+{
+ if (m_isdrc && (entry.index() >= MIPS3_R1) && (entry.index() <= MIPS3_LO))
+ {
+ // this refers to HI as R32 and LO as R33 because I'm lazy
+ const unsigned regnum = entry.index() - MIPS3_R0;
+ if (m_regmap[regnum].is_int_register())
+ logerror("debugger R%u = %08X, must update UML I%u\n", regnum, m_core->r[regnum], m_regmap[regnum].ireg() - uml::REG_I0);
+ }
+}
void mips3_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
@@ -1102,6 +1110,9 @@ void mips3_device::device_reset()
m_core->llbit = 0;
m_core->count_zero_time = total_cycles();
+ /* initialize the FPU state */
+ m_core->ccr[1][0] = compute_fpu_prid_register();
+
/* initialize the TLB state */
for (int tlbindex = 0; tlbindex < m_tlbentries; tlbindex++)
{
@@ -1117,11 +1128,11 @@ void mips3_device::device_reset()
}
/* load the fixed TLB range */
- vtlb_load(2 * m_tlbentries + 0, (0xa0000000 - 0x80000000) >> MIPS3_MIN_PAGE_SHIFT, 0x80000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
- vtlb_load(2 * m_tlbentries + 1, (0xc0000000 - 0xa0000000) >> MIPS3_MIN_PAGE_SHIFT, 0xa0000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
+ vtlb_load(2 * m_tlbentries + 0, (0xa0000000 - 0x80000000) >> MIPS3_MIN_PAGE_SHIFT, 0x80000000, 0x00000000 | READ_ALLOWED | WRITE_ALLOWED | FETCH_ALLOWED | FLAG_VALID);
+ vtlb_load(2 * m_tlbentries + 1, (0xc0000000 - 0xa0000000) >> MIPS3_MIN_PAGE_SHIFT, 0xa0000000, 0x00000000 | READ_ALLOWED | WRITE_ALLOWED | FETCH_ALLOWED | FLAG_VALID);
// TX4925 on-board peripherals pass-through
if (m_flavor == MIPS3_TYPE_TX4925)
- vtlb_load(2 * m_tlbentries + 2, (0xff200000 - 0xff1f0000) >> MIPS3_MIN_PAGE_SHIFT, 0xff1f0000, 0xff1f0000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
+ vtlb_load(2 * m_tlbentries + 2, (0xff200000 - 0xff1f0000) >> MIPS3_MIN_PAGE_SHIFT, 0xff1f0000, 0xff1f0000 | READ_ALLOWED | WRITE_ALLOWED | FETCH_ALLOWED | FLAG_VALID);
m_tlb_seed = 0;
m_core->mode = (MODE_KERNEL << 1) | 0;
@@ -1137,26 +1148,34 @@ void mips3_device::device_reset()
}
-bool mips3_device::memory_translate(int spacenum, int intention, offs_t &address)
+bool mips3_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
{
+ target_space = &space(spacenum);
+
/* only applies to the program address space */
if (spacenum == AS_PROGRAM)
{
const vtlb_entry *table = vtlb_table();
vtlb_entry entry = table[address >> MIPS3_MIN_PAGE_SHIFT];
- if ((entry & (1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)))) == 0)
+ if ((entry & (1 << intention)) == 0)
return false;
address = (entry & ~MIPS3_MIN_PAGE_MASK) | (address & MIPS3_MIN_PAGE_MASK);
}
return true;
}
+bool r4650_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
+{
+ target_space = &space(spacenum);
+ return true;
+}
+
std::unique_ptr<util::disasm_interface> mips3_device::create_disassembler()
{
return std::make_unique<mips3_disassembler>();
}
-std::unique_ptr<util::disasm_interface> r5900le_device::create_disassembler()
+std::unique_ptr<util::disasm_interface> r5900_device::create_disassembler()
{
return std::make_unique<ee_disassembler>();
}
@@ -1170,7 +1189,7 @@ std::unique_ptr<util::disasm_interface> r5900le_device::create_disassembler()
inline bool mips3_device::RBYTE(offs_t address, uint32_t *result)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
const uint32_t tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
@@ -1182,11 +1201,11 @@ inline bool mips3_device::RBYTE(offs_t address, uint32_t *result)
*result = m_fastram[ramnum].offset_base8[tlbaddress ^ m_byte_xor];
return true;
}
- *result = (*m_memory.read_byte)(*m_program, tlbaddress);
+ *result = m_program->read_byte(tlbaddress);
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1203,7 +1222,7 @@ inline bool mips3_device::RBYTE(offs_t address, uint32_t *result)
inline bool mips3_device::RHALF(offs_t address, uint32_t *result)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
const uint32_t tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
@@ -1215,11 +1234,11 @@ inline bool mips3_device::RHALF(offs_t address, uint32_t *result)
*result = m_fastram[ramnum].offset_base16[(tlbaddress ^ m_word_xor) >> 1];
return true;
}
- *result = (*m_memory.read_word)(*m_program, tlbaddress);
+ *result = m_program->read_word(tlbaddress);
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1236,7 +1255,7 @@ inline bool mips3_device::RHALF(offs_t address, uint32_t *result)
inline bool mips3_device::RWORD(offs_t address, uint32_t *result, bool insn)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
const uint32_t tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
@@ -1248,11 +1267,11 @@ inline bool mips3_device::RWORD(offs_t address, uint32_t *result, bool insn)
*result = m_fastram[ramnum].offset_base32[(tlbaddress ^ m_dword_xor) >> 2];
return true;
}
- *result = (*m_memory.read_dword)(*m_program, tlbaddress);
+ *result = m_program->read_dword(tlbaddress);
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1269,13 +1288,13 @@ inline bool mips3_device::RWORD(offs_t address, uint32_t *result, bool insn)
inline bool mips3_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
- *result = (*m_memory.read_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask);
+ *result = m_program->read_dword((tlbval & ~0xfff) | (address & 0xfff), mem_mask);
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1292,13 +1311,13 @@ inline bool mips3_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_
inline bool mips3_device::RDOUBLE(offs_t address, uint64_t *result)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
- *result = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff));
+ *result = m_program->read_qword((tlbval & ~0xfff) | (address & 0xfff));
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1315,13 +1334,13 @@ inline bool mips3_device::RDOUBLE(offs_t address, uint64_t *result)
inline bool mips3_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
- *result = (*m_memory.read_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask);
+ *result = m_program->read_qword((tlbval & ~0xfff) | (address & 0xfff), mem_mask);
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1338,7 +1357,7 @@ inline bool mips3_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint6
inline void mips3_device::WBYTE(offs_t address, uint8_t data)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
const uint32_t tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
@@ -1350,15 +1369,15 @@ inline void mips3_device::WBYTE(offs_t address, uint8_t data)
m_fastram[ramnum].offset_base8[tlbaddress ^ m_byte_xor] = data;
return;
}
- (*m_memory.write_byte)(*m_program, tlbaddress, data);
+ m_program->write_byte(tlbaddress, data);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1372,7 +1391,7 @@ inline void mips3_device::WBYTE(offs_t address, uint8_t data)
inline void mips3_device::WHALF(offs_t address, uint16_t data)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
const uint32_t tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
@@ -1384,15 +1403,15 @@ inline void mips3_device::WHALF(offs_t address, uint16_t data)
m_fastram[ramnum].offset_base16[(tlbaddress ^ m_word_xor) >> 1] = data;
return;
}
- (*m_memory.write_word)(*m_program, tlbaddress, data);
+ m_program->write_word(tlbaddress, data);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1406,7 +1425,7 @@ inline void mips3_device::WHALF(offs_t address, uint16_t data)
inline void mips3_device::WWORD(offs_t address, uint32_t data)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
const uint32_t tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
@@ -1418,15 +1437,15 @@ inline void mips3_device::WWORD(offs_t address, uint32_t data)
m_fastram[ramnum].offset_base32[(tlbaddress ^ m_dword_xor) >> 2] = data;
return;
}
- (*m_memory.write_dword)(*m_program, tlbaddress, data);
+ m_program->write_dword(tlbaddress, data);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1440,17 +1459,17 @@ inline void mips3_device::WWORD(offs_t address, uint32_t data)
inline void mips3_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
- (*m_memory.write_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
+ m_program->write_dword((tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1464,17 +1483,17 @@ inline void mips3_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t m
inline void mips3_device::WDOUBLE(offs_t address, uint64_t data)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
- (*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data);
+ m_program->write_qword((tlbval & ~0xfff) | (address & 0xfff), data);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1488,17 +1507,17 @@ inline void mips3_device::WDOUBLE(offs_t address, uint64_t data)
inline void mips3_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask)
{
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
- (*m_memory.write_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
+ m_program->write_qword((tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1509,38 +1528,211 @@ inline void mips3_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t
}
}
-inline void r5900le_device::WBYTE(offs_t address, uint8_t data)
+inline bool r4650_device::RBYTE(offs_t address, uint32_t *result)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ {
+ *result = m_program->read_byte(address);
+ return true;
+ }
+
+ if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ {
+ generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
+ *result = 0;
+ return false;
+ }
+ *result = m_program->read_byte(address + m_core->cpr[0][COP0_R4650_DBase]);
+ return true;
+}
+
+inline bool r4650_device::RHALF(offs_t address, uint32_t *result)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ {
+ *result = m_program->read_word(address);
+ return true;
+ }
+
+ if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ {
+ generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
+ *result = 0;
+ return false;
+ }
+ *result = m_program->read_word(address + m_core->cpr[0][COP0_R4650_DBase]);
+ return true;
+}
+
+inline bool r4650_device::RWORD(offs_t address, uint32_t *result, bool insn)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ {
+ *result = m_program->read_dword(address);
+ return true;
+ }
+
+ static const uint32_t BASE_INDICES[2] = { COP0_R4650_DBase, COP0_R4650_IBase };
+ static const uint32_t BOUND_INDICES[2] = { COP0_R4650_DBound, COP0_R4650_IBound };
+ const uint32_t base = m_core->cpr[0][BASE_INDICES[insn]];
+ const uint32_t bound = m_core->cpr[0][BOUND_INDICES[insn]];
+ if ((address & 0xfffff000) > bound)
+ {
+ generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
+ *result = 0;
+ return false;
+ }
+ *result = m_program->read_dword(address + base);
+ return true;
+}
+
+inline bool r4650_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ {
+ *result = m_program->read_dword(address, mem_mask);
+ return true;
+ }
+
+ if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ {
+ generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
+ *result = 0;
+ return false;
+ }
+ *result = m_program->read_dword(address + m_core->cpr[0][COP0_R4650_DBase], mem_mask);
+ return true;
+}
+
+inline bool r4650_device::RDOUBLE(offs_t address, uint64_t *result)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ {
+ *result = m_program->read_qword(address);
+ return true;
+ }
+
+ if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ {
+ generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
+ *result = 0;
+ return false;
+ }
+ *result = m_program->read_qword(address + m_core->cpr[0][COP0_R4650_DBase]);
+ return true;
+}
+
+inline bool r4650_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ {
+ *result = m_program->read_qword(address, mem_mask);
+ return true;
+ }
+
+ if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ {
+ generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
+ *result = 0;
+ return false;
+ }
+ *result = m_program->read_qword(address + m_core->cpr[0][COP0_R4650_DBase], mem_mask);
+ return true;
+}
+
+inline void r4650_device::WBYTE(offs_t address, uint8_t data)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ m_program->write_byte(address, data);
+ else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
+ else
+ m_program->write_byte(address + m_core->cpr[0][COP0_R4650_DBound], data);
+}
+
+inline void r4650_device::WHALF(offs_t address, uint16_t data)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ m_program->write_word(address, data);
+ else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
+ else
+ m_program->write_word(address + m_core->cpr[0][COP0_R4650_DBound], data);
+}
+
+inline void r4650_device::WWORD(offs_t address, uint32_t data)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ m_program->write_dword(address, data);
+ else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
+ else
+ m_program->write_dword(address + m_core->cpr[0][COP0_R4650_DBound], data);
+}
+
+inline void r4650_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ m_program->write_dword(address, data, mem_mask);
+ else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
+ else
+ m_program->write_dword(address + m_core->cpr[0][COP0_R4650_DBound], data, mem_mask);
+}
+
+inline void r4650_device::WDOUBLE(offs_t address, uint64_t data)
+{
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ m_program->write_qword(address, data);
+ else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
+ else
+ m_program->write_qword(address + m_core->cpr[0][COP0_R4650_DBound], data);
+}
+
+inline void r4650_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask)
{
- if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_byte)(*m_program, address, data);
+ if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
+ m_program->write_qword(address, data, mem_mask);
+ else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
+ generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
+ else
+ m_program->write_qword(address + m_core->cpr[0][COP0_R4650_DBound], data, mem_mask);
+}
+
+inline void r5900_device::WBYTE(offs_t address, uint8_t data)
+{
+ if (address >= 0x70000000 && address < 0x70004000) m_program->write_byte(address, data);
else mips3_device::WBYTE(address, data);
}
-inline void r5900le_device::WHALF(offs_t address, uint16_t data)
+inline void r5900_device::WHALF(offs_t address, uint16_t data)
{
- if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_word)(*m_program, address, data);
+ if (address >= 0x70000000 && address < 0x70004000) m_program->write_word(address, data);
else mips3_device::WHALF(address, data);
}
-inline void r5900le_device::WWORD(offs_t address, uint32_t data)
+inline void r5900_device::WWORD(offs_t address, uint32_t data)
{
- if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_dword)(*m_program, address, data);
+ if (address >= 0x70000000 && address < 0x70004000) m_program->write_dword(address, data);
else mips3_device::WWORD(address, data);
}
-inline void r5900le_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask)
+inline void r5900_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask)
{
- if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_dword_masked)(*m_program, address, data, mem_mask);
+ if (address >= 0x70000000 && address < 0x70004000) m_program->write_dword(address, data, mem_mask);
else mips3_device::WWORD_MASKED(address, data, mem_mask);
}
-inline void r5900le_device::WDOUBLE(offs_t address, uint64_t data) {
- if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_qword)(*m_program, address, data);
+inline void r5900_device::WDOUBLE(offs_t address, uint64_t data)
+{
+ if (address >= 0x70000000 && address < 0x70004000) m_program->write_qword(address, data);
else mips3_device::WDOUBLE(address, data);
}
-inline void r5900le_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask)
+inline void r5900_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask)
{
- if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_qword_masked)(*m_program, address, data, mem_mask);
+ if (address >= 0x70000000 && address < 0x70004000) m_program->write_qword(address, data, mem_mask);
else mips3_device::WDOUBLE_MASKED(address, data, mem_mask);
}
@@ -1548,24 +1740,56 @@ inline void r5900le_device::WQUAD(offs_t address, uint64_t data_hi, uint64_t dat
{
if (address >= 0x70000000 && address < 0x70004000)
{
- (*m_memory.write_qword)(*m_program, address, data_lo);
- (*m_memory.write_qword)(*m_program, address + 8, data_hi);
+ m_program->write_qword(address, data_lo);
+ m_program->write_qword(address + 8, data_hi);
+ return;
+ }
+
+ const uint32_t tlbval = vtlb_table()[address >> 12];
+ if (tlbval & WRITE_ALLOWED)
+ {
+ m_program->write_qword((tlbval & ~0xfff) | (address & 0xfff), data_lo);
+ m_program->write_qword((tlbval & ~0xfff) | ((address + 8) & 0xfff), data_hi);
+ }
+ else
+ {
+ if (tlbval & READ_ALLOWED)
+ {
+ generate_tlb_exception(EXCEPTION_TLBMOD, address);
+ }
+ else if (tlbval & FLAG_FIXED)
+ {
+ generate_tlb_exception(EXCEPTION_TLBSTORE, address);
+ }
+ else
+ {
+ generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address);
+ }
+ }
+}
+
+inline void r5900be_device::WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo)
+{
+ if (address >= 0x70000000 && address < 0x70004000)
+ {
+ m_program->write_qword(address, data_hi);
+ m_program->write_qword(address + 8, data_lo);
return;
}
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_WRITE_ALLOWED)
+ if (tlbval & WRITE_ALLOWED)
{
- (*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data_lo);
- (*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | ((address + 8) & 0xfff), data_hi);
+ m_program->write_qword((tlbval & ~0xfff) | (address & 0xfff), data_hi);
+ m_program->write_qword((tlbval & ~0xfff) | ((address + 8) & 0xfff), data_lo);
}
else
{
- if(tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
generate_tlb_exception(EXCEPTION_TLBMOD, address);
}
- else if(tlbval & VTLB_FLAG_FIXED)
+ else if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBSTORE, address);
}
@@ -1576,59 +1800,61 @@ inline void r5900le_device::WQUAD(offs_t address, uint64_t data_hi, uint64_t dat
}
}
-inline bool r5900le_device::RBYTE(offs_t address, uint32_t *result) {
- if (address >= 0x70000000 && address < 0x70004000) {
- *result = (*m_memory.read_byte)(*m_program, address);
+inline bool r5900_device::RBYTE(offs_t address, uint32_t *result)
+{
+ if (address >= 0x70000000 && address < 0x70004000)
+ {
+ *result = m_program->read_byte(address);
return true;
}
return mips3_device::RBYTE(address, result);
}
-inline bool r5900le_device::RHALF(offs_t address, uint32_t *result)
+inline bool r5900_device::RHALF(offs_t address, uint32_t *result)
{
if (address >= 0x70000000 && address < 0x70004000)
{
- *result = (*m_memory.read_word)(*m_program, address);
+ *result = m_program->read_word(address);
return true;
}
return mips3_device::RHALF(address, result);
}
-inline bool r5900le_device::RWORD(offs_t address, uint32_t *result, bool insn)
+inline bool r5900_device::RWORD(offs_t address, uint32_t *result, bool insn)
{
if (address >= 0x70000000 && address < 0x70004000)
{
- *result = (*m_memory.read_dword)(*m_program, address);
+ *result = m_program->read_dword(address);
return true;
}
return mips3_device::RWORD(address, result, insn);
}
-inline bool r5900le_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask)
+inline bool r5900_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask)
{
if (address >= 0x70000000 && address < 0x70004000)
{
- *result = (*m_memory.read_dword_masked)(*m_program, address, mem_mask);
+ *result = m_program->read_dword(address, mem_mask);
return true;
}
return mips3_device::RWORD_MASKED(address, result, mem_mask);
}
-inline bool r5900le_device::RDOUBLE(offs_t address, uint64_t *result)
+inline bool r5900_device::RDOUBLE(offs_t address, uint64_t *result)
{
if (address >= 0x70000000 && address < 0x70004000)
{
- *result = (*m_memory.read_qword)(*m_program, address);
+ *result = m_program->read_qword(address);
return true;
}
return mips3_device::RDOUBLE(address, result);
}
-inline bool r5900le_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask)
+inline bool r5900_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask)
{
if (address >= 0x70000000 && address < 0x70004000)
{
- *result = (*m_memory.read_qword_masked)(*m_program, address, mem_mask);
+ *result = m_program->read_qword(address, mem_mask);
return true;
}
return mips3_device::RDOUBLE_MASKED(address, result, mem_mask);
@@ -1638,20 +1864,52 @@ inline bool r5900le_device::RQUAD(offs_t address, uint64_t *result_hi, uint64_t
{
if (address >= 0x70000000 && address < 0x70004000)
{
- *result_lo = (*m_memory.read_qword)(*m_program, address);
- *result_hi = (*m_memory.read_qword)(*m_program, address + 8);
+ *result_lo = m_program->read_qword(address);
+ *result_hi = m_program->read_qword(address + 8);
return true;
}
const uint32_t tlbval = vtlb_table()[address >> 12];
- if (tlbval & VTLB_READ_ALLOWED)
+ if (tlbval & READ_ALLOWED)
{
- *result_lo = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff));
- *result_hi = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | ((address + 8) & 0xfff));
+ *result_lo = m_program->read_qword((tlbval & ~0xfff) | (address & 0xfff));
+ *result_hi = m_program->read_qword((tlbval & ~0xfff) | ((address + 8) & 0xfff));
}
else
{
- if(tlbval & VTLB_FLAG_FIXED)
+ if (tlbval & FLAG_FIXED)
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD, address);
+ }
+ else
+ {
+ generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address);
+ }
+ *result_hi = 0;
+ *result_lo = 0;
+ return false;
+ }
+ return true;
+}
+
+inline bool r5900be_device::RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo)
+{
+ if (address >= 0x70000000 && address < 0x70004000)
+ {
+ *result_hi = m_program->read_qword(address);
+ *result_lo = m_program->read_qword(address + 8);
+ return true;
+ }
+
+ const uint32_t tlbval = vtlb_table()[address >> 12];
+ if (tlbval & READ_ALLOWED)
+ {
+ *result_hi = m_program->read_qword((tlbval & ~0xfff) | (address & 0xfff));
+ *result_lo = m_program->read_qword((tlbval & ~0xfff) | ((address + 8) & 0xfff));
+ }
+ else
+ {
+ if (tlbval & FLAG_FIXED)
{
generate_tlb_exception(EXCEPTION_TLBLOAD, address);
}
@@ -1695,23 +1953,40 @@ uint64_t mips3_device::get_cop0_reg(int idx)
}
else if (idx == COP0_Random)
{
- int wired = m_core->cpr[0][COP0_Wired] & 0x3f;
- int range = 48 - wired;
- if (range > 0)
- return ((total_cycles() - m_core->count_zero_time) % range + wired) & 0x3f;
- else
- return 47;
+ uint32_t wired = m_core->cpr[0][COP0_Wired] & 0x3f;
+ uint32_t unwired = m_tlbentries - wired;
+
+ if (unwired == 0)
+ return m_tlbentries - 1;
+
+ return (generate_tlb_index() % unwired) + wired;
}
return m_core->cpr[0][idx];
}
+void r4650_device::set_cop0_reg(int idx, uint64_t val)
+{
+ switch (idx)
+ {
+ case COP0_R4650_IBase:
+ case COP0_R4650_IBound:
+ case COP0_R4650_DBase:
+ case COP0_R4650_DBound:
+ m_core->cpr[0][idx] = val;
+ break;
+ default:
+ mips3_device::set_cop0_reg(idx, val);
+ break;
+ }
+}
+
void mips3_device::set_cop0_reg(int idx, uint64_t val)
{
switch (idx)
{
case COP0_Cause:
CAUSE = (CAUSE & 0xfc00) | (val & ~0xfc00);
- if (CAUSE & 0x300)
+ if ((CAUSE & SR & 0x300) && (SR & SR_IE) && !(SR & (SR_EXL | SR_ERL)))
{
/* if we're in a delay slot, propogate the target PC before generating the exception */
if (m_nextpc != ~0)
@@ -1802,8 +2077,8 @@ void mips3_device::handle_cop0(uint32_t op)
case 0x08: /* BC */
switch (RTREG)
{
- case 0x00: /* BCzF */ if (!m_cf[0]) ADDPC(SIMMVAL); break;
- case 0x01: /* BCzF */ if (m_cf[0]) ADDPC(SIMMVAL); break;
+ case 0x00: /* BCzF */ if (!m_cf[0][0]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzF */ if (m_cf[0][0]) ADDPC(SIMMVAL); break;
case 0x02: /* BCzFL */ invalid_instruction(op); break;
case 0x03: /* BCzTL */ invalid_instruction(op); break;
default: invalid_instruction(op); break;
@@ -1980,25 +2255,31 @@ void mips3_device::handle_cop1_fr0(uint32_t op)
break;
case 0x03:
- if (IS_SINGLE(op)) { /* DIV.S */
- if (FTVALW_FR0 == 0 && (COP1_FCR31 & (1 << (FCR31_ENABLE + FPE_DIV0)))) {
+ if (IS_SINGLE(op)) /* DIV.S */
+ {
+ if (FTVALW_FR0 == 0 && (COP1_FCR31 & (1 << (FCR31_ENABLE + FPE_DIV0))))
+ {
COP1_FCR31 |= (1 << (FCR31_FLAGS + FPE_DIV0)); // Set flag
COP1_FCR31 |= (1 << (FCR31_CAUSE + FPE_DIV0)); // Set cause
generate_exception(EXCEPTION_FPE, 1);
//machine().debug_break();
}
- else {
+ else
+ {
FDVALS_FR0 = FSVALS_FR0 / FTVALS_FR0;
}
}
- else { /* DIV.D */
- if (FTVALL_FR0 == 0ull && (COP1_FCR31 & (1 << (FCR31_ENABLE + FPE_DIV0)))) {
+ else /* DIV.D */
+ {
+ if (FTVALL_FR0 == 0ull && (COP1_FCR31 & (1 << (FCR31_ENABLE + FPE_DIV0))))
+ {
COP1_FCR31 |= (1 << (FCR31_FLAGS + FPE_DIV0)); // Set flag
COP1_FCR31 |= (1 << (FCR31_CAUSE + FPE_DIV0)); // Set cause
generate_exception(EXCEPTION_FPE, 1);
//machine().debug_break();
}
- else {
+ else
+ {
FDVALD_FR0 = FSVALD_FR0 / FTVALD_FR0;
}
}
@@ -2866,7 +3147,7 @@ inline void mips3_device::set_cop2_creg(int idx, uint64_t val)
m_core->vfr[idx][0] = val;
}
-inline void r5900le_device::handle_dmfc2(uint32_t op)
+inline void r5900_device::handle_dmfc2(uint32_t op)
{
// QMFC2
if (!RTREG)
@@ -2884,7 +3165,7 @@ inline void r5900le_device::handle_dmfc2(uint32_t op)
m_core->rh[rt] = ((uint64_t)rtval[3] << 32) | rtval[2];
}
-inline void r5900le_device::handle_dmtc2(uint32_t op)
+inline void r5900_device::handle_dmtc2(uint32_t op)
{
// QMTC2
uint32_t rt = RTREG;
@@ -2896,23 +3177,23 @@ inline void r5900le_device::handle_dmtc2(uint32_t op)
}
}
-inline uint64_t r5900le_device::get_cop2_reg(int idx)
+inline uint64_t r5900_device::get_cop2_reg(int idx)
{
return reinterpret_cast<uint32_t*>(m_core->vfr[idx])[0];
}
-inline void r5900le_device::set_cop2_reg(int idx, uint64_t val)
+inline void r5900_device::set_cop2_reg(int idx, uint64_t val)
{
reinterpret_cast<uint32_t*>(m_core->vfr[idx])[0] = (uint32_t)val;
}
-inline uint64_t r5900le_device::get_cop2_creg(int idx)
+inline uint64_t r5900_device::get_cop2_creg(int idx)
{
logerror("%s: CFC2: Getting ccr[%d] (%08x)\n", machine().describe_context(), idx, m_core->vcr[idx]);
return m_core->vcr[idx];
}
-inline void r5900le_device::set_cop2_creg(int idx, uint64_t val)
+inline void r5900_device::set_cop2_creg(int idx, uint64_t val)
{
if (idx < 16)
{
@@ -3003,8 +3284,8 @@ void mips3_device::handle_cop2(uint32_t op)
case 0x08: /* BC */
switch (RTREG)
{
- case 0x00: /* BCzF */ if (!m_cf[2]) ADDPC(SIMMVAL); break;
- case 0x01: /* BCzT */ if (m_cf[2]) ADDPC(SIMMVAL); break;
+ case 0x00: /* BCzF */ if (!m_cf[2][0]) ADDPC(SIMMVAL); break;
+ case 0x01: /* BCzT */ if (m_cf[2][0]) ADDPC(SIMMVAL); break;
case 0x02: /* BCzFL */ invalid_instruction(op); break;
case 0x03: /* BCzTL */ invalid_instruction(op); break;
default: invalid_instruction(op); break;
@@ -3024,7 +3305,7 @@ void mips3_device::handle_extra_cop2(uint32_t op)
VU0/1 (COP2) EXECUTION HANDLING (R5900)
***************************************************************************/
-void r5900le_device::handle_extra_cop2(uint32_t op)
+void r5900_device::handle_extra_cop2(uint32_t op)
{
// TODO: Flags, rounding...
const int rd = (op >> 6) & 31;
@@ -3481,13 +3762,13 @@ void mips3_device::handle_regimm(uint32_t op)
void mips3_device::handle_mult(uint32_t op)
{
- uint64_t temp64 = (int64_t)(int32_t)RSVAL32 * (int64_t)(int32_t)RTVAL32;
+ uint64_t temp64 = mul_32x32(RSVAL32, RTVAL32);
LOVAL64 = (int32_t)temp64;
HIVAL64 = (int32_t)(temp64 >> 32);
m_core->icount -= 3;
}
-void r5900le_device::handle_mult(uint32_t op)
+void r5900_device::handle_mult(uint32_t op)
{
mips3_device::handle_mult(op);
if (RDREG) RDVAL64 = LOVAL64;
@@ -3495,13 +3776,13 @@ void r5900le_device::handle_mult(uint32_t op)
void mips3_device::handle_multu(uint32_t op)
{
- uint64_t temp64 = (uint64_t)RSVAL32 * (uint64_t)RTVAL32;
+ uint64_t temp64 = mulu_32x32(RSVAL32, RTVAL32);
LOVAL64 = (int32_t)temp64;
HIVAL64 = (int32_t)(temp64 >> 32);
m_core->icount -= 3;
}
-void r5900le_device::handle_multu(uint32_t op)
+void r5900_device::handle_multu(uint32_t op)
{
mips3_device::handle_multu(op);
if (RDREG) RDVAL64 = LOVAL64;
@@ -3551,11 +3832,11 @@ void mips3_device::handle_special(uint32_t op)
m_core->icount -= 35;
break;
case 0x1c: /* DMULT */
- LOVAL64 = mul_64x64(RSVAL64, RTVAL64, reinterpret_cast<s64 *>(&HIVAL64));
+ LOVAL64 = mul_64x64(RSVAL64, RTVAL64, *reinterpret_cast<s64 *>(&HIVAL64));
m_core->icount -= 7;
break;
case 0x1d: /* DMULTU */
- LOVAL64 = mulu_64x64(RSVAL64, RTVAL64, &HIVAL64);
+ LOVAL64 = mulu_64x64(RSVAL64, RTVAL64, HIVAL64);
m_core->icount -= 7;
break;
case 0x1e: /* DDIV */
@@ -3631,8 +3912,28 @@ void mips3_device::handle_idt(uint32_t op)
{
switch (op & 0x1f)
{
+ case 0: /* MAD */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ int64_t temp64 = mul_32x32(RSVAL32, RTVAL32);
+ temp64 += ((int64_t)m_core->r[REG_HI] << 32) | m_core->r[REG_LO];
+ m_core->r[REG_LO] = (int32_t)temp64;
+ m_core->r[REG_HI] = (int32_t)(temp64 >> 32);
+ }
+ m_core->icount -= 3;
+ break;
+ case 1: /* MADU */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ uint64_t temp64 = mulu_32x32(RSVAL32, RTVAL32);
+ temp64 += ((uint64_t)m_core->r[REG_HI] << 32) | m_core->r[REG_LO];
+ m_core->r[REG_LO] = (uint32_t)temp64;
+ m_core->r[REG_HI] = (uint32_t)(temp64 >> 32);
+ }
+ m_core->icount -= 3;
+ break;
case 2: /* MUL */
- RDVAL64 = (int32_t)((int32_t)RSVAL32 * (int32_t)RTVAL32);
+ if (RDREG) RDVAL64 = (int32_t)((int32_t)RSVAL32 * (int32_t)RTVAL32);
m_core->icount -= 3;
break;
default:
@@ -3641,7 +3942,7 @@ void mips3_device::handle_idt(uint32_t op)
}
}
-void r5900le_device::handle_extra_base(uint32_t op)
+void r5900_device::handle_extra_base(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rt = (op >> 16) & 31;
@@ -3670,7 +3971,7 @@ void r5900le_device::handle_extra_base(uint32_t op)
}
}
-void r5900le_device::handle_extra_special(uint32_t op)
+void r5900_device::handle_extra_special(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rd = (op >> 11) & 31;
@@ -3689,7 +3990,7 @@ void r5900le_device::handle_extra_special(uint32_t op)
}
}
-void r5900le_device::handle_extra_regimm(uint32_t op)
+void r5900_device::handle_extra_regimm(uint32_t op)
{
switch (op & 63)
{
@@ -3705,7 +4006,7 @@ void r5900le_device::handle_extra_regimm(uint32_t op)
}
}
-void r5900le_device::handle_extra_cop0(uint32_t op)
+void r5900_device::handle_extra_cop0(uint32_t op)
{
switch (op & 0x01ffffff)
{
@@ -3723,7 +4024,7 @@ void r5900le_device::handle_extra_cop0(uint32_t op)
}
}
-void r5900le_device::handle_extra_cop1(uint32_t op)
+void r5900_device::handle_extra_cop1(uint32_t op)
{
switch (op & 0x3f)
{
@@ -3738,7 +4039,7 @@ void r5900le_device::handle_extra_cop1(uint32_t op)
}
}
-void r5900le_device::handle_idt(uint32_t op)
+void r5900_device::handle_idt(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rt = (op >> 16) & 31;
@@ -3749,7 +4050,7 @@ void r5900le_device::handle_idt(uint32_t op)
{
case 0x00: /* MADD */
{
- uint64_t temp64 = (int64_t)(int32_t)RSVAL32 * (int64_t)(int32_t)RTVAL32;
+ uint64_t temp64 = mul_32x32(RSVAL32, RTVAL32);
m_core->r[REG_LO] += (int32_t)temp64;
m_core->r[REG_HI] += (int32_t)(temp64 >> 32);
if (rd)
@@ -3803,7 +4104,7 @@ void r5900le_device::handle_idt(uint32_t op)
break;
case 0x18: /* MULT1 */
{
- uint64_t temp64 = (int64_t)(int32_t)RSVAL32 * (int64_t)(int32_t)RTVAL32;
+ uint64_t temp64 = mul_32x32(RSVAL32, RTVAL32);
m_core->rh[REG_LO] = (int32_t)temp64;
m_core->rh[REG_HI] = (int32_t)(temp64 >> 32);
if (rd)
@@ -3962,7 +4263,7 @@ void r5900le_device::handle_idt(uint32_t op)
}
}
-void r5900le_device::handle_mmi0(uint32_t op)
+void r5900_device::handle_mmi0(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rt = (op >> 16) & 31;
@@ -4421,7 +4722,7 @@ void r5900le_device::handle_mmi0(uint32_t op)
}
}
-void r5900le_device::handle_mmi1(uint32_t op)
+void r5900_device::handle_mmi1(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rt = (op >> 16) & 31;
@@ -4785,7 +5086,7 @@ void r5900le_device::handle_mmi1(uint32_t op)
}
}
-void r5900le_device::handle_mmi2(uint32_t op)
+void r5900_device::handle_mmi2(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rt = (op >> 16) & 31;
@@ -4912,7 +5213,7 @@ void r5900le_device::handle_mmi2(uint32_t op)
}
}
-void r5900le_device::handle_mmi3(uint32_t op)
+void r5900_device::handle_mmi3(uint32_t op)
{
const int rs = (op >> 21) & 31;
const int rt = (op >> 16) & 31;
@@ -5011,7 +5312,7 @@ void mips3_device::handle_sdc2(uint32_t op)
WDOUBLE(SIMMVAL+RSVAL32, get_cop2_reg(RTREG));
}
-void r5900le_device::handle_ldc2(uint32_t op)
+void r5900_device::handle_ldc2(uint32_t op)
{
/* LQC2 */
const uint32_t base = SIMMVAL + RSVAL32;
@@ -5023,7 +5324,7 @@ void r5900le_device::handle_ldc2(uint32_t op)
}
}
-void r5900le_device::handle_sdc2(uint32_t op)
+void r5900_device::handle_sdc2(uint32_t op)
{
/* SQC2 */
const uint32_t base = SIMMVAL + RSVAL32;
@@ -5034,15 +5335,6 @@ void r5900le_device::handle_sdc2(uint32_t op)
}
}
-void mips3_device::burn_cycles(int32_t cycles)
-{
- execute_burn(cycles);
-}
-
-#if ENABLE_O2_DPRINTF
-#include "o2dprintf.hxx"
-#endif
-
void mips3_device::execute_run()
{
if (m_isdrc)
@@ -5200,12 +5492,12 @@ void mips3_device::execute_run()
{
// Should actually use physical address
m_core->cpr[0][COP0_LLAddr] = SIMMVAL + RSVAL32;
- RTVAL64 = temp;
+ RTVAL64 = int64_t(int32_t(temp));
m_core->llbit = 1;
if LL_BREAK
machine().debug_break();
- break;
}
+ break;
case 0x31: /* LWC1 */
if (!(SR & SR_COP1))
{
@@ -5226,18 +5518,18 @@ void mips3_device::execute_run()
m_core->llbit = 1;
if LL_BREAK
machine().debug_break();
- break;
}
+ break;
case 0x35: /* LDC1 */
- if (!(SR & SR_COP1))
- {
- m_badcop_value = 1;
- generate_exception(EXCEPTION_BADCOP, 1);
+ if (!(SR & SR_COP1))
+ {
+ m_badcop_value = 1;
+ generate_exception(EXCEPTION_BADCOP, 1);
+ break;
+ }
+ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64))
+ set_cop1_reg64(RTREG, temp64);
break;
- }
- if (RDOUBLE(SIMMVAL+RSVAL32, &temp64))
- set_cop1_reg64(RTREG, temp64);
- break;
case 0x36: handle_ldc2(op); break;
case 0x37: /* LD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) RTVAL64 = temp64; break;
case 0x38: /* SC */
@@ -5293,12 +5585,10 @@ void mips3_device::execute_run()
m_delayslot = false;
m_core->icount--;
-#if ENABLE_O2_DPRINTF
- if (m_core->pc == 0xbfc04d74)
+ if (ENABLE_O2_DPRINTF && m_core->pc == 0xbfc04d74)
{
do_o2_dprintf((uint32_t)m_core->r[4], (uint32_t)m_core->r[5], (uint32_t)m_core->r[6], (uint32_t)m_core->r[7], (uint32_t)m_core->r[29] + 16);
}
-#endif
#if ENABLE_EE_ELF_LOADER
static bool elf_loaded = false;
diff --git a/src/devices/cpu/mips/mips3.h b/src/devices/cpu/mips/mips3.h
index 147e9213620..73105cb0ad3 100644
--- a/src/devices/cpu/mips/mips3.h
+++ b/src/devices/cpu/mips/mips3.h
@@ -20,8 +20,6 @@ MIPS III/IV emulator.
#include "cpu/drcuml.h"
#include "ps2vu.h"
-#define ENABLE_O2_DPRINTF (0)
-
DECLARE_DEVICE_TYPE(R4000BE, r4000be_device)
DECLARE_DEVICE_TYPE(R4000LE, r4000le_device)
DECLARE_DEVICE_TYPE(R4400BE, r4400be_device)
@@ -49,6 +47,7 @@ DECLARE_DEVICE_TYPE(QED5271LE, qed5271le_device)
DECLARE_DEVICE_TYPE(RM7000BE, rm7000be_device)
DECLARE_DEVICE_TYPE(RM7000LE, rm7000le_device)
DECLARE_DEVICE_TYPE(R5900LE, r5900le_device)
+DECLARE_DEVICE_TYPE(R5900BE, r5900be_device)
/***************************************************************************
@@ -309,29 +308,28 @@ public:
void add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
void clear_fastram(uint32_t select_start);
void mips3drc_set_options(uint32_t options);
+ uint32_t mips3drc_get_options();
void mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles);
- void burn_cycles(int32_t cycles);
protected:
// device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_stop() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
// device_execute_interface overrides
- virtual uint32_t execute_min_cycles() const override { return 1; }
- virtual uint32_t execute_max_cycles() const override { return 40; }
- virtual uint32_t execute_input_lines() const override { return 6; }
+ virtual uint32_t execute_min_cycles() const noexcept override { return 1; }
+ virtual uint32_t execute_max_cycles() const noexcept override { return 40; }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
- virtual void execute_burn(int32_t cycles) override { m_totalcycles += cycles; }
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
- virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
+ virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
// device_state_interface overrides
virtual void state_export(const device_state_entry &entry) override;
+ 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
@@ -352,6 +350,8 @@ protected:
virtual void WDOUBLE(offs_t address, uint64_t data);
virtual void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask);
+ virtual void set_cop0_reg(int idx, uint64_t val);
+
struct internal_mips3_state {
/* core registers */
uint32_t pc;
@@ -400,6 +400,11 @@ protected:
uint8_t *m_icache;
address_space_config m_program_config;
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache m_cache32le;
+ memory_access<32, 3, 0, ENDIANNESS_LITTLE>::cache m_cache64le;
+ memory_access<32, 2, 0, ENDIANNESS_BIG>::cache m_cache32be;
+ memory_access<32, 3, 0, ENDIANNESS_BIG>::cache m_cache64be;
+
mips3_flavor m_flavor;
/* internal stuff */
@@ -427,7 +432,7 @@ protected:
address_space * m_program;
uint32_t m_data_bits;
- std::function<u32(offs_t)> m_pr32;
+ delegate<u32 (offs_t)> m_pr32;
std::function<const void * (offs_t)> m_prptr;
uint32_t c_system_clock;
uint32_t m_cpu_clock;
@@ -443,7 +448,6 @@ protected:
uint32_t m_byte_xor;
uint32_t m_word_xor;
uint32_t m_dword_xor;
- data_accessors m_memory;
/* cache memory */
size_t c_icache_size;
@@ -514,6 +518,12 @@ protected:
void generate_exception(int exception, int backup);
void generate_tlb_exception(int exception, offs_t address);
+
+ void static_generate_memory_mode_checks(drcuml_block &block, uml::code_handle &exception_addrerr, int &label, int mode);
+ void static_generate_fastram_accessor(drcuml_block &block, int &label, int size, bool iswrite, bool ismasked);
+ void static_generate_memory_rw(drcuml_block &block, int size, bool iswrite, bool ismasked);
+ virtual void static_generate_memory_accessor(drcuml_block &block, int &label, int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr);
+
virtual void check_irqs();
virtual void handle_mult(uint32_t op);
virtual void handle_multu(uint32_t op);
@@ -528,13 +538,13 @@ public:
private:
uint32_t compute_config_register();
uint32_t compute_prid_register();
+ uint32_t compute_fpu_prid_register();
uint32_t generate_tlb_index();
void tlb_map_entry(int tlbindex);
void tlb_write_common(int tlbindex);
uint64_t get_cop0_reg(int idx);
- void set_cop0_reg(int idx, uint64_t val);
uint64_t get_cop0_creg(int idx);
void set_cop0_creg(int idx, uint64_t val);
void handle_cop0(uint32_t op);
@@ -610,16 +620,15 @@ private:
uml::code_label labelnum; /* index for local labels */
};
- void static_generate_entry_point();
- void static_generate_nocode_handler();
- void static_generate_out_of_cycles();
- void static_generate_tlb_mismatch();
- void static_generate_exception(uint8_t exception, int recover, const char *name);
- void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr);
+ void static_generate_entry_point(drcuml_block &block, int &label);
+ void static_generate_nocode_handler(drcuml_block &block, int &label);
+ void static_generate_out_of_cycles(drcuml_block &block, int &label);
+ void static_generate_tlb_mismatch(drcuml_block &block, int &label);
+ void static_generate_exception(drcuml_block &block, int &label, uint8_t exception, int recover, const char *name);
void generate_update_mode(drcuml_block &block);
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_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast, const opcode_desc *codelast);
void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
void generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg);
@@ -644,9 +653,7 @@ private:
void log_opcode_desc(const opcode_desc *desclist, int indent);
void load_elf();
-#if ENABLE_O2_DPRINTF
- void do_o2_dprintf(uint32_t fmt_addr, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t stack);
-#endif
+ [[maybe_unused]] void do_o2_dprintf(uint32_t fmt_addr, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t stack);
};
@@ -740,20 +747,49 @@ public:
}
};
-class r4650be_device : public mips3_device {
+class r4650_device : public mips3_device {
+public:
+ // construction/destruction
+ r4650_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness)
+ : mips3_device(mconfig, type, tag, owner, clock, MIPS3_TYPE_R4650, endianness, 32) // Should be 64 bits
+ {
+ }
+
+protected:
+ virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
+
+ virtual void static_generate_memory_accessor(drcuml_block &block, int &label, int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr) override;
+
+ virtual bool RBYTE(offs_t address, uint32_t *result) override;
+ virtual bool RHALF(offs_t address, uint32_t *result) override;
+ virtual bool RWORD(offs_t address, uint32_t *result, bool insn = false) override;
+ virtual bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask) override;
+ virtual bool RDOUBLE(offs_t address, uint64_t *result) override;
+ virtual bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask) override;
+ virtual void WBYTE(offs_t address, uint8_t data) override;
+ virtual void WHALF(offs_t address, uint16_t data) override;
+ virtual void WWORD(offs_t address, uint32_t data) override;
+ virtual void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask) override;
+ virtual void WDOUBLE(offs_t address, uint64_t data) override;
+ virtual void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask) override;
+
+ virtual void set_cop0_reg(int idx, uint64_t val) override;
+};
+
+class r4650be_device : public r4650_device {
public:
// construction/destruction
r4650be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : mips3_device(mconfig, R4650BE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_BIG, 32) // Should be 64 bits
+ : r4650_device(mconfig, R4650BE, tag, owner, clock, ENDIANNESS_BIG)
{
}
};
-class r4650le_device : public mips3_device {
+class r4650le_device : public r4650_device {
public:
// construction/destruction
r4650le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : mips3_device(mconfig, R4650LE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_LITTLE, 32) // Should be 64 bits
+ : r4650_device(mconfig, R4650LE, tag, owner, clock, ENDIANNESS_LITTLE)
{
}
};
@@ -833,24 +869,16 @@ public:
}
};
-class r5900le_device : public mips3_device {
-public:
+class r5900_device : public mips3_device {
+protected:
// construction/destruction
- template <typename T>
- r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&vu0_tag)
- : r5900le_device(mconfig, tag, owner, clock)
- {
- m_vu0.set_tag(std::forward<T>(vu0_tag));
- }
-
- r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : mips3_device(mconfig, R5900LE, tag, owner, clock, MIPS3_TYPE_R5900, ENDIANNESS_LITTLE, 64)
+ r5900_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness)
+ : mips3_device(mconfig, type, tag, owner, clock, MIPS3_TYPE_R5900, endianness, 64)
, m_vu0(*this, finder_base::DUMMY_TAG)
{
}
-protected:
- virtual void device_start() override;
+ virtual void device_start() override ATTR_COLD;
// device_disasm_interface overrides
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
@@ -868,8 +896,8 @@ protected:
void WDOUBLE(offs_t address, uint64_t data) override;
void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask) override;
- bool RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo);
- void WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo);
+ virtual bool RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo) = 0;
+ virtual void WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo) = 0;
uint64_t get_cop2_reg(int idx) override;
void set_cop2_reg(int idx, uint64_t val) override;
@@ -899,6 +927,46 @@ protected:
required_device<sonyvu0_device> m_vu0;
};
+class r5900le_device : public r5900_device {
+public:
+ // construction/destruction
+ template <typename T>
+ r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&vu0_tag)
+ : r5900le_device(mconfig, tag, owner, clock)
+ {
+ m_vu0.set_tag(std::forward<T>(vu0_tag));
+ }
+
+ r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : r5900_device(mconfig, R5900LE, tag, owner, clock, ENDIANNESS_LITTLE)
+ {
+ }
+
+protected:
+ bool RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo) override;
+ void WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo) override;
+};
+
+class r5900be_device : public r5900_device {
+public:
+ // construction/destruction
+ template <typename T>
+ r5900be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&vu0_tag)
+ : r5900be_device(mconfig, tag, owner, clock)
+ {
+ m_vu0.set_tag(std::forward<T>(vu0_tag));
+ }
+
+ r5900be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : r5900_device(mconfig, R5900BE, tag, owner, clock, ENDIANNESS_BIG)
+ {
+ }
+
+protected:
+ bool RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo) override;
+ void WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo) override;
+};
+
class qed5271be_device : public mips3_device {
public:
// construction/destruction
@@ -965,17 +1033,16 @@ private:
COMPILER-SPECIFIC OPTIONS
***************************************************************************/
-/* fix me -- how do we make this work?? */
#define MIPS3DRC_STRICT_VERIFY 0x0001 /* verify all instructions */
#define MIPS3DRC_STRICT_COP0 0x0002 /* validate all COP0 instructions */
#define MIPS3DRC_STRICT_COP1 0x0004 /* validate all COP1 instructions */
#define MIPS3DRC_STRICT_COP2 0x0008 /* validate all COP2 instructions */
-#define MIPS3DRC_FLUSH_PC 0x0010 /* flush the PC value before each memory access */
+#define MIPS3DRC_DISABLE_INTRABLOCK 0x0010 /* disable intrablock branching */
#define MIPS3DRC_CHECK_OVERFLOWS 0x0020 /* actually check overflows on add/sub instructions */
#define MIPS3DRC_ACCURATE_DIVZERO 0x0040 /* load correct values into HI/LO on integer divide-by-zero */
+#define MIPS3DRC_EXTRA_INSTR_CHECK 0x0080 /* adds the last instruction value to all validation entry locations, used with STRICT_VERIFY */
-#define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP2 | MIPS3DRC_FLUSH_PC)
+#define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP2)
#define MIPS3DRC_FASTEST_OPTIONS (0)
-
#endif // MAME_CPU_MIPS_MIPS3_H
diff --git a/src/devices/cpu/mips/mips3com.cpp b/src/devices/cpu/mips/mips3com.cpp
index f671ba2c335..2a9a933ef87 100644
--- a/src/devices/cpu/mips/mips3com.cpp
+++ b/src/devices/cpu/mips/mips3com.cpp
@@ -143,7 +143,7 @@ generate_tlb_index - generate a random tlb index
uint32_t mips3_device::generate_tlb_index()
{
// Actual hardware uses a free running counter to generate the index.
- // This impementation uses a linear congruential generator so that DRC and non-DRC code sequences match.
+ // This implementation uses a linear congruential generator so that DRC and non-DRC code sequences match.
m_tlb_seed = 214013 * m_tlb_seed + 2531011;
return (m_tlb_seed >> 16) & 0x3f;
}
@@ -336,8 +336,10 @@ uint32_t mips3_device::compute_prid_register()
return 0x5500;
case MIPS3_TYPE_R4600:
+ return 0x2020;
+
case MIPS3_TYPE_R4650:
- return 0x2000;
+ return 0x2200;
case MIPS3_TYPE_R4700:
return 0x2100;
@@ -364,6 +366,12 @@ uint32_t mips3_device::compute_prid_register()
//return 0x2000;
}
+uint32_t mips3_device::compute_fpu_prid_register()
+{
+ /* For most CPUs they are same */
+ return compute_prid_register();
+}
+
/*-------------------------------------------------
tlb_map_entry - map a single TLB
entry
@@ -414,15 +422,15 @@ void mips3_device::tlb_map_entry(int tlbindex)
/* valid? */
if ((lo & 2) != 0)
{
- flags |= VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED;
+ flags |= FLAG_VALID | READ_ALLOWED | FETCH_ALLOWED;
/* writable? */
if ((lo & 4) != 0)
- flags |= VTLB_WRITE_ALLOWED;
+ flags |= WRITE_ALLOWED;
/* mirror the flags for user mode if the VPN is in user space */
if (effvpn < (0x80000000 >> MIPS3_MIN_PAGE_SHIFT))
- flags |= (flags << 4) & (VTLB_USER_READ_ALLOWED | VTLB_USER_WRITE_ALLOWED | VTLB_USER_FETCH_ALLOWED);
+ flags |= (flags << 4) & (USER_READ_ALLOWED | USER_WRITE_ALLOWED | USER_FETCH_ALLOWED);
}
/* load the virtual TLB with the corresponding entries */
diff --git a/src/devices/cpu/mips/mips3com.h b/src/devices/cpu/mips/mips3com.h
index 343e161ee68..8976f42575f 100644
--- a/src/devices/cpu/mips/mips3com.h
+++ b/src/devices/cpu/mips/mips3com.h
@@ -107,6 +107,10 @@
#define COP0_TagLo 28
#define COP0_TagHi 29
#define COP0_ErrorPC 30
+#define COP0_R4650_IBase 0
+#define COP0_R4650_IBound 1
+#define COP0_R4650_DBase 2
+#define COP0_R4650_DBound 3
/* Status register bits */
#define SR_IE 0x00000001
diff --git a/src/devices/cpu/mips/mips3drc.cpp b/src/devices/cpu/mips/mips3drc.cpp
index 0f1cd0a29d4..f682da6b212 100644
--- a/src/devices/cpu/mips/mips3drc.cpp
+++ b/src/devices/cpu/mips/mips3drc.cpp
@@ -24,7 +24,6 @@
***************************************************************************/
#include "emu.h"
-#include "debugger.h"
#include "mips3com.h"
#include "mips3fe.h"
#include "mips3dsm.h"
@@ -34,6 +33,11 @@
#include "cpu/drcumlsh.h"
+/* Use with STRICT_VERIFY to print debug info to console for extra validation checks */
+/* Set to 1 to activate and use MIPS3DRC_STRICT_VERIFY in the drc options */
+#define DEBUG_STRICT_VERIFY 0
+
+
/***************************************************************************
MACROS
***************************************************************************/
@@ -120,7 +124,7 @@ inline void mips3_device::load_fast_iregs(drcuml_block &block)
{
int regnum;
- for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ for (regnum = 0; regnum < std::size(m_regmap); regnum++)
if (m_regmap[regnum].is_int_register())
UML_DMOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum]));
}
@@ -135,7 +139,7 @@ inline void mips3_device::save_fast_iregs(drcuml_block &block)
{
int regnum;
- for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ for (regnum = 0; regnum < std::size(m_regmap); regnum++)
if (m_regmap[regnum].is_int_register())
UML_DMOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0));
}
@@ -157,6 +161,15 @@ void mips3_device::mips3drc_set_options(uint32_t options)
}
/*-------------------------------------------------
+ mips3drc_get_options - return current DRC options
+-------------------------------------------------*/
+
+uint32_t mips3_device::mips3drc_get_options()
+{
+ return m_drcoptions;
+}
+
+/*-------------------------------------------------
mips3drc_clears_fastram - clears fastram
region starting at index select_start
-------------------------------------------------*/
@@ -174,7 +187,7 @@ void mips3_device::clear_fastram(uint32_t select_start)
void mips3_device::add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base)
{
- if (m_fastram_select < ARRAY_LENGTH(m_fastram))
+ if (m_fastram_select < std::size(m_fastram))
{
m_fastram[m_fastram_select].start = start;
m_fastram[m_fastram_select].end = end;
@@ -197,7 +210,7 @@ void mips3_device::add_fastram(offs_t start, offs_t end, uint8_t readonly, void
void mips3_device::mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles)
{
if (!allow_drc()) return;
- if (m_hotspot_select < ARRAY_LENGTH(m_hotspot))
+ if (m_hotspot_select < std::size(m_hotspot))
{
m_hotspot[m_hotspot_select].pc = pc;
m_hotspot[m_hotspot_select].opcode = opcode;
@@ -226,45 +239,55 @@ void mips3_device::code_flush_cache()
try
{
- /* generate the entry point and out-of-cycles handlers */
- static_generate_entry_point();
- static_generate_nocode_handler();
- static_generate_out_of_cycles();
- static_generate_tlb_mismatch();
-
- /* append exception handlers for various types */
- static_generate_exception(EXCEPTION_INTERRUPT, true, "exception_interrupt");
- static_generate_exception(EXCEPTION_INTERRUPT, false, "exception_interrupt_norecover");
- static_generate_exception(EXCEPTION_TLBMOD, true, "exception_tlbmod");
- static_generate_exception(EXCEPTION_TLBLOAD, true, "exception_tlbload");
- static_generate_exception(EXCEPTION_TLBSTORE, true, "exception_tlbstore");
- static_generate_exception(EXCEPTION_TLBLOAD_FILL, true, "exception_tlbload_fill");
- static_generate_exception(EXCEPTION_TLBSTORE_FILL, true, "exception_tlbstore_fill");
- static_generate_exception(EXCEPTION_ADDRLOAD, true, "exception_addrload");
- static_generate_exception(EXCEPTION_ADDRSTORE, true, "exception_addrstore");
- static_generate_exception(EXCEPTION_SYSCALL, true, "exception_syscall");
- static_generate_exception(EXCEPTION_BREAK, true, "exception_break");
- static_generate_exception(EXCEPTION_INVALIDOP, true, "exception_invalidop");
- static_generate_exception(EXCEPTION_BADCOP, true, "exception_badcop");
- static_generate_exception(EXCEPTION_OVERFLOW, true, "exception_overflow");
- static_generate_exception(EXCEPTION_TRAP, true, "exception_trap");
- static_generate_exception(EXCEPTION_FPE, true, "exception_fpe");
+ {
+ drcuml_block &block(m_drcuml->begin_block(1024));
+ int label = 1;
+
+ /* generate the entry point and out-of-cycles handlers */
+ static_generate_entry_point(block, label);
+ static_generate_nocode_handler(block, label);
+ static_generate_out_of_cycles(block, label);
+ static_generate_tlb_mismatch(block, label);
+
+ /* append exception handlers for various types */
+ static_generate_exception(block, label, EXCEPTION_INTERRUPT, true, "exception_interrupt");
+ static_generate_exception(block, label, EXCEPTION_INTERRUPT, false, "exception_interrupt_norecover");
+ static_generate_exception(block, label, EXCEPTION_TLBMOD, true, "exception_tlbmod");
+ static_generate_exception(block, label, EXCEPTION_TLBLOAD, true, "exception_tlbload");
+ static_generate_exception(block, label, EXCEPTION_TLBSTORE, true, "exception_tlbstore");
+ static_generate_exception(block, label, EXCEPTION_TLBLOAD_FILL, true, "exception_tlbload_fill");
+ static_generate_exception(block, label, EXCEPTION_TLBSTORE_FILL, true, "exception_tlbstore_fill");
+ static_generate_exception(block, label, EXCEPTION_ADDRLOAD, true, "exception_addrload");
+ static_generate_exception(block, label, EXCEPTION_ADDRSTORE, true, "exception_addrstore");
+ static_generate_exception(block, label, EXCEPTION_SYSCALL, true, "exception_syscall");
+ static_generate_exception(block, label, EXCEPTION_BREAK, true, "exception_break");
+ static_generate_exception(block, label, EXCEPTION_INVALIDOP, true, "exception_invalidop");
+ static_generate_exception(block, label, EXCEPTION_BADCOP, true, "exception_badcop");
+ static_generate_exception(block, label, EXCEPTION_OVERFLOW, true, "exception_overflow");
+ static_generate_exception(block, label, EXCEPTION_TRAP, true, "exception_trap");
+ static_generate_exception(block, label, EXCEPTION_FPE, true, "exception_fpe");
+
+ block.end();
+ }
/* add subroutines for memory accesses */
for (mode = 0; mode < 3; mode++)
{
- static_generate_memory_accessor(mode, 1, false, false, "read8", m_read8[mode]);
- static_generate_memory_accessor(mode, 1, true, false, "write8", m_write8[mode]);
- static_generate_memory_accessor(mode, 2, false, false, "read16", m_read16[mode]);
- static_generate_memory_accessor(mode, 2, true, false, "write16", m_write16[mode]);
- static_generate_memory_accessor(mode, 4, false, false, "read32", m_read32[mode]);
- static_generate_memory_accessor(mode, 4, false, true, "read32mask", m_read32mask[mode]);
- static_generate_memory_accessor(mode, 4, true, false, "write32", m_write32[mode]);
- static_generate_memory_accessor(mode, 4, true, true, "write32mask", m_write32mask[mode]);
- static_generate_memory_accessor(mode, 8, false, false, "read64", m_read64[mode]);
- static_generate_memory_accessor(mode, 8, false, true, "read64mask", m_read64mask[mode]);
- static_generate_memory_accessor(mode, 8, true, false, "write64", m_write64[mode]);
- static_generate_memory_accessor(mode, 8, true, true, "write64mask", m_write64mask[mode]);
+ drcuml_block &block(m_drcuml->begin_block(1024));
+ int label = 1;
+ static_generate_memory_accessor(block, label, mode, 1, false, false, "read8", m_read8[mode]);
+ static_generate_memory_accessor(block, label, mode, 1, true, false, "write8", m_write8[mode]);
+ static_generate_memory_accessor(block, label, mode, 2, false, false, "read16", m_read16[mode]);
+ static_generate_memory_accessor(block, label, mode, 2, true, false, "write16", m_write16[mode]);
+ static_generate_memory_accessor(block, label, mode, 4, false, false, "read32", m_read32[mode]);
+ static_generate_memory_accessor(block, label, mode, 4, false, true, "read32mask", m_read32mask[mode]);
+ static_generate_memory_accessor(block, label, mode, 4, true, false, "write32", m_write32[mode]);
+ static_generate_memory_accessor(block, label, mode, 4, true, true, "write32mask", m_write32mask[mode]);
+ static_generate_memory_accessor(block, label, mode, 8, false, false, "read64", m_read64[mode]);
+ static_generate_memory_accessor(block, label, mode, 8, false, true, "read64mask", m_read64mask[mode]);
+ static_generate_memory_accessor(block, label, mode, 8, true, false, "write64", m_write64[mode]);
+ static_generate_memory_accessor(block, label, mode, 8, true, true, "write64mask", m_write64mask[mode]);
+ block.end();
}
}
catch (drcuml_block::abort_compilation &)
@@ -283,13 +306,16 @@ void mips3_device::code_compile_block(uint8_t mode, offs_t pc)
{
compiler_state compiler = { 0 };
const opcode_desc *seqhead, *seqlast;
+ const opcode_desc *codelast;
const opcode_desc *desclist;
bool override = false;
- g_profiler.start(PROFILER_DRC_COMPILE);
+ auto profile = g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */
desclist = m_drcfe->describe_code(pc);
+ /* get last instruction of the code (potentially used in generate_checksum) */
+ codelast = m_drcfe->get_last();
if (m_drcuml->logging() || m_drcuml->logging_native())
log_opcode_desc(desclist, 0);
@@ -341,7 +367,7 @@ void mips3_device::code_compile_block(uint8_t mode, offs_t pc)
/* 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);
+ generate_checksum_block(block, compiler, seqhead, seqlast, codelast);
/* label this instruction, if it may be jumped to locally */
if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
@@ -379,7 +405,6 @@ void mips3_device::code_compile_block(uint8_t mode, offs_t pc)
/* end the sequence */
block.end();
- g_profiler.stop();
succeeded = true;
}
catch (drcuml_block::abort_compilation &)
@@ -570,44 +595,40 @@ static void cfunc_unimplemented(void *param)
static entry point
-------------------------------------------------*/
-void mips3_device::static_generate_entry_point()
+void mips3_device::static_generate_entry_point(drcuml_block &block, int &label)
{
- uml::code_label const skip = 1;
-
- drcuml_block &block(m_drcuml->begin_block(20));
+ uml::code_label const skip = label++;
/* forward references */
alloc_handle(*m_drcuml, m_exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover");
alloc_handle(*m_drcuml, m_nocode, "nocode");
alloc_handle(*m_drcuml, m_entry, "entry");
- UML_HANDLE(block, *m_entry); // handle entry
+ UML_HANDLE(block, *m_entry); // handle entry
/* reset the FPU mode */
- UML_AND(block, I0, CCR132(31), 3); // and i0,ccr1[31],3
- UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1);// load i0,fpmode,i0,byte
- UML_SETFMOD(block, I0); // setfmod i0
+ UML_AND(block, I0, CCR132(31), 3); // and i0,ccr1[31],3
+ UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1); // load i0,fpmode,i0,byte
+ UML_SETFMOD(block, I0); // setfmod i0
/* load fast integer registers */
load_fast_iregs(block);
/* check for interrupts */
UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status]
- UML_AND(block, I0, I0, 0xfc00); // and i0,i0,0xfc00,Z
- UML_JMPc(block, COND_Z, skip); // jmp skip,Z
+ UML_AND(block, I0, I0, 0xfc00); // and i0,i0,0xfc00,Z
+ UML_JMPc(block, COND_Z, skip); // jmp skip,Z
UML_TEST(block, CPR032(COP0_Status), SR_IE); // test [Status],SR_IE
- UML_JMPc(block, COND_Z, skip); // jmp skip,Z
+ UML_JMPc(block, COND_Z, skip); // jmp skip,Z
UML_TEST(block, CPR032(COP0_Status), SR_EXL | SR_ERL); // test [Status],SR_EXL | SR_ERL
- UML_JMPc(block, COND_NZ, skip); // jmp skip,NZ
- UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc
- UML_MOV(block, I1, 0); // mov i1,0
- UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]); // callh exception_norecover
+ UML_JMPc(block, COND_NZ, skip); // jmp skip,NZ
+ UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc
+ UML_MOV(block, I1, 0); // mov i1,0
+ UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]); // callh exception_norecover
UML_LABEL(block, skip); // skip:
/* generate a hash jump via the current mode and PC */
- UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode);
- // hashjmp <mode>,<pc>,nocode
- block.end();
+ UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
}
@@ -616,11 +637,8 @@ void mips3_device::static_generate_entry_point()
exception handler for "out of code"
-------------------------------------------------*/
-void mips3_device::static_generate_nocode_handler()
+void mips3_device::static_generate_nocode_handler(drcuml_block &block, int &label)
{
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(10));
-
/* generate a hash jump via the current mode and PC */
alloc_handle(*m_drcuml, m_nocode, "nocode");
UML_HANDLE(block, *m_nocode); // handle nocode
@@ -628,8 +646,6 @@ void mips3_device::static_generate_nocode_handler()
UML_MOV(block, mem(&m_core->pc), I0); // mov [pc],i0
save_fast_iregs(block);
UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
-
- block.end();
}
@@ -638,11 +654,8 @@ void mips3_device::static_generate_nocode_handler()
out of cycles exception handler
-------------------------------------------------*/
-void mips3_device::static_generate_out_of_cycles()
+void mips3_device::static_generate_out_of_cycles(drcuml_block &block, int &label)
{
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(10));
-
/* generate a hash jump via the current mode and PC */
alloc_handle(*m_drcuml, m_out_of_cycles, "out_of_cycles");
UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles
@@ -650,8 +663,6 @@ void mips3_device::static_generate_out_of_cycles()
UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0
save_fast_iregs(block);
UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES
-
- block.end();
}
@@ -660,15 +671,14 @@ void mips3_device::static_generate_out_of_cycles()
TLB mismatch handler
-------------------------------------------------*/
-void mips3_device::static_generate_tlb_mismatch()
+void mips3_device::static_generate_tlb_mismatch(drcuml_block &block, int &label)
{
+ uml::code_label const skip = label++;
+
/* forward references */
alloc_handle(*m_drcuml, m_exception[EXCEPTION_TLBLOAD], "exception_tlbload");
alloc_handle(*m_drcuml, m_exception[EXCEPTION_TLBLOAD_FILL], "exception_tlbload_fill");
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(20));
-
/* generate a hash jump via the current mode and PC */
alloc_handle(*m_drcuml, m_tlb_mismatch, "tlb_mismatch");
UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch
@@ -687,12 +697,12 @@ void mips3_device::static_generate_tlb_mismatch()
UML_MOV(block, mem(&m_core->arg1), I1); // mov [arg1],i1
UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug
}
- UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED
- UML_JMPc(block, COND_NZ, 1); // jmp 1,nz
- UML_TEST(block, I1, VTLB_FLAG_FIXED); // test i1,VTLB_FLAG_FIXED
+ UML_TEST(block, I1, FETCH_ALLOWED); // test i1,FETCH_ALLOWED
+ UML_JMPc(block, COND_NZ, skip); // jmp skip,nz
+ UML_TEST(block, I1, FLAG_FIXED); // test i1,FLAG_FIXED
UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBLOAD], I0); // exh exception[TLBLOAD],i0,nz
UML_EXH(block, *m_exception[EXCEPTION_TLBLOAD_FILL], I0); // exh exception[TLBLOAD_FILL],i0
- UML_LABEL(block, 1); // 1:
+ UML_LABEL(block, skip); // skip:
save_fast_iregs(block);
// the saved PC may be set 1 instruction back with the low bit set to indicate
@@ -702,8 +712,6 @@ void mips3_device::static_generate_tlb_mismatch()
UML_MOV(block, mem(&m_core->pc), I0); // mov i0,[pc]
UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
-
- block.end();
}
@@ -712,12 +720,12 @@ void mips3_device::static_generate_tlb_mismatch()
exception handler
-------------------------------------------------*/
-void mips3_device::static_generate_exception(uint8_t exception, int recover, const char *name)
+void mips3_device::static_generate_exception(drcuml_block &block, int &label, uint8_t exception, int recover, const char *name)
{
uml::code_handle *&exception_handle = recover ? m_exception[exception] : m_exception_norecover[exception];
uint32_t offset = 0x180;
- uml::code_label const next = 1;
- uml::code_label const skip = 2;
+ uml::code_label const next = label++;
+ uml::code_label const skip = label++;
/* translate our fake fill exceptions into real exceptions */
if (exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL)
@@ -726,9 +734,6 @@ void mips3_device::static_generate_exception(uint8_t exception, int recover, con
exception = (exception - EXCEPTION_TLBLOAD_FILL) + EXCEPTION_TLBLOAD;
}
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(1024));
-
/* add a global entry for this */
alloc_handle(*m_drcuml, exception_handle, name);
UML_HANDLE(block, *exception_handle); // handle name
@@ -741,7 +746,7 @@ void mips3_device::static_generate_exception(uint8_t exception, int recover, con
UML_MOV(block, CPR032(COP0_BadVAddr), I0); // mov [BadVAddr],i0
}
- if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
+ if (exception == EXCEPTION_TLBMOD || exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
{
/* set the upper bits of EntryHi and the lower bits of Context to the fault page */
UML_ROLINS(block, CPR032(COP0_EntryHi), I0, 0, 0xffffe000); // rolins [EntryHi],i0,0,0xffffe000
@@ -783,7 +788,7 @@ void mips3_device::static_generate_exception(uint8_t exception, int recover, con
}
/* set EXL in the SR */
- UML_OR(block, I0, CPR032(COP0_Status), SR_EXL); // or i0,[Status],SR_EXL
+ UML_OR(block, I0, CPR032(COP0_Status), SR_EXL); // or i0,[Status],SR_EXL
UML_MOV(block, CPR032(COP0_Status), I0); // mov [Status],i0
generate_update_mode(block);
@@ -791,142 +796,126 @@ void mips3_device::static_generate_exception(uint8_t exception, int recover, con
if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_INTERRUPT && exception != EXCEPTION_SYSCALL) ||
(PRINTF_MMU && (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)))
{
- UML_CALLC(block, cfunc_printf_exception, this); // callc cfunc_printf_exception,nullptr
+ UML_CALLC(block, cfunc_printf_exception, this); // callc cfunc_printf_exception,nullptr
//UML_CALLC(block, cfunc_debug_break, this); // callc cfunc_debug_break,nullptr
}
/* choose our target PC */
- UML_ADD(block, I0, I3, 0xbfc00200); // add i0,i3,0xbfc00200
- UML_TEST(block, CPR032(COP0_Status), SR_BEV); // test CPR032(COP0_Status),SR_BEV
- UML_JMPc(block, COND_NZ, skip); // jnz <skip>
- UML_ADD(block, I0, I3, 0x80000000); // add i0,i3,0x80000000,z
+ UML_ADD(block, I0, I3, 0xbfc00200); // add i0,i3,0xbfc00200
+ UML_TEST(block, CPR032(COP0_Status), SR_BEV); // test CPR032(COP0_Status),SR_BEV
+ UML_JMPc(block, COND_NZ, skip); // jnz <skip>
+ UML_ADD(block, I0, I3, 0x80000000); // add i0,i3,0x80000000,z
UML_LABEL(block, skip); // <skip>:
/* adjust cycles */
- UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I1); // sub icount,icount,cycles,S
- UML_EXHc(block, COND_S, *m_out_of_cycles, I0); // exh out_of_cycles,i0
-
- UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode);// hashjmp <mode>,i0,nocode
+ UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I1); // sub icount,icount,cycles,S
+ UML_EXHc(block, COND_S, *m_out_of_cycles, I0); // exh out_of_cycles,i0
- block.end();
+ UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp <mode>,i0,nocode
}
/*------------------------------------------------------------------
- static_generate_memory_accessor
+ static_generate_memory_mode_checks
------------------------------------------------------------------*/
-void mips3_device::static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr)
+void mips3_device::static_generate_memory_mode_checks(drcuml_block &block, uml::code_handle &exception_addrerr, int &label, int mode)
{
- /* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
- /* on exit, read result is in I0 */
- /* routine trashes I0-I3 */
- uml::code_handle &exception_tlb = *m_exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD];
- uml::code_handle &exception_tlbfill = *m_exception[iswrite ? EXCEPTION_TLBSTORE_FILL : EXCEPTION_TLBLOAD_FILL];
- uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
- int tlbmiss = 0;
- int label = 1;
- int ramnum;
-
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(1024));
-
- /* add a global entry for this */
- alloc_handle(*m_drcuml, handleptr, name);
- UML_HANDLE(block, *handleptr); // handle handleptr
-
/* user mode? generate address exception if top bit is set */
if (mode == MODE_USER)
{
- UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
- UML_EXHc(block, COND_NZ, exception_addrerr, I0); // exh addrerr,i0,nz
+ UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
+ UML_EXHc(block, COND_NZ, exception_addrerr, I0); // exh addrerr,i0,nz
}
/* supervisor mode? generate address exception if not in user space or in $C0000000-DFFFFFFF */
if (mode == MODE_SUPER)
{
int addrok;
- UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
+ UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
UML_JMPc(block, COND_Z, addrok = label++); // jz addrok
- UML_SHR(block, I3, I0, 29); // shr i3,i0,29
- UML_CMP(block, I3, 6); // cmp i3,6
+ UML_SHR(block, I3, I0, 29); // shr i3,i0,29
+ UML_CMP(block, I3, 6); // cmp i3,6
UML_EXHc(block, COND_NE, exception_addrerr, I0); // exh addrerr,i0,ne
- UML_LABEL(block, addrok); // addrok:
+ UML_LABEL(block, addrok); // addrok:
}
+}
- /* general case: assume paging and perform a translation */
- UML_SHR(block, I3, I0, 12); // shr i3,i0,12
- UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb_table],i3,dword
- UML_TEST(block, I3, iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED);// test i3,iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED
- UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
- UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000
- if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0)
- for (ramnum = 0; ramnum < m_fastram_select; ramnum++)
+/*------------------------------------------------------------------
+ static_generate_fastram_accessor
+------------------------------------------------------------------*/
+
+void mips3_device::static_generate_fastram_accessor(drcuml_block &block, int &label, int size, bool iswrite, bool ismasked)
+{
+ if (!debugger_enabled())
+ {
+ for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
+ {
if (!(iswrite && m_fastram[ramnum].readonly))
{
void *fastbase = (uint8_t *)m_fastram[ramnum].base - m_fastram[ramnum].start;
uint32_t skip = label++;
if (m_fastram[ramnum].end != 0xffffffff)
{
- UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end
- UML_JMPc(block, COND_A, skip); // ja skip
+ UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end
+ UML_JMPc(block, COND_A, skip); // ja skip
}
if (m_fastram[ramnum].start != 0x00000000)
{
- UML_CMP(block, I0, m_fastram[ramnum].start);// cmp i0,fastram_start
- UML_JMPc(block, COND_B, skip); // jb skip
+ UML_CMP(block, I0, m_fastram[ramnum].start); // cmp i0,fastram_start
+ UML_JMPc(block, COND_B, skip); // jb skip
}
if (!iswrite)
{
if (size == 1)
{
UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0));
- // xor i0,i0,bytexor
- UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte
+ // xor i0,i0,bytexor
+ UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte
}
else if (size == 2)
{
UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0));
- // xor i0,i0,wordxor
- UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1
+ // xor i0,i0,wordxor
+ 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_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1
}
else if (size == 8)
{
- UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i0,fastbase,i0,qword_x1
+ UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i0,fastbase,i0,qword_x1
UML_DROR(block, I0, I0, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
- // dror i0,i0,32*bytexor
+ // dror i0,i0,32*bytexor
}
- UML_RET(block); // ret
+ UML_RET(block); // ret
}
else
{
if (size == 1)
{
UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0));
- // xor i0,i0,bytexor
- UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1);// store fastbase,i0,i1,byte
+ // xor i0,i0,bytexor
+ UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1); // store fastbase,i0,i1,byte
}
else if (size == 2)
{
UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0));
- // xor i0,i0,wordxor
- UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1);// store fastbase,i0,i1,word_x1
+ // xor i0,i0,wordxor
+ UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1); // store fastbase,i0,i1,word_x1
}
else if (size == 4)
{
if (ismasked)
{
- UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i3,fastbase,i0,dword_x1
- UML_ROLINS(block, I3, I1, 0, I2); // rolins i3,i1,0,i2
- UML_STORE(block, fastbase, I0, I3, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i3,dword_x1
+ UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i3,fastbase,i0,dword_x1
+ UML_ROLINS(block, I3, I1, 0, I2); // rolins i3,i1,0,i2
+ UML_STORE(block, fastbase, I0, I3, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i3,dword_x1
}
else
- UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1
+ UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1
}
else if (size == 8)
{
@@ -936,8 +925,8 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
{
UML_DROR(block, I2, I2, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
// dror i2,i2,32*bytexor
- UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i3,fastbase,i0,qword_x1
- UML_DROLINS(block, I3, I1, 0, I2); // drolins i3,i1,0,i2
+ UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i3,fastbase,i0,qword_x1
+ UML_DROLINS(block, I3, I1, 0, I2); // drolins i3,i1,0,i2
UML_DSTORE(block, fastbase, I0, I3, SIZE_QWORD, SCALE_x1); // dstore fastbase,i0,i3,qword_x1
}
else
@@ -946,9 +935,19 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
UML_RET(block); // ret
}
- UML_LABEL(block, skip); // skip:
+ UML_LABEL(block, skip); // skip:
}
+ }
+ }
+}
+
+
+/*------------------------------------------------------------------
+ static_generate_memory_rw
+------------------------------------------------------------------*/
+void mips3_device::static_generate_memory_rw(drcuml_block &block, int size, bool iswrite, bool ismasked)
+{
switch (size)
{
case 1:
@@ -969,9 +968,9 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
if (iswrite)
{
if (!ismasked)
- UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write i0,i1,program_dword
+ UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write i0,i1,program_dword
else
- UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM); // writem i0,i1,i2,program_dword
+ UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM); // writem i0,i1,i2,program_dword
}
else
{
@@ -986,38 +985,90 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
if (iswrite)
{
if (!ismasked)
- UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM); // dwrite i0,i1,program_qword
+ UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM); // dwrite i0,i1,program_qword
else
- UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM); // dwritem i0,i1,i2,program_qword
+ UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM); // dwritem i0,i1,i2,program_qword
}
else
{
if (!ismasked)
- UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM); // dread i0,i0,program_qword
+ UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM); // dread i0,i0,program_qword
else
- UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM); // dreadm i0,i0,i2,program_qword
+ UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM); // dreadm i0,i0,i2,program_qword
}
break;
}
UML_RET(block); // ret
+}
- if (tlbmiss != 0)
+
+/*------------------------------------------------------------------
+ static_generate_memory_accessor
+------------------------------------------------------------------*/
+
+void mips3_device::static_generate_memory_accessor(drcuml_block &block, int &label, int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr)
+{
+ /* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
+ /* on exit, read result is in I0 */
+ /* routine trashes I0-I3 */
+ uml::code_handle &exception_tlb = *m_exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD];
+ uml::code_handle &exception_tlbfill = *m_exception[iswrite ? EXCEPTION_TLBSTORE_FILL : EXCEPTION_TLBLOAD_FILL];
+ uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
+ int tlbmiss = 0;
+
+ /* add a global entry for this */
+ alloc_handle(*m_drcuml, handleptr, name);
+ UML_HANDLE(block, *handleptr); // handle handleptr
+
+ static_generate_memory_mode_checks(block, exception_addrerr, label, mode);
+
+ /* general case: assume paging and perform a translation */
+ UML_SHR(block, I3, I0, 12); // shr i3,i0,12
+ UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4); // load i3,[vtlb_table],i3,dword
+ UML_TEST(block, I3, iswrite ? WRITE_ALLOWED : READ_ALLOWED); // test i3,iswrite ? WRITE_ALLOWED : READ_ALLOWED
+ UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
+ UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000
+
+ static_generate_fastram_accessor(block, label, size, iswrite, ismasked);
+ static_generate_memory_rw(block, size, iswrite, ismasked);
+
+ UML_LABEL(block, tlbmiss); // tlbmiss:
+ if (iswrite)
{
- UML_LABEL(block, tlbmiss); // tlbmiss:
- if (iswrite)
- {
- UML_TEST(block, I3, VTLB_READ_ALLOWED); // test i3,VTLB_READ_ALLOWED
- UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBMOD], I0);
- // exh tlbmod,i0,nz
- }
- UML_TEST(block, I3, VTLB_FLAG_FIXED); // test i3,VTLB_FLAG_FIXED
- UML_EXHc(block, COND_NZ, exception_tlb, I0); // exh tlb,i0,nz
- UML_EXH(block, exception_tlbfill, I0); // exh tlbfill,i0
+ UML_TEST(block, I3, READ_ALLOWED); // test i3,READ_ALLOWED
+ UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBMOD], I0); // exh tlbmod,i0,nz
}
-
- block.end();
+ UML_TEST(block, I3, FLAG_FIXED); // test i3,FLAG_FIXED
+ UML_EXHc(block, COND_NZ, exception_tlb, I0); // exh tlb,i0,nz
+ UML_EXH(block, exception_tlbfill, I0); // exh tlbfill,i0
}
+void r4650_device::static_generate_memory_accessor(drcuml_block &block, int &label, int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr)
+{
+ /* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
+ /* on exit, read result is in I0 */
+ /* routine trashes I0-I3 */
+ uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
+
+ /* add a global entry for this */
+ alloc_handle(*m_drcuml, handleptr, name);
+ UML_HANDLE(block, *handleptr); // handle handleptr
+
+ static_generate_memory_mode_checks(block, exception_addrerr, label, mode);
+
+ if (mode == MODE_USER)
+ {
+ int addrok;
+ UML_CMP(block, I0, CPR032(COP0_R4650_DBound)); // cmp i0,CPR0[DBound]
+ UML_JMPc(block, COND_LE, addrok = label++); // jle addrok
+ UML_EXHc(block, COND_G, exception_addrerr, I0); // exh addrerr,i0,ne
+ UML_LABEL(block, addrok); // addrok:
+ UML_ADD(block, I0, I0, CPR032(COP0_R4650_DBase)); // add i0,i0,CPR0[DBase]
+ }
+
+ static_generate_fastram_accessor(block, label, size, iswrite, ismasked);
+ static_generate_memory_rw(block, size, iswrite, ismasked);
+}
/***************************************************************************
@@ -1098,7 +1149,7 @@ void mips3_device::generate_update_cycles(drcuml_block &block, compiler_state &c
validate a sequence of opcodes
-------------------------------------------------*/
-void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
+void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast, const opcode_desc *codelast)
{
const opcode_desc *curdesc;
if (m_drcuml->logging())
@@ -1147,35 +1198,130 @@ void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &
#else
uint32_t sum = 0;
const void *base = m_prptr(seqhead->physpc);
- uint32_t low_bits = (seqhead->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
+ const uint32_t data_bits_mask = (m_data_bits == 64 ? 4 : 0);
+ const uint32_t last_physpc = codelast->physpc;
+ uint32_t low_bits = (seqhead->physpc & data_bits_mask) ^ m_dword_xor;
UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1); // load i0,base,0,dword
sum += seqhead->opptr.l[0];
- for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if ((m_drcoptions & MIPS3DRC_EXTRA_INSTR_CHECK) && !(codelast->flags & OPFLAG_VIRTUAL_NOOP) && last_physpc != seqhead->physpc)
{
- if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ base = m_prptr(last_physpc);
+ assert(base != nullptr);
+ low_bits = (last_physpc & data_bits_mask) ^ m_dword_xor;
+ UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += codelast->opptr.l[0];
+ }
+ if (!(m_drcoptions & MIPS3DRC_EXTRA_INSTR_CHECK))
+ {
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
{
- base = m_prptr(curdesc->physpc);
- assert(base != nullptr);
- uint32_t low_bits = (curdesc->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
- UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
- UML_ADD(block, I0, I0, I1); // add i0,i0,i1
- sum += curdesc->opptr.l[0];
-
- if (curdesc->delay.first() != nullptr
- && !(curdesc->delay.first()->flags & OPFLAG_VIRTUAL_NOOP)
- && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
- base = m_prptr(curdesc->delay.first()->physpc);
+ base = m_prptr(curdesc->physpc);
assert(base != nullptr);
- uint32_t low_bits = (curdesc->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
- UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
- UML_ADD(block, I0, I0, I1); // add i0,i0,i1
- sum += curdesc->delay.first()->opptr.l[0];
+ low_bits = (curdesc->physpc & data_bits_mask) ^ m_dword_xor;
+ UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->opptr.l[0];
+
+ if (curdesc->delay.first() != nullptr
+ && !(curdesc->delay.first()->flags & OPFLAG_VIRTUAL_NOOP)
+ && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
+ {
+ base = m_prptr(curdesc->delay.first()->physpc);
+ assert(base != nullptr);
+ low_bits = (curdesc->delay.first()->physpc & data_bits_mask) ^ m_dword_xor;
+ UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->delay.first()->opptr.l[0];
+ }
+ }
+ }
+ }
+ else
+ {
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ {
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ // Skip the last if it was already included above
+ if (curdesc->physpc != last_physpc)
+ {
+ base = m_prptr(curdesc->physpc);
+ assert(base != nullptr);
+ low_bits = (curdesc->physpc & data_bits_mask) ^ m_dword_xor;
+ UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->opptr.l[0];
+ }
+
+ if (curdesc->delay.first() != nullptr
+ && !(curdesc->delay.first()->flags & OPFLAG_VIRTUAL_NOOP)
+ && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
+ {
+ base = m_prptr(curdesc->delay.first()->physpc);
+ assert(base != nullptr);
+ low_bits = (curdesc->delay.first()->physpc & data_bits_mask) ^ m_dword_xor;
+ UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->delay.first()->opptr.l[0];
+ }
}
}
}
UML_CMP(block, I0, sum); // cmp i0,sum
UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ if (DEBUG_STRICT_VERIFY)
+ {
+ // This code will do additional checks on the last instruction and last delay slot and indicate if the check failed
+ uml::code_label check_second = compiler.labelnum++;
+ uml::code_label check_failed = compiler.labelnum++;
+ uml::code_label check_passed = compiler.labelnum++;
+ // Check the last instruction
+ if (!(codelast->flags & OPFLAG_VIRTUAL_NOOP) && last_physpc != seqhead->physpc)
+ {
+ base = m_prptr(last_physpc);
+ assert(base != nullptr);
+ low_bits = (last_physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
+ UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ sum = codelast->opptr.l[0];
+ UML_CMP(block, I0, sum); // cmp i0,sum
+ UML_JMPc(block, COND_E, check_second);
+ static const char text[] = "Last instr validation fail seq: %08X end: %08x\n";
+ UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text
+ UML_MOV(block, mem(&m_core->arg0), seqhead->pc);
+ UML_MOV(block, mem(&m_core->arg1), last_physpc); // mov [arg0],desc->pc
+ UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug
+ //UML_CALLC(block, cfunc_debug_break, this);
+ // Skip delay slot check
+ UML_JMP(block, check_failed);
+ // Check the last instruction delay slot
+ UML_LABEL(block, check_second);
+ if (codelast->delay.first() != nullptr && !(codelast->delay.first()->flags & OPFLAG_VIRTUAL_NOOP)
+ && last_physpc != seqhead->physpc)
+ {
+ base = m_prptr(codelast->delay.first()->physpc);
+ assert(base != nullptr);
+ low_bits = (codelast->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
+ UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword
+ sum = codelast->delay.first()->opptr.l[0];
+ UML_CMP(block, I0, sum); // cmp i0,sum
+ UML_JMPc(block, COND_E, check_passed);
+ static const char text[] = "Last delay slot validation fail seq: %08X end: %08x\n";
+ UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text
+ UML_MOV(block, mem(&m_core->arg0), seqhead->pc);
+ UML_MOV(block, mem(&m_core->arg1), last_physpc); // mov [arg0],desc->pc
+ UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug
+ //UML_CALLC(block, cfunc_debug_break, this);
+ UML_JMP(block, check_failed);
+ }
+ }
+ UML_JMP(block, check_passed);
+ UML_LABEL(block, check_failed);
+ UML_EXH(block, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ UML_LABEL(block, check_passed);
+ }
#endif
}
}
@@ -1188,22 +1334,19 @@ void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &
void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
- offs_t expc;
- int hotnum;
-
/* add an entry for the log */
if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]);
/* set the PC map variable */
- expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc;
+ offs_t expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc;
UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc
/* accumulate total cycles */
compiler.cycles += desc->cycles;
/* is this a hotspot? */
- for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
+ for (int hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
if (m_hotspot[hotnum].pc != 0 && desc->pc == m_hotspot[hotnum].pc && desc->opptr.l[0] == m_hotspot[hotnum].opcode)
{
compiler.cycles += m_hotspot[hotnum].cycles;
@@ -1221,7 +1364,7 @@ void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_s
}
/* if we are debugging, call the debugger */
- if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ if (debugger_enabled())
{
UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc
save_fast_iregs(block);
@@ -1247,6 +1390,8 @@ void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_s
UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug
}
UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0
+ // Unconditional tlb exception, no point going further
+ return;
}
/* validate our TLB entry at this PC; if we fail, we need to handle it */
@@ -1255,7 +1400,7 @@ void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_s
const vtlb_entry *tlbtable = vtlb_table();
/* if we currently have a valid TLB read entry, we just verify */
- if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED)
+ if (tlbtable[desc->pc >> 12] & FETCH_ALLOWED)
{
if (PRINTF_MMU)
{
@@ -1280,6 +1425,8 @@ void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_s
UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug
}
UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0
+ // Unconditional tlb exception, no point going further
+ return;
}
}
@@ -1331,7 +1478,7 @@ void mips3_device::generate_delay_slot_and_branch(drcuml_block &block, compiler_
if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
{
generate_update_cycles(block, compiler_temp, desc->targetpc, true); // <subtract cycles>
- if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
+ if (!(m_drcoptions & MIPS3DRC_DISABLE_INTRABLOCK) && (desc->flags & OPFLAG_INTRABLOCK_BRANCH))
{
UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000
}
@@ -2456,6 +2603,11 @@ bool mips3_device::generate_set_cop0_reg(drcuml_block &block, compiler_state &co
return true;
case COP0_Count:
+ // don't count the cycle for this instruction yet; we need a non-zero cycle
+ // count in case we are in a delay slot, otherwise the test for negative cycles
+ // won't be generated (due to compiler.cycles == 0); see the loop during early
+ // boot of gauntdl, @BFC01A24
+ compiler.cycles--;
generate_update_cycles(block, compiler, desc->pc, !in_delay_slot); // <subtract cycles>
UML_MOV(block, CPR032(COP0_Count), I0); // mov [Count],i0
UML_CALLC(block, cfunc_get_cycles, this); // callc cfunc_get_cycles,mips3
@@ -2464,6 +2616,7 @@ bool mips3_device::generate_set_cop0_reg(drcuml_block &block, compiler_state &co
UML_DSUB(block, mem(&m_core->count_zero_time), mem(&m_core->numcycles), I0);
// dsub [count_zero_time],[m_numcycles],i0
UML_CALLC(block, cfunc_mips3com_update_cycle_counting, this); // callc mips3com_update_cycle_counting,mips.core
+ compiler.cycles++;
return true;
case COP0_Compare:
@@ -2509,12 +2662,18 @@ bool mips3_device::generate_get_cop0_reg(drcuml_block &block, compiler_state &co
switch (reg)
{
case COP0_Count:
+ // don't count the cycle for this instruction yet; we need a non-zero cycle
+ // count in case we are in a delay slot, otherwise the test for negative cycles
+ // won't be generated (due to compiler.cycles == 0); see the loop during early
+ // boot of gauntdl, @BFC01A24
+ compiler.cycles--;
generate_update_cycles(block, compiler, desc->pc, false); // <subtract cycles>
UML_CALLC(block, cfunc_get_cycles, this); // callc cfunc_get_cycles,mips3
UML_DSUB(block, I0, mem(&m_core->numcycles), mem(&m_core->count_zero_time));
// dsub i0,[numcycles],[count_zero_time]
UML_DSHR(block, I0, I0, 1); // dshr i0,i0,1
UML_DSEXT(block, I0, I0, SIZE_DWORD); // dsext i0,i0,dword
+ compiler.cycles++;
return true;
case COP0_Random:
diff --git a/src/devices/cpu/mips/mips3dsm.cpp b/src/devices/cpu/mips/mips3dsm.cpp
index 9e1113819b7..cdad3375ae7 100644
--- a/src/devices/cpu/mips/mips3dsm.cpp
+++ b/src/devices/cpu/mips/mips3dsm.cpp
@@ -124,10 +124,12 @@ const char *const mips3_disassembler::ccreg[4][32] =
inline std::string mips3_disassembler::signed_16bit(int16_t val)
{
- if (val < 0)
- return util::string_format("-$%x", -val);
+ if (val >= -9 && val <= 9)
+ return util::string_format("%d", val);
+ else if (val < 0)
+ return util::string_format("-0x%x", -val);
else
- return util::string_format("$%x", val);
+ return util::string_format("0x%x", val);
}
uint32_t mips3_disassembler::dasm_cop0(uint32_t pc, uint32_t op, std::ostream &stream)
@@ -147,11 +149,9 @@ uint32_t mips3_disassembler::dasm_cop0(uint32_t pc, uint32_t op, std::ostream &s
case 0x08: /* BC */
switch (rt)
{
- case 0x00: util::stream_format(stream, "bc0f $%08x", pc + 4 + ((int16_t)op << 2)); break;
- case 0x01: util::stream_format(stream, "bc0t $%08x", pc + 4 + ((int16_t)op << 2)); break;
- case 0x02: util::stream_format(stream, "bc0fl [invalid]"); break;
- case 0x03: util::stream_format(stream, "bc0tl [invalid]"); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ case 0x00: util::stream_format(stream, "bc0f 0x%08x", pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bc0t 0x%08x", pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
case 0x10:
@@ -181,14 +181,14 @@ uint32_t mips3_disassembler::dasm_cop0(uint32_t pc, uint32_t op, std::ostream &s
default: dasm_extra_cop0(pc, op, stream); break;
}
break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return flags;
}
uint32_t mips3_disassembler::dasm_extra_cop0(uint32_t pc, uint32_t op, std::ostream &stream)
{
- util::stream_format(stream, "cop0 $%07x", op & 0x01ffffff);
+ util::stream_format(stream, "cop0 0x%07x", op & 0x01ffffff);
return 0;
}
@@ -218,10 +218,10 @@ uint32_t mips3_disassembler::dasm_cop1(uint32_t pc, uint32_t op, std::ostream &s
case 0x08: /* BC */
switch (rt & 3)
{
- case 0x00: util::stream_format(stream, "bc1f $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); break;
- case 0x01: util::stream_format(stream, "bc1t $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); break;
- case 0x02: util::stream_format(stream, "bc1fl $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_OVER | step_over_extra(1); break;
- case 0x03: util::stream_format(stream, "bc1tl $%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_OVER | step_over_extra(1); break;
+ case 0x00: util::stream_format(stream, "bc1f 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bc1t 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
+ case 0x02: util::stream_format(stream, "bc1fl 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
+ case 0x03: util::stream_format(stream, "bc1tl 0x%08x,%d", pc + 4 + ((int16_t)op << 2), (op >> 18) & 7); flags = STEP_COND | step_over_extra(1); break;
}
break;
default: /* COP */
@@ -277,7 +277,7 @@ uint32_t mips3_disassembler::dasm_cop1(uint32_t pc, uint32_t op, std::ostream &s
uint32_t mips3_disassembler::dasm_extra_cop1(uint32_t pc, uint32_t op, std::ostream &stream)
{
- util::stream_format(stream, "cop1 $%07x", op & 0x01ffffff);
+ util::stream_format(stream, "cop1 0x%07x", op & 0x01ffffff);
return 0;
}
@@ -336,7 +336,7 @@ uint32_t mips3_disassembler::dasm_cop1x(uint32_t pc, uint32_t op, std::ostream &
case 0x3d:
case 0x3e:
case 0x3f: util::stream_format(stream, "nmsub.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break;
- default: util::stream_format(stream, "cop1 $%07x", op & 0x01ffffff); break;
+ default: util::stream_format(stream, "cop1 0x%07x", op & 0x01ffffff); break;
}
return flags;
}
@@ -358,11 +358,9 @@ uint32_t mips3_disassembler::dasm_cop2(uint32_t pc, uint32_t op, std::ostream &s
case 0x08: /* BC */
switch (rt)
{
- case 0x00: util::stream_format(stream, "bc2f $%08x", pc + 4 + ((int16_t)op << 2)); break;
- case 0x01: util::stream_format(stream, "bc2t $%08x", pc + 4 + ((int16_t)op << 2)); break;
- case 0x02: util::stream_format(stream, "bc2fl [invalid]"); break;
- case 0x03: util::stream_format(stream, "bc2tl [invalid]"); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ case 0x00: util::stream_format(stream, "bc2f 0x%08x", pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bc2t 0x%08x", pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
case 0x10:
@@ -383,14 +381,14 @@ uint32_t mips3_disassembler::dasm_cop2(uint32_t pc, uint32_t op, std::ostream &s
case 0x1f: /* COP */
flags = dasm_extra_cop2(pc, op, stream);
break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return flags;
}
uint32_t mips3_disassembler::dasm_extra_cop2(uint32_t pc, uint32_t op, std::ostream &stream)
{
- util::stream_format(stream, "cop2 $%07x", op & 0x01ffffff);
+ util::stream_format(stream, "cop2 0x%07x", op & 0x01ffffff);
return 0;
}
@@ -406,9 +404,9 @@ uint32_t mips3_disassembler::dasm_idt(uint32_t pc, uint32_t op, std::ostream &st
{
case 0: util::stream_format(stream, "mad %s,%s", reg[rs], reg[rt]); break;
case 1: util::stream_format(stream, "madu %s,%s", reg[rs], reg[rt]); break;
- case 2: util::stream_format(stream, "mul %s,%s,%s", reg[rs], reg[rt], reg[rd]); break;
+ case 2: util::stream_format(stream, "mul %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 4: util::stream_format(stream, "msub %s,%s", reg[rs], reg[rt]); break;
- default:util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default:util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return flags;
@@ -416,19 +414,19 @@ uint32_t mips3_disassembler::dasm_idt(uint32_t pc, uint32_t op, std::ostream &st
uint32_t mips3_disassembler::dasm_extra_base(uint32_t pc, uint32_t op, std::ostream &stream)
{
- util::stream_format(stream, "dc.l $%08x [invalid]", op);
+ util::stream_format(stream, ".word 0x%08x /*invalid*/", op);
return 0;
}
uint32_t mips3_disassembler::dasm_extra_regimm(uint32_t pc, uint32_t op, std::ostream &stream)
{
- util::stream_format(stream, "dc.l $%08x [invalid]", op);
+ util::stream_format(stream, ".word 0x%08x /*invalid*/", op);
return 0;
}
uint32_t mips3_disassembler::dasm_extra_special(uint32_t pc, uint32_t op, std::ostream &stream)
{
- util::stream_format(stream, "dc.l $%08x [invalid]", op);
+ util::stream_format(stream, ".word 0x%08x /*invalid*/", op);
return 0;
}
@@ -438,7 +436,7 @@ uint32_t ee_disassembler::dasm_extra_cop0(uint32_t pc, uint32_t op, std::ostream
{
case 0x38: util::stream_format(stream, "ei"); break;
case 0x39: util::stream_format(stream, "di"); break;
- default: util::stream_format(stream, "cop1 $%07x", op & 0x01ffffff); break;
+ default: util::stream_format(stream, "cop1 0x%07x", op & 0x01ffffff); break;
}
return 0;
}
@@ -453,7 +451,7 @@ uint32_t ee_disassembler::dasm_extra_cop1(uint32_t pc, uint32_t op, std::ostream
{
case 0x18: util::stream_format(stream, "adda.s %s,%s", cpreg[1][fs], cpreg[1][ft]); break;
case 0x1c: util::stream_format(stream, "madd.s %s,%s,%s", cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
}
@@ -522,10 +520,10 @@ uint32_t ee_disassembler::dasm_extra_cop2(uint32_t pc, uint32_t op, std::ostream
case 0x2f: util::stream_format(stream, "vmini.%s %s%s %s%s %s%s", dest, vfreg[rd], destc, vfreg[rs], destc, vfreg[rt], dest); break;
case 0x30: util::stream_format(stream, "viadd %s, %s, %s", vireg[rd], vireg[rs], vireg[rt]); break;
case 0x31: util::stream_format(stream, "visub %s, %s, %s", vireg[rd], vireg[rs], vireg[rt]); break;
- case 0x32: util::stream_format(stream, "viaddi %s, %s, $%x", vireg[rt], vireg[rs], imm5); break;
+ case 0x32: util::stream_format(stream, "viaddi %s, %s, 0x%x", vireg[rt], vireg[rs], imm5); break;
case 0x34: util::stream_format(stream, "viand %s, %s, %s", vireg[rd], vireg[rs], vireg[rt]); break;
case 0x35: util::stream_format(stream, "vior %s, %s, %s", vireg[rd], vireg[rs], vireg[rt]); break;
- case 0x38: util::stream_format(stream, "vcallms $06x", (op & 0x001fffc0) >> 3); break;
+ case 0x38: util::stream_format(stream, "vcallms 0x%06x", (op & 0x001fffc0) >> 3); break;
case 0x39: util::stream_format(stream, "vcallmsr $vi27"); break;
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
switch (ext)
@@ -588,10 +586,10 @@ uint32_t ee_disassembler::dasm_extra_cop2(uint32_t pc, uint32_t op, std::ostream
case 0x41: util::stream_format(stream, "vrget.%s %s%s R", dest, vfreg[rt], destc); break;
case 0x42: util::stream_format(stream, "vrinit R, %s%s", vfreg[rs], fsf); break;
case 0x43: util::stream_format(stream, "vrxor R, %s%s", vfreg[rs], fsf); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
@@ -663,14 +661,14 @@ uint32_t ee_disassembler::dasm_idt(uint32_t pc, uint32_t op, std::ostream &strea
case 2: util::stream_format(stream, "pmfhl.slw %s", reg[rd]); break;
case 3: util::stream_format(stream, "pmfhl.lh %s", reg[rd]); break;
case 4: util::stream_format(stream, "pmfhl.sh %s", reg[rd]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
case 0x31:
switch (fmt)
{
case 0: util::stream_format(stream, "pmthl.lw %s", reg[rd]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
break;
case 0x34: util::stream_format(stream, "psllh %s,%s,%d", reg[rd], reg[rt], shift); break;
@@ -679,7 +677,7 @@ uint32_t ee_disassembler::dasm_idt(uint32_t pc, uint32_t op, std::ostream &strea
case 0x3c: util::stream_format(stream, "psllw %s,%s,%d", reg[rd], reg[rt], shift); break;
case 0x3e: util::stream_format(stream, "psrlw %s,%s,%d", reg[rd], reg[rt], shift); break;
case 0x3f: util::stream_format(stream, "psraw %s,%s,%d", reg[rd], reg[rt], shift); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return flags;
@@ -719,7 +717,7 @@ uint32_t ee_disassembler::dasm_mmi0(uint32_t pc, uint32_t op, std::ostream &stre
case 0x1b: util::stream_format(stream, "ppacb %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 0x1e: util::stream_format(stream, "pext5 %s,%s", reg[rd], reg[rt]); break;
case 0x1f: util::stream_format(stream, "ppac5 %s,%s", reg[rd], reg[rt]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
@@ -752,7 +750,7 @@ uint32_t ee_disassembler::dasm_mmi1(uint32_t pc, uint32_t op, std::ostream &stre
case 0x19: util::stream_format(stream, "psubub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 0x1a: util::stream_format(stream, "pextub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 0x1b: util::stream_format(stream, "qfsrv %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
@@ -789,7 +787,7 @@ uint32_t ee_disassembler::dasm_mmi2(uint32_t pc, uint32_t op, std::ostream &stre
case 0x1d: util::stream_format(stream, "pdivbw %s,%s", reg[rs], reg[rt]); break;
case 0x1e: util::stream_format(stream, "pexew %s,%s", reg[rd], reg[rt]); break;
case 0x1f: util::stream_format(stream, "prot3w %s,%s", reg[rd], reg[rt]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
@@ -817,7 +815,7 @@ uint32_t ee_disassembler::dasm_mmi3(uint32_t pc, uint32_t op, std::ostream &stre
case 0x1a: util::stream_format(stream, "pexch %s,%s", reg[rd], reg[rt]); break;
case 0x1b: util::stream_format(stream, "pcpyh %s,%s", reg[rd], reg[rt]); break;
case 0x1e: util::stream_format(stream, "pexcw %s,%s", reg[rd], reg[rt]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
@@ -832,7 +830,7 @@ uint32_t ee_disassembler::dasm_extra_base(uint32_t pc, uint32_t op, std::ostream
{
case 0x1e: util::stream_format(stream, "lq %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x1f: util::stream_format(stream, "sq %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
@@ -847,7 +845,7 @@ uint32_t ee_disassembler::dasm_extra_special(uint32_t pc, uint32_t op, std::ostr
{
case 0x28: util::stream_format(stream, "mfsa %s", reg[rd]); break;
case 0x29: util::stream_format(stream, "mtsa %s", reg[rs]); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
}
@@ -860,7 +858,7 @@ uint32_t ee_disassembler::dasm_extra_regimm(uint32_t pc, uint32_t op, std::ostre
{
case 0x18: util::stream_format(stream, "mtsab %s,%s", reg[rs], signed_16bit(op)); break;
case 0x19: util::stream_format(stream, "mtsah %s,%s", reg[rs], signed_16bit(op)); break;
- default: util::stream_format(stream, "dc.l $%08x [invalid]", op); break;
+ default: util::stream_format(stream, ".word 0x%08x /*invalid*/", op); break;
}
return 0;
}
@@ -894,7 +892,7 @@ offs_t mips3_disassembler::dasm_one(std::ostream &stream, offs_t pc, u32 op)
case 0x04: util::stream_format(stream, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
case 0x06: util::stream_format(stream, "srlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
case 0x07: util::stream_format(stream, "srav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
- case 0x08: util::stream_format(stream, "jr %s", reg[rs]); if (rs == 31) flags = STEP_OUT; break;
+ case 0x08: util::stream_format(stream, "jr %s", reg[rs]); if (rs == 31) flags = STEP_OUT | step_over_extra(1); break;
case 0x09: if (rd == 31)
util::stream_format(stream, "jalr %s", reg[rs]);
else
@@ -922,13 +920,33 @@ offs_t mips3_disassembler::dasm_one(std::ostream &stream, offs_t pc, u32 op)
case 0x1e: util::stream_format(stream, "ddiv %s,%s", reg[rs], reg[rt]); break;
case 0x1f: util::stream_format(stream, "ddivu %s,%s", reg[rs], reg[rt]); break;
case 0x20: util::stream_format(stream, "add %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x21: util::stream_format(stream, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x22: util::stream_format(stream, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x23: util::stream_format(stream, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x21: if (rs == 0 || rt == 0)
+ util::stream_format(stream, "move %s,%s", reg[rd], reg[rs == 0 ? rt : rs]);
+ else
+ util::stream_format(stream, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
+ case 0x22: if (rs == 0)
+ util::stream_format(stream, "neg %s,%s", reg[rd], reg[rt]);
+ else
+ util::stream_format(stream, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
+ case 0x23: if (rs == 0)
+ util::stream_format(stream, "negu %s,%s", reg[rd], reg[rt]);
+ else
+ util::stream_format(stream, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
case 0x24: util::stream_format(stream, "and %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x25: util::stream_format(stream, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x25: if (rs == 0 || rt == 0)
+ util::stream_format(stream, "move %s,%s", reg[rd], reg[rs == 0 ? rt : rs]);
+ else
+ util::stream_format(stream, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
case 0x26: util::stream_format(stream, "xor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
- case 0x27: util::stream_format(stream, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x27: if (rs == 0)
+ util::stream_format(stream, "not %s,%s", reg[rd], reg[rt]);
+ else
+ util::stream_format(stream, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]);
+ break;
case 0x2a: util::stream_format(stream, "slt %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 0x2b: util::stream_format(stream, "sltu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
case 0x2c: util::stream_format(stream, "dadd %s,%s,%s", reg[rd], reg[rs], reg[rt]); break;
@@ -954,50 +972,84 @@ offs_t mips3_disassembler::dasm_one(std::ostream &stream, offs_t pc, u32 op)
case 0x01: /* REGIMM */
switch ((op >> 16) & 31)
{
- case 0x00: util::stream_format(stream, "bltz %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x01: util::stream_format(stream, "bgez %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x02: util::stream_format(stream, "bltzl %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x03: util::stream_format(stream, "bgezl %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x08: util::stream_format(stream, "tgei %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER; break;
- case 0x09: util::stream_format(stream, "tgeiu %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER; break;
- case 0x0a: util::stream_format(stream, "tlti %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER; break;
- case 0x0b: util::stream_format(stream, "tltiu %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER; break;
- case 0x0c: util::stream_format(stream, "teqi %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER; break;
- case 0x0e: util::stream_format(stream, "tnei %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER; break;
- case 0x10: util::stream_format(stream, "bltzal %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | step_over_extra(1); break;
- case 0x11: util::stream_format(stream, "bgezal %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | step_over_extra(1); break;
- case 0x12: util::stream_format(stream, "bltzall %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | step_over_extra(1); break;
- case 0x13: util::stream_format(stream, "bgezall %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | step_over_extra(1); break;
+ case 0x00: util::stream_format(stream, "bltz %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x01: util::stream_format(stream, "bgez %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x02: util::stream_format(stream, "bltzl %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x03: util::stream_format(stream, "bgezl %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x08: util::stream_format(stream, "tgei %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER | STEP_COND; break;
+ case 0x09: util::stream_format(stream, "tgeiu %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER | STEP_COND; break;
+ case 0x0a: util::stream_format(stream, "tlti %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER | STEP_COND; break;
+ case 0x0b: util::stream_format(stream, "tltiu %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER | STEP_COND; break;
+ case 0x0c: util::stream_format(stream, "teqi %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER | STEP_COND; break;
+ case 0x0e: util::stream_format(stream, "tnei %s,%s", reg[rs], signed_16bit(op)); flags = STEP_OVER | STEP_COND; break;
+ case 0x10: util::stream_format(stream, "bltzal %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_OVER | STEP_COND | step_over_extra(1); break;
+ case 0x11: if (rs == 0)
+ util::stream_format(stream, "bal 0x%08x", pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "bgezal %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_OVER | (rs != 0 ? STEP_COND : 0) | step_over_extra(1);
+ break;
+ case 0x12: util::stream_format(stream, "bltzall %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_OVER | STEP_COND | step_over_extra(1); break;
+ case 0x13: util::stream_format(stream, "bgezall %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_OVER | (rs != 0 ? STEP_COND : 0) | step_over_extra(1); break;
default: flags = dasm_extra_regimm(pc, op, stream); break;
}
break;
- case 0x02: util::stream_format(stream, "j $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); break;
- case 0x03: util::stream_format(stream, "jal $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); flags = STEP_OVER | step_over_extra(1); break;
+ case 0x02: util::stream_format(stream, "j 0x%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); break;
+ case 0x03: util::stream_format(stream, "jal 0x%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); flags = STEP_OVER | step_over_extra(1); break;
case 0x04: if (rs == 0 && rt == 0)
- util::stream_format(stream, "b $%08x", pc + 4 + ((int16_t)op << 2));
+ util::stream_format(stream, "b 0x%08x", pc + 4 + ((int16_t)op << 2));
else
- util::stream_format(stream, "beq %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
- break;
- case 0x05: util::stream_format(stream, "bne %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));break;
- case 0x06: util::stream_format(stream, "blez %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
- case 0x07: util::stream_format(stream, "bgtz %s,$%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); break;
+ {
+ if (rt == 0)
+ util::stream_format(stream, "beqz %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "beq %s,%s,0x%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_COND | step_over_extra(1);
+ }
+ break;
+ case 0x05: if (rt == 0)
+ util::stream_format(stream, "bnez %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "bne %s,%s,0x%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_COND | step_over_extra(1);
+ break;
+ case 0x06: util::stream_format(stream, "blez %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x07: util::stream_format(stream, "bgtz %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
case 0x08: util::stream_format(stream, "addi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
- case 0x09: util::stream_format(stream, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
+ case 0x09: if (rs == 0)
+ util::stream_format(stream, "li %s,%s", reg[rt], signed_16bit(op));
+ else
+ util::stream_format(stream, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op));
+ break;
case 0x0a: util::stream_format(stream, "slti %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
case 0x0b: util::stream_format(stream, "sltiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
- case 0x0c: util::stream_format(stream, "andi %s,%s,$%04x", reg[rt], reg[rs], (uint16_t)op); break;
- case 0x0d: util::stream_format(stream, "ori %s,%s,$%04x", reg[rt], reg[rs], (uint16_t)op); break;
- case 0x0e: util::stream_format(stream, "xori %s,%s,$%04x", reg[rt], reg[rs], (uint16_t)op); break;
- case 0x0f: util::stream_format(stream, "lui %s,$%04x", reg[rt], (uint16_t)op); break;
+ case 0x0c: util::stream_format(stream, "andi %s,%s,0x%04x", reg[rt], reg[rs], (uint16_t)op); break;
+ case 0x0d: if (rs == 0)
+ util::stream_format(stream, "li %s,0x%04x", reg[rt], (uint16_t)op);
+ else
+ util::stream_format(stream, "ori %s,%s,0x%04x", reg[rt], reg[rs], (uint16_t)op);
+ break;
+ case 0x0e: util::stream_format(stream, "xori %s,%s,0x%04x", reg[rt], reg[rs], (uint16_t)op); break;
+ case 0x0f: util::stream_format(stream, "lui %s,0x%04x", reg[rt], (uint16_t)op); break;
case 0x10: flags = dasm_cop0(pc, op, stream); break;
case 0x11: flags = dasm_cop1(pc, op, stream); break;
case 0x12: flags = dasm_cop2(pc, op, stream); break;
case 0x13: flags = dasm_cop1x(pc, op, stream); break;
- case 0x14: util::stream_format(stream, "beql %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));break;
- case 0x15: util::stream_format(stream, "bnel %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));break;
- case 0x16: util::stream_format(stream, "blezl %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));break;
- case 0x17: util::stream_format(stream, "bgtzl %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));break;
+ case 0x14: if (rt == 0)
+ util::stream_format(stream, "beqzl %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "beql %s,%s,0x%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
+ if (rs != 0 || rt != 0) flags = STEP_COND | step_over_extra(1);
+ break;
+ case 0x15: if (rt == 0)
+ util::stream_format(stream, "bnezl %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2));
+ else
+ util::stream_format(stream, "bnel %s,%s,0x%08x", reg[rs], reg[rt], pc + 4 + ((int16_t)op << 2));
+ flags = STEP_COND | step_over_extra(1);
+ break;
+ case 0x16: util::stream_format(stream, "blezl %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); if (rs != 0) flags = STEP_COND | step_over_extra(1); break;
+ case 0x17: util::stream_format(stream, "bgtzl %s,0x%08x", reg[rs], pc + 4 + ((int16_t)op << 2)); flags = STEP_COND | step_over_extra(1); break;
case 0x18: util::stream_format(stream, "daddi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
case 0x19: util::stream_format(stream, "daddiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break;
case 0x1a: util::stream_format(stream, "ldl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
@@ -1022,7 +1074,7 @@ offs_t mips3_disassembler::dasm_one(std::ostream &stream, offs_t pc, u32 op)
case 0x30: util::stream_format(stream, "ll %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x31: util::stream_format(stream, "lwc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
case 0x32: util::stream_format(stream, "lwc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
- case 0x33: util::stream_format(stream, "pref $%x,%s(%s)", rt, signed_16bit(op), reg[rs]); break;
+ case 0x33: util::stream_format(stream, "pref 0x%x,%s(%s)", rt, signed_16bit(op), reg[rs]); break;
case 0x34: util::stream_format(stream, "lld %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break;
case 0x35: util::stream_format(stream, "ldc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break;
case 0x36: util::stream_format(stream, "ldc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break;
diff --git a/src/devices/cpu/mips/mips3fe.cpp b/src/devices/cpu/mips/mips3fe.cpp
index 77b72c9b48b..49b86be681b 100644
--- a/src/devices/cpu/mips/mips3fe.cpp
+++ b/src/devices/cpu/mips/mips3fe.cpp
@@ -40,7 +40,8 @@ bool mips3_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
// compute the physical PC
assert((desc.physpc & 3) == 0);
- if (!m_mips3->memory_translate(AS_PROGRAM, TRANSLATE_FETCH, desc.physpc))
+ address_space *tspace;
+ if (!m_mips3->memory_translate(AS_PROGRAM, device_memory_interface::TR_FETCH, desc.physpc, tspace))
{
// uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and
// mark as needing to validate; otherwise, just end the sequence here
@@ -155,6 +156,7 @@ bool mips3_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
case 0x22: // LWL
case 0x26: // LWR
desc.regin[0] |= REGFLAG_R(RTREG);
+ [[fallthrough]];
case 0x20: // LB
case 0x21: // LH
case 0x23: // LW
@@ -217,6 +219,7 @@ bool mips3_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
case 0x33: // PREF
if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV)
return false;
+ [[fallthrough]];
case 0x2f: // CACHE
// effective no-op
return true;
@@ -253,6 +256,7 @@ bool mips3_frontend::describe_special(uint32_t op, opcode_desc &desc)
if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV)
return false;
desc.regin[0] |= REGFLAG_R(RDREG);
+ [[fallthrough]];
case 0x04: // SLLV
case 0x06: // SRLV
case 0x07: // SRAV
@@ -596,6 +600,7 @@ bool mips3_frontend::describe_cop1(uint32_t op, opcode_desc &desc)
case 0x13: // MOVN - MIPS IV
if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV)
return false;
+ [[fallthrough]];
case 0x00: // ADD
case 0x01: // SUB
case 0x02: // MUL
@@ -608,6 +613,7 @@ bool mips3_frontend::describe_cop1(uint32_t op, opcode_desc &desc)
case 0x16: // RSQRT - MIPS IV
if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV)
return false;
+ [[fallthrough]];
case 0x04: // SQRT
case 0x05: // ABS
case 0x06: // MOV
diff --git a/src/devices/cpu/mips/o2dprintf.hxx b/src/devices/cpu/mips/o2dprintf.hxx
index 83915aed0b4..6c5f0af5ac6 100644
--- a/src/devices/cpu/mips/o2dprintf.hxx
+++ b/src/devices/cpu/mips/o2dprintf.hxx
@@ -1,6 +1,8 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
+#include "multibyte.h"
+
static char digit[] = "0123456789abcdef";
static void dprintdec(int64_t val, bool zeropad, int size)
@@ -175,32 +177,31 @@ void dprintoct(uint64_t val, bool zeropad, int pos)
#define Ioct 30
#define Loct 63
-static uint64_t dprintf_get_arg64(uint8_t *buf, uint32_t &curr)
+static uint64_t dprintf_get_arg64(const uint8_t *buf, uint32_t &curr)
{
curr = (curr + 3) & ~3;
- const uint64_t ret = ((uint64_t)buf[curr+0] << 56) | ((uint64_t)buf[curr+1] << 48) | ((uint64_t)buf[curr+2] << 40) | ((uint64_t)buf[curr+3] << 32) |
- ((uint64_t)buf[curr+4] << 24) | ((uint64_t)buf[curr+5] << 16) | ((uint64_t)buf[curr+6] << 8) | buf[curr+7];
+ const uint64_t ret = get_u64be(&buf[curr]);
curr += 8;
return ret;
}
-static uint32_t dprintf_get_arg32(uint8_t *buf, uint32_t &curr)
+static uint32_t dprintf_get_arg32(const uint8_t *buf, uint32_t &curr)
{
curr = (curr + 3) & ~3;
- const uint32_t ret = ((uint32_t)buf[curr+0] << 24) | ((uint32_t)buf[curr+1] << 16) | ((uint32_t)buf[curr+2] << 8) | buf[curr+3];
+ const uint32_t ret = get_u32be(&buf[curr]);
curr += 4;
return ret;
}
-static uint16_t dprintf_get_arg16(uint8_t *buf, uint32_t &curr)
+static uint16_t dprintf_get_arg16(const uint8_t *buf, uint32_t &curr)
{
curr = (curr + 1) & ~1;
- const uint16_t ret = ((uint16_t)buf[curr+0] << 8) | buf[curr+1];
+ const uint16_t ret = get_u16be(&buf[curr]);
curr += 2;
return ret;
}
-static uint8_t dprintf_get_arg8(uint8_t *buf, uint32_t &curr)
+static uint8_t dprintf_get_arg8(const uint8_t *buf, uint32_t &curr)
{
const uint8_t ret = buf[curr++];
return ret;
@@ -213,18 +214,9 @@ void mips3_device::do_o2_dprintf(uint32_t fmt_addr, uint32_t a1, uint32_t a2, ui
int idx = 0;
uint8_t byte_val = 0;
fmt_addr &= 0x1fffffff;
- argbuf[0] = (uint8_t)(a1 >> 24);
- argbuf[1] = (uint8_t)(a1 >> 16);
- argbuf[2] = (uint8_t)(a1 >> 8);
- argbuf[3] = (uint8_t)a1;
- argbuf[4] = (uint8_t)(a2 >> 24);
- argbuf[5] = (uint8_t)(a2 >> 16);
- argbuf[6] = (uint8_t)(a2 >> 8);
- argbuf[7] = (uint8_t)a2;
- argbuf[8] = (uint8_t)(a3 >> 24);
- argbuf[9] = (uint8_t)(a3 >> 16);
- argbuf[10] = (uint8_t)(a3 >> 8);
- argbuf[11] = (uint8_t)a3;
+ put_u32be(&argbuf[0], a1);
+ put_u32be(&argbuf[4], a2);
+ put_u32be(&argbuf[8], a3);
stack &= 0x1fffffff;
for (int i = 0; i < 4096-12; i++)
{
diff --git a/src/devices/cpu/mips/ps2vif1.cpp b/src/devices/cpu/mips/ps2vif1.cpp
index 30f7aadc0bc..43fc71a2267 100644
--- a/src/devices/cpu/mips/ps2vif1.cpp
+++ b/src/devices/cpu/mips/ps2vif1.cpp
@@ -131,7 +131,7 @@ void ps2_vif1_device::device_reset()
m_unpack_format = FMT_S32;
}
-READ32_MEMBER(ps2_vif1_device::regs_r)
+uint32_t ps2_vif1_device::regs_r(offs_t offset)
{
uint32_t ret = 0;
switch (offset)
@@ -235,12 +235,12 @@ READ32_MEMBER(ps2_vif1_device::regs_r)
return ret;
}
-WRITE32_MEMBER(ps2_vif1_device::regs_w)
+void ps2_vif1_device::regs_w(offs_t offset, uint32_t data)
{
logerror("%s: Write: Unknown %08x = %08x\n", machine().describe_context(), 0x10003c00 + (offset << 2), data);
}
-READ64_MEMBER(ps2_vif1_device::mmio_r)
+uint64_t ps2_vif1_device::mmio_r(offs_t offset)
{
uint64_t ret = 0ULL;
if (offset)
@@ -254,7 +254,7 @@ READ64_MEMBER(ps2_vif1_device::mmio_r)
return ret;
}
-WRITE64_MEMBER(ps2_vif1_device::mmio_w)
+void ps2_vif1_device::mmio_w(offs_t offset, uint64_t data)
{
if (offset)
{
@@ -349,7 +349,7 @@ void ps2_vif1_device::execute_run()
m_icount = 0;
break;
}
- // Intentional fall-through
+ [[fallthrough]];
case STAT_MODE_DECODE:
decode_vifcode();
break;
@@ -359,7 +359,7 @@ void ps2_vif1_device::execute_run()
m_icount = 0;
break;
}
- // Intentional fall-through
+ [[fallthrough]];
case STAT_MODE_DATA:
transfer_vifcode_data();
break;
diff --git a/src/devices/cpu/mips/ps2vif1.h b/src/devices/cpu/mips/ps2vif1.h
index 90ec1417ded..e054b448852 100644
--- a/src/devices/cpu/mips/ps2vif1.h
+++ b/src/devices/cpu/mips/ps2vif1.h
@@ -33,19 +33,19 @@ public:
ps2_vif1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~ps2_vif1_device() override;
- DECLARE_READ64_MEMBER(mmio_r);
- DECLARE_WRITE64_MEMBER(mmio_w);
+ uint64_t mmio_r(offs_t offset);
+ void mmio_w(offs_t offset, uint64_t data);
- DECLARE_READ32_MEMBER(regs_r);
- DECLARE_WRITE32_MEMBER(regs_w);
+ uint32_t regs_r(offs_t offset);
+ void regs_w(offs_t offset, uint32_t data);
void dma_write(const uint64_t hi, const uint64_t lo);
void tag_write(uint32_t *data);
bool fifo_available(uint32_t count) const { return (BUFFER_SIZE - m_end) >= count; }
protected:
- virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
virtual void execute_run() override;
uint32_t calculate_unpack_count();
diff --git a/src/devices/cpu/mips/ps2vu.cpp b/src/devices/cpu/mips/ps2vu.cpp
index 1587c92dd3a..8f0b125314d 100644
--- a/src/devices/cpu/mips/ps2vu.cpp
+++ b/src/devices/cpu/mips/ps2vu.cpp
@@ -14,7 +14,6 @@
#include "video/ps2gif.h"
#include "vudasm.h"
-#include "debugger.h"
DEFINE_DEVICE_TYPE(SONYPS2_VU0, sonyvu0_device, "sonyvu0", "Sony PlayStation 2 VU0")
DEFINE_DEVICE_TYPE(SONYPS2_VU1, sonyvu1_device, "sonyvu1", "Sony PlayStation 2 VU1")
@@ -78,14 +77,14 @@ ps2_vif1_device* sonyvu1_device::interface()
return m_vif.target();
}
-READ64_MEMBER(sonyvu1_device::vif_r)
+uint64_t sonyvu1_device::vif_r(offs_t offset)
{
- return m_vif->mmio_r(space, offset, mem_mask);
+ return m_vif->mmio_r(offset);
}
-WRITE64_MEMBER(sonyvu1_device::vif_w)
+void sonyvu1_device::vif_w(offs_t offset, uint64_t data)
{
- m_vif->mmio_w(space, offset, data, mem_mask);
+ m_vif->mmio_w(offset, data);
}
void sonyvu_device::device_start()
@@ -975,12 +974,12 @@ void sonyvu0_device::device_reset()
m_cmsar1 = 0;
}
-READ32_MEMBER(sonyvu0_device::vu1_reg_r)
+uint32_t sonyvu0_device::vu1_reg_r(offs_t offset)
{
return m_vu1_regs[offset];
}
-WRITE32_MEMBER(sonyvu0_device::vu1_reg_w)
+void sonyvu0_device::vu1_reg_w(offs_t offset, uint32_t data)
{
m_vu1_regs[offset] = data;
}
@@ -996,7 +995,7 @@ void sonyvu1_device::device_start()
save_item(NAME(m_p));
- state_add(SONYVU1_P, "P", *(uint32_t*)&m_p).formatstr("%17s");;
+ state_add(SONYVU1_P, "P", *(uint32_t*)&m_p).formatstr("%17s");
}
void sonyvu1_device::device_reset()
diff --git a/src/devices/cpu/mips/ps2vu.h b/src/devices/cpu/mips/ps2vu.h
index c2e99668ffd..245c623ebfa 100644
--- a/src/devices/cpu/mips/ps2vu.h
+++ b/src/devices/cpu/mips/ps2vu.h
@@ -110,13 +110,12 @@ protected:
};
// device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
// device_execute_interface overrides
- virtual uint32_t execute_min_cycles() const override { return 1; }
- virtual uint32_t execute_max_cycles() const override { return 1; }
- virtual uint32_t execute_input_lines() const override { return 0; }
+ virtual uint32_t execute_min_cycles() const noexcept override { return 1; }
+ virtual uint32_t execute_max_cycles() const noexcept override { return 1; }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override { }
@@ -188,18 +187,18 @@ public:
ps2_vif1_device* interface();
- DECLARE_READ64_MEMBER(vif_r);
- DECLARE_WRITE64_MEMBER(vif_w);
+ uint64_t vif_r(offs_t offset);
+ void vif_w(offs_t offset, uint64_t data);
protected:
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
- void micro_map(address_map &map);
- void vu_map(address_map &map);
+ void micro_map(address_map &map) ATTR_COLD;
+ void vu_map(address_map &map) ATTR_COLD;
void execute_xgkick(uint32_t rs) override;
@@ -222,16 +221,16 @@ public:
sonyvu0_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
- void micro_map(address_map &map);
- void vu_map(address_map &map);
+ void micro_map(address_map &map) ATTR_COLD;
+ void vu_map(address_map &map) ATTR_COLD;
void execute_xgkick(uint32_t rs) override;
- DECLARE_READ32_MEMBER(vu1_reg_r);
- DECLARE_WRITE32_MEMBER(vu1_reg_w);
+ uint32_t vu1_reg_r(offs_t offset);
+ void vu1_reg_w(offs_t offset, uint32_t data);
required_device<sonyvu1_device> m_vu1;
diff --git a/src/devices/cpu/mips/r4000.cpp b/src/devices/cpu/mips/r4000.cpp
index 7b26493f61c..47e2cd784a7 100644
--- a/src/devices/cpu/mips/r4000.cpp
+++ b/src/devices/cpu/mips/r4000.cpp
@@ -27,13 +27,17 @@
*/
#include "emu.h"
-#include "debugger.h"
#include "r4000.h"
+
#include "mips3dsm.h"
+#include "divtlb.h"
+#include "debug/debugcpu.h"
+
+#include "unicode.h"
+
#include "softfloat3/source/include/softfloat.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_TLB (1U << 1)
#define LOG_CACHE (1U << 2)
#define LOG_EXCEPTION (1U << 3)
@@ -41,6 +45,7 @@
#define LOG_STATS (1U << 5)
#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
// operating system specific system call logging
#define SYSCALL_IRIX53 (1U << 0)
@@ -54,11 +59,11 @@
// experimental primary instruction cache
#define ICACHE 0
-#include "logmacro.h"
+#define SCACHE !(m_cp0[CP0_Config] & CONFIG_SC)
#define USE_ABI_REG_NAMES 1
-// cpu instruction fiels
+// cpu instruction fields
#define RSREG ((op >> 21) & 31)
#define RTREG ((op >> 16) & 31)
#define RDREG ((op >> 11) & 31)
@@ -84,11 +89,20 @@
DEFINE_DEVICE_TYPE(R4000, r4000_device, "r4000", "MIPS R4000")
DEFINE_DEVICE_TYPE(R4400, r4400_device, "r4400", "MIPS R4400")
DEFINE_DEVICE_TYPE(R4600, r4600_device, "r4600", "QED R4600")
+DEFINE_DEVICE_TYPE(R5000, r5000_device, "r5000", "MIPS R5000")
+
+u32 const r5000_device::s_fcc_masks[8] = { (1U << 23), (1U << 25), (1U << 26), (1U << 27), (1U << 28), (1U << 29), (1U << 30), (1U << 31) };
+u32 const r5000_device::s_fcc_shifts[8] = { 23, 25, 26, 27, 28, 29, 30, 31 };
-r4000_base_device::r4000_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size_t icache_size, cache_size_t dcache_size)
+r4000_base_device::r4000_base_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size icache_size, cache_size dcache_size, unsigned m32, unsigned m64, unsigned d32, unsigned d64, bool timer_interrupt_disabled)
: cpu_device(mconfig, type, tag, owner, clock)
, m_program_config_le("program", ENDIANNESS_LITTLE, 64, 32)
, m_program_config_be("program", ENDIANNESS_BIG, 64, 32)
+ , m_hilo_cycles{ m32, m64, d32, d64 }
+ , m_r{}
+ , m_cp0{}
+ , m_timer_interrupt_disabled(timer_interrupt_disabled)
+ , m_f{}
, m_fcr0(fcr)
{
m_cp0[CP0_PRId] = prid;
@@ -175,7 +189,9 @@ void r4000_base_device::device_start()
set_icountptr(m_icount);
- m_cp0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(r4000_base_device::cp0_timer_callback), this));
+ m_hard_reset = true;
+
+ m_cp0_timer = timer_alloc(FUNC(r4000_base_device::cp0_timer_callback), this);
// compute icache line selection mask and allocate tag and data
unsigned const config_ic = (m_cp0[CP0_Config] & CONFIG_IC) >> 9;
@@ -183,32 +199,49 @@ void r4000_base_device::device_start()
m_icache_mask_hi = (0x1000U << config_ic) - 1;
m_icache_tag = std::make_unique<u32[]>(0x100U << config_ic);
m_icache_data = std::make_unique<u32 []>((0x1000U << config_ic) >> 2);
+
+ R4000_ENDIAN_LE_BE(accessors(m_le), accessors(m_be));
+
+ if (SCACHE)
+ save_pointer(NAME(m_scache_tag), m_scache_tag_size);
}
void r4000_base_device::device_reset()
{
+ if (!m_hard_reset)
+ {
+ m_cp0[CP0_Status] = SR_BEV | SR_ERL | SR_SR;
+ m_cp0[CP0_ErrorEPC] = m_pc;
+ }
+ else
+ m_cp0[CP0_Status] = SR_BEV | SR_ERL;
+
+ m_hilo_delay = 0;
m_branch_state = NONE;
m_pc = s64(s32(0xbfc00000));
+ m_r[0] = 0;
- m_cp0[CP0_Status] = SR_BEV | SR_ERL;
m_cp0[CP0_Wired] = 0;
m_cp0[CP0_Compare] = 0;
m_cp0[CP0_Count] = 0;
m_cp0_timer_zero = total_cycles();
+ m_hard_reset = false;
m_ll_active = false;
m_bus_error = false;
+ m_cp0[CP0_Cause] = 0;
+
m_cp0[CP0_WatchLo] = 0;
m_cp0[CP0_WatchHi] = 0;
// initialize tlb mru index with identity mapping
- for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++)
+ for (unsigned i = 0; i < std::size(m_tlb); i++)
{
- m_tlb_mru[TRANSLATE_READ][i] = i;
- m_tlb_mru[TRANSLATE_WRITE][i] = i;
- m_tlb_mru[TRANSLATE_FETCH][i] = i;
+ m_tlb_mru[TR_READ][i] = i;
+ m_tlb_mru[TR_WRITE][i] = i;
+ m_tlb_mru[TR_FETCH][i] = i;
}
// initialize statistics
@@ -235,12 +268,13 @@ device_memory_interface::space_config_vector r4000_base_device::memory_space_con
};
}
-bool r4000_base_device::memory_translate(int spacenum, int intention, offs_t &address)
+bool r4000_base_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
{
+ target_space = &space(spacenum);
// FIXME: address truncation
u64 placeholder = s32(address);
- translate_t const t = translate(intention, placeholder);
+ translate_result const t = translate(intention, true, placeholder);
if (t == ERROR || t == MISS)
return false;
@@ -256,7 +290,7 @@ std::unique_ptr<util::disasm_interface> r4000_base_device::create_disassembler()
void r4000_base_device::execute_run()
{
- while (m_icount-- > 0)
+ while (m_icount > 0)
{
debugger_instruction_hook(m_pc);
@@ -274,31 +308,32 @@ void r4000_base_device::execute_run()
});
// update pc and branch state
- switch (m_branch_state)
+ switch (m_branch_state & STATE)
{
case NONE:
m_pc += 4;
break;
- case DELAY:
+ case BRANCH:
+ m_pc = m_branch_state & TARGET;
m_branch_state = NONE;
- m_pc = m_branch_target;
break;
- case BRANCH:
- m_branch_state = DELAY;
+ case DELAY:
m_pc += 4;
- break;
-
- case EXCEPTION:
- m_branch_state = NONE;
+ m_branch_state = (m_branch_state & TARGET) | BRANCH;
break;
case NULLIFY:
- m_branch_state = NONE;
m_pc += 8;
+ m_branch_state = NONE;
break;
}
+
+ if (m_hilo_delay)
+ m_hilo_delay--;
+
+ m_icount--;
}
}
@@ -338,12 +373,12 @@ void r4000_base_device::cpu_execute(u32 const op)
m_r[RDREG] = s64(s32(m_r[RTREG]) >> (m_r[RSREG] & 31));
break;
case 0x08: // JR
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_r[RSREG], 0);
+ // FIXME: address error if low bits are set
+ m_branch_state = ADDR(m_r[RSREG], 0) | DELAY;
break;
case 0x09: // JALR
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_r[RSREG], 0);
+ // FIXME: address error if low bits are set
+ m_branch_state = ADDR(m_r[RSREG], 0) | DELAY;
m_r[RDREG] = ADDR(m_pc, 8);
break;
//case 0x0a: // *
@@ -407,12 +442,22 @@ void r4000_base_device::cpu_execute(u32 const op)
break;
case 0x10: // MFHI
m_r[RDREG] = m_hi;
+ if (m_hilo_delay)
+ {
+ m_icount -= m_hilo_delay;
+ m_hilo_delay = 0;
+ }
break;
case 0x11: // MTHI
m_hi = m_r[RSREG];
break;
case 0x12: // MFLO
m_r[RDREG] = m_lo;
+ if (m_hilo_delay)
+ {
+ m_icount -= m_hilo_delay;
+ m_hilo_delay = 0;
+ }
break;
case 0x13: // MTLO
m_lo = m_r[RSREG];
@@ -433,6 +478,7 @@ void r4000_base_device::cpu_execute(u32 const op)
m_lo = s64(s32(product));
m_hi = s64(s32(product >> 32));
+ m_hilo_delay = m_hilo_cycles[0];
}
break;
case 0x19: // MULTU
@@ -441,6 +487,7 @@ void r4000_base_device::cpu_execute(u32 const op)
m_lo = s64(s32(product));
m_hi = s64(s32(product >> 32));
+ m_hilo_delay = m_hilo_cycles[0];
}
break;
case 0x1a: // DIV
@@ -448,6 +495,7 @@ void r4000_base_device::cpu_execute(u32 const op)
{
m_lo = s64(s32(m_r[RSREG]) / s32(m_r[RTREG]));
m_hi = s64(s32(m_r[RSREG]) % s32(m_r[RTREG]));
+ m_hilo_delay = m_hilo_cycles[2];
}
break;
case 0x1b: // DIVU
@@ -455,19 +503,23 @@ void r4000_base_device::cpu_execute(u32 const op)
{
m_lo = s64(s32(u32(m_r[RSREG]) / u32(m_r[RTREG])));
m_hi = s64(s32(u32(m_r[RSREG]) % u32(m_r[RTREG])));
+ m_hilo_delay = m_hilo_cycles[2];
}
break;
case 0x1c: // DMULT
- m_lo = mul_64x64(m_r[RSREG], m_r[RTREG], reinterpret_cast<s64 *>(&m_hi));
+ m_lo = mul_64x64(m_r[RSREG], m_r[RTREG], *reinterpret_cast<s64 *>(&m_hi));
+ m_hilo_delay = m_hilo_cycles[1];
break;
case 0x1d: // DMULTU
- m_lo = mulu_64x64(m_r[RSREG], m_r[RTREG], &m_hi);
+ m_lo = mulu_64x64(m_r[RSREG], m_r[RTREG], m_hi);
+ m_hilo_delay = m_hilo_cycles[1];
break;
case 0x1e: // DDIV
if (m_r[RTREG])
{
m_lo = s64(m_r[RSREG]) / s64(m_r[RTREG]);
m_hi = s64(m_r[RSREG]) % s64(m_r[RTREG]);
+ m_hilo_delay = m_hilo_cycles[3];
}
break;
case 0x1f: // DDIVU
@@ -475,6 +527,7 @@ void r4000_base_device::cpu_execute(u32 const op)
{
m_lo = m_r[RSREG] / m_r[RTREG];
m_hi = m_r[RSREG] % m_r[RTREG];
+ m_hilo_delay = m_hilo_cycles[3];
}
break;
case 0x20: // ADD
@@ -601,10 +654,7 @@ void r4000_base_device::cpu_execute(u32 const op)
break;
default:
- // * Operation codes marked with an asterisk cause reserved
- // instruction exceptions in all current implementations and are
- // reserved for future versions of the architecture.
- cpu_exception(EXCEPTION_RI);
+ handle_reserved_instruction(op);
break;
}
break;
@@ -613,33 +663,21 @@ void r4000_base_device::cpu_execute(u32 const op)
{
case 0x00: // BLTZ
if (s64(m_r[RSREG]) < 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x01: // BGEZ
if (s64(m_r[RSREG]) >= 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x02: // BLTZL
if (s64(m_r[RSREG]) < 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
case 0x03: // BGEZL
if (s64(m_r[RSREG]) >= 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
@@ -675,36 +713,24 @@ void r4000_base_device::cpu_execute(u32 const op)
//case 0x0f: // *
case 0x10: // BLTZAL
if (s64(m_r[RSREG]) < 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_r[31] = ADDR(m_pc, 8);
break;
case 0x11: // BGEZAL
if (s64(m_r[RSREG]) >= 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_r[31] = ADDR(m_pc, 8);
break;
case 0x12: // BLTZALL
if (s64(m_r[RSREG]) < 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
m_r[31] = ADDR(m_pc, 8);
break;
case 0x13: // BGEZALL
if (s64(m_r[RSREG]) >= 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
m_r[31] = ADDR(m_pc, 8);
@@ -726,46 +752,32 @@ void r4000_base_device::cpu_execute(u32 const op)
// * Operation codes marked with an asterisk cause reserved
// instruction exceptions in all current implementations and are
// reserved for future versions of the architecture.
- cpu_exception(EXCEPTION_RI);
+ handle_reserved_instruction(op);
break;
}
break;
case 0x02: // J
- m_branch_state = BRANCH;
- m_branch_target = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2);
+ m_branch_state = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2) | DELAY;
break;
case 0x03: // JAL
- m_branch_state = BRANCH;
- m_branch_target = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2);
+ m_branch_state = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2) | DELAY;
m_r[31] = ADDR(m_pc, 8);
break;
case 0x04: // BEQ
if (m_r[RSREG] == m_r[RTREG])
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x05: // BNE
if (m_r[RSREG] != m_r[RTREG])
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x06: // BLEZ
if (s64(m_r[RSREG]) <= 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x07: // BGTZ
if (s64(m_r[RSREG]) > 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x08: // ADDI
{
@@ -808,40 +820,30 @@ void r4000_base_device::cpu_execute(u32 const op)
case 0x12: // COP2
cp2_execute(op);
break;
- //case 0x13: // *
+ case 0x13: // COP1X
+ cp1x_execute(op);
+ break;
case 0x14: // BEQL
if (m_r[RSREG] == m_r[RTREG])
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
case 0x15: // BNEL
if (m_r[RSREG] != m_r[RTREG])
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
case 0x16: // BLEZL
if (s64(m_r[RSREG]) <= 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
case 0x17: // BGTZL
if (s64(m_r[RSREG]) > 0)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
@@ -951,75 +953,7 @@ void r4000_base_device::cpu_execute(u32 const op)
cpu_swr(op);
break;
case 0x2f: // CACHE
- if ((SR & SR_KSU) && !(SR & SR_CU0) && !(SR & (SR_EXL | SR_ERL)))
- {
- cpu_exception(EXCEPTION_CP0);
- break;
- }
-
- switch ((op >> 16) & 0x1f)
- {
- case 0x00: // index invalidate (I)
- if (ICACHE)
- {
- m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] &= ~ICACHE_V;
- break;
- }
-
- case 0x04: // index load tag (I)
- if (ICACHE)
- {
- u32 const tag = m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift];
-
- m_cp0[CP0_TagLo] = ((tag & ICACHE_PTAG) << 8) | ((tag & ICACHE_V) >> 18) | ((tag & ICACHE_P) >> 25);
- m_cp0[CP0_ECC] = 0; // data ecc or parity
-
- break;
- }
-
- case 0x08: // index store tag (I)
- if (ICACHE)
- {
- // FIXME: compute parity
- m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] =
- (m_cp0[CP0_TagLo] & TAGLO_PTAGLO) >> 8 | (m_cp0[CP0_TagLo] & TAGLO_PSTATE) << 18;
-
- break;
- }
-
- case 0x01: // index writeback invalidate (D)
- case 0x02: // index invalidate (SI)
- case 0x03: // index writeback invalidate (SD)
-
- case 0x05: // index load tag (D)
- case 0x06: // index load tag (SI)
- case 0x07: // index load tag (SI)
-
- case 0x09: // index store tag (D)
- case 0x0a: // index store tag (SI)
- case 0x0b: // index store tag (SD)
-
- case 0x0d: // create dirty exclusive (D)
- case 0x0f: // create dirty exclusive (SD)
-
- case 0x10: // hit invalidate (I)
- case 0x11: // hit invalidate (D)
- case 0x12: // hit invalidate (SI)
- case 0x13: // hit invalidate (SD)
-
- case 0x14: // fill (I)
- case 0x15: // hit writeback invalidate (D)
- case 0x17: // hit writeback invalidate (SD)
-
- case 0x18: // hit writeback (I)
- case 0x19: // hit writeback (D)
- case 0x1b: // hit writeback (SD)
-
- case 0x1e: // hit set virtual (SI)
- case 0x1f: // hit set virtual (SD)
- //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
- break;
- }
+ cp0_cache(op);
break;
case 0x30: // LL
load_linked<u32>(ADDR(m_r[RSREG], s16(op)),
@@ -1036,7 +970,6 @@ void r4000_base_device::cpu_execute(u32 const op)
case 0x32: // LWC2
cp2_execute(op);
break;
- //case 0x33: // *
case 0x34: // LLD
load_linked<u64>(ADDR(m_r[RSREG], s16(op)),
[this, op](u64 address, u64 data)
@@ -1106,11 +1039,50 @@ void r4000_base_device::cpu_execute(u32 const op)
// * Operation codes marked with an asterisk cause reserved instruction
// exceptions in all current implementations and are reserved for future
// versions of the architecture.
- cpu_exception(EXCEPTION_RI);
+ handle_reserved_instruction(op);
break;
}
}
+void r4000_base_device::handle_reserved_instruction(u32 const op)
+{
+ // Unhandled operation codes cause reserved instruction
+ // exceptions in all current implementations and are
+ // reserved for future versions of the architecture.
+ cpu_exception(EXCEPTION_RI);
+}
+
+void r5000_device::handle_reserved_instruction(u32 const op)
+{
+ switch (op >> 26)
+ {
+ case 0x00: // SPECIAL
+ switch (op & 0x3f)
+ {
+ case 0x01: // MOVT / MOVF
+ if (((m_fcr31 >> s_fcc_shifts[(op >> 18) & 7]) & 1) == ((op >> 16) & 1))
+ {
+ if (RDREG)
+ {
+ m_r[RDREG] = m_r[RSREG];
+ }
+ }
+ return;
+ case 0x0a: // MOVZ
+ if (m_r[RTREG] == 0) { if (RDREG) m_r[RDREG] = m_r[RSREG]; }
+ return;
+ case 0x0b: // MOVN
+ if (m_r[RTREG] != 0) { if (RDREG) m_r[RDREG] = m_r[RSREG]; }
+ return;
+ }
+ break;
+ case 0x33: // PREF (effective no-op)
+ return;
+ }
+
+ r4000_base_device::handle_reserved_instruction(op);
+}
+
void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
{
if (exception != EXCEPTION_INT)
@@ -1122,8 +1094,8 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
CAUSE = (CAUSE & CAUSE_IP) | exception;
- // if in a branch delay slot, restart at the branch instruction
- if (m_branch_state == DELAY)
+ // if executing a delay slot instruction, restart from the branch
+ if ((m_branch_state & STATE) == BRANCH)
{
m_cp0[CP0_EPC] -= 4;
CAUSE |= CAUSE_BD;
@@ -1134,10 +1106,20 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
else
CAUSE = (CAUSE & (CAUSE_BD | CAUSE_IP)) | exception;
- m_branch_state = EXCEPTION;
- m_pc = ((SR & SR_BEV) ? s64(s32(0xbfc00200)) : s64(s32(0x80000000))) + vector;
+ m_branch_state = (((SR & SR_BEV) ? s64(s32(0xbfc00200)) : s64(s32(0x80000000))) + vector) | BRANCH;
- if (exception != EXCEPTION_INT)
+ if (exception == EXCEPTION_INT)
+ {
+ if (debugger_enabled())
+ {
+ // notify the debugger of the first pending hardware interrupt
+ u32 const iphw = CAUSE & SR & CAUSE_IPHW;
+
+ if (iphw)
+ debug()->interrupt_hook(22 - count_leading_zeros_32((iphw - 1) & ~iphw), m_pc);
+ }
+ }
+ else
debugger_exception_hook(exception);
}
@@ -1146,7 +1128,7 @@ void r4000_base_device::cpu_lwl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 3) ^ R4000_ENDIAN_LE_BE(3, 0)) << 3;
- load<u32>(offset & ~3,
+ load<u32, false>(offset,
[this, op, shift](u32 const data)
{
m_r[RTREG] = s32((m_r[RTREG] & ~u32(~u32(0) << shift)) | (data << shift));
@@ -1158,7 +1140,7 @@ void r4000_base_device::cpu_lwr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 0x3) ^ R4000_ENDIAN_LE_BE(0, 3)) << 3;
- load<u32>(offset & ~3,
+ load<u32, false>(offset,
[this, op, shift](u32 const data)
{
m_r[RTREG] = s32((m_r[RTREG] & ~u32(~u32(0) >> shift)) | (data >> shift));
@@ -1170,7 +1152,7 @@ void r4000_base_device::cpu_swl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 3) ^ R4000_ENDIAN_LE_BE(3, 0)) << 3;
- store<u32>(offset & ~3, u32(m_r[RTREG]) >> shift, ~u32(0) >> shift);
+ store<u32, false>(offset, u32(m_r[RTREG]) >> shift, ~u32(0) >> shift);
}
void r4000_base_device::cpu_swr(u32 const op)
@@ -1178,7 +1160,7 @@ void r4000_base_device::cpu_swr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 3) ^ R4000_ENDIAN_LE_BE(0, 3)) << 3;
- store<u32>(offset & ~3, u32(m_r[RTREG]) << shift, ~u32(0) << shift);
+ store<u32, false>(offset, u32(m_r[RTREG]) << shift, ~u32(0) << shift);
}
void r4000_base_device::cpu_ldl(u32 const op)
@@ -1186,7 +1168,7 @@ void r4000_base_device::cpu_ldl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(7, 0)) << 3;
- load<u64>(offset & ~7,
+ load<u64, false>(offset,
[this, op, shift](u64 const data)
{
m_r[RTREG] = (m_r[RTREG] & ~u64(~u64(0) << shift)) | (data << shift);
@@ -1198,7 +1180,7 @@ void r4000_base_device::cpu_ldr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(0, 7)) << 3;
- load<u64>(offset & ~7,
+ load<u64, false>(offset,
[this, op, shift](u64 const data)
{
m_r[RTREG] = (m_r[RTREG] & ~u64(~u64(0) >> shift)) | (data >> shift);
@@ -1210,7 +1192,7 @@ void r4000_base_device::cpu_sdl(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(7, 0)) << 3;
- store<u64>(offset & ~7, m_r[RTREG] >> shift, ~u64(0) >> shift);
+ store<u64, false>(offset, m_r[RTREG] >> shift, ~u64(0) >> shift);
}
void r4000_base_device::cpu_sdr(u32 const op)
@@ -1218,7 +1200,129 @@ void r4000_base_device::cpu_sdr(u32 const op)
u64 const offset = ADDR(m_r[RSREG], s16(op));
unsigned const shift = ((offset & 7) ^ R4000_ENDIAN_LE_BE(0, 7)) << 3;
- store<u64>(offset & ~7, m_r[RTREG] << shift, ~u64(0) << shift);
+ store<u64, false>(offset, m_r[RTREG] << shift, ~u64(0) << shift);
+}
+
+void r4000_base_device::cp0_cache(u32 const op)
+{
+ if ((SR & SR_KSU) && !(SR & SR_CU0) && !(SR & (SR_EXL | SR_ERL)))
+ {
+ cpu_exception(EXCEPTION_CP0);
+ return;
+ }
+
+ switch ((op >> 16) & 0x1f)
+ {
+ case 0x00: // index invalidate (I)
+ if (ICACHE)
+ {
+ m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] &= ~ICACHE_V;
+ break;
+ }
+ [[fallthrough]];
+ case 0x04: // index load tag (I)
+ if (ICACHE)
+ {
+ u32 const tag = m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift];
+
+ m_cp0[CP0_TagLo] = ((tag & ICACHE_PTAG) << 8) | ((tag & ICACHE_V) >> 18) | ((tag & ICACHE_P) >> 25);
+ m_cp0[CP0_ECC] = 0; // data ecc or parity
+
+ break;
+ }
+ [[fallthrough]];
+ case 0x08: // index store tag (I)
+ if (ICACHE)
+ {
+ // FIXME: compute parity
+ m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] =
+ (m_cp0[CP0_TagLo] & TAGLO_PTAGLO) >> 8 | (m_cp0[CP0_TagLo] & TAGLO_PSTATE) << 18;
+ break;
+ }
+ [[fallthrough]];
+ case 0x01: // index writeback invalidate (D)
+ case 0x02: // index invalidate (SI)
+ case 0x03: // index writeback invalidate (SD)
+ case 0x05: // index load tag (D)
+ //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
+ break;
+ case 0x06: // index load tag (SI)
+ case 0x07: // index load tag (SD)
+ if (SCACHE)
+ {
+ // TODO: translation type for CACHE instruction? Read seems reasonable since only the tag is changing here
+ u64 physical_address = ADDR(m_r[RSREG], s16(op));
+ translate_result const t = translate(TR_READ, false, physical_address);
+ if (t == ERROR || t == MISS)
+ return;
+
+ u32 const index = (physical_address & m_scache_tag_mask) >> m_scache_line_index;
+ if (index < m_scache_tag_size)
+ {
+ // TODO: Load the ECC register here
+ u32 const tag = m_scache_tag[index];
+ u32 const cs = (tag & SCACHE_CS) >> 22;
+ u32 const stag = tag & SCACHE_STAG;
+ u32 const pidx = (tag & SCACHE_PIDX) >> 19;
+ m_cp0[CP0_TagLo] = (stag << 13) | (cs << 10) | (pidx << 7);
+ }
+ else
+ fatalerror("r4000 scache load tag index out of range!");
+ }
+ else
+ LOGMASKED(LOG_CACHE, "cache 0x%08x called without scache enabled (%s)\n", op, machine().describe_context());
+ break;
+ case 0x09: // index store tag (D)
+ //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
+ break;
+ case 0x0a: // index store tag (SI)
+ case 0x0b: // index store tag (SD)
+ if (SCACHE)
+ {
+ // TODO: translation type for CACHE instruction? Read seems reasonable since only the tag is changing here
+ u64 const virtual_address = ADDR(m_r[RSREG], s16(op));
+ u64 physical_address = virtual_address;
+ translate_result const t = translate(TR_READ, false, physical_address);
+ if (t == ERROR || t == MISS)
+ return;
+
+ u64 const index = (physical_address & m_scache_tag_mask) >> m_scache_line_index;
+ if (index < m_scache_tag_size)
+ {
+ // TODO: Calculate ECC bits here
+ u64 const tag_lo = m_cp0[CP0_TagLo];
+ u32 const cs = (tag_lo & TAGLO_CS) >> 10;
+ u32 const stag = (tag_lo & TAGLO_STAG) >> 13;
+ u32 const pidx = (virtual_address & 0x7000) >> 12;
+ m_scache_tag[index] = cs << 22 | pidx << 19 | stag;
+ }
+ else
+ fatalerror("r4000 scache store tag index out of range!");
+ }
+ else
+ LOGMASKED(LOG_CACHE, "cache 0x%08x called without scache enabled (%s)\n", op, machine().describe_context());
+ break;
+ case 0x0d: // create dirty exclusive (D)
+ case 0x0f: // create dirty exclusive (SD)
+
+ case 0x10: // hit invalidate (I)
+ case 0x11: // hit invalidate (D)
+ case 0x12: // hit invalidate (SI)
+ case 0x13: // hit invalidate (SD)
+
+ case 0x14: // fill (I)
+ case 0x15: // hit writeback invalidate (D)
+ case 0x17: // hit writeback invalidate (SD)
+
+ case 0x18: // hit writeback (I)
+ case 0x19: // hit writeback (D)
+ case 0x1b: // hit writeback (SD)
+
+ case 0x1e: // hit set virtual (SI)
+ case 0x1f: // hit set virtual (SD)
+ //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
+ break;
+ }
}
void r4000_base_device::cp0_execute(u32 const op)
@@ -1312,14 +1416,12 @@ void r4000_base_device::cp0_execute(u32 const op)
case 0x18: // ERET
if (SR & SR_ERL)
{
- m_branch_state = EXCEPTION;
- m_pc = m_cp0[CP0_ErrorEPC];
+ m_branch_state = m_cp0[CP0_ErrorEPC] | BRANCH;
SR &= ~SR_ERL;
}
else
{
- m_branch_state = EXCEPTION;
- m_pc = m_cp0[CP0_EPC];
+ m_branch_state = m_cp0[CP0_EPC] | BRANCH;
SR &= ~SR_EXL;
}
@@ -1353,10 +1455,10 @@ u64 r4000_base_device::cp0_get(unsigned const reg)
{
u8 const wired = m_cp0[CP0_Wired] & 0x3f;
- if (wired < ARRAY_LENGTH(m_tlb))
- return ((total_cycles() - m_cp0_timer_zero) % (ARRAY_LENGTH(m_tlb) - wired) + wired) & 0x3f;
+ if (wired < std::size(m_tlb))
+ return ((total_cycles() - m_cp0_timer_zero) % (std::size(m_tlb) - wired) + wired) & 0x3f;
else
- return ARRAY_LENGTH(m_tlb) - 1;
+ return std::size(m_tlb) - 1;
}
break;
@@ -1398,7 +1500,8 @@ void r4000_base_device::cp0_set(unsigned const reg, u64 const data)
break;
case CP0_Compare:
m_cp0[CP0_Compare] = u32(data);
- CAUSE &= ~CAUSE_IPEX5;
+ if (!m_timer_interrupt_disabled)
+ CAUSE &= ~CAUSE_IPEX5;
cp0_update_timer(true);
break;
@@ -1467,22 +1570,23 @@ void r4000_base_device::cp0_tlbr()
{
u8 const index = m_cp0[CP0_Index] & 0x3f;
- if (index < ARRAY_LENGTH(m_tlb))
+ if (index < std::size(m_tlb))
{
- tlb_entry_t const &entry = m_tlb[index];
+ tlb_entry const &entry = m_tlb[index];
m_cp0[CP0_PageMask] = entry.mask;
m_cp0[CP0_EntryHi] = entry.vpn;
- m_cp0[CP0_EntryLo0] = entry.pfn[0];
- m_cp0[CP0_EntryLo1] = entry.pfn[1];
+ u64 const global = (entry.vpn & EH_G) ? EL_G : 0x0;
+ m_cp0[CP0_EntryLo0] = entry.pfn[0] | global;
+ m_cp0[CP0_EntryLo1] = entry.pfn[1] | global;
}
}
void r4000_base_device::cp0_tlbwi(u8 const index)
{
- if (index < ARRAY_LENGTH(m_tlb))
+ if (index < std::size(m_tlb))
{
- tlb_entry_t &entry = m_tlb[index];
+ tlb_entry &entry = m_tlb[index];
entry.mask = m_cp0[CP0_PageMask];
entry.vpn = m_cp0[CP0_EntryHi] & EH_WM;
@@ -1491,7 +1595,7 @@ void r4000_base_device::cp0_tlbwi(u8 const index)
entry.pfn[0] = m_cp0[CP0_EntryLo0] & EL_WM;
entry.pfn[1] = m_cp0[CP0_EntryLo1] & EL_WM;
- entry.low_bit = 32 - count_leading_zeros((entry.mask >> 1) | 0xfff);
+ entry.low_bit = 32 - count_leading_zeros_32((entry.mask >> 1) | 0xfff);
LOGMASKED(LOG_TLB, "tlb write index %02d mask 0x%016x vpn2 0x%016x %c asid 0x%02x pfn0 0x%016x %c%c pfn1 0x%016x %c%c (%s)\n",
index, entry.mask,
@@ -1505,9 +1609,9 @@ void r4000_base_device::cp0_tlbwi(u8 const index)
void r4000_base_device::cp0_tlbwr()
{
u8 const wired = m_cp0[CP0_Wired] & 0x3f;
- u8 const unwired = ARRAY_LENGTH(m_tlb) - wired;
+ u8 const unwired = std::size(m_tlb) - wired;
- u8 const index = (unwired > 0) ? ((total_cycles() - m_cp0_timer_zero) % unwired + wired) & 0x3f : (ARRAY_LENGTH(m_tlb) - 1);
+ u8 const index = (unwired > 0) ? ((total_cycles() - m_cp0_timer_zero) % unwired + wired) & 0x3f : (std::size(m_tlb) - 1);
cp0_tlbwi(index);
}
@@ -1515,9 +1619,9 @@ void r4000_base_device::cp0_tlbwr()
void r4000_base_device::cp0_tlbp()
{
m_cp0[CP0_Index] = 0x80000000;
- for (u8 index = 0; index < ARRAY_LENGTH(m_tlb); index++)
+ for (u8 index = 0; index < std::size(m_tlb); index++)
{
- tlb_entry_t const &entry = m_tlb[index];
+ tlb_entry const &entry = m_tlb[index];
u64 const mask = (cp0_64() ? EH_R | (EH_VPN2_64 & ~entry.mask) : (EH_VPN2_32 & ~entry.mask))
| ((entry.vpn & EH_G) ? 0 : EH_ASID);
@@ -1530,13 +1634,16 @@ void r4000_base_device::cp0_tlbp()
}
if (m_cp0[CP0_Index] == 0x80000000)
- LOGMASKED(LOG_TLB, "tlbp miss 0x%08x\n", m_cp0[CP0_EntryHi]);
+ LOGMASKED(LOG_TLB, "tlbp miss 0x%08x (%s)\n", m_cp0[CP0_EntryHi], machine().describe_context());
else
- LOGMASKED(LOG_TLB, "tlbp hit 0x%08x index %02d\n", m_cp0[CP0_EntryHi], m_cp0[CP0_Index]);
+ LOGMASKED(LOG_TLB, "tlbp hit 0x%08x index %02d (%s)\n", m_cp0[CP0_EntryHi], m_cp0[CP0_Index], machine().describe_context());
}
void r4000_base_device::cp0_update_timer(bool start)
{
+ if (m_timer_interrupt_disabled)
+ return;
+
if (start || m_cp0_timer->enabled())
{
u32 const count = (total_cycles() - m_cp0_timer_zero) / 2;
@@ -1596,6 +1703,486 @@ template <> bool r4000_base_device::cp1_op<float64_t>(float64_t op)
return true;
}
+void r5000_device::cp1_execute(u32 const op)
+{
+ if (!(SR & SR_CU1))
+ {
+ cpu_exception(EXCEPTION_CP1);
+ return;
+ }
+
+ softfloat_exceptionFlags = 0;
+ switch (op >> 26)
+ {
+ case 0x11: // COP1
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x10: // S
+ {
+ switch (op & 0x3f)
+ {
+ case 0x11: // MOVF.S / MOVT.S
+ if (((m_fcr31 >> s_fcc_shifts[(op >> 18) & 7]) & 1) == ((op >> 16) & 1))
+ cp1_mov_s(op);
+ return;
+ case 0x12: // MOVZ.S
+ if (m_r[RTREG] == 0)
+ cp1_mov_s(op);
+ return;
+ case 0x13: // MOVN.S
+ if (m_r[RTREG] != 0)
+ cp1_mov_s(op);
+ return;
+ case 0x15: // RECIP.S
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float32_t const fs = float32_t{ u32(m_f[FSREG]) };
+
+ if (cp1_op(fs))
+ {
+ cp1_set(FDREG, f32_div(i32_to_f32(1), fs).v);
+ }
+ }
+ return;
+ case 0x16: // RSQRT.S
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float32_t const fs = float32_t{ u32(m_f[FSREG]) };
+
+ if (cp1_op(fs))
+ {
+ cp1_set(FDREG, f32_div(i32_to_f32(1), f32_sqrt(fs)).v);
+ }
+ }
+ return;
+ case 0x30: // C.F.S (false)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ return;
+ case 0x31: // C.UN.S (unordered)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ // detect unordered
+ f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) });
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x32: // C.EQ.S (equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x33: // C.UEQ.S (unordered equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x34: // C.OLT.S (less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_lt(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x35: // C.ULT.S (unordered less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_lt(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x36: // C.OLE.S (less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_le(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x37: // C.ULE.S (unordered less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_le(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+
+ case 0x38: // C.SF.S (signalling false)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ // detect unordered
+ f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) });
+
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x39: // C.NGLE.S (not greater, less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ // detect unordered
+ f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) });
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7] | FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x3a: // C.SEQ.S (signalling equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3b: // C.NGL.S (not greater or less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_eq(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3c: // C.LT.S (less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_lt(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3d: // C.NGE.S (not greater or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_lt(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3e: // C.LE.S (less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_le(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3f: // C.NGT.S (not greater than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f32_le(float32_t{ u32(m_f[FSREG]) }, float32_t{ u32(m_f[FTREG]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ }
+ }
+ [[fallthrough]];
+ case 0x11: // D
+ switch (op & 0x3f)
+ {
+ case 0x11: // MOVF.D / MOVT.D
+ if (((m_fcr31 >> s_fcc_shifts[(op >> 18) & 7]) & 1) == ((op >> 16) & 1))
+ cp1_mov_d(op);
+ return;
+ case 0x12: // MOVZ.D
+ if (m_r[RTREG] == 0)
+ cp1_mov_d(op);
+ return;
+ case 0x13: // MOVN.D
+ if (m_r[RTREG] != 0)
+ cp1_mov_d(op);
+ return;
+ case 0x15: // RECIP.D
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float64_t const fs = float64_t{ m_f[FSREG] };
+
+ if (cp1_op(fs))
+ {
+ cp1_set(FDREG, f64_div(i32_to_f64(1), fs).v);
+ }
+ }
+ return;
+ case 0x16: // RSQRT.D
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float64_t const fs = float64_t{ m_f[FSREG] };
+
+ if (cp1_op(fs))
+ {
+ cp1_set(FDREG, f64_div(i32_to_f64(1), f64_sqrt(fs)).v);
+ }
+ }
+ return;
+ case 0x30: // C.F.D (false)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ return;
+ case 0x31: // C.UN.D (unordered)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ // detect unordered
+ f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] });
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x32: // C.EQ.D (equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x33: // C.UEQ.D (unordered equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x34: // C.OLT.D (less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_lt(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x35: // C.ULT.D (unordered less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_lt(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x36: // C.OLE.D (less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_le(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x37: // C.ULE.D (unordered less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_le(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+
+ case 0x38: // C.SF.D (signalling false)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ // detect unordered
+ f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] });
+
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x39: // C.NGLE.D (not greater, less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ // detect unordered
+ f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] });
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7] | FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+ }
+ return;
+ case 0x3a: // C.SEQ.D (signalling equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3b: // C.NGL.D (not greater or less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_eq(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3c: // C.LT.D (less than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_lt(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3d: // C.NGE.D (not greater or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_lt(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3e: // C.LE.D (less than or equal)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_le(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ case 0x3f: // C.NGT.D (not greater than)
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ if (f64_le(float64_t{ m_f[FSREG] }, float64_t{ m_f[FTREG] }) || (softfloat_exceptionFlags & softfloat_flag_invalid))
+ m_fcr31 |= s_fcc_masks[(op >> 18) & 7];
+ else
+ m_fcr31 &= ~s_fcc_masks[(op >> 18) & 7];
+
+ if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
+ m_fcr31 |= FCR31_CV;
+ cpu_exception(EXCEPTION_FPE);
+ }
+ }
+ return;
+ }
+ return;
+ }
+ }
+
+ r4000_base_device::cp1_execute(op);
+}
+
void r4000_base_device::cp1_execute(u32 const op)
{
if (!(SR & SR_CU1))
@@ -1692,33 +2279,21 @@ void r4000_base_device::cp1_execute(u32 const op)
{
case 0x00: // BC1F
if (!(m_fcr31 & FCR31_C))
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x01: // BC1T
if (m_fcr31 & FCR31_C)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
break;
case 0x02: // BC1FL
if (!(m_fcr31 & FCR31_C))
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
case 0x03: // BC1TL
if (m_fcr31 & FCR31_C)
- {
- m_branch_state = BRANCH;
- m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
- }
+ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
else
m_branch_state = NULLIFY;
break;
@@ -1797,23 +2372,7 @@ void r4000_base_device::cp1_execute(u32 const op)
}
break;
case 0x06: // MOV.S
- if (SR & SR_FR)
- m_f[FDREG] = (m_f[FDREG] & ~0xffffffffULL) | u32(m_f[FSREG]);
- else
- if (FDREG & 1)
- if (FSREG & 1)
- // move high half to high half
- m_f[FDREG & ~1] = (m_f[FSREG & ~1] & ~0xffffffffULL) | u32(m_f[FDREG & ~1]);
- else
- // move low half to high half
- m_f[FDREG & ~1] = (m_f[FSREG & ~1] << 32) | u32(m_f[FDREG & ~1]);
- else
- if (FSREG & 1)
- // move high half to low half
- m_f[FDREG & ~1] = (m_f[FDREG & ~1] & ~0xffffffffULL) | (m_f[FSREG & ~1] >> 32);
- else
- // move low half to low half
- m_f[FDREG & ~1] = (m_f[FDREG & ~1] & ~0xffffffffULL) | u32(m_f[FSREG & ~1]);
+ cp1_mov_s(op);
break;
case 0x07: // NEG.S
if ((SR & SR_FR) || !(op & ODD_REGS))
@@ -2193,8 +2752,7 @@ void r4000_base_device::cp1_execute(u32 const op)
}
break;
case 0x06: // MOV.D
- if ((SR & SR_FR) || !(op & ODD_REGS))
- m_f[FDREG] = m_f[FSREG];
+ cp1_mov_d(op);
break;
case 0x07: // NEG.D
if ((SR & SR_FR) || !(op & ODD_REGS))
@@ -2528,11 +3086,11 @@ void r4000_base_device::cp1_execute(u32 const op)
// TODO: MIPS3 only
switch (op & 0x3f)
{
- case 0x02a00020: // CVT.S.L
+ case 0x20: // CVT.S.L
if ((SR & SR_FR) || !(op & ODD_REGS))
cp1_set(FDREG, i64_to_f32(s64(m_f[FSREG])).v);
break;
- case 0x02a00021: // CVT.D.L
+ case 0x21: // CVT.D.L
if ((SR & SR_FR) || !(op & ODD_REGS))
cp1_set(FDREG, i64_to_f64(s64(m_f[FSREG])).v);
break;
@@ -2587,8 +3145,214 @@ void r4000_base_device::cp1_execute(u32 const op)
break;
case 0x3d: // SDC1
+ store<u64>(ADDR(m_r[RSREG], s16(op)), m_f[RTREG]);
+ break;
+ }
+}
+
+void r4000_base_device::cp1_mov_s(u32 const op)
+{
+ if (SR & SR_FR)
+ m_f[FDREG] = (m_f[FDREG] & ~0xffffffffULL) | u32(m_f[FSREG]);
+ else
+ if (FDREG & 1)
+ if (FSREG & 1)
+ // move high half to high half
+ m_f[FDREG & ~1] = (m_f[FSREG & ~1] & ~0xffffffffULL) | u32(m_f[FDREG & ~1]);
+ else
+ // move low half to high half
+ m_f[FDREG & ~1] = (m_f[FSREG & ~1] << 32) | u32(m_f[FDREG & ~1]);
+ else
+ if (FSREG & 1)
+ // move high half to low half
+ m_f[FDREG & ~1] = (m_f[FDREG & ~1] & ~0xffffffffULL) | (m_f[FSREG & ~1] >> 32);
+ else
+ // move low half to low half
+ m_f[FDREG & ~1] = (m_f[FDREG & ~1] & ~0xffffffffULL) | u32(m_f[FSREG & ~1]);
+}
+
+void r4000_base_device::cp1_mov_d(u32 const op)
+{
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ m_f[FDREG] = m_f[FSREG];
+}
+
+void r4000_base_device::cp1x_execute(u32 const op)
+{
+ if (!(SR & SR_CU1))
+ {
+ cpu_exception(EXCEPTION_CP1);
+ return;
+ }
+
+ logerror("cp1x not supported < R5000 (%s)\n", machine().describe_context());
+}
+
+void r5000_device::cp1x_execute(u32 const op)
+{
+ if (!(SR & SR_CU1))
+ {
+ cpu_exception(EXCEPTION_CP1);
+ return;
+ }
+
+ switch (op & 0x3f)
+ {
+ case 0x00: // LWXC1
+ load<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))),
+ [this, op](u32 data)
+ {
+ if (SR & SR_FR)
+ m_f[RTREG] = (m_f[RTREG] & ~0xffffffffULL) | data;
+ else
+ if (RTREG & 1)
+ // load the high half of the even floating point register
+ m_f[RTREG & ~1] = (u64(data) << 32) | u32(m_f[RTREG & ~1]);
+ else
+ // load the low half of the even floating point register
+ m_f[RTREG & ~1] = (m_f[RTREG & ~1] & ~0xffffffffULL) | data;
+ });
+ break;
+ case 0x01: // LDXC1
+ load<u64>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))),
+ [this, op](u64 data)
+ {
+ if ((SR & SR_FR) || !(RTREG & 1))
+ m_f[RTREG] = data;
+ });
+ break;
+ case 0x08: // SWXC1
+ if (SR & SR_FR)
+ store<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), u32(m_f[RTREG]));
+ else
+ if (RTREG & 1)
+ // store the high half of the even floating point register
+ store<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), u32(m_f[RTREG & ~1] >> 32));
+ else
+ // store the low half of the even floating point register
+ store<u32>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), u32(m_f[RTREG & ~1]));
+ break;
+ case 0x09: // SDXC1
if ((SR & SR_FR) || !(RTREG & 1))
- store<u64>(ADDR(m_r[RSREG], s16(op)), m_f[RTREG]);
+ store<u64>(s64(s32(u32(m_r[RSREG]) + u32(m_r[RTREG]))), m_f[RTREG]);
+ break;
+ case 0x0f: // PREFX
+ // Do nothing for now (implementations are permitted to do this)
+ break;
+ case 0x20: // MADD.S
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float32_t const fr = float32_t{ u32(m_f[FRREG]) };
+ float32_t const fs = float32_t{ u32(m_f[FSREG]) };
+ float32_t const ft = float32_t{ u32(m_f[FTREG]) };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f32_add(f32_mul(fs, ft), fr).v);
+ }
+ break;
+ case 0x21: // MADD.D
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float64_t const fr = float64_t{ m_f[FRREG] };
+ float64_t const fs = float64_t{ m_f[FSREG] };
+ float64_t const ft = float64_t{ m_f[FTREG] };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f64_add(f64_mul(fs, ft), fr).v);
+ }
+ break;
+ case 0x28: // MSUB.S
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float32_t const fr = float32_t{ u32(m_f[FRREG]) };
+ float32_t const fs = float32_t{ u32(m_f[FSREG]) };
+ float32_t const ft = float32_t{ u32(m_f[FTREG]) };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f32_sub(f32_mul(fs, ft), fr).v);
+ }
+ break;
+ case 0x29: // MSUB.D
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float64_t const fr = float64_t{ m_f[FRREG] };
+ float64_t const fs = float64_t{ m_f[FSREG] };
+ float64_t const ft = float64_t{ m_f[FTREG] };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f64_sub(f64_mul(fs, ft), fr).v);
+ }
+ break;
+ case 0x30: // NMADD.S
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float32_t const fr = float32_t{ u32(m_f[FRREG]) };
+ float32_t const fs = float32_t{ u32(m_f[FSREG]) };
+ float32_t const ft = float32_t{ u32(m_f[FTREG]) };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f32_mul(f32_add(f32_mul(fs, ft), fr), i32_to_f32(-1)).v);
+ }
+ break;
+ case 0x31: // NMADD.D
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float64_t const fr = float64_t{ m_f[FRREG] };
+ float64_t const fs = float64_t{ m_f[FSREG] };
+ float64_t const ft = float64_t{ m_f[FTREG] };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f64_mul(f64_add(f64_mul(fs, ft), fr), i32_to_f64(-1)).v);
+ }
+ break;
+ case 0x38: // NMSUB.S
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float32_t const fr = float32_t{ u32(m_f[FRREG]) };
+ float32_t const fs = float32_t{ u32(m_f[FSREG]) };
+ float32_t const ft = float32_t{ u32(m_f[FTREG]) };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f32_mul(f32_sub(f32_mul(fs, ft), fr), i32_to_f32(-1)).v);
+ }
+ break;
+ case 0x39: // NMSUB.D
+ if ((SR & SR_FR) || !(op & ODD_REGS))
+ {
+ float64_t const fr = float64_t{ m_f[FRREG] };
+ float64_t const fs = float64_t{ m_f[FSREG] };
+ float64_t const ft = float64_t{ m_f[FTREG] };
+
+ if (cp1_op(fr) && cp1_op(fs) && cp1_op(ft))
+ cp1_set(FDREG, f64_mul(f64_sub(f64_mul(fs, ft), fr), i32_to_f64(-1)).v);
+ }
+ break;
+ case 0x24: /* MADD.W */
+ logerror("cp1x unsupported op (%s): MADD.W\n", machine().describe_context());
+ break;
+ case 0x25: /* MADD.L */
+ logerror("cp1x unsupported op (%s): MADD.L\n", machine().describe_context());
+ break;
+ case 0x2c: /* MSUB.W */
+ logerror("cp1x unsupported op (%s): MSUB.W\n", machine().describe_context());
+ break;
+ case 0x2d: /* MSUB.L */
+ logerror("cp1x unsupported op (%s): MSUB.L\n", machine().describe_context());
+ break;
+ case 0x34: /* NMADD.W */
+ logerror("cp1x unsupported op (%s): NMADD.W\n", machine().describe_context());
+ break;
+ case 0x35: /* NMADD.L */
+ logerror("cp1x unsupported op (%s): NMADD.L\n", machine().describe_context());
+ break;
+ case 0x3c: /* NMSUB.W */
+ logerror("cp1x unsupported op (%s): NMSUB.W\n", machine().describe_context());
+ break;
+ case 0x3d: /* NMSUB.L */
+ logerror("cp1x unsupported op (%s): NMSUB.L\n", machine().describe_context());
+ break;
+ default:
+ logerror("cp1x unsupported op (%s): [unknown]\n", machine().describe_context());
break;
}
}
@@ -2727,7 +3491,7 @@ void r4000_base_device::cp2_execute(u32 const op)
}
}
-r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &address)
+r4000_base_device::translate_result r4000_base_device::translate(int intention, bool debug, u64 &address)
{
/*
* Decode the program address into one of the following ranges depending on
@@ -2881,16 +3645,16 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
// address needs translation, using a combination of VPN2 and ASID
u64 const key = (address & (extended ? (EH_R | EH_VPN2_64) : EH_VPN2_32)) | (m_cp0[CP0_EntryHi] & EH_ASID);
- unsigned *mru = m_tlb_mru[intention & TRANSLATE_TYPE_MASK];
- if (LOG_STATS)
+ unsigned *mru = m_tlb_mru[intention];
+ if (VERBOSE & LOG_STATS)
m_tlb_scans++;
bool invalid = false;
bool modify = false;
- for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++)
+ for (unsigned i = 0; i < std::size(m_tlb); i++)
{
unsigned const index = mru[i];
- tlb_entry_t const &entry = m_tlb[index];
+ tlb_entry const &entry = m_tlb[index];
// test vpn and asid
u64 const mask = (extended ? EH_R | (EH_VPN2_64 & ~entry.mask) : (EH_VPN2_32 & ~entry.mask))
@@ -2899,7 +3663,7 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
if ((entry.vpn & mask) != (key & mask))
continue;
- if (LOG_STATS)
+ if (VERBOSE & LOG_STATS)
m_tlb_loops += i + 1;
u64 const pfn = entry.pfn[BIT(address, entry.low_bit)];
@@ -2912,7 +3676,7 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
}
// test dirty
- if ((intention & TRANSLATE_WRITE) && !(pfn & EL_D))
+ if ((intention == TR_WRITE) && !(pfn & EL_D))
{
modify = true;
break;
@@ -2930,18 +3694,18 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
}
// tlb miss, invalid entry, or a store to a non-dirty entry
- if (!machine().side_effects_disabled() && !(intention & TRANSLATE_DEBUG_MASK))
+ if (!machine().side_effects_disabled() && !debug)
{
if (VERBOSE & LOG_TLB)
{
- char const mode[] = { 'r', 'w', 'x' };
+ static char const mode[] = { 'r', 'w', 'x' };
if (modify)
- LOGMASKED(LOG_TLB, "tlb modify asid %d address 0x%016x (%s)\n",
- m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
+ LOGMASKED(LOG_TLB, "tlb modify asid 0x%02x address 0x%016x (%s)\n",
+ m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
else
- LOGMASKED(LOG_TLB, "tlb miss %c asid %d address 0x%016x (%s)\n",
- mode[intention & TRANSLATE_TYPE_MASK], m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
+ LOGMASKED(LOG_TLB, "tlb miss %c asid 0x%02x address 0x%016x (%s)\n",
+ mode[intention], m_cp0[CP0_EntryHi] & EH_ASID, address, machine().describe_context());
}
// load tlb exception registers
@@ -2951,9 +3715,9 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
m_cp0[CP0_XContext] = (m_cp0[CP0_XContext] & XCONTEXT_PTEBASE) | ((address >> 31) & XCONTEXT_R) | ((address >> 9) & XCONTEXT_BADVPN2);
if (invalid || modify || (SR & SR_EXL))
- cpu_exception(modify ? EXCEPTION_MOD : (intention & TRANSLATE_WRITE) ? EXCEPTION_TLBS : EXCEPTION_TLBL);
+ cpu_exception(modify ? EXCEPTION_MOD : (intention == TR_WRITE) ? EXCEPTION_TLBS : EXCEPTION_TLBL);
else
- cpu_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_TLBS : EXCEPTION_TLBL, extended ? 0x080 : 0x000);
+ cpu_exception((intention == TR_WRITE) ? EXCEPTION_TLBS : EXCEPTION_TLBL, extended ? 0x080 : 0x000);
}
return MISS;
@@ -2961,7 +3725,7 @@ r4000_base_device::translate_t r4000_base_device::translate(int intention, u64 &
void r4000_base_device::address_error(int intention, u64 const address)
{
- if (!machine().side_effects_disabled() && !(intention & TRANSLATE_DEBUG_MASK))
+ if (!machine().side_effects_disabled())
{
logerror("address_error 0x%016x (%s)\n", address, machine().describe_context());
@@ -2969,28 +3733,43 @@ void r4000_base_device::address_error(int intention, u64 const address)
if (!(SR & SR_EXL))
m_cp0[CP0_BadVAddr] = address;
- cpu_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADES : EXCEPTION_ADEL);
+ cpu_exception((intention == TR_WRITE) ? EXCEPTION_ADES : EXCEPTION_ADEL);
// address errors shouldn't typically occur, so a breakpoint is handy
machine().debug_break();
}
}
-template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> r4000_base_device::load(u64 address, U &&apply)
+template <typename T> void r4000_base_device::accessors(T &m)
+{
+ space(AS_PROGRAM).specific(m);
+
+ read_byte = [&m](offs_t offset) { return m.read_byte(offset); };
+ read_word = [&m](offs_t offset) { return m.read_word(offset); };
+ read_dword = [&m](offs_t offset) { return m.read_dword(offset); };
+ read_qword = [&m](offs_t offset) { return m.read_qword(offset); };
+
+ write_byte = [&m](offs_t offset, u8 data) { m.write_byte(offset, data); };
+ write_word = [&m](offs_t offset, u16 data, u16 mem_mask) { m.write_word(offset, data, mem_mask); };
+ write_dword = [&m](offs_t offset, u32 data, u32 mem_mask) { m.write_dword(offset, data, mem_mask); };
+ write_qword = [&m](offs_t offset, u64 data, u64 mem_mask) { m.write_qword(offset, data, mem_mask); };
+}
+
+template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> r4000_base_device::load(u64 address, U &&apply)
{
// alignment error
- if (address & (sizeof(T) - 1))
+ if (Aligned && (address & (sizeof(T) - 1)))
{
- address_error(TRANSLATE_READ, address);
+ address_error(TR_READ, address);
return false;
}
- translate_t const t = translate(TRANSLATE_READ, address);
+ translate_result const t = translate(TR_READ, false, address);
// address error
if (t == ERROR)
{
- address_error(TRANSLATE_READ, address);
+ address_error(TR_READ, address);
return false;
}
@@ -3011,15 +3790,19 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f
}
}
+ // align address for l[dw][lr] instructions
+ if (!Aligned)
+ address &= ~(sizeof(T) - 1);
+
// TODO: cache lookup
T value = 0;
switch (sizeof(T))
{
- case 1: value = T(space(0).read_byte(address)); break;
- case 2: value = T(space(0).read_word(address)); break;
- case 4: value = T(space(0).read_dword(address)); break;
- case 8: value = T(space(0).read_qword(address)); break;
+ case 1: value = T(read_byte(address)); break;
+ case 2: value = T(read_word(address)); break;
+ case 4: value = T(read_dword(address)); break;
+ case 8: value = T(read_qword(address)); break;
}
if (m_bus_error)
@@ -3040,16 +3823,16 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f
// alignment error
if (address & (sizeof(T) - 1))
{
- address_error(TRANSLATE_READ, address);
+ address_error(TR_READ, address);
return false;
}
- translate_t const t = translate(TRANSLATE_READ, address);
+ translate_result const t = translate(TR_READ, false, address);
// address error
if (t == ERROR)
{
- address_error(TRANSLATE_READ, address);
+ address_error(TR_READ, address);
return false;
}
@@ -3073,28 +3856,28 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::f
switch (sizeof(T))
{
- case 4: apply(address, T(space(0).read_dword(address))); break;
- case 8: apply(address, T(space(0).read_qword(address))); break;
+ case 4: apply(address, T(read_dword(address))); break;
+ case 8: apply(address, T(read_qword(address))); break;
}
return true;
}
-template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> r4000_base_device::store(u64 address, U data, T mem_mask)
+template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> r4000_base_device::store(u64 address, U data, T mem_mask)
{
// alignment error
- if (address & (sizeof(T) - 1))
+ if (Aligned && (address & (sizeof(T) - 1)))
{
- address_error(TRANSLATE_WRITE, address);
+ address_error(TR_WRITE, address);
return false;
}
- translate_t const t = translate(TRANSLATE_WRITE, address);
+ translate_result const t = translate(TR_WRITE, false, address);
// address error
if (t == ERROR)
{
- address_error(TRANSLATE_WRITE, address);
+ address_error(TR_WRITE, address);
return false;
}
@@ -3114,14 +3897,18 @@ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::va
}
}
+ // align address for s[dw][lr] instructions
+ if (!Aligned)
+ address &= ~(sizeof(T) - 1);
+
// TODO: cache lookup
switch (sizeof(T))
{
- case 1: space(0).write_byte(address, T(data)); break;
- case 2: space(0).write_word(address, T(data), mem_mask); break;
- case 4: space(0).write_dword(address, T(data), mem_mask); break;
- case 8: space(0).write_qword(address, T(data), mem_mask); break;
+ case 1: write_byte(address, T(data)); break;
+ case 2: write_word(address, T(data), mem_mask); break;
+ case 4: write_dword(address, T(data), mem_mask); break;
+ case 8: write_qword(address, T(data), mem_mask); break;
}
return true;
@@ -3134,17 +3921,17 @@ bool r4000_base_device::fetch(u64 address, std::function<void(u32)> &&apply)
// alignment error
if (address & 3)
{
- address_error(TRANSLATE_FETCH, address);
+ address_error(TR_FETCH, address);
return false;
}
- translate_t const t = translate(TRANSLATE_FETCH, address);
+ translate_result const t = translate(TR_FETCH, false, address);
// address error
if (t == ERROR)
{
- address_error(TRANSLATE_FETCH, address);
+ address_error(TR_FETCH, address);
return false;
}
@@ -3157,7 +3944,7 @@ bool r4000_base_device::fetch(u64 address, std::function<void(u32)> &&apply)
{
if (t == UNCACHED)
{
- const u32 insn = space(0).read_dword(address);
+ const u32 insn = read_dword(address);
if (m_bus_error)
{
@@ -3186,7 +3973,7 @@ bool r4000_base_device::fetch(u64 address, std::function<void(u32)> &&apply)
tag = ICACHE_V | (address >> 12);
for (unsigned i = 0; i < m_icache_line_size; i += 8)
{
- u64 const data = space(0).read_qword((address & m_icache_mask_lo) | i);
+ u64 const data = read_qword((address & m_icache_mask_lo) | i);
m_icache_data[(((cache_address & m_icache_mask_lo) | i) >> 2) + 0] = u32(data);
m_icache_data[(((cache_address & m_icache_mask_lo) | i) >> 2) + 1] = data >> 32;
@@ -3200,7 +3987,7 @@ bool r4000_base_device::fetch(u64 address, std::function<void(u32)> &&apply)
}
else
{
- const u32 insn = space(0).read_dword(address);
+ const u32 insn = read_dword(address);
if (m_bus_error)
{
@@ -3296,3 +4083,46 @@ std::string r4000_base_device::debug_unicode_string(u64 unicode_string_pointer)
return utf8_from_wstring(result);
}
+
+void r4000_base_device::configure_scache()
+{
+ if (m_scache_size > 0)
+ {
+ /*
+ * Secondary cache tag size depends on the cache line size
+ * (how many bytes are transferred with one cache operation) and the
+ * size of the cache itself.
+ * For example, the Sony NEWS NWS-5000X has a 1MB secondary cache
+ * and a cache line size of 16 words. So, the slice of the physical
+ * address used to index into the cache is bits 19:6.
+ * See chapter 11 of the R4000 user manual for more details.
+ */
+ if (m_scache_line_size == 0)
+ fatalerror("SCACHE size set but line size was not set!");
+
+ if (m_scache_line_size <= 0x10)
+ m_scache_line_index = 4;
+ else if (m_scache_line_size <= 0x20)
+ {
+ m_scache_line_index = 5;
+ m_cp0[CP0_Config] |= 1 << 22;
+ }
+ else if (m_scache_line_size <= 0x40)
+ {
+ m_scache_line_index = 6;
+ m_cp0[CP0_Config] |= 2 << 22;
+ }
+ else
+ {
+ m_scache_line_index = 7;
+ m_cp0[CP0_Config] |= 3 << 22;
+ }
+
+ m_scache_tag_size = m_scache_size >> m_scache_line_index;
+ m_scache_tag_mask = m_scache_size - 1;
+
+ m_scache_tag = std::make_unique<u32[]>(m_scache_tag_size);
+ }
+ else
+ m_cp0[CP0_Config] |= CONFIG_SC;
+}
diff --git a/src/devices/cpu/mips/r4000.h b/src/devices/cpu/mips/r4000.h
index 2430812919c..a6e0f816d9a 100644
--- a/src/devices/cpu/mips/r4000.h
+++ b/src/devices/cpu/mips/r4000.h
@@ -9,6 +9,7 @@
DECLARE_DEVICE_TYPE(R4000, r4000_device)
DECLARE_DEVICE_TYPE(R4400, r4400_device)
DECLARE_DEVICE_TYPE(R4600, r4600_device)
+DECLARE_DEVICE_TYPE(R5000, r5000_device)
class r4000_base_device : public cpu_device
{
@@ -16,7 +17,7 @@ public:
enum config_mask : u32
{
CONFIG_K0 = 0x00000007, // kseg0 cache coherency
- CONFIG_CU = 0x00000080, // store conditional cache coherent
+ CONFIG_CU = 0x00000008, // store conditional cache coherent
CONFIG_DB = 0x00000010, // primary d-cache line 32 bytes
CONFIG_IB = 0x00000020, // primary i-cache line 32 bytes
CONFIG_DC = 0x000001c0, // primary d-cache size
@@ -45,7 +46,7 @@ public:
void bus_error() { m_bus_error = true; }
protected:
- enum cache_size_t
+ enum cache_size
{
CACHE_4K = 0,
CACHE_8K = 1,
@@ -56,7 +57,7 @@ protected:
CACHE_256K = 6,
CACHE_512K = 7,
};
- r4000_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size_t icache_size, cache_size_t dcache_size);
+ r4000_base_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size icache_size, cache_size dcache_size, unsigned m32, unsigned m64, unsigned d32, unsigned d64, bool timer_interrupt_disabled);
enum cp0_reg : int
{
@@ -290,6 +291,8 @@ protected:
TAGLO_PTAGLO = 0xffffff00, // physical adddress bits 35:12
TAGLO_PSTATE = 0x000000c0, // primary cache state
TAGLO_P = 0x00000001, // primary tag even parity
+ TAGLO_CS = 0x00001c00, // scache status
+ TAGLO_STAG = 0xffffe000, // scache tag
};
enum icache_mask : u32
{
@@ -305,27 +308,35 @@ protected:
DCACHE_W = 0x02000000, // write-back
DCACHE_WP = 0x02000000, // even parity for write-back
};
+ enum scache_mask : u32
+ {
+ SCACHE_CS = 0x01c00000, // cache state
+ SCACHE_STAG = 0x0007ffff, // physical tag
+ SCACHE_PIDX = 0x00380000, // primary cache index
+ };
// device_t overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_stop() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
- virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
+ virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
// device_disasm_interface overrides
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
// device_execute_interface overrides
- virtual u32 execute_min_cycles() const override { return 1; }
- virtual u32 execute_max_cycles() const override { return 40; }
- virtual u32 execute_input_lines() const override { return 6; }
+ virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks * 2); }
+ virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles + 1) / 2; }
+ virtual u32 execute_min_cycles() const noexcept override { return 1; }
+ virtual u32 execute_max_cycles() const noexcept override { return *std::max_element(std::begin(m_hilo_cycles), std::end(m_hilo_cycles)); }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
// cpu implementation
+ virtual void handle_reserved_instruction(u32 const op);
void cpu_execute(u32 const op);
void cpu_exception(u32 exception, u16 const vector = 0x180);
void cpu_lwl(u32 const op);
@@ -338,6 +349,7 @@ protected:
void cpu_sdr(u32 const op);
// cp0 implementation
+ void cp0_cache(u32 const op);
void cp0_execute(u32 const op);
u64 cp0_get(unsigned const reg);
void cp0_set(unsigned const reg, u64 const data);
@@ -354,20 +366,24 @@ protected:
// cp1 implementation
void cp1_unimplemented();
template <typename T> bool cp1_op(T op);
- void cp1_execute(u32 const op);
+ virtual void cp1_execute(u32 const op);
+ virtual void cp1x_execute(u32 const op);
template <typename T> void cp1_set(unsigned const reg, T const data);
+ void cp1_mov_s(u32 const op);
+ void cp1_mov_d(u32 const op);
// cp2 implementation
void cp2_execute(u32 const op);
// address and memory handling
- enum translate_t { ERROR, MISS, UNCACHED, CACHED };
- translate_t translate(int intention, u64 &address);
+ enum translate_result : unsigned { ERROR, MISS, UNCACHED, CACHED };
+ translate_result translate(int intention, bool debug, u64 &address);
void address_error(int intention, u64 const address);
- template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(u64 program_address, U &&apply);
+ template <typename T> void accessors(T &m);
+ template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(u64 program_address, U &&apply);
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(u64, T)>>::value, bool> load_linked(u64 program_address, U &&apply);
- template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(u64 program_address, U data, T mem_mask = ~T(0));
+ template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(u64 program_address, U data, T mem_mask = ~T(0));
bool fetch(u64 address, std::function<void(u32)> &&apply);
// debugging helpers
@@ -375,36 +391,60 @@ protected:
std::string debug_string_array(u64 array_pointer);
std::string debug_unicode_string(u64 unicode_string_pointer);
+ // configuration helpers
+ void configure_scache();
+
// device configuration state
address_space_config m_program_config_le;
address_space_config m_program_config_be;
+ // memory access helpers
+ memory_access<32, 3, 0, ENDIANNESS_LITTLE>::specific m_le;
+ memory_access<32, 3, 0, ENDIANNESS_BIG>::specific m_be;
+
+ std::function<u8(offs_t offset)> read_byte;
+ std::function<u16(offs_t offset)> read_word;
+ std::function<u32(offs_t offset)> read_dword;
+ std::function<u64(offs_t offset)> read_qword;
+ std::function<void(offs_t offset, u8 data)> write_byte;
+ std::function<void(offs_t offset, u16 data, u16 mem_mask)> write_word;
+ std::function<void(offs_t offset, u32 data, u32 mem_mask)> write_dword;
+ std::function<void(offs_t offset, u64 data, u64 mem_mask)> write_qword;
+
+ enum branch_state : u64
+ {
+ STATE = 0x00000000'00000003,
+ TARGET = 0xffffffff'fffffffc,
+
+ NONE = 0,
+ BRANCH = 1, // retire delayed branch
+ DELAY = 2, // delay slot instruction
+ NULLIFY = 3, // next instruction nullified
+ };
+
// runtime state
int m_icount;
+ // integer multiple/divide state
+ unsigned const m_hilo_cycles[4];
+ unsigned m_hilo_delay;
+
// cpu state
u64 m_pc;
u64 m_r[32];
u64 m_hi;
u64 m_lo;
- enum branch_state_t : unsigned
- {
- NONE = 0,
- DELAY = 1, // delay slot instruction active
- BRANCH = 2, // branch instruction active
- EXCEPTION = 3, // exception triggered
- NULLIFY = 4, // next instruction nullified
- }
- m_branch_state;
- u64 m_branch_target;
+ u64 m_branch_state;
// cp0 state
u64 m_cp0[32];
u64 m_cp0_timer_zero;
emu_timer *m_cp0_timer;
+ bool m_hard_reset;
bool m_ll_active;
bool m_bus_error;
- struct tlb_entry_t
+ bool m_timer_interrupt_disabled;
+ struct tlb_entry
{
u64 mask;
u64 vpn;
@@ -429,6 +469,14 @@ protected:
std::unique_ptr<u32[]> m_icache_tag;
std::unique_ptr<u32[]> m_icache_data;
+ // experimental scache state
+ u32 m_scache_size; // Size in bytes
+ u8 m_scache_line_size;
+ u32 m_scache_line_index; // Secondary cache line shift
+ u32 m_scache_tag_mask; // Mask for extracting the tag from a physical address
+ u32 m_scache_tag_size;
+ std::unique_ptr<u32[]> m_scache_tag;
+
// statistics
u64 m_tlb_scans;
u64 m_tlb_loops;
@@ -440,33 +488,73 @@ class r4000_device : public r4000_base_device
{
public:
// NOTE: R4000 chips prior to 3.0 have an xtlb bug
- r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : r4000_base_device(mconfig, R4000, tag, owner, clock, 0x0430, 0x0500, CACHE_8K, CACHE_8K)
+ r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled)
+ : r4000_base_device(mconfig, R4000, tag, owner, clock, 0x0430, 0x0500, CACHE_8K, CACHE_8K, 10, 20, 69, 133, timer_interrupt_disabled)
{
// no secondary cache
m_cp0[CP0_Config] |= CONFIG_SC;
}
+
+ r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : r4000_device(mconfig, tag, owner, clock, false)
+ {
+ }
};
class r4400_device : public r4000_base_device
{
public:
+ r4400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled, u32 scache_size, u8 scache_line_size)
+ : r4000_base_device(mconfig, R4400, tag, owner, clock, 0x0440, 0x0500, CACHE_16K, CACHE_16K, 10, 20, 69, 133, timer_interrupt_disabled)
+ {
+ m_scache_size = scache_size;
+ m_scache_line_size = scache_line_size;
+ configure_scache();
+ }
+
r4400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : r4000_base_device(mconfig, R4400, tag, owner, clock, 0x0440, 0x0500, CACHE_16K, CACHE_16K)
+ : r4400_device(mconfig, tag, owner, clock, false, 0, 0)
{
- // no secondary cache
- m_cp0[CP0_Config] |= CONFIG_SC;
}
};
class r4600_device : public r4000_base_device
{
public:
+ r4600_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled)
+ : r4000_base_device(mconfig, R4600, tag, owner, clock, 0x2020, 0x2020, CACHE_16K, CACHE_16K, 10, 12, 42, 74, timer_interrupt_disabled)
+ {
+ // no secondary cache
+ m_cp0[CP0_Config] |= CONFIG_SC;
+ }
+
r4600_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : r4000_base_device(mconfig, R4600, tag, owner, clock, 0x2020, 0x2020, CACHE_16K, CACHE_16K)
+ : r4600_device(mconfig, tag, owner, clock, false)
+ {
+ }
+};
+
+class r5000_device : public r4000_base_device
+{
+public:
+ r5000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled)
+ : r4000_base_device(mconfig, R5000, tag, owner, clock, 0x2320, 0x2320, CACHE_32K, CACHE_32K, 5, 9, 36, 68, timer_interrupt_disabled)
{
// no secondary cache
m_cp0[CP0_Config] |= CONFIG_SC;
}
+
+ r5000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : r5000_device(mconfig, tag, owner, clock, false)
+ {
+ }
+
+private:
+ virtual void handle_reserved_instruction(u32 const op) override;
+ virtual void cp1_execute(u32 const op) override;
+ virtual void cp1x_execute(u32 const op) override;
+
+ static u32 const s_fcc_masks[8];
+ static u32 const s_fcc_shifts[8];
};
#endif // MAME_CPU_MIPS_R4000_H