/**************************************************************************** * * * Project 64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" CTLB::CTLB(CTLB_CB * CallBack ): m_CB(CallBack) { WriteTrace(TraceTLB,__FUNCTION__ ": Start"); memset(m_tlb,0,sizeof(m_tlb)); memset(m_FastTlb,0,sizeof(m_FastTlb)); Reset(true); WriteTrace(TraceTLB,__FUNCTION__ ": Done"); } CTLB::~CTLB() { WriteTrace(TraceTLB,__FUNCTION__ ": Start"); WriteTrace(TraceTLB,__FUNCTION__ ": Done"); } void CTLB::Reset (bool InvalidateTLB) { uint32_t count; for (count = 0; count < 64; count++) { m_FastTlb[count].ValidEntry = false; } if (InvalidateTLB) { for (count = 0; count < 32; count++) { m_tlb[count].EntryDefined = false; } } else { for (count = 0; count < 32; count ++) { SetupTLB_Entry(count,false); } } } bool CTLB::AddressDefined ( uint32_t VAddr) { uint32_t i; if (VAddr >= 0x80000000 && VAddr <= 0xBFFFFFFF) { return true; } for (i = 0; i < 64; i++) { if (m_FastTlb[i].ValidEntry && VAddr >= m_FastTlb[i].VSTART && VAddr <= m_FastTlb[i].VEND) { return true; } } return false; } void CTLB::Probe() { int Counter; WriteTrace(TraceTLB,__FUNCTION__ ": Start"); g_Reg->INDEX_REGISTER |= 0x80000000; for (Counter = 0; Counter < 32; Counter ++) { if (!m_tlb[Counter].EntryDefined) { continue; } uint32_t & TlbEntryHiValue = m_tlb[Counter].EntryHi.Value; uint32_t Mask = ~m_tlb[Counter].PageMask.Mask << 13; uint32_t TlbValueMasked = TlbEntryHiValue & Mask; uint32_t EntryHiMasked = g_Reg->ENTRYHI_REGISTER & Mask; if (TlbValueMasked == EntryHiMasked) { if ((TlbEntryHiValue & 0x100) != 0 || //Global ((TlbEntryHiValue & 0xFF) == (g_Reg->ENTRYHI_REGISTER & 0xFF))) //SameAsid { g_Reg->INDEX_REGISTER = Counter; int FastIndx = Counter << 1; m_FastTlb[FastIndx].Probed = true; m_FastTlb[FastIndx + 1].Probed = true; return; } } } WriteTrace(TraceTLB,__FUNCTION__ ": Done"); } void CTLB::ReadEntry() { uint32_t index = g_Reg->INDEX_REGISTER & 0x1F; g_Reg->PAGE_MASK_REGISTER = m_tlb[index].PageMask.Value ; g_Reg->ENTRYHI_REGISTER = (m_tlb[index].EntryHi.Value & ~m_tlb[index].PageMask.Value) ; g_Reg->ENTRYLO0_REGISTER = m_tlb[index].EntryLo0.Value; g_Reg->ENTRYLO1_REGISTER = m_tlb[index].EntryLo1.Value; } void CTLB::WriteEntry (int index, bool Random) { int FastIndx; WriteTraceF(TraceTLB,__FUNCTION__ ": %02d %d %08X %08X %08X %08X ",index,Random,g_Reg->PAGE_MASK_REGISTER,g_Reg->ENTRYHI_REGISTER,g_Reg->ENTRYLO0_REGISTER,g_Reg->ENTRYLO1_REGISTER); //Check to see if entry is unmapping it self if (m_tlb[index].EntryDefined) { FastIndx = index << 1; if (*_PROGRAM_COUNTER >= m_FastTlb[FastIndx].VSTART && *_PROGRAM_COUNTER < m_FastTlb[FastIndx].VEND && m_FastTlb[FastIndx].ValidEntry && m_FastTlb[FastIndx].VALID) { WriteTraceF(TraceTLB,__FUNCTION__ ": Ignored PC: %X VAddr Start: %X VEND: %X",*_PROGRAM_COUNTER,m_FastTlb[FastIndx].VSTART,m_FastTlb[FastIndx].VEND); return; } if (*_PROGRAM_COUNTER >= m_FastTlb[FastIndx + 1].VSTART && *_PROGRAM_COUNTER < m_FastTlb[FastIndx + 1].VEND && m_FastTlb[FastIndx + 1].ValidEntry && m_FastTlb[FastIndx + 1].VALID) { WriteTraceF(TraceTLB,__FUNCTION__ ": Ignored PC: %X VAddr Start: %X VEND: %X",*_PROGRAM_COUNTER,m_FastTlb[FastIndx + 1].VSTART,m_FastTlb[FastIndx + 1].VEND); return; } } //Reset old addresses if (m_tlb[index].EntryDefined) { for ( FastIndx = index << 1; FastIndx <= (index << 1) + 1; FastIndx++) { if (!m_FastTlb[FastIndx].ValidEntry) { continue; } if (!m_FastTlb[FastIndx].VALID) { continue; } if (m_tlb[index].PageMask.Value == g_Reg->PAGE_MASK_REGISTER && m_tlb[index].EntryHi.Value == g_Reg->ENTRYHI_REGISTER) { if (FastIndx == (index << 1) && m_tlb[index].EntryLo0.Value == g_Reg->ENTRYLO0_REGISTER) { continue; } if (FastIndx != (index << 1) && m_tlb[index].EntryLo1.Value == g_Reg->ENTRYLO1_REGISTER) { continue; } } m_CB->TLB_Unmaped(m_FastTlb[FastIndx].VSTART,m_FastTlb[FastIndx].Length); } } //fill in m_tlb entry m_tlb[index].PageMask.Value = g_Reg->PAGE_MASK_REGISTER; m_tlb[index].EntryHi.Value = g_Reg->ENTRYHI_REGISTER; m_tlb[index].EntryLo0.Value = g_Reg->ENTRYLO0_REGISTER; m_tlb[index].EntryLo1.Value = g_Reg->ENTRYLO1_REGISTER; m_tlb[index].EntryDefined = true; SetupTLB_Entry(index,Random); m_CB->TLB_Changed(); } void CTLB::SetupTLB_Entry (int index, bool Random) { //Fix up Fast TLB entries if (!m_tlb[index].EntryDefined) { return; } int FastIndx = index << 1; if (m_FastTlb[FastIndx].VALID) { m_CB->TLB_Unmaped(m_FastTlb[FastIndx].VSTART,m_FastTlb[FastIndx].Length); } m_FastTlb[FastIndx].Length = (m_tlb[index].PageMask.Mask << 12) + 0xFFF; m_FastTlb[FastIndx].VSTART=m_tlb[index].EntryHi.VPN2 << 13; m_FastTlb[FastIndx].VEND = m_FastTlb[FastIndx].VSTART + m_FastTlb[FastIndx].Length; m_FastTlb[FastIndx].PHYSSTART = m_tlb[index].EntryLo0.PFN << 12; m_FastTlb[FastIndx].PHYSEND = m_FastTlb[FastIndx].PHYSSTART + m_FastTlb[FastIndx].Length; m_FastTlb[FastIndx].VALID = m_tlb[index].EntryLo0.V; m_FastTlb[FastIndx].DIRTY = m_tlb[index].EntryLo0.D; m_FastTlb[FastIndx].GLOBAL = m_tlb[index].EntryLo0.GLOBAL & m_tlb[index].EntryLo1.GLOBAL; m_FastTlb[FastIndx].ValidEntry = false; m_FastTlb[FastIndx].Random = Random; m_FastTlb[FastIndx].Probed = false; FastIndx = (index << 1) + 1; if (m_FastTlb[FastIndx].VALID) { m_CB->TLB_Unmaped(m_FastTlb[FastIndx].VSTART,m_FastTlb[FastIndx].Length); } m_FastTlb[FastIndx].Length = (m_tlb[index].PageMask.Mask << 12) + 0xFFF; m_FastTlb[FastIndx].VSTART=(m_tlb[index].EntryHi.VPN2 << 13) + (m_FastTlb[FastIndx].Length + 1); m_FastTlb[FastIndx].VEND = m_FastTlb[FastIndx].VSTART + m_FastTlb[FastIndx].Length; m_FastTlb[FastIndx].PHYSSTART = m_tlb[index].EntryLo1.PFN << 12; m_FastTlb[FastIndx].PHYSEND = m_FastTlb[FastIndx].PHYSSTART + m_FastTlb[FastIndx].Length; m_FastTlb[FastIndx].VALID = m_tlb[index].EntryLo1.V; m_FastTlb[FastIndx].DIRTY = m_tlb[index].EntryLo1.D; m_FastTlb[FastIndx].GLOBAL = m_tlb[index].EntryLo0.GLOBAL & m_tlb[index].EntryLo1.GLOBAL; m_FastTlb[FastIndx].ValidEntry = false; m_FastTlb[FastIndx].Random = Random; m_FastTlb[FastIndx].Probed = false; //Test both entries to see if they are valid for ( FastIndx = index << 1; FastIndx <= (index << 1) + 1; FastIndx++) { if (!m_FastTlb[FastIndx].VALID) { m_FastTlb[FastIndx].ValidEntry = true; continue; } if (m_FastTlb[FastIndx].VEND <= m_FastTlb[FastIndx].VSTART) { continue; } if (m_FastTlb[FastIndx].VSTART >= 0x80000000 && m_FastTlb[FastIndx].VEND <= 0xBFFFFFFF) { continue; } if (m_FastTlb[FastIndx].PHYSSTART > 0x1FFFFFFF) { continue; } //MAP the new m_tlb entry for reading and writing m_FastTlb[FastIndx].ValidEntry = true; m_CB->TLB_Mapped(m_FastTlb[FastIndx].VSTART,m_FastTlb[FastIndx].Length,m_FastTlb[FastIndx].PHYSSTART, !m_FastTlb[FastIndx].DIRTY); } } bool CTLB::PAddrToVAddr(uint32_t PAddr, uint32_t & VAddr, uint32_t & Index ) { for (int i = Index; i < 64; i++) { if (m_FastTlb[i].ValidEntry == false) { continue; } if (PAddr >= m_FastTlb[i].PHYSSTART && PAddr < m_FastTlb[i].PHYSEND) { VAddr = m_FastTlb[i].VSTART + (PAddr - m_FastTlb[i].PHYSSTART); Index = i + 1; return true; } } return false; } void CTLB::RecordDifference( CLog &LogFile, const CTLB& rTLB) { for (int i = 0, n = sizeof(m_tlb)/sizeof(m_tlb[0]); i < n; i++) { if (m_tlb[i].EntryDefined != rTLB.m_tlb[i].EntryDefined) { LogFile.LogF("TLB[%d] Defined: %s %s\r\n",i,m_tlb[i].EntryDefined ? "Yes" : "No",rTLB.m_tlb[i].EntryDefined ? "Yes" : "No"); continue; } if (!m_tlb[i].EntryDefined) { continue; } if (m_tlb[i].PageMask.Value != rTLB.m_tlb[i].PageMask.Value) { LogFile.LogF("TLB[%d] PageMask: %X %X\r\n",i,m_tlb[i].PageMask.Value,rTLB.m_tlb[i].PageMask.Value); } if (m_tlb[i].EntryHi.Value != rTLB.m_tlb[i].EntryHi.Value) { LogFile.LogF("TLB[%d] EntryHi: %X %X\r\n",i,m_tlb[i].EntryHi.Value,rTLB.m_tlb[i].EntryHi.Value); } if (m_tlb[i].EntryLo0.Value != rTLB.m_tlb[i].EntryLo0.Value) { LogFile.LogF("TLB[%d] EntryLo0: %X %X\r\n",i,m_tlb[i].EntryLo0.Value,rTLB.m_tlb[i].EntryLo0.Value); } if (m_tlb[i].EntryLo1.Value != rTLB.m_tlb[i].EntryLo1.Value) { LogFile.LogF("TLB[%d] EntryLo1: %X %X\r\n",i,m_tlb[i].EntryLo1.Value,rTLB.m_tlb[i].EntryLo1.Value); } } } bool CTLB::operator == (const CTLB& rTLB) const { for (size_t i = 0, n = sizeof(m_tlb)/sizeof(m_tlb[0]); i < n; i++) { if (m_tlb[i].EntryDefined != rTLB.m_tlb[i].EntryDefined) { return false; } if (!m_tlb[i].EntryDefined) { continue; } if (m_tlb[i].PageMask.Value != rTLB.m_tlb[i].PageMask.Value || m_tlb[i].EntryHi.Value != rTLB.m_tlb[i].EntryHi.Value || m_tlb[i].EntryLo0.Value != rTLB.m_tlb[i].EntryLo0.Value || m_tlb[i].EntryLo1.Value != rTLB.m_tlb[i].EntryLo1.Value) { return false; } } return true; } bool CTLB::operator != (const CTLB& rTLB) const { return !(*this == rTLB); }