CacheMemory.cc revision 7805
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 "base/intmath.hh" 30#include "mem/ruby/system/CacheMemory.hh" 31 32using namespace std; 33 34ostream& 35operator<<(ostream& out, const CacheMemory& obj) 36{ 37 obj.print(out); 38 out << flush; 39 return out; 40} 41 42CacheMemory * 43RubyCacheParams::create() 44{ 45 return new CacheMemory(this); 46} 47 48CacheMemory::CacheMemory(const Params *p) 49 : SimObject(p) 50{ 51 m_cache_size = p->size; 52 m_latency = p->latency; 53 m_cache_assoc = p->assoc; 54 m_policy = p->replacement_policy; 55 m_profiler_ptr = new CacheProfiler(name()); 56 m_start_index_bit = p->start_index_bit; 57} 58 59void 60CacheMemory::init() 61{ 62 m_cache_num_sets = (m_cache_size / m_cache_assoc) / 63 RubySystem::getBlockSizeBytes(); 64 assert(m_cache_num_sets > 1); 65 m_cache_num_set_bits = floorLog2(m_cache_num_sets); 66 assert(m_cache_num_set_bits > 0); 67 68 if (m_policy == "PSEUDO_LRU") 69 m_replacementPolicy_ptr = 70 new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); 71 else if (m_policy == "LRU") 72 m_replacementPolicy_ptr = 73 new LRUPolicy(m_cache_num_sets, m_cache_assoc); 74 else 75 assert(false); 76 77 m_cache.resize(m_cache_num_sets); 78 m_locked.resize(m_cache_num_sets); 79 for (int i = 0; i < m_cache_num_sets; i++) { 80 m_cache[i].resize(m_cache_assoc); 81 m_locked[i].resize(m_cache_assoc); 82 for (int j = 0; j < m_cache_assoc; j++) { 83 m_cache[i][j] = NULL; 84 m_locked[i][j] = -1; 85 } 86 } 87} 88 89CacheMemory::~CacheMemory() 90{ 91 if (m_replacementPolicy_ptr != NULL) 92 delete m_replacementPolicy_ptr; 93 delete m_profiler_ptr; 94 for (int i = 0; i < m_cache_num_sets; i++) { 95 for (int j = 0; j < m_cache_assoc; j++) { 96 delete m_cache[i][j]; 97 } 98 } 99} 100 101void 102CacheMemory::printConfig(ostream& out) 103{ 104 int block_size = RubySystem::getBlockSizeBytes(); 105 106 out << "Cache config: " << m_cache_name << endl; 107 out << " cache_associativity: " << m_cache_assoc << endl; 108 out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; 109 const int cache_num_sets = 1 << m_cache_num_set_bits; 110 out << " num_cache_sets: " << cache_num_sets << endl; 111 out << " cache_set_size_bytes: " << cache_num_sets * block_size << endl; 112 out << " cache_set_size_Kbytes: " 113 << double(cache_num_sets * block_size) / (1<<10) << endl; 114 out << " cache_set_size_Mbytes: " 115 << double(cache_num_sets * block_size) / (1<<20) << endl; 116 out << " cache_size_bytes: " 117 << cache_num_sets * block_size * m_cache_assoc << endl; 118 out << " cache_size_Kbytes: " 119 << double(cache_num_sets * block_size * m_cache_assoc) / (1<<10) 120 << endl; 121 out << " cache_size_Mbytes: " 122 << double(cache_num_sets * block_size * m_cache_assoc) / (1<<20) 123 << endl; 124} 125 126// convert a Address to its location in the cache 127Index 128CacheMemory::addressToCacheSet(const Address& address) const 129{ 130 assert(address == line_address(address)); 131 return address.bitSelect(m_start_index_bit, 132 m_start_index_bit + m_cache_num_set_bits - 1); 133} 134 135// Given a cache index: returns the index of the tag in a set. 136// returns -1 if the tag is not found. 137int 138CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const 139{ 140 assert(tag == line_address(tag)); 141 // search the set for the tags 142 m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag); 143 if (it != m_tag_index.end()) 144 if (m_cache[cacheSet][it->second]->m_Permission != 145 AccessPermission_NotPresent) 146 return it->second; 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 153CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, 154 const Address& tag) const 155{ 156 assert(tag == line_address(tag)); 157 // search the set for the tags 158 m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag); 159 if (it != m_tag_index.end()) 160 return it->second; 161 return -1; // Not found 162} 163 164bool 165CacheMemory::tryCacheAccess(const Address& address, CacheRequestType type, 166 DataBlock*& data_ptr) 167{ 168 assert(address == line_address(address)); 169 DPRINTF(RubyCache, "address: %s\n", address); 170 Index cacheSet = addressToCacheSet(address); 171 int loc = findTagInSet(cacheSet, address); 172 if (loc != -1) { 173 // Do we even have a tag match? 174 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 175 m_replacementPolicy_ptr-> 176 touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 177 data_ptr = &(entry->getDataBlk()); 178 179 if (entry->m_Permission == AccessPermission_Read_Write) { 180 return true; 181 } 182 if ((entry->m_Permission == AccessPermission_Read_Only) && 183 (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { 184 return true; 185 } 186 // The line must not be accessible 187 } 188 data_ptr = NULL; 189 return false; 190} 191 192bool 193CacheMemory::testCacheAccess(const Address& address, CacheRequestType type, 194 DataBlock*& data_ptr) 195{ 196 assert(address == line_address(address)); 197 DPRINTF(RubyCache, "address: %s\n", address); 198 Index cacheSet = addressToCacheSet(address); 199 int loc = findTagInSet(cacheSet, address); 200 201 if (loc != -1) { 202 // Do we even have a tag match? 203 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 204 m_replacementPolicy_ptr-> 205 touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 206 data_ptr = &(entry->getDataBlk()); 207 208 return m_cache[cacheSet][loc]->m_Permission != 209 AccessPermission_NotPresent; 210 } 211 212 data_ptr = NULL; 213 return false; 214} 215 216// tests to see if an address is present in the cache 217bool 218CacheMemory::isTagPresent(const Address& address) const 219{ 220 assert(address == line_address(address)); 221 Index cacheSet = addressToCacheSet(address); 222 int loc = findTagInSet(cacheSet, address); 223 224 if (loc == -1) { 225 // We didn't find the tag 226 DPRINTF(RubyCache, "No tag match for address: %s\n", address); 227 return false; 228 } 229 DPRINTF(RubyCache, "address: %s found\n", address); 230 return true; 231} 232 233// Returns true if there is: 234// a) a tag match on this address or there is 235// b) an unused line in the same cache "way" 236bool 237CacheMemory::cacheAvail(const Address& address) const 238{ 239 assert(address == line_address(address)); 240 241 Index cacheSet = addressToCacheSet(address); 242 243 for (int i = 0; i < m_cache_assoc; i++) { 244 AbstractCacheEntry* entry = m_cache[cacheSet][i]; 245 if (entry != NULL) { 246 if (entry->m_Address == address || 247 entry->m_Permission == AccessPermission_NotPresent) { 248 // Already in the cache or we found an empty entry 249 return true; 250 } 251 } else { 252 return true; 253 } 254 } 255 return false; 256} 257 258void 259CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) 260{ 261 assert(address == line_address(address)); 262 assert(!isTagPresent(address)); 263 assert(cacheAvail(address)); 264 DPRINTF(RubyCache, "address: %s\n", address); 265 266 // Find the first open slot 267 Index cacheSet = addressToCacheSet(address); 268 std::vector<AbstractCacheEntry*> &set = m_cache[cacheSet]; 269 for (int i = 0; i < m_cache_assoc; i++) { 270 if (!set[i] || set[i]->m_Permission == AccessPermission_NotPresent) { 271 set[i] = entry; // Init entry 272 set[i]->m_Address = address; 273 set[i]->m_Permission = AccessPermission_Invalid; 274 DPRINTF(RubyCache, "Allocate clearing lock for addr: %x\n", 275 address); 276 m_locked[cacheSet][i] = -1; 277 m_tag_index[address] = i; 278 279 m_replacementPolicy_ptr-> 280 touch(cacheSet, i, g_eventQueue_ptr->getTime()); 281 282 return; 283 } 284 } 285 panic("Allocate didn't find an available entry"); 286} 287 288void 289CacheMemory::deallocate(const Address& address) 290{ 291 assert(address == line_address(address)); 292 assert(isTagPresent(address)); 293 DPRINTF(RubyCache, "address: %s\n", address); 294 Index cacheSet = addressToCacheSet(address); 295 int loc = findTagInSet(cacheSet, address); 296 if (loc != -1) { 297 delete m_cache[cacheSet][loc]; 298 m_cache[cacheSet][loc] = NULL; 299 DPRINTF(RubyCache, "Deallocate clearing lock for addr: %x\n", 300 address); 301 m_locked[cacheSet][loc] = -1; 302 m_tag_index.erase(address); 303 } 304} 305 306// Returns with the physical address of the conflicting cache line 307Address 308CacheMemory::cacheProbe(const Address& address) const 309{ 310 assert(address == line_address(address)); 311 assert(!cacheAvail(address)); 312 313 Index cacheSet = addressToCacheSet(address); 314 return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]-> 315 m_Address; 316} 317 318// looks an address up in the cache 319AbstractCacheEntry& 320CacheMemory::lookup(const Address& address) 321{ 322 assert(address == line_address(address)); 323 Index cacheSet = addressToCacheSet(address); 324 int loc = findTagInSet(cacheSet, address); 325 assert(loc != -1); 326 return *m_cache[cacheSet][loc]; 327} 328 329// looks an address up in the cache 330const AbstractCacheEntry& 331CacheMemory::lookup(const Address& address) const 332{ 333 assert(address == line_address(address)); 334 Index cacheSet = addressToCacheSet(address); 335 int loc = findTagInSet(cacheSet, address); 336 assert(loc != -1); 337 return *m_cache[cacheSet][loc]; 338} 339 340AccessPermission 341CacheMemory::getPermission(const Address& address) const 342{ 343 assert(address == line_address(address)); 344 return lookup(address).m_Permission; 345} 346 347void 348CacheMemory::changePermission(const Address& address, 349 AccessPermission new_perm) 350{ 351 assert(address == line_address(address)); 352 lookup(address).m_Permission = new_perm; 353 Index cacheSet = addressToCacheSet(address); 354 int loc = findTagInSet(cacheSet, address); 355 if ((new_perm == AccessPermission_Invalid) || 356 (new_perm == AccessPermission_NotPresent) || 357 (new_perm == AccessPermission_Stale)) { 358 DPRINTF(RubyCache, "Permission clearing lock for addr: %x\n", address); 359 m_locked[cacheSet][loc] = -1; 360 } 361 assert(getPermission(address) == new_perm); 362} 363 364// Sets the most recently used bit for a cache block 365void 366CacheMemory::setMRU(const Address& address) 367{ 368 Index cacheSet; 369 370 cacheSet = addressToCacheSet(address); 371 m_replacementPolicy_ptr-> 372 touch(cacheSet, findTagInSet(cacheSet, address), 373 g_eventQueue_ptr->getTime()); 374} 375 376void 377CacheMemory::profileMiss(const CacheMsg& msg) 378{ 379 m_profiler_ptr->addCacheStatSample(msg.getType(), 380 msg.getAccessMode(), 381 msg.getPrefetch()); 382} 383 384void 385CacheMemory::profileGenericRequest(GenericRequestType requestType, 386 AccessModeType accessType, 387 PrefetchBit pfBit) 388{ 389 m_profiler_ptr->addGenericStatSample(requestType, 390 accessType, 391 pfBit); 392} 393 394void 395CacheMemory::recordCacheContents(CacheRecorder& tr) const 396{ 397 for (int i = 0; i < m_cache_num_sets; i++) { 398 for (int j = 0; j < m_cache_assoc; j++) { 399 AccessPermission perm = m_cache[i][j]->m_Permission; 400 CacheRequestType request_type = CacheRequestType_NULL; 401 if (perm == AccessPermission_Read_Only) { 402 if (m_is_instruction_only_cache) { 403 request_type = CacheRequestType_IFETCH; 404 } else { 405 request_type = CacheRequestType_LD; 406 } 407 } else if (perm == AccessPermission_Read_Write) { 408 request_type = CacheRequestType_ST; 409 } 410 411 if (request_type != CacheRequestType_NULL) { 412#if 0 413 tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, 414 Address(0), request_type, 415 m_replacementPolicy_ptr->getLastAccess(i, j)); 416#endif 417 } 418 } 419 } 420} 421 422void 423CacheMemory::print(ostream& out) const 424{ 425 out << "Cache dump: " << m_cache_name << endl; 426 for (int i = 0; i < m_cache_num_sets; i++) { 427 for (int j = 0; j < m_cache_assoc; j++) { 428 if (m_cache[i][j] != NULL) { 429 out << " Index: " << i 430 << " way: " << j 431 << " entry: " << *m_cache[i][j] << endl; 432 } else { 433 out << " Index: " << i 434 << " way: " << j 435 << " entry: NULL" << endl; 436 } 437 } 438 } 439} 440 441void 442CacheMemory::printData(ostream& out) const 443{ 444 out << "printData() not supported" << endl; 445} 446 447void 448CacheMemory::clearStats() const 449{ 450 m_profiler_ptr->clearStats(); 451} 452 453void 454CacheMemory::printStats(ostream& out) const 455{ 456 m_profiler_ptr->printStats(out); 457} 458 459void 460CacheMemory::getMemoryValue(const Address& addr, char* value, 461 unsigned size_in_bytes) 462{ 463 AbstractCacheEntry& entry = lookup(line_address(addr)); 464 unsigned startByte = addr.getAddress() - line_address(addr).getAddress(); 465 for (unsigned i = 0; i < size_in_bytes; ++i) { 466 value[i] = entry.getDataBlk().getByte(i + startByte); 467 } 468} 469 470void 471CacheMemory::setMemoryValue(const Address& addr, char* value, 472 unsigned size_in_bytes) 473{ 474 AbstractCacheEntry& entry = lookup(line_address(addr)); 475 unsigned startByte = addr.getAddress() - line_address(addr).getAddress(); 476 assert(size_in_bytes > 0); 477 for (unsigned i = 0; i < size_in_bytes; ++i) { 478 entry.getDataBlk().setByte(i + startByte, value[i]); 479 } 480 481 // entry = lookup(line_address(addr)); 482} 483 484void 485CacheMemory::setLocked(const Address& address, int context) 486{ 487 DPRINTF(RubyCache, "Setting Lock for addr: %x to %d\n", address, context); 488 assert(address == line_address(address)); 489 Index cacheSet = addressToCacheSet(address); 490 int loc = findTagInSet(cacheSet, address); 491 assert(loc != -1); 492 m_locked[cacheSet][loc] = context; 493} 494 495void 496CacheMemory::clearLocked(const Address& address) 497{ 498 DPRINTF(RubyCache, "Clear Lock for addr: %x\n", address); 499 assert(address == line_address(address)); 500 Index cacheSet = addressToCacheSet(address); 501 int loc = findTagInSet(cacheSet, address); 502 assert(loc != -1); 503 m_locked[cacheSet][loc] = -1; 504} 505 506bool 507CacheMemory::isLocked(const Address& address, int context) 508{ 509 assert(address == line_address(address)); 510 Index cacheSet = addressToCacheSet(address); 511 int loc = findTagInSet(cacheSet, address); 512 assert(loc != -1); 513 DPRINTF(RubyCache, "Testing Lock for addr: %llx cur %d con %d\n", 514 address, m_locked[cacheSet][loc], context); 515 return m_locked[cacheSet][loc] == context; 516} 517 518