CacheMemory.hh revision 6374
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/* 30 * CacheMemory.hh 31 * 32 * Description: 33 * 34 * $Id: CacheMemory.hh,v 3.7 2004/06/18 20:15:15 beckmann Exp $ 35 * 36 */ 37 38#ifndef CACHEMEMORY_H 39#define CACHEMEMORY_H 40 41#include "mem/ruby/common/Global.hh" 42#include "mem/protocol/AccessPermission.hh" 43#include "mem/ruby/common/Address.hh" 44#include "mem/ruby/recorder/CacheRecorder.hh" 45#include "mem/protocol/CacheRequestType.hh" 46#include "mem/gems_common/Vector.hh" 47#include "mem/ruby/common/DataBlock.hh" 48#include "mem/protocol/MachineType.hh" 49#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" 50#include "mem/ruby/system/PseudoLRUPolicy.hh" 51#include "mem/ruby/system/LRUPolicy.hh" 52#include "mem/ruby/slicc_interface/AbstractCacheEntry.hh" 53#include "mem/ruby/system/System.hh" 54#include "mem/ruby/slicc_interface/AbstractController.hh" 55#include "mem/ruby/profiler/CacheProfiler.hh" 56#include "mem/protocol/CacheMsg.hh" 57#include <vector> 58 59class CacheMemory { 60public: 61 62 // Constructors 63 CacheMemory(const string & name); 64 void init(const vector<string> & argv); 65 66 // Destructor 67 ~CacheMemory(); 68 69 // factory 70 // static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)()); 71 // static CacheMemory* getCache(int cache_id); 72 73 // Public Methods 74 void printConfig(ostream& out); 75 76 // perform a cache access and see if we hit or not. Return true on a hit. 77 bool tryCacheAccess(const Address& address, CacheRequestType type, DataBlock*& data_ptr); 78 79 // similar to above, but doesn't require full access check 80 bool testCacheAccess(const Address& address, CacheRequestType type, DataBlock*& data_ptr); 81 82 // tests to see if an address is present in the cache 83 bool isTagPresent(const Address& address) const; 84 85 // Returns true if there is: 86 // a) a tag match on this address or there is 87 // b) an unused line in the same cache "way" 88 bool cacheAvail(const Address& address) const; 89 90 // find an unused entry and sets the tag appropriate for the address 91 void allocate(const Address& address, AbstractCacheEntry* new_entry); 92 93 // Explicitly free up this address 94 void deallocate(const Address& address); 95 96 // Returns with the physical address of the conflicting cache line 97 Address cacheProbe(const Address& address) const; 98 99 // looks an address up in the cache 100 AbstractCacheEntry& lookup(const Address& address); 101 const AbstractCacheEntry& lookup(const Address& address) const; 102 103 // Get/Set permission of cache block 104 AccessPermission getPermission(const Address& address) const; 105 void changePermission(const Address& address, AccessPermission new_perm); 106 107 int getLatency() const { return m_latency; } 108 109 // Hook for checkpointing the contents of the cache 110 void recordCacheContents(CacheRecorder& tr) const; 111 void setAsInstructionCache(bool is_icache) { m_is_instruction_only_cache = is_icache; } 112 113 // Set this address to most recently used 114 void setMRU(const Address& address); 115 116 void profileMiss(const CacheMsg & msg); 117 118 void getMemoryValue(const Address& addr, char* value, 119 unsigned int size_in_bytes ); 120 void setMemoryValue(const Address& addr, char* value, 121 unsigned int size_in_bytes ); 122 123 void setLocked (const Address& addr, int context); 124 void clearLocked (const Address& addr); 125 bool isLocked (const Address& addr, int context); 126 // Print cache contents 127 void print(ostream& out) const; 128 void printData(ostream& out) const; 129 130 void printStats(ostream& out) const; 131 132private: 133 // Private Methods 134 135 // convert a Address to its location in the cache 136 Index addressToCacheSet(const Address& address) const; 137 138 // Given a cache tag: returns the index of the tag in a set. 139 // returns -1 if the tag is not found. 140 int findTagInSet(Index line, const Address& tag) const; 141 int findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const; 142 143 // Private copy constructor and assignment operator 144 CacheMemory(const CacheMemory& obj); 145 CacheMemory& operator=(const CacheMemory& obj); 146 147private: 148 const string m_cache_name; 149 AbstractController* m_controller; 150 int m_latency; 151 152 // Data Members (m_prefix) 153 bool m_is_instruction_only_cache; 154 bool m_is_data_only_cache; 155 156 // The first index is the # of cache lines. 157 // The second index is the the amount associativity. 158 Vector<Vector<AbstractCacheEntry*> > m_cache; 159 Vector<Vector<int> > m_locked; 160 161 AbstractReplacementPolicy *m_replacementPolicy_ptr; 162 163 CacheProfiler* m_profiler_ptr; 164 165 int m_cache_num_sets; 166 int m_cache_num_set_bits; 167 int m_cache_assoc; 168 169 static Vector< CacheMemory* > m_all_caches; 170}; 171 172// Output operator declaration 173//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj); 174 175// ******************* Definitions ******************* 176 177// Output operator definition 178inline 179ostream& operator<<(ostream& out, const CacheMemory& obj) 180{ 181 obj.print(out); 182 out << flush; 183 return out; 184} 185 186 187// **************************************************************** 188 189inline 190CacheMemory::CacheMemory(const string & name) 191 : m_cache_name(name) 192{ 193 m_profiler_ptr = new CacheProfiler(name); 194} 195 196inline 197void CacheMemory::init(const vector<string> & argv) 198{ 199 int cache_size = 0; 200 string policy; 201 202 m_controller = NULL; 203 for (uint32 i=0; i<argv.size(); i+=2) { 204 if (argv[i] == "size_kb") { 205 cache_size = atoi(argv[i+1].c_str()); 206 } else if (argv[i] == "latency") { 207 m_latency = atoi(argv[i+1].c_str()); 208 } else if (argv[i] == "assoc") { 209 m_cache_assoc = atoi(argv[i+1].c_str()); 210 } else if (argv[i] == "replacement_policy") { 211 policy = argv[i+1]; 212 } else if (argv[i] == "controller") { 213 m_controller = RubySystem::getController(argv[i+1]); 214 } else { 215 cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl; 216 } 217 } 218 219 m_cache_num_sets = cache_size / m_cache_assoc; 220 m_cache_num_set_bits = log_int(m_cache_num_sets); 221 222 if(policy == "PSEUDO_LRU") 223 m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); 224 else if (policy == "LRU") 225 m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc); 226 else 227 assert(false); 228 229 m_cache.setSize(m_cache_num_sets); 230 m_locked.setSize(m_cache_num_sets); 231 for (int i = 0; i < m_cache_num_sets; i++) { 232 m_cache[i].setSize(m_cache_assoc); 233 m_locked[i].setSize(m_cache_assoc); 234 for (int j = 0; j < m_cache_assoc; j++) { 235 m_cache[i][j] = NULL; 236 m_locked[i][j] = -1; 237 } 238 } 239} 240 241inline 242CacheMemory::~CacheMemory() 243{ 244 if(m_replacementPolicy_ptr != NULL) 245 delete m_replacementPolicy_ptr; 246} 247 248inline 249void CacheMemory::printConfig(ostream& out) 250{ 251 out << "Cache config: " << m_cache_name << endl; 252 if (m_controller != NULL) 253 out << " controller: " << m_controller->getName() << endl; 254 out << " cache_associativity: " << m_cache_assoc << endl; 255 out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; 256 const int cache_num_sets = 1 << m_cache_num_set_bits; 257 out << " num_cache_sets: " << cache_num_sets << endl; 258 out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl; 259 out << " cache_set_size_Kbytes: " 260 << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl; 261 out << " cache_set_size_Mbytes: " 262 << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl; 263 out << " cache_size_bytes: " 264 << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl; 265 out << " cache_size_Kbytes: " 266 << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl; 267 out << " cache_size_Mbytes: " 268 << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl; 269} 270 271// PRIVATE METHODS 272 273// convert a Address to its location in the cache 274inline 275Index CacheMemory::addressToCacheSet(const Address& address) const 276{ 277 assert(address == line_address(address)); 278 return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1); 279} 280 281// Given a cache index: returns the index of the tag in a set. 282// returns -1 if the tag is not found. 283inline 284int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const 285{ 286 assert(tag == line_address(tag)); 287 // search the set for the tags 288 for (int i=0; i < m_cache_assoc; i++) { 289 if ((m_cache[cacheSet][i] != NULL) && 290 (m_cache[cacheSet][i]->m_Address == tag) && 291 (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) { 292 return i; 293 } 294 } 295 return -1; // Not found 296} 297 298// Given a cache index: returns the index of the tag in a set. 299// returns -1 if the tag is not found. 300inline 301int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const 302{ 303 assert(tag == line_address(tag)); 304 // search the set for the tags 305 for (int i=0; i < m_cache_assoc; i++) { 306 if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag) 307 return i; 308 } 309 return -1; // Not found 310} 311 312// PUBLIC METHODS 313inline 314bool CacheMemory::tryCacheAccess(const Address& address, 315 CacheRequestType type, 316 DataBlock*& data_ptr) 317{ 318 assert(address == line_address(address)); 319 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 320 Index cacheSet = addressToCacheSet(address); 321 int loc = findTagInSet(cacheSet, address); 322 if(loc != -1){ // Do we even have a tag match? 323 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 324 m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 325 data_ptr = &(entry->getDataBlk()); 326 327 if(entry->m_Permission == AccessPermission_Read_Write) { 328 return true; 329 } 330 if ((entry->m_Permission == AccessPermission_Read_Only) && 331 (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { 332 return true; 333 } 334 // The line must not be accessible 335 } 336 data_ptr = NULL; 337 return false; 338} 339 340inline 341bool CacheMemory::testCacheAccess(const Address& address, 342 CacheRequestType type, 343 DataBlock*& data_ptr) 344{ 345 assert(address == line_address(address)); 346 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 347 Index cacheSet = addressToCacheSet(address); 348 int loc = findTagInSet(cacheSet, address); 349 if(loc != -1){ // Do we even have a tag match? 350 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 351 m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 352 data_ptr = &(entry->getDataBlk()); 353 354 return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent); 355 } 356 data_ptr = NULL; 357 return false; 358} 359 360// tests to see if an address is present in the cache 361inline 362bool CacheMemory::isTagPresent(const Address& address) const 363{ 364 assert(address == line_address(address)); 365 Index cacheSet = addressToCacheSet(address); 366 int location = findTagInSet(cacheSet, address); 367 368 if (location == -1) { 369 // We didn't find the tag 370 DEBUG_EXPR(CACHE_COMP, LowPrio, address); 371 DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match"); 372 return false; 373 } 374 DEBUG_EXPR(CACHE_COMP, LowPrio, address); 375 DEBUG_MSG(CACHE_COMP, LowPrio, "found"); 376 return true; 377} 378 379// Returns true if there is: 380// a) a tag match on this address or there is 381// b) an unused line in the same cache "way" 382inline 383bool CacheMemory::cacheAvail(const Address& address) const 384{ 385 assert(address == line_address(address)); 386 387 Index cacheSet = addressToCacheSet(address); 388 389 for (int i=0; i < m_cache_assoc; i++) { 390 AbstractCacheEntry* entry = m_cache[cacheSet][i]; 391 if (entry != NULL) { 392 if (entry->m_Address == address || // Already in the cache 393 entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry 394 return true; 395 } 396 } else { 397 return true; 398 } 399 } 400 return false; 401} 402 403inline 404void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) 405{ 406 assert(address == line_address(address)); 407 assert(!isTagPresent(address)); 408 assert(cacheAvail(address)); 409 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 410 411 // Find the first open slot 412 Index cacheSet = addressToCacheSet(address); 413 for (int i=0; i < m_cache_assoc; i++) { 414 if (m_cache[cacheSet][i] == NULL || 415 m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) { 416 m_cache[cacheSet][i] = entry; // Init entry 417 m_cache[cacheSet][i]->m_Address = address; 418 m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid; 419 m_locked[cacheSet][i] = -1; 420 421 m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime()); 422 423 return; 424 } 425 } 426 ERROR_MSG("Allocate didn't find an available entry"); 427} 428 429inline 430void CacheMemory::deallocate(const Address& address) 431{ 432 assert(address == line_address(address)); 433 assert(isTagPresent(address)); 434 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 435 Index cacheSet = addressToCacheSet(address); 436 int location = findTagInSet(cacheSet, address); 437 if (location != -1){ 438 delete m_cache[cacheSet][location]; 439 m_cache[cacheSet][location] = NULL; 440 m_locked[cacheSet][location] = -1; 441 } 442} 443 444// Returns with the physical address of the conflicting cache line 445inline 446Address CacheMemory::cacheProbe(const Address& address) const 447{ 448 assert(address == line_address(address)); 449 assert(!cacheAvail(address)); 450 451 Index cacheSet = addressToCacheSet(address); 452 return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address; 453} 454 455// looks an address up in the cache 456inline 457AbstractCacheEntry& CacheMemory::lookup(const Address& address) 458{ 459 assert(address == line_address(address)); 460 Index cacheSet = addressToCacheSet(address); 461 int loc = findTagInSet(cacheSet, address); 462 assert(loc != -1); 463 return *m_cache[cacheSet][loc]; 464} 465 466// looks an address up in the cache 467inline 468const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const 469{ 470 assert(address == line_address(address)); 471 Index cacheSet = addressToCacheSet(address); 472 int loc = findTagInSet(cacheSet, address); 473 assert(loc != -1); 474 return *m_cache[cacheSet][loc]; 475} 476 477inline 478AccessPermission CacheMemory::getPermission(const Address& address) const 479{ 480 assert(address == line_address(address)); 481 return lookup(address).m_Permission; 482} 483 484inline 485void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) 486{ 487 assert(address == line_address(address)); 488 lookup(address).m_Permission = new_perm; 489 Index cacheSet = addressToCacheSet(address); 490 int loc = findTagInSet(cacheSet, address); 491 m_locked[cacheSet][loc] = -1; 492 assert(getPermission(address) == new_perm); 493} 494 495// Sets the most recently used bit for a cache block 496inline 497void CacheMemory::setMRU(const Address& address) 498{ 499 Index cacheSet; 500 501 cacheSet = addressToCacheSet(address); 502 m_replacementPolicy_ptr->touch(cacheSet, 503 findTagInSet(cacheSet, address), 504 g_eventQueue_ptr->getTime()); 505} 506 507inline 508void CacheMemory::profileMiss(const CacheMsg & msg) 509{ 510 m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(), 511 msg.getSize(), msg.getPrefetch()); 512} 513 514inline 515void CacheMemory::recordCacheContents(CacheRecorder& tr) const 516{ 517 for (int i = 0; i < m_cache_num_sets; i++) { 518 for (int j = 0; j < m_cache_assoc; j++) { 519 AccessPermission perm = m_cache[i][j]->m_Permission; 520 CacheRequestType request_type = CacheRequestType_NULL; 521 if (perm == AccessPermission_Read_Only) { 522 if (m_is_instruction_only_cache) { 523 request_type = CacheRequestType_IFETCH; 524 } else { 525 request_type = CacheRequestType_LD; 526 } 527 } else if (perm == AccessPermission_Read_Write) { 528 request_type = CacheRequestType_ST; 529 } 530 531 if (request_type != CacheRequestType_NULL) { 532 // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, 533 // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); 534 } 535 } 536 } 537} 538 539inline 540void CacheMemory::print(ostream& out) const 541{ 542 out << "Cache dump: " << m_cache_name << endl; 543 for (int i = 0; i < m_cache_num_sets; i++) { 544 for (int j = 0; j < m_cache_assoc; j++) { 545 if (m_cache[i][j] != NULL) { 546 out << " Index: " << i 547 << " way: " << j 548 << " entry: " << *m_cache[i][j] << endl; 549 } else { 550 out << " Index: " << i 551 << " way: " << j 552 << " entry: NULL" << endl; 553 } 554 } 555 } 556} 557 558inline 559void CacheMemory::printData(ostream& out) const 560{ 561 out << "printData() not supported" << endl; 562} 563 564inline 565void CacheMemory::printStats(ostream& out) const 566{ 567 m_profiler_ptr->printStats(out); 568} 569 570inline 571void CacheMemory::getMemoryValue(const Address& addr, char* value, 572 unsigned int size_in_bytes ){ 573 AbstractCacheEntry& entry = lookup(line_address(addr)); 574 unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); 575 for(unsigned int i=0; i<size_in_bytes; ++i){ 576 value[i] = entry.getDataBlk().getByte(i + startByte); 577 } 578} 579 580inline 581void CacheMemory::setMemoryValue(const Address& addr, char* value, 582 unsigned int size_in_bytes ){ 583 AbstractCacheEntry& entry = lookup(line_address(addr)); 584 unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); 585 assert(size_in_bytes > 0); 586 for(unsigned int i=0; i<size_in_bytes; ++i){ 587 entry.getDataBlk().setByte(i + startByte, value[i]); 588 } 589 590 // entry = lookup(line_address(addr)); 591} 592 593inline 594void 595CacheMemory::setLocked(const Address& address, int context) 596{ 597 assert(address == line_address(address)); 598 Index cacheSet = addressToCacheSet(address); 599 int loc = findTagInSet(cacheSet, address); 600 assert(loc != -1); 601 m_locked[cacheSet][loc] = context; 602} 603 604inline 605void 606CacheMemory::clearLocked(const Address& address) 607{ 608 assert(address == line_address(address)); 609 Index cacheSet = addressToCacheSet(address); 610 int loc = findTagInSet(cacheSet, address); 611 assert(loc != -1); 612 m_locked[cacheSet][loc] = -1; 613} 614 615inline 616bool 617CacheMemory::isLocked(const Address& address, int context) 618{ 619 assert(address == line_address(address)); 620 Index cacheSet = addressToCacheSet(address); 621 int loc = findTagInSet(cacheSet, address); 622 assert(loc != -1); 623 return m_locked[cacheSet][loc] == context; 624} 625 626#endif //CACHEMEMORY_H 627 628