CacheMemory.cc revision 6782
1/* 2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "mem/ruby/system/CacheMemory.hh" 30 31// Output operator declaration 32//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj); 33 34// ******************* Definitions ******************* 35 36// Output operator definition 37ostream& operator<<(ostream& out, const CacheMemory& obj) 38{ 39 obj.print(out); 40 out << flush; 41 return out; 42} 43 44 45// **************************************************************** 46 47CacheMemory::CacheMemory(const string & name) 48 : m_cache_name(name) 49{ 50 m_profiler_ptr = new CacheProfiler(name); 51} 52 53void CacheMemory::init(const vector<string> & argv) 54{ 55 int cache_size = 0; 56 string policy; 57 58 m_controller = NULL; 59 for (uint32 i=0; i<argv.size(); i+=2) { 60 if (argv[i] == "size_kb") { 61 cache_size = atoi(argv[i+1].c_str()); 62 } else if (argv[i] == "latency") { 63 m_latency = atoi(argv[i+1].c_str()); 64 } else if (argv[i] == "assoc") { 65 m_cache_assoc = atoi(argv[i+1].c_str()); 66 } else if (argv[i] == "replacement_policy") { 67 policy = argv[i+1]; 68 } else if (argv[i] == "controller") { 69 m_controller = RubySystem::getController(argv[i+1]); 70 } else { 71 cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl; 72 } 73 } 74 75 m_cache_num_sets = cache_size / m_cache_assoc; 76 m_cache_num_set_bits = log_int(m_cache_num_sets); 77 78 if(policy == "PSEUDO_LRU") 79 m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); 80 else if (policy == "LRU") 81 m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc); 82 else 83 assert(false); 84 85 m_cache.setSize(m_cache_num_sets); 86 m_locked.setSize(m_cache_num_sets); 87 for (int i = 0; i < m_cache_num_sets; i++) { 88 m_cache[i].setSize(m_cache_assoc); 89 m_locked[i].setSize(m_cache_assoc); 90 for (int j = 0; j < m_cache_assoc; j++) { 91 m_cache[i][j] = NULL; 92 m_locked[i][j] = -1; 93 } 94 } 95} 96 97CacheMemory::~CacheMemory() 98{ 99 if(m_replacementPolicy_ptr != NULL) 100 delete m_replacementPolicy_ptr; 101} 102 103void CacheMemory::printConfig(ostream& out) 104{ 105 out << "Cache config: " << m_cache_name << endl; 106 if (m_controller != NULL) 107 out << " controller: " << m_controller->getName() << endl; 108 out << " cache_associativity: " << m_cache_assoc << endl; 109 out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; 110 const int cache_num_sets = 1 << m_cache_num_set_bits; 111 out << " num_cache_sets: " << cache_num_sets << endl; 112 out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl; 113 out << " cache_set_size_Kbytes: " 114 << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl; 115 out << " cache_set_size_Mbytes: " 116 << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl; 117 out << " cache_size_bytes: " 118 << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl; 119 out << " cache_size_Kbytes: " 120 << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl; 121 out << " cache_size_Mbytes: " 122 << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl; 123} 124 125// PRIVATE METHODS 126 127// convert a Address to its location in the cache 128Index CacheMemory::addressToCacheSet(const Address& address) const 129{ 130 assert(address == line_address(address)); 131 return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1); 132} 133 134// Given a cache index: returns the index of the tag in a set. 135// returns -1 if the tag is not found. 136int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const 137{ 138 assert(tag == line_address(tag)); 139 // search the set for the tags 140 for (int i=0; i < m_cache_assoc; i++) { 141 if ((m_cache[cacheSet][i] != NULL) && 142 (m_cache[cacheSet][i]->m_Address == tag) && 143 (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) { 144 return i; 145 } 146 } 147 return -1; // Not found 148} 149 150// Given a cache index: returns the index of the tag in a set. 151// returns -1 if the tag is not found. 152int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const 153{ 154 assert(tag == line_address(tag)); 155 // search the set for the tags 156 for (int i=0; i < m_cache_assoc; i++) { 157 if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag) 158 return i; 159 } 160 return -1; // Not found 161} 162 163// PUBLIC METHODS 164bool CacheMemory::tryCacheAccess(const Address& address, 165 CacheRequestType type, 166 DataBlock*& data_ptr) 167{ 168 assert(address == line_address(address)); 169 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 170 Index cacheSet = addressToCacheSet(address); 171 int loc = findTagInSet(cacheSet, address); 172 if(loc != -1){ // Do we even have a tag match? 173 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 174 m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 175 data_ptr = &(entry->getDataBlk()); 176 177 if(entry->m_Permission == AccessPermission_Read_Write) { 178 return true; 179 } 180 if ((entry->m_Permission == AccessPermission_Read_Only) && 181 (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { 182 return true; 183 } 184 // The line must not be accessible 185 } 186 data_ptr = NULL; 187 return false; 188} 189 190bool CacheMemory::testCacheAccess(const Address& address, 191 CacheRequestType type, 192 DataBlock*& data_ptr) 193{ 194 assert(address == line_address(address)); 195 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 196 Index cacheSet = addressToCacheSet(address); 197 int loc = findTagInSet(cacheSet, address); 198 if(loc != -1){ // Do we even have a tag match? 199 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 200 m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 201 data_ptr = &(entry->getDataBlk()); 202 203 return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent); 204 } 205 data_ptr = NULL; 206 return false; 207} 208 209// tests to see if an address is present in the cache 210bool CacheMemory::isTagPresent(const Address& address) const 211{ 212 assert(address == line_address(address)); 213 Index cacheSet = addressToCacheSet(address); 214 int location = findTagInSet(cacheSet, address); 215 216 if (location == -1) { 217 // We didn't find the tag 218 DEBUG_EXPR(CACHE_COMP, LowPrio, address); 219 DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match"); 220 return false; 221 } 222 DEBUG_EXPR(CACHE_COMP, LowPrio, address); 223 DEBUG_MSG(CACHE_COMP, LowPrio, "found"); 224 return true; 225} 226 227// Returns true if there is: 228// a) a tag match on this address or there is 229// b) an unused line in the same cache "way" 230bool CacheMemory::cacheAvail(const Address& address) const 231{ 232 assert(address == line_address(address)); 233 234 Index cacheSet = addressToCacheSet(address); 235 236 for (int i=0; i < m_cache_assoc; i++) { 237 AbstractCacheEntry* entry = m_cache[cacheSet][i]; 238 if (entry != NULL) { 239 if (entry->m_Address == address || // Already in the cache 240 entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry 241 return true; 242 } 243 } else { 244 return true; 245 } 246 } 247 return false; 248} 249 250void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) 251{ 252 assert(address == line_address(address)); 253 assert(!isTagPresent(address)); 254 assert(cacheAvail(address)); 255 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 256 257 // Find the first open slot 258 Index cacheSet = addressToCacheSet(address); 259 for (int i=0; i < m_cache_assoc; i++) { 260 if (m_cache[cacheSet][i] == NULL || 261 m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) { 262 m_cache[cacheSet][i] = entry; // Init entry 263 m_cache[cacheSet][i]->m_Address = address; 264 m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid; 265 m_locked[cacheSet][i] = -1; 266 267 m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime()); 268 269 return; 270 } 271 } 272 ERROR_MSG("Allocate didn't find an available entry"); 273} 274 275void CacheMemory::deallocate(const Address& address) 276{ 277 assert(address == line_address(address)); 278 assert(isTagPresent(address)); 279 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 280 Index cacheSet = addressToCacheSet(address); 281 int location = findTagInSet(cacheSet, address); 282 if (location != -1){ 283 delete m_cache[cacheSet][location]; 284 m_cache[cacheSet][location] = NULL; 285 m_locked[cacheSet][location] = -1; 286 } 287} 288 289// Returns with the physical address of the conflicting cache line 290Address CacheMemory::cacheProbe(const Address& address) const 291{ 292 assert(address == line_address(address)); 293 assert(!cacheAvail(address)); 294 295 Index cacheSet = addressToCacheSet(address); 296 return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address; 297} 298 299// looks an address up in the cache 300AbstractCacheEntry& CacheMemory::lookup(const Address& address) 301{ 302 assert(address == line_address(address)); 303 Index cacheSet = addressToCacheSet(address); 304 int loc = findTagInSet(cacheSet, address); 305 assert(loc != -1); 306 return *m_cache[cacheSet][loc]; 307} 308 309// looks an address up in the cache 310const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const 311{ 312 assert(address == line_address(address)); 313 Index cacheSet = addressToCacheSet(address); 314 int loc = findTagInSet(cacheSet, address); 315 assert(loc != -1); 316 return *m_cache[cacheSet][loc]; 317} 318 319AccessPermission CacheMemory::getPermission(const Address& address) const 320{ 321 assert(address == line_address(address)); 322 return lookup(address).m_Permission; 323} 324 325void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) 326{ 327 assert(address == line_address(address)); 328 lookup(address).m_Permission = new_perm; 329 Index cacheSet = addressToCacheSet(address); 330 int loc = findTagInSet(cacheSet, address); 331 m_locked[cacheSet][loc] = -1; 332 assert(getPermission(address) == new_perm); 333} 334 335// Sets the most recently used bit for a cache block 336void CacheMemory::setMRU(const Address& address) 337{ 338 Index cacheSet; 339 340 cacheSet = addressToCacheSet(address); 341 m_replacementPolicy_ptr->touch(cacheSet, 342 findTagInSet(cacheSet, address), 343 g_eventQueue_ptr->getTime()); 344} 345 346void CacheMemory::profileMiss(const CacheMsg & msg) 347{ 348 m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(), 349 msg.getSize(), msg.getPrefetch()); 350} 351 352void CacheMemory::recordCacheContents(CacheRecorder& tr) const 353{ 354 for (int i = 0; i < m_cache_num_sets; i++) { 355 for (int j = 0; j < m_cache_assoc; j++) { 356 AccessPermission perm = m_cache[i][j]->m_Permission; 357 CacheRequestType request_type = CacheRequestType_NULL; 358 if (perm == AccessPermission_Read_Only) { 359 if (m_is_instruction_only_cache) { 360 request_type = CacheRequestType_IFETCH; 361 } else { 362 request_type = CacheRequestType_LD; 363 } 364 } else if (perm == AccessPermission_Read_Write) { 365 request_type = CacheRequestType_ST; 366 } 367 368 if (request_type != CacheRequestType_NULL) { 369 // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, 370 // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); 371 } 372 } 373 } 374} 375 376void CacheMemory::print(ostream& out) const 377{ 378 out << "Cache dump: " << m_cache_name << endl; 379 for (int i = 0; i < m_cache_num_sets; i++) { 380 for (int j = 0; j < m_cache_assoc; j++) { 381 if (m_cache[i][j] != NULL) { 382 out << " Index: " << i 383 << " way: " << j 384 << " entry: " << *m_cache[i][j] << endl; 385 } else { 386 out << " Index: " << i 387 << " way: " << j 388 << " entry: NULL" << endl; 389 } 390 } 391 } 392} 393 394void CacheMemory::printData(ostream& out) const 395{ 396 out << "printData() not supported" << endl; 397} 398 399void CacheMemory::clearStats() const 400{ 401 m_profiler_ptr->clearStats(); 402} 403 404void CacheMemory::printStats(ostream& out) const 405{ 406 m_profiler_ptr->printStats(out); 407} 408 409void CacheMemory::getMemoryValue(const Address& addr, char* value, 410 unsigned int size_in_bytes ){ 411 AbstractCacheEntry& entry = lookup(line_address(addr)); 412 unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); 413 for(unsigned int i=0; i<size_in_bytes; ++i){ 414 value[i] = entry.getDataBlk().getByte(i + startByte); 415 } 416} 417 418void CacheMemory::setMemoryValue(const Address& addr, char* value, 419 unsigned int size_in_bytes ){ 420 AbstractCacheEntry& entry = lookup(line_address(addr)); 421 unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); 422 assert(size_in_bytes > 0); 423 for(unsigned int i=0; i<size_in_bytes; ++i){ 424 entry.getDataBlk().setByte(i + startByte, value[i]); 425 } 426 427 // entry = lookup(line_address(addr)); 428} 429 430void 431CacheMemory::setLocked(const Address& address, int context) 432{ 433 assert(address == line_address(address)); 434 Index cacheSet = addressToCacheSet(address); 435 int loc = findTagInSet(cacheSet, address); 436 assert(loc != -1); 437 m_locked[cacheSet][loc] = context; 438} 439 440void 441CacheMemory::clearLocked(const Address& address) 442{ 443 assert(address == line_address(address)); 444 Index cacheSet = addressToCacheSet(address); 445 int loc = findTagInSet(cacheSet, address); 446 assert(loc != -1); 447 m_locked[cacheSet][loc] = -1; 448} 449 450bool 451CacheMemory::isLocked(const Address& address, int context) 452{ 453 assert(address == line_address(address)); 454 Index cacheSet = addressToCacheSet(address); 455 int loc = findTagInSet(cacheSet, address); 456 assert(loc != -1); 457 return m_locked[cacheSet][loc] == context; 458} 459 460