From eb02f89a2c19572aecfb80c66b01acca74c99434 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 20 Dec 2018 12:48:45 +0700 Subject: [PATCH] mips1: tlb fixes (nw) * corrected cop0 context register encoding * corrected invalid tlb entry exception vector * improved logging --- src/devices/cpu/mips/mips1.cpp | 49 ++++++++++++++++++++++++---------- src/devices/cpu/mips/mips1.h | 15 +++++++---- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index 8483d1d8b2c..7c5b0fe1e99 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -91,7 +91,7 @@ r2000_device::r2000_device(const machine_config &mconfig, const char *tag, devic } 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, 0x0216, icache_size, dcache_size) + : mips1_device_base(mconfig, R2000A, tag, owner, clock, 0x0210, icache_size, dcache_size) { } @@ -270,7 +270,7 @@ std::unique_ptr mips1core_device_base::create_disassembl return std::make_unique(); } -void mips1core_device_base::generate_exception(int exception) +void mips1core_device_base::generate_exception(int exception, bool refill) { // set the exception PC m_cpr[0][COP0_EPC] = m_pc; @@ -289,8 +289,7 @@ void mips1core_device_base::generate_exception(int exception) // shift the exception bits SR = (SR & 0xffffffc0) | ((SR << 2) & 0x3c); - // only tlb misses on kuseg have dedicated vectors - if ((exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) && !BIT(m_cpr[0][COP0_BadVAddr], 31)) + if (refill) m_pc = (SR & SR_BEV) ? 0xbfc00100 : 0x80000000; else m_pc = (SR & SR_BEV) ? 0xbfc00180 : 0x80000080; @@ -347,6 +346,8 @@ void mips1core_device_base::set_cop0_reg(int const index, u32 const data) // 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; } @@ -420,8 +421,13 @@ void mips1_device_base::handle_cop0(u32 const op) m_tlb[index][0] = m_cpr[0][COP0_EntryHi]; m_tlb[index][1] = m_cpr[0][COP0_EntryLo]; - LOGMASKED(LOG_TLB, "tlb index %d program 0x%08x physical 0x%08x\n", - index, m_cpr[0][COP0_EntryHi] & ~0xfff, m_cpr[0][COP0_EntryLo] & ~0xfff); + LOGMASKED(LOG_TLB, "tlbwi %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; @@ -432,8 +438,13 @@ void mips1_device_base::handle_cop0(u32 const op) m_tlb[random][0] = m_cpr[0][COP0_EntryHi]; m_tlb[random][1] = m_cpr[0][COP0_EntryLo]; - LOGMASKED(LOG_TLB, "tlb random %d program 0x%08x physical 0x%08x\n", - random, m_cpr[0][COP0_EntryHi] & ~0xfff, m_cpr[0][COP0_EntryLo] & ~0xfff); + LOGMASKED(LOG_TLB, "tlbwr %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; @@ -445,10 +456,16 @@ void mips1_device_base::handle_cop0(u32 const op) 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: @@ -975,6 +992,7 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad // key is a combination of VPN and ASID u32 const key = (address & EH_VPN) | (m_cpr[0][COP0_EntryHi] & EH_ASID); + bool refill = !BIT(m_cpr[0][COP0_BadVAddr], 31); bool dirty = false; for (u32 const *entry : m_tlb) @@ -986,11 +1004,15 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad // test valid if (!(entry[1] & EL_V)) + { + refill = false; break; + } // test dirty if ((intention & TRANSLATE_WRITE) && !(entry[1] & EL_D)) { + refill = false; dirty = true; break; } @@ -1004,16 +1026,15 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad if (!(intention & TRANSLATE_DEBUG_MASK)) { if ((VERBOSE & LOG_TLB) && !dirty) - LOGMASKED(LOG_TLB, "tlb miss %s address 0x%08x (%s)\n", - (intention & TRANSLATE_WRITE) ? "store" : "load", address, machine().describe_context()); + 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()); - // exception + // load tlb exception registers m_cpr[0][COP0_BadVAddr] = address; m_cpr[0][COP0_EntryHi] = key; - m_cpr[0][COP0_Context] &= ~0x001fffff; - m_cpr[0][COP0_Context] |= (address >> 11) & ~0x3; + m_cpr[0][COP0_Context] = (m_cpr[0][COP0_Context] & PTE_BASE) | ((address >> 10) & BAD_VPN); - generate_exception(dirty ? EXCEPTION_TLBMOD : (intention & TRANSLATE_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD); + generate_exception(dirty ? EXCEPTION_TLBMOD : (intention & TRANSLATE_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill); } return false; diff --git a/src/devices/cpu/mips/mips1.h b/src/devices/cpu/mips/mips1.h index 08c8d1fd95b..d77bdef3cdb 100644 --- a/src/devices/cpu/mips/mips1.h +++ b/src/devices/cpu/mips/mips1.h @@ -101,12 +101,12 @@ protected: enum sr_mask : u32 { - SR_IEc = 0x00000001, // interrupt enable - SR_KUc = 0x00000002, // kernel mode + SR_IEc = 0x00000001, // interrupt enable (current) + SR_KUc = 0x00000002, // user mode (current) SR_IEp = 0x00000004, // interrupt enable (previous) - SR_KUp = 0x00000008, // kernel mode (previous) + SR_KUp = 0x00000008, // user mode (previous) SR_IEo = 0x00000010, // interrupt enable (old) - SR_KUo = 0x00000020, // kernel mode (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 @@ -142,6 +142,11 @@ protected: EL_V = 0x00000200, // valid EL_G = 0x00000100, // global }; + 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; @@ -166,7 +171,7 @@ protected: void dcache_map(address_map &map); // interrupts - void generate_exception(int exception); + void generate_exception(int exception, bool refill = false); void check_irqs(); void set_irq_line(int irqline, int state);