From b380514764cf857469bae61c11143a19f79a74c5 Mon Sep 17 00:00:00 2001 From: andreasnaive Date: Mon, 25 Mar 2019 23:13:40 +0100 Subject: Revert "conflict resolution (nw)" This reverts commit c24473ddff715ecec2e258a6eb38960cf8c8e98e, reversing changes made to 009cba4fb8102102168ef32870892438327f3705. --- src/devices/cpu/mips/mips1.cpp | 2302 ++++++++++++---------------------------- 1 file changed, 705 insertions(+), 1597 deletions(-) (limited to 'src/devices/cpu/mips/mips1.cpp') diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index 1ed202c0d63..72479a6065d 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -7,6 +7,8 @@ * while those without have hard-wired address translation. * * TODO + * - FPU support + * - further cleanup on coprocessors * - R3041 features * - cache emulation * @@ -15,32 +17,37 @@ #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" +#define ENABLE_IOP_KPUTS (0) + #define RSREG ((op >> 21) & 31) #define RTREG ((op >> 16) & 31) #define RDREG ((op >> 11) & 31) #define SHIFT ((op >> 6) & 31) -#define FTREG ((op >> 16) & 31) -#define FSREG ((op >> 11) & 31) -#define FDREG ((op >> 6) & 31) +#define RSVAL m_r[RSREG] +#define RTVAL m_r[RTREG] +#define RDVAL m_r[RDREG] #define SIMMVAL s16(op) #define UIMMVAL u16(op) #define LIMMVAL (op & 0x03ffffff) -#define SR m_cop0[COP0_Status] -#define CAUSE m_cop0[COP0_Cause] +#define ADDPC(x) do { m_branch_state = BRANCH; m_branch_target = m_pc + 4 + ((x) << 2); } while (0) +#define ADDPCL(x,l) do { m_branch_state = BRANCH; m_branch_target = m_pc + 4 + ((x) << 2); m_r[l] = m_pc + 8; } while (0) +#define ABSPC(x) do { m_branch_state = BRANCH; m_branch_target = ((m_pc + 4) & 0xf0000000) | ((x) << 2); } while (0) +#define ABSPCL(x,l) do { m_branch_state = BRANCH; m_branch_target = ((m_pc + 4) & 0xf0000000) | ((x) << 2); m_r[l] = m_pc + 8; } while (0) +#define SETPC(x) do { m_branch_state = BRANCH; m_branch_target = (x); } while (0) +#define SETPCL(x,l) do { m_branch_state = BRANCH; m_branch_target = (x); m_r[l] = m_pc + 8; } while (0) + +#define SR m_cpr[0][COP0_Status] +#define CAUSE m_cpr[0][COP0_Cause] DEFINE_DEVICE_TYPE(R2000, r2000_device, "r2000", "MIPS R2000") DEFINE_DEVICE_TYPE(R2000A, r2000a_device, "r2000a", "MIPS R2000A") @@ -63,6 +70,8 @@ mips1core_device_base::mips1core_device_base(const machine_config &mconfig, devi , m_icache_config("icache", ENDIANNESS_BIG, 32, 32) , m_dcache_config("dcache", ENDIANNESS_BIG, 32, 32) , m_cpurev(cpurev) + , m_hasfpu(false) + , m_fpurev(0) , m_endianness(ENDIANNESS_BIG) , m_icount(0) , m_icache_size(icache_size) @@ -73,7 +82,6 @@ mips1core_device_base::mips1core_device_base(const machine_config &mconfig, devi 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) - , m_fcr0(0) { } @@ -118,14 +126,14 @@ r3052e_device::r3052e_device(const machine_config &mconfig, const char *tag, dev } 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) + : mips1core_device_base(mconfig, R3071, tag, owner, clock, 0x0200, icache_size, dcache_size) { } 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) + : mips1core_device_base(mconfig, R3081, tag, owner, clock, 0x0200, icache_size, dcache_size) { - set_fpu(0x0300); + set_fpurev(0x0300); } iop_device::iop_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) @@ -145,6 +153,18 @@ void mips1core_device_base::device_add_mconfig(machine_config &config) set_addrmap(2, &mips1core_device_base::dcache_map); } +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::device_start() { // set our instruction counter @@ -157,32 +177,49 @@ void mips1core_device_base::device_start() // register our state for the debugger state_add(STATE_GENPC, "GENPC", m_pc).noshow(); state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); + state_add(STATE_GENSP, "GENSP", m_r[31]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_cpr[0][COP0_Status]).noshow(); - state_add(MIPS1_PC, "PC", m_pc); - state_add(MIPS1_COP0 + COP0_Status, "SR", m_cop0[COP0_Status]); + state_add(MIPS1_PC, "PC", m_pc); + state_add(MIPS1_COP0_SR, "SR", m_cpr[0][COP0_Status]); - for (unsigned i = 0; i < ARRAY_LENGTH(m_r); i++) + for (int i = 0; i < 32; i++) state_add(MIPS1_R0 + i, util::string_format("R%d", i).c_str(), m_r[i]); state_add(MIPS1_HI, "HI", m_hi); state_add(MIPS1_LO, "LO", m_lo); - - // cop0 exception registers - state_add(MIPS1_COP0 + COP0_BadVAddr, "BadVAddr", m_cop0[COP0_BadVAddr]); - state_add(MIPS1_COP0 + COP0_Cause, "Cause", m_cop0[COP0_Cause]); - state_add(MIPS1_COP0 + COP0_EPC, "EPC", m_cop0[COP0_EPC]); + state_add(MIPS1_COP0_BADVADDR, "BadVAddr", m_cpr[0][COP0_BadVAddr]); + state_add(MIPS1_COP0_CAUSE, "Cause", m_cpr[0][COP0_Cause]); + state_add(MIPS1_COP0_EPC, "EPC", m_cpr[0][COP0_EPC]); // register our state for saving save_item(NAME(m_pc)); save_item(NAME(m_hi)); save_item(NAME(m_lo)); save_item(NAME(m_r)); - save_item(NAME(m_cop0)); + save_item(NAME(m_cpr)); + save_item(NAME(m_ccr)); save_item(NAME(m_branch_state)); save_item(NAME(m_branch_target)); - // initialise cpu id register - m_cop0[COP0_PRId] = m_cpurev; + // initialise cpu and fpu id registers + m_cpr[0][COP0_PRId] = m_cpurev; + m_ccr[1][0] = m_fpurev; +} + +void mips1_device_base::device_start() +{ + mips1core_device_base::device_start(); + + // cop0 tlb registers + state_add(MIPS1_COP0_INDEX, "Index", m_cpr[0][COP0_Index]); + state_add(MIPS1_COP0_RANDOM, "Random", m_cpr[0][COP0_Random]); + state_add(MIPS1_COP0_ENTRYLO, "EntryLo", m_cpr[0][COP0_EntryLo]); + state_add(MIPS1_COP0_ENTRYHI, "EntryHi", m_cpr[0][COP0_EntryHi]); + state_add(MIPS1_COP0_CONTEXT, "Context", m_cpr[0][COP0_Context]); + + save_item(NAME(m_reset_time)); + save_item(NAME(m_tlb)); } void r3041_device::device_start() @@ -190,11 +227,11 @@ void r3041_device::device_start() mips1core_device_base::device_start(); // cop0 r3041 registers - state_add(MIPS1_COP0 + COP0_BusCtrl, "BusCtrl", m_cop0[COP0_BusCtrl]); - state_add(MIPS1_COP0 + COP0_Config, "Config", m_cop0[COP0_Config]); - 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]); + state_add(MIPS1_COP0_BUSCTRL, "BusCtrl", m_cpr[0][COP0_BusCtrl]); + state_add(MIPS1_COP0_CONFIG, "Config", m_cpr[0][COP0_Config]); + state_add(MIPS1_COP0_COUNT, "Count", m_cpr[0][COP0_Count]); + state_add(MIPS1_COP0_PORTSIZE, "PortSize", m_cpr[0][COP0_PortSize]); + state_add(MIPS1_COP0_COMPARE, "Compare", m_cpr[0][COP0_Compare]); } void mips1core_device_base::device_reset() @@ -204,1632 +241,723 @@ void mips1core_device_base::device_reset() m_branch_state = NONE; // non-tlb devices have tlb shut down - m_cop0[COP0_Status] = SR_BEV | SR_TS; + m_cpr[0][COP0_Status] = SR_BEV | SR_TS; m_data_spacenum = 0; } +void mips1_device_base::device_reset() +{ + mips1core_device_base::device_reset(); + + // tlb is not shut down + m_cpr[0][COP0_Status] &= ~SR_TS; + + m_reset_time = total_cycles(); +} + +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::unique_ptr mips1core_device_base::create_disassembler() +{ + return std::make_unique(); +} + +void mips1core_device_base::generate_exception(int exception, bool refill) +{ + // set the exception PC + m_cpr[0][COP0_EPC] = m_pc; + + // put the cause in the low 8 bits and clear the branch delay flag + CAUSE = (CAUSE & ~0x800000ff) | (exception << 2); + + // if in a branch delay slot, restart the branch + if (m_branch_state == DELAY) + { + m_cpr[0][COP0_EPC] -= 4; + CAUSE |= 0x80000000; + } + m_branch_state = EXCEPTION; + + // shift the exception bits + SR = (SR & 0xffffffc0) | ((SR << 2) & 0x3c); + + if (refill) + m_pc = (SR & SR_BEV) ? 0xbfc00100 : 0x80000000; + else + m_pc = (SR & SR_BEV) ? 0xbfc00180 : 0x80000080; + + debugger_exception_hook(exception); +} + +void mips1core_device_base::check_irqs() +{ + if ((CAUSE & SR & 0xff00) && (SR & SR_IEc)) + generate_exception(EXCEPTION_INTERRUPT); +} + +void mips1core_device_base::set_irq_line(int irqline, int state) +{ + if (state != CLEAR_LINE) + CAUSE |= 0x400 << irqline; + else + CAUSE &= ~(0x400 << irqline); + + check_irqs(); +} + +u32 mips1core_device_base::get_cop0_reg(int const index) +{ + return m_cpr[0][index]; +} + +u32 mips1_device_base::get_cop0_reg(int const index) +{ + // assume 64-entry tlb with 8 wired entries + if (index == COP0_Random) + m_cpr[0][index] = (63 - ((total_cycles() - m_reset_time) % 56)) << 8; + + return m_cpr[0][index]; +} + +void mips1core_device_base::set_cop0_reg(int const index, u32 const data) +{ + if (index == COP0_Cause) + { + CAUSE = (CAUSE & 0xfc00) | (data & ~0xfc00); + + // update interrupts -- software ints can occur this way + check_irqs(); + } + else if (index == COP0_Status) + { + m_cpr[0][index] = data; + + // handle cache isolation and swap + m_data_spacenum = (data & SR_IsC) ? ((data & SR_SwC) ? 1 : 2) : 0; + + // update interrupts + check_irqs(); + } + else if (index == COP0_Context) + m_cpr[0][index] = (m_cpr[0][index] & ~PTE_BASE) | (data & PTE_BASE); + else if (index != COP0_PRId) + m_cpr[0][index] = data; +} + +void mips1core_device_base::handle_cop0(u32 const op) +{ + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop_creg<0>(RDREG); break; + case 0x04: /* MTCz */ set_cop0_reg(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop_creg<0>(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond[0]()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond[0]()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x03: /* BCzTL */ generate_exception(EXCEPTION_INVALIDOP); break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + switch (op & 0x01ffffff) + { + case 0x01: /* TLBR */ break; + case 0x02: /* TLBWI */ break; + case 0x06: /* TLBWR */ break; + case 0x08: /* TLBP */ break; + case 0x10: /* RFE */ SR = (SR & 0xfffffff0) | ((SR >> 2) & 0x0f); break; + case 0x18: /* ERET */ generate_exception(EXCEPTION_INVALIDOP); break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } + break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } +} + +void mips1_device_base::handle_cop0(u32 const op) +{ + switch (op) + { + case 0x42000001: // TLBR - read tlb + { + u8 const index = (m_cpr[0][COP0_Index] >> 8) & 0x3f; + + m_cpr[0][COP0_EntryHi] = m_tlb[index][0]; + m_cpr[0][COP0_EntryLo] = m_tlb[index][1]; + } + break; + + case 0x42000002: // TLBWI - write tlb (indexed) + { + u8 const index = (m_cpr[0][COP0_Index] >> 8) & 0x3f; + + m_tlb[index][0] = m_cpr[0][COP0_EntryHi]; + m_tlb[index][1] = m_cpr[0][COP0_EntryLo]; + + LOGMASKED(LOG_TLB, "tlb write index %d asid %d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", + index, (m_cpr[0][COP0_EntryHi] & EH_ASID) >> 6, m_cpr[0][COP0_EntryHi] & EH_VPN, m_cpr[0][COP0_EntryLo] & EL_PFN, + m_cpr[0][COP0_EntryLo] & EL_N ? 'N' : '-', + m_cpr[0][COP0_EntryLo] & EL_D ? 'D' : '-', + m_cpr[0][COP0_EntryLo] & EL_V ? 'V' : '-', + m_cpr[0][COP0_EntryLo] & EL_G ? 'G' : '-', + machine().describe_context()); + } + break; + + case 0x42000006: // TLBWR - write tlb (random) + { + u8 const random = get_cop0_reg(COP0_Random) >> 8; + + m_tlb[random][0] = m_cpr[0][COP0_EntryHi]; + m_tlb[random][1] = m_cpr[0][COP0_EntryLo]; + + LOGMASKED(LOG_TLB, "tlb write random %d asid %d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", + random, (m_cpr[0][COP0_EntryHi] & EH_ASID) >> 6, m_cpr[0][COP0_EntryHi] & EH_VPN, m_cpr[0][COP0_EntryLo] & EL_PFN, + m_cpr[0][COP0_EntryLo] & EL_N ? 'N' : '-', + m_cpr[0][COP0_EntryLo] & EL_D ? 'D' : '-', + m_cpr[0][COP0_EntryLo] & EL_V ? 'V' : '-', + m_cpr[0][COP0_EntryLo] & EL_G ? 'G' : '-', + machine().describe_context()); + } + break; + + case 0x42000008: // TLBP - probe tlb + m_cpr[0][COP0_Index] = 0x80000000; + for (u8 index = 0; index < 64; index++) + { + // test vpn and optionally asid + u32 const mask = (m_tlb[index][1] & EL_G) ? EH_VPN : EH_VPN | EH_ASID; + if ((m_tlb[index][0] & mask) == (m_cpr[0][COP0_EntryHi] & mask)) + { + LOGMASKED(LOG_TLB, "tlb probe hit vpn 0x%08x index %d (%s)\n", + m_cpr[0][COP0_EntryHi] & mask, index, machine().describe_context()); + + m_cpr[0][COP0_Index] = index << 8; + break; + } + } + if ((VERBOSE & LOG_TLB) && BIT(m_cpr[0][COP0_Index], 31)) + LOGMASKED(LOG_TLB, "tlb probe miss asid %d vpn 0x%08x(%s)\n", + (m_cpr[0][COP0_EntryHi] & EH_ASID) >> 6, m_cpr[0][COP0_EntryHi] & EH_VPN, machine().describe_context()); + break; + + default: + mips1core_device_base::handle_cop0(op); + } +} + +void mips1core_device_base::set_cop1_creg(int idx, u32 val) +{ + // fpu revision register is read-only + if (idx) + m_ccr[1][idx] = val; +} + +void mips1core_device_base::handle_cop1(u32 const op) +{ + if (!m_hasfpu) + return; + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop_reg<1>(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop_creg<1>(RDREG); break; + case 0x04: /* MTCz */ set_cop_reg<1>(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond[1]()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond[1]()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x03: /* BCzTL */ generate_exception(EXCEPTION_INVALIDOP); break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ generate_exception(EXCEPTION_INVALIDOP); break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } +} + +template void mips1core_device_base::handle_cop(u32 const op) +{ + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop_reg(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop_creg(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond[Coprocessor]()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond[Coprocessor]()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x03: /* BCzTL */ generate_exception(EXCEPTION_INVALIDOP); break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ generate_exception(EXCEPTION_INVALIDOP); break; + default: generate_exception(EXCEPTION_INVALIDOP); break; + } +} + void mips1core_device_base::execute_run() { - // check for interrupts + // check for IRQs check_irqs(); // core execution loop - while (m_icount-- > 0) + do { // debugging debugger_instruction_hook(m_pc); - if (VERBOSE & LOG_IOP) +#if ENABLE_IOP_KPUTS + if ((m_pc & 0x1fffffff) == 0x00012C48 || (m_pc & 0x1fffffff) == 0x0001420C || (m_pc & 0x1fffffff) == 0x0001430C) { - 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) { - u32 ptr = m_r[5]; - u32 length = m_r[6]; - if (length >= 4096) - length = 4095; - while (length) - { - load(ptr, [](char c) { printf("%c", c); }); - ptr++; - length--; - } - fflush(stdout); + load(ptr, [this](char c) { printf("%c", c); }); + ptr++; + length--; } + fflush(stdout); } +#endif // fetch and execute instruction fetch(m_pc, [this](u32 const op) { - // parse the instruction - switch (op >> 26) - { - case 0x00: // SPECIAL - switch (op & 63) + // parse the instruction + switch (op >> 26) { - case 0x00: // SLL - m_r[RDREG] = m_r[RTREG] << SHIFT; - break; - case 0x02: // SRL - m_r[RDREG] = m_r[RTREG] >> SHIFT; - break; - case 0x03: // SRA - m_r[RDREG] = s32(m_r[RTREG]) >> SHIFT; - break; - case 0x04: // SLLV - m_r[RDREG] = m_r[RTREG] << (m_r[RSREG] & 31); - break; - case 0x06: // SRLV - m_r[RDREG] = m_r[RTREG] >> (m_r[RSREG] & 31); - break; - case 0x07: // SRAV - m_r[RDREG] = s32(m_r[RTREG]) >> (m_r[RSREG] & 31); - break; - case 0x08: // JR - m_branch_state = BRANCH; - m_branch_target = m_r[RSREG]; - break; - case 0x09: // JALR - m_branch_state = BRANCH; - m_branch_target = m_r[RSREG]; - m_r[RDREG] = m_pc + 8; - break; - case 0x0c: // SYSCALL - generate_exception(EXCEPTION_SYSCALL); - break; - case 0x0d: // BREAK - generate_exception(EXCEPTION_BREAK); - break; - case 0x10: // MFHI - m_r[RDREG] = m_hi; - break; - case 0x11: // MTHI - m_hi = m_r[RSREG]; - break; - case 0x12: // MFLO - m_r[RDREG] = m_lo; - break; - case 0x13: // MTLO - m_lo = m_r[RSREG]; - break; - case 0x18: // MULT + case 0x00: /* SPECIAL */ + switch (op & 63) { - u64 product = mul_32x32(m_r[RSREG], m_r[RTREG]); + case 0x00: /* SLL */ if (RDREG) RDVAL = RTVAL << SHIFT; break; + case 0x02: /* SRL */ if (RDREG) RDVAL = RTVAL >> SHIFT; break; + case 0x03: /* SRA */ if (RDREG) RDVAL = s32(RTVAL) >> SHIFT; break; + case 0x04: /* SLLV */ if (RDREG) RDVAL = RTVAL << (RSVAL & 31); break; + case 0x06: /* SRLV */ if (RDREG) RDVAL = RTVAL >> (RSVAL & 31); break; + case 0x07: /* SRAV */ if (RDREG) RDVAL = s32(RTVAL) >> (RSVAL & 31); break; + case 0x08: /* JR */ SETPC(RSVAL); break; + case 0x09: /* JALR */ SETPCL(RSVAL, RDREG); break; + case 0x0c: /* SYSCALL */ generate_exception(EXCEPTION_SYSCALL); break; + case 0x0d: /* BREAK */ generate_exception(EXCEPTION_BREAK); break; + case 0x0f: /* SYNC */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x10: /* MFHI */ if (RDREG) RDVAL = m_hi; break; + case 0x11: /* MTHI */ m_hi = RSVAL; break; + case 0x12: /* MFLO */ if (RDREG) RDVAL = m_lo; break; + case 0x13: /* MTLO */ m_lo = RSVAL; break; + case 0x18: /* MULT */ + { + u64 product = mul_32x32(RSVAL, RTVAL); m_lo = product; m_hi = product >> 32; m_icount -= 11; } break; - case 0x19: // MULTU + case 0x19: /* MULTU */ { - u64 product = mulu_32x32(m_r[RSREG], m_r[RTREG]); + u64 product = mulu_32x32(RSVAL, RTVAL); m_lo = product; m_hi = product >> 32; m_icount -= 11; } break; - case 0x1a: // DIV - if (m_r[RTREG]) - { - m_lo = s32(m_r[RSREG]) / s32(m_r[RTREG]); - m_hi = s32(m_r[RSREG]) % s32(m_r[RTREG]); + case 0x1a: /* DIV */ + if (RTVAL) + { + m_lo = s32(RSVAL) / s32(RTVAL); + m_hi = s32(RSVAL) % s32(RTVAL); + } + m_icount -= 34; + break; + case 0x1b: /* DIVU */ + if (RTVAL) + { + m_lo = RSVAL / RTVAL; + m_hi = RSVAL % RTVAL; + } + m_icount -= 34; + break; + case 0x20: /* ADD */ + { + u32 const sum = RSVAL + RTVAL; + + // overflow: (sign(addend0) == sign(addend1)) && (sign(addend0) != sign(sum)) + if (!BIT(RSVAL ^ RTVAL, 31) && BIT(RSVAL ^ sum, 31)) + generate_exception(EXCEPTION_OVERFLOW); + else if (RDREG) + RDVAL = sum; + } + break; + case 0x21: /* ADDU */ if (RDREG) RDVAL = RSVAL + RTVAL; break; + case 0x22: /* SUB */ + { + u32 const difference = RSVAL - RTVAL; + + // overflow: (sign(minuend) != sign(subtrahend)) && (sign(minuend) != sign(difference)) + if (BIT(RSVAL ^ RTVAL, 31) && BIT(RSVAL ^ difference, 31)) + generate_exception(EXCEPTION_OVERFLOW); + else if (RDREG) + RDVAL = difference; + } + break; + case 0x23: /* SUBU */ if (RDREG) RDVAL = RSVAL - RTVAL; break; + case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break; + case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break; + case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break; + case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; + case 0x2a: /* SLT */ if (RDREG) RDVAL = s32(RSVAL) < s32(RTVAL); break; + case 0x2b: /* SLTU */ if (RDREG) RDVAL = u32(RSVAL) < u32(RTVAL); break; + case 0x30: /* TEQ */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x31: /* TGEU */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x32: /* TLT */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x33: /* TLTU */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x34: /* TGE */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x36: /* TNE */ generate_exception(EXCEPTION_INVALIDOP); break; + default: /* ??? */ generate_exception(EXCEPTION_INVALIDOP); break; } - m_icount -= 34; break; - case 0x1b: // DIVU - if (m_r[RTREG]) + + case 0x01: /* REGIMM */ + switch (RTREG) { - m_lo = m_r[RSREG] / m_r[RTREG]; - m_hi = m_r[RSREG] % m_r[RTREG]; + case 0x00: /* BLTZ */ if (s32(RSVAL) < 0) ADDPC(SIMMVAL); break; + case 0x01: /* BGEZ */ if (s32(RSVAL) >= 0) ADDPC(SIMMVAL); break; + case 0x02: /* BLTZL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x03: /* BGEZL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x08: /* TGEI */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x09: /* TGEIU */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x0a: /* TLTI */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x0b: /* TLTIU */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x0c: /* TEQI */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x0e: /* TNEI */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x10: /* BLTZAL */ if (s32(RSVAL) < 0) ADDPCL(SIMMVAL, 31); break; + case 0x11: /* BGEZAL */ if (s32(RSVAL) >= 0) ADDPCL(SIMMVAL, 31); break; + case 0x12: /* BLTZALL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x13: /* BGEZALL */ generate_exception(EXCEPTION_INVALIDOP); break; + default: /* ??? */ generate_exception(EXCEPTION_INVALIDOP); break; } - m_icount -= 34; break; - case 0x20: // ADD - { - u32 const sum = m_r[RSREG] + m_r[RTREG]; - // overflow: (sign(addend0) == sign(addend1)) && (sign(addend0) != sign(sum)) - if (!BIT(m_r[RSREG] ^ m_r[RTREG], 31) && BIT(m_r[RSREG] ^ sum, 31)) - generate_exception(EXCEPTION_OVERFLOW); - else - m_r[RDREG] = sum; - } - break; - case 0x21: // ADDU - m_r[RDREG] = m_r[RSREG] + m_r[RTREG]; - break; - case 0x22: // SUB + case 0x02: /* J */ ABSPC(LIMMVAL); break; + case 0x03: /* JAL */ ABSPCL(LIMMVAL, 31); break; + case 0x04: /* BEQ */ if (RSVAL == RTVAL) ADDPC(SIMMVAL); break; + case 0x05: /* BNE */ if (RSVAL != RTVAL) ADDPC(SIMMVAL); break; + case 0x06: /* BLEZ */ if (s32(RSVAL) <= 0) ADDPC(SIMMVAL); break; + case 0x07: /* BGTZ */ if (s32(RSVAL) > 0) ADDPC(SIMMVAL); break; + case 0x08: /* ADDI */ { - u32 const difference = m_r[RSREG] - m_r[RTREG]; + u32 const sum = RSVAL + SIMMVAL; - // overflow: (sign(minuend) != sign(subtrahend)) && (sign(minuend) != sign(difference)) - if (BIT(m_r[RSREG] ^ m_r[RTREG], 31) && BIT(m_r[RSREG] ^ difference, 31)) + // overflow: (sign(addend0) == sign(addend1)) && (sign(addend0) != sign(sum)) + if (!BIT(RSVAL ^ s32(SIMMVAL), 31) && BIT(RSVAL ^ sum, 31)) generate_exception(EXCEPTION_OVERFLOW); - else - m_r[RDREG] = difference; - } - break; - case 0x23: // SUBU - m_r[RDREG] = m_r[RSREG] - m_r[RTREG]; - break; - case 0x24: // AND - m_r[RDREG] = m_r[RSREG] & m_r[RTREG]; - break; - case 0x25: // OR - m_r[RDREG] = m_r[RSREG] | m_r[RTREG]; - break; - case 0x26: // XOR - m_r[RDREG] = m_r[RSREG] ^ m_r[RTREG]; - break; - case 0x27: // NOR - m_r[RDREG] = ~(m_r[RSREG] | m_r[RTREG]); - break; - case 0x2a: // SLT - m_r[RDREG] = s32(m_r[RSREG]) < s32(m_r[RTREG]); - break; - case 0x2b: // SLTU - m_r[RDREG] = u32(m_r[RSREG]) < u32(m_r[RTREG]); - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - break; - case 0x01: // REGIMM - switch (RTREG) - { - case 0x00: // BLTZ - if (s32(m_r[RSREG]) < 0) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); + else if (RTREG) + RTVAL = sum; } break; - case 0x01: // BGEZ - if (s32(m_r[RSREG]) >= 0) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } + case 0x09: /* ADDIU */ if (RTREG) RTVAL = RSVAL + SIMMVAL; break; + case 0x0a: /* SLTI */ if (RTREG) RTVAL = s32(RSVAL) < s32(SIMMVAL); break; + case 0x0b: /* SLTIU */ if (RTREG) RTVAL = u32(RSVAL) < u32(SIMMVAL); break; + case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMMVAL; break; + case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMMVAL; break; + case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMMVAL; break; + case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMMVAL << 16; break; + case 0x10: /* COP0 */ + if (!(SR & SR_KUc) || (SR & SR_COP0)) + handle_cop0(op); + else + generate_exception(EXCEPTION_BADCOP); break; - case 0x10: // BLTZAL - if (s32(m_r[RSREG]) < 0) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - m_r[31] = m_pc + 8; - } + case 0x11: // COP1 + if (SR & SR_COP1) + handle_cop1(op); + else + generate_exception(EXCEPTION_BADCOP); break; - case 0x11: // BGEZAL - if (s32(m_r[RSREG]) >= 0) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - m_r[31] = m_pc + 8; - } + case 0x12: // COP2 + if (SR & SR_COP2) + handle_cop<2>(op); + else + generate_exception(EXCEPTION_BADCOP); break; - default: - generate_exception(EXCEPTION_INVALIDOP); + case 0x13: // COP3 + if (SR & SR_COP3) + handle_cop<3>(op); + else + generate_exception(EXCEPTION_BADCOP); break; + case 0x14: /* BEQL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x15: /* BNEL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x16: /* BLEZL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x17: /* BGTZL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x20: /* LB */ load(SIMMVAL + RSVAL, [this, op](s8 temp) { if (RTREG) RTVAL = temp; }); break; + case 0x21: /* LH */ load(SIMMVAL + RSVAL, [this, op](s16 temp) { if (RTREG) RTVAL = temp; }); break; + case 0x22: /* LWL */ lwl(op); break; + case 0x23: /* LW */ load(SIMMVAL + RSVAL, [this, op](u32 temp) { if (RTREG) RTVAL = temp; }); break; + case 0x24: /* LBU */ load(SIMMVAL + RSVAL, [this, op](u8 temp) { if (RTREG) RTVAL = temp; }); break; + case 0x25: /* LHU */ load(SIMMVAL + RSVAL, [this, op](u16 temp) { if (RTREG) RTVAL = temp; }); break; + case 0x26: /* LWR */ lwr(op); break; + case 0x28: /* SB */ store(SIMMVAL + RSVAL, RTVAL); break; + case 0x29: /* SH */ store(SIMMVAL + RSVAL, RTVAL); break; + case 0x2a: /* SWL */ swl(op); break; + case 0x2b: /* SW */ store(SIMMVAL + RSVAL, RTVAL); break; + case 0x2e: /* SWR */ swr(op); break; + case 0x2f: /* CACHE */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x30: /* LL */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x31: /* LWC1 */ load(SIMMVAL + RSVAL, [this, op](u32 temp) { set_cop_reg<1>(RTREG, temp); }); break; + case 0x32: /* LWC2 */ load(SIMMVAL + RSVAL, [this, op](u32 temp) { set_cop_reg<2>(RTREG, temp); }); break; + case 0x33: /* LWC3 */ load(SIMMVAL + RSVAL, [this, op](u32 temp) { set_cop_reg<3>(RTREG, temp); }); break; + case 0x34: /* LDC0 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x35: /* LDC1 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x36: /* LDC2 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x37: /* LDC3 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x38: /* SC */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x39: /* LWC1 */ store(SIMMVAL + RSVAL, get_cop_reg<1>(RTREG)); break; + case 0x3a: /* LWC2 */ store(SIMMVAL + RSVAL, get_cop_reg<2>(RTREG)); break; + case 0x3b: /* LWC3 */ store(SIMMVAL + RSVAL, get_cop_reg<3>(RTREG)); break; + case 0x3c: /* SDC0 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x3d: /* SDC1 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x3e: /* SDC2 */ generate_exception(EXCEPTION_INVALIDOP); break; + case 0x3f: /* SDC3 */ generate_exception(EXCEPTION_INVALIDOP); break; + default: /* ??? */ generate_exception(EXCEPTION_INVALIDOP); break; } + + // update pc and branch state + switch (m_branch_state) + { + case NONE: + m_pc += 4; break; - case 0x02: // J - m_branch_state = BRANCH; - m_branch_target = ((m_pc + 4) & 0xf0000000) | (LIMMVAL << 2); - break; - case 0x03: // JAL - m_branch_state = BRANCH; - m_branch_target = ((m_pc + 4) & 0xf0000000) | (LIMMVAL << 2); - m_r[31] = m_pc + 8; + + case DELAY: + m_branch_state = NONE; + m_pc = m_branch_target; break; - case 0x04: // BEQ - if (m_r[RSREG] == m_r[RTREG]) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x05: // BNE - if (m_r[RSREG] != m_r[RTREG]) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x06: // BLEZ - if (s32(m_r[RSREG]) <= 0) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x07: // BGTZ - if (s32(m_r[RSREG]) > 0) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x08: // ADDI - { - u32 const sum = m_r[RSREG] + SIMMVAL; - - // overflow: (sign(addend0) == sign(addend1)) && (sign(addend0) != sign(sum)) - if (!BIT(m_r[RSREG] ^ s32(SIMMVAL), 31) && BIT(m_r[RSREG] ^ sum, 31)) - generate_exception(EXCEPTION_OVERFLOW); - else - m_r[RTREG] = sum; - } - break; - case 0x09: // ADDIU - m_r[RTREG] = m_r[RSREG] + SIMMVAL; - break; - case 0x0a: // SLTI - m_r[RTREG] = s32(m_r[RSREG]) < s32(SIMMVAL); - break; - case 0x0b: // SLTIU - m_r[RTREG] = u32(m_r[RSREG]) < u32(SIMMVAL); - break; - case 0x0c: // ANDI - m_r[RTREG] = m_r[RSREG] & UIMMVAL; - break; - case 0x0d: // ORI - m_r[RTREG] = m_r[RSREG] | UIMMVAL; - break; - case 0x0e: // XORI - m_r[RTREG] = m_r[RSREG] ^ UIMMVAL; - break; - case 0x0f: // LUI - m_r[RTREG] = UIMMVAL << 16; - break; - case 0x10: // COP0 - if (!(SR & SR_KUc) || (SR & SR_COP0)) - handle_cop0(op); - else - generate_exception(EXCEPTION_BADCOP0); - break; - case 0x11: // COP1 - handle_cop1(op); - break; - case 0x12: // COP2 - handle_cop2(op); - break; - case 0x13: // COP3 - handle_cop3(op); - break; - case 0x20: // LB - load(SIMMVAL + m_r[RSREG], [this, op](s8 temp) { m_r[RTREG] = temp; }); - break; - case 0x21: // LH - load(SIMMVAL + m_r[RSREG], [this, op](s16 temp) { m_r[RTREG] = temp; }); - break; - case 0x22: // LWL - lwl(op); - break; - case 0x23: // LW - load(SIMMVAL + m_r[RSREG], [this, op](u32 temp) { m_r[RTREG] = temp; }); - break; - case 0x24: // LBU - load(SIMMVAL + m_r[RSREG], [this, op](u8 temp) { m_r[RTREG] = temp; }); - break; - case 0x25: // LHU - load(SIMMVAL + m_r[RSREG], [this, op](u16 temp) { m_r[RTREG] = temp; }); - break; - case 0x26: // LWR - lwr(op); - break; - case 0x28: // SB - store(SIMMVAL + m_r[RSREG], m_r[RTREG]); - break; - case 0x29: // SH - store(SIMMVAL + m_r[RSREG], m_r[RTREG]); - break; - case 0x2a: // SWL - swl(op); - break; - case 0x2b: // SW - store(SIMMVAL + m_r[RSREG], m_r[RTREG]); - break; - case 0x2e: // SWR - swr(op); - break; - case 0x31: // LWC1 - handle_cop1(op); - break; - case 0x32: // LWC2 - handle_cop2(op); - break; - case 0x33: // LWC3 - handle_cop3(op); - break; - case 0x39: // SWC1 - handle_cop1(op); - break; - case 0x3a: // SWC2 - handle_cop2(op); - break; - case 0x3b: // SWC3 - handle_cop3(op); - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - - // update pc and branch state - switch (m_branch_state) - { - case NONE: - m_pc += 4; - break; - - case DELAY: - m_branch_state = NONE; - m_pc = m_branch_target; - break; - - case BRANCH: - m_branch_state = DELAY; - m_pc += 4; - break; - - case EXCEPTION: - m_branch_state = NONE; - break; - } - - // clear register 0 - m_r[0] = 0; - }); - } -} - -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); - - check_irqs(); -} - -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) - }; -} - -bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t &address) -{ - // check for kernel memory address - if (BIT(address, 31)) - { - // check debug or kernel mode - if ((intention & TRANSLATE_DEBUG_MASK) || !(SR & SR_KUc)) - { - switch (address & 0xe0000000) - { - case 0x80000000: // kseg0: unmapped, cached, privileged - case 0xa0000000: // kseg1: unmapped, uncached, privileged - address &= ~0xe0000000; - break; - - case 0xc0000000: // kseg2: mapped, cached, privileged - case 0xe0000000: - break; - } - } - else if (SR & SR_KUc) - { - if (!machine().side_effects_disabled()) - { - // exception - m_cop0[COP0_BadVAddr] = address; - - generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); - } - return false; - } - } - else - // kuseg physical addresses have a 1GB offset - address += 0x40000000; - - return true; -} - -std::unique_ptr mips1core_device_base::create_disassembler() -{ - return std::make_unique(); -} - -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; - - // load the cause register - CAUSE = (CAUSE & CAUSE_IP) | exception; - - // if in a branch delay slot, restart the branch - if (m_branch_state == DELAY) - { - m_cop0[COP0_EPC] -= 4; - CAUSE |= CAUSE_BD; - } - 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; - - debugger_exception_hook(exception); - - if (SR & SR_KUp) - debugger_privilege_hook(); -} - -void mips1core_device_base::check_irqs() -{ - if ((CAUSE & SR & SR_IM) && (SR & SR_IEc)) - generate_exception(EXCEPTION_INTERRUPT); -} - -void mips1core_device_base::handle_cop0(u32 const op) -{ - switch (RSREG) - { - case 0x00: // MFC0 - m_r[RTREG] = get_cop0_reg(RDREG); - break; - case 0x04: // MTC0 - set_cop0_reg(RDREG, m_r[RTREG]); - break; - case 0x08: // BC0 - switch (RTREG) - { - case 0x00: // BC0F - if (!m_in_brcond[0]()) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x01: // BC0T - if (m_in_brcond[0]()) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - break; - case 0x10: // COP0 - switch (op & 31) - { - case 0x10: // RFE - SR = (SR & ~SR_KUIEpc) | ((SR >> 2) & SR_KUIEpc); - if (bool(SR & SR_KUc) ^ bool(SR & SR_KUp)) - debugger_privilege_hook(); - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } -} - -u32 mips1core_device_base::get_cop0_reg(unsigned const reg) -{ - return m_cop0[reg]; -} - -void mips1core_device_base::set_cop0_reg(unsigned const reg, u32 const data) -{ - switch (reg) - { - case COP0_Context: - m_cop0[COP0_Context] = (m_cop0[COP0_Context] & ~PTE_BASE) | (data & PTE_BASE); - break; - case COP0_Status: - { - u32 const delta = SR ^ data; - - m_cop0[COP0_Status] = data; - - // handle cache isolation and swap - m_data_spacenum = (data & SR_IsC) ? ((data & SR_SwC) ? 1 : 2) : 0; - - // update interrupts - if (delta & (SR_IEc | SR_IM)) - check_irqs(); - - if ((delta & SR_KUc) && (m_branch_state != EXCEPTION)) - debugger_privilege_hook(); - } - break; - case COP0_Cause: - CAUSE = (CAUSE & CAUSE_IPEX) | (data & ~CAUSE_IPEX); - - // update interrupts -- software ints can occur this way - check_irqs(); - break; - case COP0_PRId: - // read-only register - break; - - default: - m_cop0[reg] = data; - break; - } -} - -void mips1core_device_base::handle_cop1(u32 const op) -{ - if (!(SR & SR_COP1)) - generate_exception(EXCEPTION_BADCOP1); -} - -void mips1core_device_base::handle_cop2(u32 const op) -{ - if (SR & SR_COP2) - { - switch (RSREG) - { - case 0x08: // BC2 - switch (RTREG) - { - case 0x00: // BC2F - if (!m_in_brcond[2]()) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x01: // BC2T - if (m_in_brcond[2]()) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - } - else - generate_exception(EXCEPTION_BADCOP2); -} - -void mips1core_device_base::handle_cop3(u32 const op) -{ - if (SR & SR_COP3) - { - switch (RSREG) - { - case 0x08: // BC3 - switch (RTREG) - { - case 0x00: // BC3F - if (!m_in_brcond[3]()) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x01: // BC3T - if (m_in_brcond[3]()) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - break; - default: - generate_exception(EXCEPTION_INVALIDOP); - break; - } - } - else - generate_exception(EXCEPTION_BADCOP3); -} - -void mips1core_device_base::lwl(u32 const op) -{ - offs_t const offset = SIMMVAL + m_r[RSREG]; - load(offset & ~3, [this, op, offset](u32 temp) - { - unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3; - - m_r[RTREG] = (m_r[RTREG] & ~u32(0xffffffffU << shift)) | (temp << shift); - }); -} - -void mips1core_device_base::lwr(u32 const op) -{ - offs_t const offset = SIMMVAL + m_r[RSREG]; - load(offset & ~3, [this, op, offset](u32 temp) - { - unsigned const shift = ((offset & 0x3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3; - - m_r[RTREG] = (m_r[RTREG] & ~u32(0xffffffffU >> shift)) | (temp >> shift); - }); -} - -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; - - store(offset & ~3, 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; - - store(offset & ~3, m_r[RTREG] << shift, 0xffffffffU << shift); -} - -template std::enable_if_t>::value, void> mips1core_device_base::load(u32 address, U &&apply) -{ - if (memory_translate(m_data_spacenum, TRANSLATE_READ, address)) - { - switch (sizeof(T)) - { - case 1: apply(T(space(m_data_spacenum).read_byte(address))); break; - case 2: apply(T(space(m_data_spacenum).read_word(address))); break; - case 4: apply(T(space(m_data_spacenum).read_dword(address))); break; - } - } -} - -template std::enable_if_t::value, void> mips1core_device_base::store(u32 address, U data, T mem_mask) -{ - 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; - } - } -} - -bool mips1core_device_base::fetch(u32 address, std::function &&apply) -{ - if (memory_translate(0, TRANSLATE_FETCH, address)) - { - apply(space(0).read_dword(address)); - - return true; - } - else - return false; -} - -std::string mips1core_device_base::debug_string(u32 string_pointer, unsigned const limit) -{ - auto const suppressor(machine().disable_side_effects()); - - bool done = false; - bool mapped = false; - std::string result(""); - - while (!done) - { - done = true; - load(string_pointer++, [limit, &done, &mapped, &result](u8 byte) - { - mapped = true; - if (byte != 0) - { - result += byte; - - done = result.length() == limit; - } - }); - } - - if (!mapped) - result.assign("[unmapped]"); - - return result; -} - -std::string mips1core_device_base::debug_string_array(u32 array_pointer) -{ - auto const suppressor(machine().disable_side_effects()); - - bool done = false; - std::string result(""); - - while (!done) - { - done = true; - load(array_pointer, [this, &done, &result](u32 string_pointer) - { - if (string_pointer != 0) - { - if (!result.empty()) - result += ", "; - - result += '\"' + debug_string(string_pointer) + '\"'; - - done = false; - } - }); - - array_pointer += 4; - } - - return result; -} - -void mips1_device_base::device_start() -{ - mips1core_device_base::device_start(); - - // cop0 tlb registers - state_add(MIPS1_COP0 + COP0_Index, "Index", m_cop0[COP0_Index]); - state_add(MIPS1_COP0 + COP0_Random, "Random", m_cop0[COP0_Random]); - state_add(MIPS1_COP0 + COP0_EntryLo, "EntryLo", m_cop0[COP0_EntryLo]); - state_add(MIPS1_COP0 + COP0_EntryHi, "EntryHi", m_cop0[COP0_EntryHi]); - state_add(MIPS1_COP0 + COP0_Context, "Context", m_cop0[COP0_Context]); - - // cop1 registers - if (m_fcr0) - { - state_add(MIPS1_FCR31, "FCSR", m_fcr31); - for (unsigned i = 0; i < ARRAY_LENGTH(m_f); i++) - state_add(MIPS1_F0 + i, util::string_format("F%d", i).c_str(), m_f[i]); - } - - save_item(NAME(m_reset_time)); - save_item(NAME(m_tlb)); - - save_item(NAME(m_fcr30)); - save_item(NAME(m_fcr31)); - save_item(NAME(m_f)); -} - -void mips1_device_base::device_reset() -{ - mips1core_device_base::device_reset(); - - // tlb is not shut down - m_cop0[COP0_Status] &= ~SR_TS; - - m_reset_time = total_cycles(); - - // initialize tlb mru index with identity mapping - for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++) - { - m_tlb_mru[TRANSLATE_READ][i] = i; - m_tlb_mru[TRANSLATE_WRITE][i] = i; - m_tlb_mru[TRANSLATE_FETCH][i] = i; - } -} - -void mips1_device_base::handle_cop0(u32 const op) -{ - switch (op) - { - case 0x42000001: // TLBR - read tlb - { - u8 const index = (m_cop0[COP0_Index] >> 8) & 0x3f; - - m_cop0[COP0_EntryHi] = m_tlb[index][0]; - m_cop0[COP0_EntryLo] = m_tlb[index][1]; - } - break; - - case 0x42000002: // TLBWI - write tlb (indexed) - { - u8 const index = (m_cop0[COP0_Index] >> 8) & 0x3f; - - m_tlb[index][0] = m_cop0[COP0_EntryHi]; - m_tlb[index][1] = m_cop0[COP0_EntryLo]; - - LOGMASKED(LOG_TLB, "tlb write index %d asid %d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", - index, (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, m_cop0[COP0_EntryHi] & EH_VPN, m_cop0[COP0_EntryLo] & EL_PFN, - m_cop0[COP0_EntryLo] & EL_N ? 'N' : '-', - m_cop0[COP0_EntryLo] & EL_D ? 'D' : '-', - m_cop0[COP0_EntryLo] & EL_V ? 'V' : '-', - m_cop0[COP0_EntryLo] & EL_G ? 'G' : '-', - machine().describe_context()); - } - break; - - case 0x42000006: // TLBWR - write tlb (random) - { - u8 const random = get_cop0_reg(COP0_Random) >> 8; - - m_tlb[random][0] = m_cop0[COP0_EntryHi]; - m_tlb[random][1] = m_cop0[COP0_EntryLo]; - - LOGMASKED(LOG_TLB, "tlb write random %d asid %d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", - random, (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, m_cop0[COP0_EntryHi] & EH_VPN, m_cop0[COP0_EntryLo] & EL_PFN, - m_cop0[COP0_EntryLo] & EL_N ? 'N' : '-', - m_cop0[COP0_EntryLo] & EL_D ? 'D' : '-', - m_cop0[COP0_EntryLo] & EL_V ? 'V' : '-', - m_cop0[COP0_EntryLo] & EL_G ? 'G' : '-', - machine().describe_context()); - } - break; - case 0x42000008: // TLBP - probe tlb - m_cop0[COP0_Index] = 0x80000000; - for (u8 index = 0; index < 64; index++) - { - // test vpn and optionally asid - u32 const mask = (m_tlb[index][1] & EL_G) ? EH_VPN : EH_VPN | EH_ASID; - if ((m_tlb[index][0] & mask) == (m_cop0[COP0_EntryHi] & mask)) - { - LOGMASKED(LOG_TLB, "tlb probe hit vpn 0x%08x index %d (%s)\n", - m_cop0[COP0_EntryHi] & mask, index, machine().describe_context()); + case BRANCH: + m_branch_state = DELAY; + m_pc += 4; + break; - m_cop0[COP0_Index] = index << 8; + case EXCEPTION: + m_branch_state = NONE; break; } - } - if ((VERBOSE & LOG_TLB) && BIT(m_cop0[COP0_Index], 31)) - LOGMASKED(LOG_TLB, "tlb probe miss asid %d vpn 0x%08x(%s)\n", - (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, m_cop0[COP0_EntryHi] & EH_VPN, machine().describe_context()); - break; + }); + m_icount--; - default: - mips1core_device_base::handle_cop0(op); - } + } while (m_icount > 0 || m_branch_state); } -u32 mips1_device_base::get_cop0_reg(unsigned const reg) +void mips1core_device_base::lwl(u32 const op) { - // assume 64-entry tlb with 8 wired entries - if (reg == COP0_Random) - m_cop0[reg] = (63 - ((total_cycles() - m_reset_time) % 56)) << 8; + offs_t const offset = SIMMVAL + RSVAL; + load(offset & ~3, [this, op, offset](u32 temp) + { + if (RTREG) + { + unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3; - return m_cop0[reg]; + RTVAL = (RTVAL & ~u32(0xffffffffU << shift)) | (temp << shift); + } + }); } -void mips1_device_base::handle_cop1(u32 const op) +void mips1core_device_base::lwr(u32 const op) { - if (!(SR & SR_COP1)) - { - generate_exception(EXCEPTION_BADCOP1); - return; - } - - if (!m_fcr0) - return; - - switch (op >> 26) + offs_t const offset = SIMMVAL + RSVAL; + load(offset & ~3, [this, op, offset](u32 temp) { - case 0x11: // COP1 - switch ((op >> 21) & 0x1f) + if (RTREG) { - case 0x00: // MFC1 - if (FSREG & 1) - // move the high half of the floating point register - m_r[RTREG] = m_f[FSREG >> 1] >> 32; - else - // move the low half of the floating point register - m_r[RTREG] = m_f[FSREG >> 1] >> 0; - break; - case 0x02: // CFC1 - switch (FSREG) - { - case 0: m_r[RTREG] = m_fcr0; break; - case 30: m_r[RTREG] = m_fcr30; break; - case 31: m_r[RTREG] = m_fcr31; break; - break; - - default: - logerror("cfc1 undefined fpu control register %d (%s)\n", FSREG, machine().describe_context()); - break; - } - break; - case 0x04: // MTC1 - if (FSREG & 1) - // load the high half of the floating point register - m_f[FSREG >> 1] = (u64(m_r[RTREG]) << 32) | u32(m_f[FSREG >> 1]); - else - // load the low half of the floating point register - m_f[FSREG >> 1] = (m_f[FSREG >> 1] & ~0xffffffffULL) | m_r[RTREG]; - break; - case 0x06: // CTC1 - switch (RDREG) - { - case 0: // register is read-only - break; - - case 30: - m_fcr30 = m_r[RTREG]; - break; - - case 31: - m_fcr31 = m_r[RTREG]; - - // update rounding mode - switch (m_fcr31 & FCR31_RM) - { - case 0: softfloat_roundingMode = softfloat_round_near_even; break; - case 1: softfloat_roundingMode = softfloat_round_minMag; break; - case 2: softfloat_roundingMode = softfloat_round_max; break; - case 3: softfloat_roundingMode = softfloat_round_min; break; - } - - // exception check - if ((m_fcr31 & FCR31_CE) || ((m_fcr31 & FCR31_CM) >> 5) & (m_fcr31 & FCR31_EM)) - execute_set_input(m_fpu_irq, ASSERT_LINE); - break; - - default: - logerror("ctc1 undefined fpu control register %d (%s)\n", RDREG, machine().describe_context()); - break; - } - break; - case 0x08: // BC - switch ((op >> 16) & 0x1f) - { - case 0x00: // BC1F - if (!(m_fcr31 & FCR31_C)) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - case 0x01: // BC1T - if (m_fcr31 & FCR31_C) - { - m_branch_state = BRANCH; - m_branch_target = m_pc + 4 + (s32(SIMMVAL) << 2); - } - break; - - default: - // unimplemented operation - m_fcr31 |= FCR31_CE; - execute_set_input(m_fpu_irq, ASSERT_LINE); - break; - } - break; - case 0x10: // S - switch (op & 0x3f) - { - case 0x00: // ADD.S - set_cop1_reg(FDREG >> 1, f32_add(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }).v); - break; - case 0x01: // SUB.S - set_cop1_reg(FDREG >> 1, f32_sub(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }).v); - break; - case 0x02: // MUL.S - set_cop1_reg(FDREG >> 1, f32_mul(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }).v); - break; - case 0x03: // DIV.S - set_cop1_reg(FDREG >> 1, f32_div(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }).v); - break; - case 0x05: // ABS.S - if (f32_lt(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ 0 })) - set_cop1_reg(FDREG >> 1, f32_mul(float32_t{ u32(m_f[FSREG >> 1]) }, i32_to_f32(-1)).v); - else - set_cop1_reg(FDREG >> 1, m_f[FSREG >> 1]); - break; - case 0x06: // MOV.S - m_f[FDREG >> 1] = m_f[FSREG >> 1]; - break; - case 0x07: // NEG.S - set_cop1_reg(FDREG >> 1, f32_mul(float32_t{ u32(m_f[FSREG >> 1]) }, i32_to_f32(-1)).v); - break; - - case 0x21: // CVT.D.S - 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)); - break; - - case 0x30: // C.F.S (false) - m_fcr31 &= ~FCR31_C; - break; - case 0x31: // C.UN.S (unordered) - f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }); - if (softfloat_exceptionFlags & softfloat_flag_invalid) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x32: // C.EQ.S (equal) - if (f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x33: // C.UEQ.S (unordered equal) - if (f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x34: // C.OLT.S (less than) - if (f32_lt(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x35: // C.ULT.S (unordered less than) - if (f32_lt(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x36: // C.OLE.S (less than or equal) - if (f32_le(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x37: // C.ULE.S (unordered less than or equal) - if (f32_le(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - - case 0x38: // C.SF.S (signalling false) - f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }); - - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x39: // C.NGLE.S (not greater, less than or equal) - f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }); - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_C | FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - else - m_fcr31 &= ~FCR31_C; - break; - case 0x3a: // C.SEQ.S (signalling equal) - if (f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3b: // C.NGL.S (not greater or less than) - if (f32_eq(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3c: // C.LT.S (less than) - if (f32_lt(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3d: // C.NGE.S (not greater or equal) - if (f32_lt(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3e: // C.LE.S (less than or equal) - if (f32_le(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3f: // C.NGT.S (not greater than) - if (f32_le(float32_t{ u32(m_f[FSREG >> 1]) }, float32_t{ u32(m_f[FTREG >> 1]) }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - - default: // unimplemented operation - m_fcr31 |= FCR31_CE; - execute_set_input(m_fpu_irq, ASSERT_LINE); - break; - } - break; - case 0x11: // D - switch (op & 0x3f) - { - case 0x00: // ADD.D - set_cop1_reg(FDREG >> 1, f64_add(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }).v); - break; - case 0x01: // SUB.D - set_cop1_reg(FDREG >> 1, f64_sub(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }).v); - break; - case 0x02: // MUL.D - set_cop1_reg(FDREG >> 1, f64_mul(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }).v); - break; - case 0x03: // DIV.D - set_cop1_reg(FDREG >> 1, f64_div(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }).v); - break; + unsigned const shift = ((offset & 0x3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3; - case 0x05: // ABS.D - if (f64_lt(float64_t{ m_f[FSREG >> 1] }, float64_t{ 0 })) - set_cop1_reg(FDREG >> 1, f64_mul(float64_t{ m_f[FSREG >> 1] }, i32_to_f64(-1)).v); - else - set_cop1_reg(FDREG >> 1, m_f[FSREG >> 1]); - break; - case 0x06: // MOV.D - m_f[FDREG >> 1] = m_f[FSREG >> 1]; - break; - case 0x07: // NEG.D - set_cop1_reg(FDREG >> 1, f64_mul(float64_t{ m_f[FSREG >> 1] }, i32_to_f64(-1)).v); - break; + RTVAL = (RTVAL & ~u32(0xffffffffU >> shift)) | (temp >> shift); + } + }); +} - case 0x20: // CVT.S.D - 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)); - break; +void mips1core_device_base::swl(u32 const op) +{ + offs_t const offset = SIMMVAL + RSVAL; + unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 3, 0)) << 3; - case 0x30: // C.F.D (false) - m_fcr31 &= ~FCR31_C; - break; - case 0x31: // C.UN.D (unordered) - f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }); - if (softfloat_exceptionFlags & softfloat_flag_invalid) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x32: // C.EQ.D (equal) - if (f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x33: // C.UEQ.D (unordered equal) - if (f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x34: // C.OLT.D (less than) - if (f64_lt(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x35: // C.ULT.D (unordered less than) - if (f64_lt(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x36: // C.OLE.D (less than or equal) - if (f64_le(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; - case 0x37: // C.ULE.D (unordered less than or equal) - if (f64_le(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; - break; + // only load if necessary + if (shift) + { + load(offset & ~3, [this, op, offset, shift](u32 temp) + { + store(offset & ~3, (temp & ~u32(0xffffffffU >> shift)) | (RTVAL >> shift)); + }); + } + else + store(offset & ~3, RTVAL); +} - case 0x38: // C.SF.D (signalling false) - f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }); - m_fcr31 &= ~FCR31_C; +void mips1core_device_base::swr(u32 const op) +{ + offs_t const offset = SIMMVAL + RSVAL; + unsigned const shift = ((offset & 3) ^ ENDIAN_VALUE_LE_BE(m_endianness, 0, 3)) << 3; - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x39: // C.NGLE.D (not greater, less than or equal) - f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }); + // only load if necessary + if (shift) + { + load(offset & ~3, [this, op, offset, shift](u32 temp) + { + store(offset & ~3, (temp & ~u32(0xffffffffU << shift)) | (RTVAL << shift)); + }); + } + else + store(offset & ~3, RTVAL); +} - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_C | FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - else - m_fcr31 &= ~FCR31_C; - break; - case 0x3a: // C.SEQ.D (signalling equal) - if (f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; +template std::enable_if_t>::value, void> mips1core_device_base::load(u32 program_address, U &&apply) +{ + offs_t translated_address = program_address; - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3b: // C.NGL.D (not greater or less than) - if (f64_eq(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; + if (memory_translate(m_data_spacenum, TRANSLATE_READ, translated_address)) + { + switch (sizeof(T)) + { + case 1: apply(T(space(m_data_spacenum).read_byte(translated_address))); break; + case 2: apply(T(space(m_data_spacenum).read_word(translated_address))); break; + case 4: apply(T(space(m_data_spacenum).read_dword(translated_address))); break; + } + } +} - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3c: // C.LT.D (less than) - if (f64_lt(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; +template std::enable_if_t::value, void> mips1core_device_base::store(u32 program_address, U data) +{ + offs_t translated_address = program_address; - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3d: // C.NGE.D (not greater or equal) - if (f64_lt(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; + if (memory_translate(m_data_spacenum, TRANSLATE_WRITE, translated_address)) + { + switch (sizeof(T)) + { + case 1: space(m_data_spacenum).write_byte(translated_address, T(data)); break; + case 2: space(m_data_spacenum).write_word(translated_address, T(data)); break; + case 4: space(m_data_spacenum).write_dword(translated_address, T(data)); break; + } + } +} - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3e: // C.LE.D (less than or equal) - if (f64_le(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] })) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; +bool mips1core_device_base::fetch(u32 program_address, std::function &&apply) +{ + offs_t translated_address = program_address; - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; - case 0x3f: // C.NGT.D (not greater than) - if (f64_le(float64_t{ m_f[FSREG >> 1] }, float64_t{ m_f[FTREG >> 1] }) || (softfloat_exceptionFlags & softfloat_flag_invalid)) - m_fcr31 |= FCR31_C; - else - m_fcr31 &= ~FCR31_C; + if (memory_translate(0, TRANSLATE_FETCH, translated_address)) + { + apply(space(0).read_dword(translated_address)); - if (softfloat_exceptionFlags & softfloat_flag_invalid) - { - m_fcr31 |= FCR31_CV; - execute_set_input(m_fpu_irq, ASSERT_LINE); - } - break; + return true; + } + else + return false; +} - default: // unimplemented operation - m_fcr31 |= FCR31_CE; - execute_set_input(m_fpu_irq, ASSERT_LINE); - break; - } - break; - case 0x14: // W - switch (op & 0x3f) +bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t &address) +{ + // check for kernel memory address + if (BIT(address, 31)) + { + // check debug or kernel mode + if ((intention & TRANSLATE_DEBUG_MASK) || !(SR & SR_KUc)) + { + switch (address & 0xe0000000) { - case 0x20: // CVT.S.W - set_cop1_reg(FDREG >> 1, i32_to_f32(s32(m_f[FSREG >> 1])).v); - break; - case 0x21: // CVT.D.W - set_cop1_reg(FDREG >> 1, i32_to_f64(s32(m_f[FSREG >> 1])).v); + case 0x80000000: // kseg0: unmapped, cached, privileged + case 0xa0000000: // kseg1: unmapped, uncached, privileged + address &= ~0xe0000000; break; - default: // unimplemented operation - m_fcr31 |= FCR31_CE; - execute_set_input(m_fpu_irq, ASSERT_LINE); + case 0xc0000000: // kseg2: mapped, cached, privileged + case 0xe0000000: break; } - break; - - default: // unimplemented operation - m_fcr31 |= FCR31_CE; - execute_set_input(m_fpu_irq, ASSERT_LINE); - break; } - break; - case 0x31: // LWC1 - load(SIMMVAL + m_r[RSREG], - [this, op](u32 data) + else if (SR & SR_KUc) { - if (FTREG & 1) - // load the high half of the floating point register - m_f[FTREG >> 1] = (u64(data) << 32) | u32(m_f[FTREG >> 1]); - else - // load the low half of the floating point register - m_f[FTREG >> 1] = (m_f[FTREG >> 1] & ~0xffffffffULL) | data; - }); - break; - case 0x39: // SWC1 - if (FTREG & 1) - // store the high half of the floating point register - store(SIMMVAL + m_r[RSREG], m_f[FTREG >> 1] >> 32); - else - // store the low half of the floating point register - store(SIMMVAL + m_r[RSREG], m_f[FTREG >> 1]); - break; - } -} + // exception + m_cpr[0][COP0_BadVAddr] = address; -void mips1_device_base::set_cop1_reg(unsigned const reg, u64 const data) -{ - // translate softfloat exception flags to cause register - if (softfloat_exceptionFlags) - { - if (softfloat_exceptionFlags & softfloat_flag_inexact) - m_fcr31 |= FCR31_CI; - if (softfloat_exceptionFlags & softfloat_flag_underflow) - m_fcr31 |= FCR31_CU; - if (softfloat_exceptionFlags & softfloat_flag_overflow) - m_fcr31 |= FCR31_CO; - if (softfloat_exceptionFlags & softfloat_flag_infinite) - m_fcr31 |= FCR31_CZ; - if (softfloat_exceptionFlags & softfloat_flag_invalid) - m_fcr31 |= FCR31_CV; - - // check if exception is enabled - if (((m_fcr31 & FCR31_CM) >> 5) & (m_fcr31 & FCR31_EM)) - { - execute_set_input(m_fpu_irq, ASSERT_LINE); - return; + generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); + return false; } - - // set flags - m_fcr31 |= ((m_fcr31 & FCR31_CM) >> 10); } + else + // kuseg physical addresses have a 1GB offset + address += 0x40000000; - m_f[reg] = data; + return true; } bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &address) @@ -1854,30 +982,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; + // exception + m_cpr[0][COP0_BadVAddr] = address; - generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); - } + generate_exception((intention & TRANSLATE_WRITE) ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD); return false; } } // 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]; - + u32 const key = (address & EH_VPN) | (m_cpr[0][COP0_EntryHi] & EH_ASID); bool refill = !BIT(address, 31); - bool modify = false; + bool dirty = false; - for (unsigned i = 0; i < ARRAY_LENGTH(m_tlb); i++) + for (u32 const *entry : m_tlb) { - unsigned const index = mru[i]; - u32 const *const entry = m_tlb[index]; - // test vpn and optionally asid u32 const mask = (entry[1] & EL_G) ? EH_VPN : EH_VPN | EH_ASID; if ((entry[0] & mask) != (key & mask)) @@ -1894,39 +1013,28 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad if ((intention & TRANSLATE_WRITE) && !(entry[1] & EL_D)) { refill = false; - modify = true; + dirty = true; break; } // translate the address address &= ~EH_VPN; address |= (entry[1] & EL_PFN); - - // promote the entry in the mru index - if (i > 0) - std::swap(mru[i - 1], mru[i]); - return true; } - if (!machine().side_effects_disabled() && !(intention & TRANSLATE_DEBUG_MASK)) + if (!(intention & TRANSLATE_DEBUG_MASK)) { - if (VERBOSE & LOG_TLB) - { - if (modify) - LOGMASKED(LOG_TLB, "tlb modify asid %d address 0x%08x (%s)\n", - (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, address, machine().describe_context()); - else - LOGMASKED(LOG_TLB, "tlb miss %c asid %d address 0x%08x (%s)\n", - (intention & TRANSLATE_WRITE) ? 'w' : 'r', (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, address, machine().describe_context()); - } + if ((VERBOSE & LOG_TLB) && !dirty) + LOGMASKED(LOG_TLB, "tlb miss %c asid %d address 0x%08x (%s)\n", + (intention & TRANSLATE_WRITE) ? 'w' : 'r', (m_cpr[0][COP0_EntryHi] & EH_ASID) >> 6, address, machine().describe_context()); // load tlb exception registers - m_cop0[COP0_BadVAddr] = address; - m_cop0[COP0_EntryHi] = key; - m_cop0[COP0_Context] = (m_cop0[COP0_Context] & PTE_BASE) | ((address >> 10) & BAD_VPN); + m_cpr[0][COP0_BadVAddr] = address; + m_cpr[0][COP0_EntryHi] = key; + m_cpr[0][COP0_Context] = (m_cpr[0][COP0_Context] & PTE_BASE) | ((address >> 10) & BAD_VPN); - generate_exception(modify ? EXCEPTION_TLBMOD : (intention & TRANSLATE_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill); + generate_exception(dirty ? EXCEPTION_TLBMOD : (intention & TRANSLATE_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill); } return false; -- cgit v1.2.3-70-g09d2