///////////////////////////////////////////////////////////////////////// // $Id: icache.h,v 1.54 2010-05-18 07:28:04 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2007-2010 Stanislav Shwartsman // Written by Stanislav Shwartsman [sshwarts at sourceforge net] // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA // ///////////////////////////////////////////////////////////////////////// #ifndef BX_ICACHE_H #define BX_ICACHE_H // bit 31 indicates code page const Bit32u ICacheWriteStampInvalid = 0xffffffff; const Bit32u ICacheWriteStampStart = 0x7fffffff; const Bit32u ICacheWriteStampFetchModeMask = ~ICacheWriteStampStart; #if BX_SUPPORT_TRACE_CACHE extern void handleSMC(bx_phy_address pAddr); #endif class bxPageWriteStampTable { // A table (dynamically allocated) to store write-stamp generation IDs. // Each time a write occurs to a physical page, a generation ID is // decremented. Only iCache entries which have write stamps matching // the physical page write stamp are valid. Bit32u *pageWriteStampTable; #define PHY_MEM_PAGES (1024*1024) public: bxPageWriteStampTable() { pageWriteStampTable = new Bit32u[PHY_MEM_PAGES]; resetWriteStamps(); } ~bxPageWriteStampTable() { delete [] pageWriteStampTable; } BX_CPP_INLINE Bit32u hash(bx_phy_address pAddr) const { // can share writeStamps between multiple pages if >32 bit phy address return ((Bit32u) pAddr) >> 12; } BX_CPP_INLINE Bit32u getPageWriteStamp(bx_phy_address pAddr) const { return pageWriteStampTable[hash(pAddr)]; } BX_CPP_INLINE const Bit32u *getPageWriteStampPtr(bx_phy_address pAddr) const { return &pageWriteStampTable[hash(pAddr)]; } BX_CPP_INLINE void setPageWriteStamp(bx_phy_address pAddr, Bit32u pageWriteStamp) { pageWriteStampTable[hash(pAddr)] = pageWriteStamp; } BX_CPP_INLINE void markICache(bx_phy_address pAddr) { pageWriteStampTable[hash(pAddr)] |= ICacheWriteStampFetchModeMask; } BX_CPP_INLINE void decWriteStamp(bx_phy_address pAddr) { Bit32u index = hash(pAddr); if (pageWriteStampTable[index] & ICacheWriteStampFetchModeMask) { #if BX_SUPPORT_TRACE_CACHE handleSMC(pAddr); // one of the CPUs might be running trace from this page #endif // Decrement page write stamp, so iCache entries with older stamps are // effectively invalidated. pageWriteStampTable[index] = (pageWriteStampTable[index] - 1) & ~ICacheWriteStampFetchModeMask; } } BX_CPP_INLINE void resetWriteStamps(void); }; BX_CPP_INLINE void bxPageWriteStampTable::resetWriteStamps(void) { for (Bit32u i=0; i>6)) & (BxICacheEntries-1)) ^ fetchModeMask; return ((pAddr) & (BxICacheEntries-1)) ^ fetchModeMask; } #if BX_SUPPORT_TRACE_CACHE BX_CPP_INLINE void alloc_trace(bxICacheEntry_c *e) { if (mpindex + BX_MAX_TRACE_LENGTH > BxICacheMemPool) { flushICacheEntries(); } e->i = &mpool[mpindex]; e->tlen = 0; } BX_CPP_INLINE void commit_trace(unsigned len) { mpindex += len; } BX_CPP_INLINE void commit_page_split_trace(bx_phy_address paddr, bxICacheEntry_c *entry) { mpindex++; // commit_trace(1) // register page split entry if (pageSplitIndex[nextPageSplitIndex].ppf != BX_ICACHE_INVALID_PHY_ADDRESS) pageSplitIndex[nextPageSplitIndex].e->writeStamp = ICacheWriteStampInvalid; pageSplitIndex[nextPageSplitIndex].ppf = paddr; pageSplitIndex[nextPageSplitIndex].e = entry; nextPageSplitIndex = (nextPageSplitIndex+1) & (BX_ICACHE_PAGE_SPLIT_ENTRIES-1); } BX_CPP_INLINE void handleSMC(bx_phy_address pAddr); #endif BX_CPP_INLINE void purgeICacheEntries(void); BX_CPP_INLINE void flushICacheEntries(void); BX_CPP_INLINE bxICacheEntry_c* get_entry(bx_phy_address pAddr, unsigned fetchModeMask) { return &(entry[hash(pAddr, fetchModeMask)]); } }; BX_CPP_INLINE void bxICache_c::flushICacheEntries(void) { bxICacheEntry_c* e = entry; unsigned i; for (i=0; iwriteStamp = ICacheWriteStampInvalid; #if BX_SUPPORT_TRACE_CACHE for (i=0;iwriteStamp = ICacheWriteStampInvalid; pageSplitIndex[i].ppf = BX_ICACHE_INVALID_PHY_ADDRESS; } } } #endif // Since the write stamps may overflow if we always simply decrese them, // this function has to be called often enough that we can reset them. BX_CPP_INLINE void bxICache_c::purgeICacheEntries(void) { flushICacheEntries(); } extern void purgeICaches(void); extern void flushICaches(void); #endif