///////////////////////////////////////////////////////////////////////// // $Id: icache.h,v 1.18 2006-09-20 20:52:23 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001 MandrakeSoft S.A. // // MandrakeSoft S.A. // 43, rue d'Aboukir // 75002 Paris - France // http://www.linux-mandrake.com/ // http://www.mandrakesoft.com/ // // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef BX_ICACHE_H #define BX_ICACHE_H #include // bit31: 1=CS is 32/64-bit, 0=CS is 16-bit. // bit30: 1=Long Mode, 0=not Long Mode. // Combination bit31=1 & bit30=1 is invalid. const Bit32u ICacheWriteStampInvalid = 0xffffffff; const Bit32u ICacheWriteStampStart = 0x3fffffff; const Bit32u ICacheWriteStampMask = 0x3fffffff; const Bit32u ICacheFetchModeMask = ~ICacheWriteStampMask; 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; Bit32u memSizeInBytes; public: bxPageWriteStampTable(): pageWriteStampTable(NULL), memSizeInBytes(0) {} bxPageWriteStampTable(Bit32u memSize) { alloc(memSize); } ~bxPageWriteStampTable() { delete [] pageWriteStampTable; } BX_CPP_INLINE void alloc(Bit32u memSize) { if (memSizeInBytes > 0) { delete [] pageWriteStampTable; } memSizeInBytes = memSize; pageWriteStampTable = new Bit32u [memSizeInBytes>>12]; resetWriteStamps(); } BX_CPP_INLINE Bit32u getPageWriteStamp(bx_phy_address pAddr) const { if (pAddr < memSizeInBytes) return pageWriteStampTable[pAddr>>12]; else return ICacheWriteStampInvalid; } BX_CPP_INLINE const Bit32u *getPageWriteStampPtr(bx_phy_address pAddr) const { if (pAddr < memSizeInBytes) return &pageWriteStampTable[pAddr>>12]; else return &ICacheWriteStampInvalid; } BX_CPP_INLINE void setPageWriteStamp(bx_phy_address pAddr, Bit32u pageWriteStamp) { if (pAddr < memSizeInBytes) pageWriteStampTable[pAddr>>12] = pageWriteStamp; } BX_CPP_INLINE void decWriteStamp(bx_phy_address pAddr) { assert(pAddr < memSizeInBytes); // Decrement page write stamp, so iCache entries with older stamps // are effectively invalidated. pageWriteStampTable[pAddr >> 12]--; } BX_CPP_INLINE void resetWriteStamps(void); BX_CPP_INLINE void purgeWriteStamps(void); }; BX_CPP_INLINE void bxPageWriteStampTable::resetWriteStamps(void) { for (Bit32u i=0; i<(memSizeInBytes>>12); i++) { pageWriteStampTable[i] = ICacheWriteStampInvalid; } } BX_CPP_INLINE void bxPageWriteStampTable::purgeWriteStamps(void) { for (Bit32u i=0; i<(memSizeInBytes>>12); i++) { pageWriteStampTable[i] |= ICacheWriteStampMask; } } extern bxPageWriteStampTable pageWriteStampTable; #define BxICacheEntries (32 * 1024) // Must be a power of 2. struct bxICacheEntry_c { bx_phy_address pAddr; // Physical address of the instruction Bit32u writeStamp; // Generation ID. Each write to a physical page // decrements this value bxInstruction_c i; // The instruction decode information }; class BOCHSAPI bxICache_c { public: bxICacheEntry_c entry[BxICacheEntries]; public: bxICache_c() { flushICacheEntries(); } BX_CPP_INLINE unsigned hash(bx_phy_address pAddr) const { // A pretty dumb hash function for now. return pAddr & (BxICacheEntries-1); } BX_CPP_INLINE void purgeICacheEntries(void); BX_CPP_INLINE void flushICacheEntries(void); }; BX_CPP_INLINE void bxICache_c::flushICacheEntries(void) { bxICacheEntry_c* e = entry; for (unsigned i=0; iwriteStamp = ICacheWriteStampInvalid; } } BX_CPP_INLINE void bxICache_c::purgeICacheEntries(void) { bxICacheEntry_c* e = entry; // 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 // (without invalidating the cache). for (unsigned i=0;ipAddr); if (e->writeStamp != pageWriteStamp) e->writeStamp = ICacheWriteStampInvalid; // invalidate entry else e->writeStamp |= ICacheWriteStampMask; } } extern void purgeICaches(void); extern void flushICaches(void); #endif