CacheMemory.cc revision 7055
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 31using namespace std; 32 33ostream& 34operator<<(ostream& out, const CacheMemory& obj) 35{ 36 obj.print(out); 37 out << flush; 38 return out; 39} 40 41CacheMemory * 42RubyCacheParams::create() 43{ 44 return new CacheMemory(this); 45} 46 47CacheMemory::CacheMemory(const Params *p) 48 : SimObject(p) 49{ 50 m_cache_size = p->size; 51 m_latency = p->latency; 52 m_cache_assoc = p->assoc; 53 m_policy = p->replacement_policy; 54 m_profiler_ptr = new CacheProfiler(name()); 55} 56 57void 58CacheMemory::init() 59{ 60 m_cache_num_sets = (m_cache_size / m_cache_assoc) / 61 RubySystem::getBlockSizeBytes(); 62 assert(m_cache_num_sets > 1); 63 m_cache_num_set_bits = log_int(m_cache_num_sets); 64 assert(m_cache_num_set_bits > 0); 65 66 if (m_policy == "PSEUDO_LRU") 67 m_replacementPolicy_ptr = 68 new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); 69 else if (m_policy == "LRU") 70 m_replacementPolicy_ptr = 71 new LRUPolicy(m_cache_num_sets, m_cache_assoc); 72 else 73 assert(false); 74 75 m_cache.setSize(m_cache_num_sets); 76 m_locked.setSize(m_cache_num_sets); 77 for (int i = 0; i < m_cache_num_sets; i++) { 78 m_cache[i].setSize(m_cache_assoc); 79 m_locked[i].setSize(m_cache_assoc); 80 for (int j = 0; j < m_cache_assoc; j++) { 81 m_cache[i][j] = NULL; 82 m_locked[i][j] = -1; 83 } 84 } 85} 86 87CacheMemory::~CacheMemory() 88{ 89 if (m_replacementPolicy_ptr != NULL) 90 delete m_replacementPolicy_ptr; 91 delete m_profiler_ptr; 92 for (int i = 0; i < m_cache_num_sets; i++) { 93 for (int j = 0; j < m_cache_assoc; j++) { 94 delete m_cache[i][j]; 95 } 96 } 97} 98 99void 100CacheMemory::printConfig(ostream& out) 101{ 102 int block_size = RubySystem::getBlockSizeBytes(); 103 104 out << "Cache config: " << m_cache_name << endl; 105 out << " cache_associativity: " << m_cache_assoc << endl; 106 out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; 107 const int cache_num_sets = 1 << m_cache_num_set_bits; 108 out << " num_cache_sets: " << cache_num_sets << endl; 109 out << " cache_set_size_bytes: " << cache_num_sets * block_size << endl; 110 out << " cache_set_size_Kbytes: " 111 << double(cache_num_sets * block_size) / (1<<10) << endl; 112 out << " cache_set_size_Mbytes: " 113 << double(cache_num_sets * block_size) / (1<<20) << endl; 114 out << " cache_size_bytes: " 115 << cache_num_sets * block_size * m_cache_assoc << endl; 116 out << " cache_size_Kbytes: " 117 << double(cache_num_sets * block_size * m_cache_assoc) / (1<<10) 118 << endl; 119 out << " cache_size_Mbytes: " 120 << double(cache_num_sets * block_size * m_cache_assoc) / (1<<20) 121 << endl; 122} 123 124// convert a Address to its location in the cache 125Index 126CacheMemory::addressToCacheSet(const Address& address) const 127{ 128 assert(address == line_address(address)); 129 return address.bitSelect(RubySystem::getBlockSizeBits(), 130 RubySystem::getBlockSizeBits() + m_cache_num_set_bits - 1); 131} 132 133// Given a cache index: returns the index of the tag in a set. 134// returns -1 if the tag is not found. 135int 136CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const 137{ 138 assert(tag == line_address(tag)); 139 // search the set for the tags 140 m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag); 141 if (it != m_tag_index.end()) 142 if (m_cache[cacheSet][it->second]->m_Permission != 143 AccessPermission_NotPresent) 144 return it->second; 145 return -1; // Not found 146} 147 148// Given a cache index: returns the index of the tag in a set. 149// returns -1 if the tag is not found. 150int 151CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, 152 const Address& tag) const 153{ 154 assert(tag == line_address(tag)); 155 // search the set for the tags 156 m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag); 157 if (it != m_tag_index.end()) 158 return it->second; 159 return -1; // Not found 160} 161 162bool 163CacheMemory::tryCacheAccess(const Address& address, CacheRequestType type, 164 DataBlock*& data_ptr) 165{ 166 assert(address == line_address(address)); 167 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 168 Index cacheSet = addressToCacheSet(address); 169 int loc = findTagInSet(cacheSet, address); 170 if (loc != -1) { 171 // Do we even have a tag match? 172 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 173 m_replacementPolicy_ptr-> 174 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 191CacheMemory::testCacheAccess(const Address& address, 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 199 if (loc != -1) { 200 // Do we even have a tag match? 201 AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 202 m_replacementPolicy_ptr-> 203 touch(cacheSet, loc, g_eventQueue_ptr->getTime()); 204 data_ptr = &(entry->getDataBlk()); 205 206 return m_cache[cacheSet][loc]->m_Permission != 207 AccessPermission_NotPresent; 208 } 209 210 data_ptr = NULL; 211 return false; 212} 213 214// tests to see if an address is present in the cache 215bool 216CacheMemory::isTagPresent(const Address& address) const 217{ 218 assert(address == line_address(address)); 219 Index cacheSet = addressToCacheSet(address); 220 int loc = findTagInSet(cacheSet, address); 221 222 if (loc == -1) { 223 // We didn't find the tag 224 DEBUG_EXPR(CACHE_COMP, LowPrio, address); 225 DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match"); 226 return false; 227 } 228 DEBUG_EXPR(CACHE_COMP, LowPrio, address); 229 DEBUG_MSG(CACHE_COMP, LowPrio, "found"); 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 DEBUG_EXPR(CACHE_COMP, HighPrio, address); 265 266 // Find the first open slot 267 Index cacheSet = addressToCacheSet(address); 268 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 ERROR_MSG("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 DEBUG_EXPR(CACHE_COMP, HighPrio, 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_Read_Write) { 356 DPRINTF(RubyCache, "Permission clearing lock for addr: %x\n", address); 357 m_locked[cacheSet][loc] = -1; 358 } 359 assert(getPermission(address) == new_perm); 360} 361 362// Sets the most recently used bit for a cache block 363void 364CacheMemory::setMRU(const Address& address) 365{ 366 Index cacheSet; 367 368 cacheSet = addressToCacheSet(address); 369 m_replacementPolicy_ptr-> 370 touch(cacheSet, findTagInSet(cacheSet, address), 371 g_eventQueue_ptr->getTime()); 372} 373 374void 375CacheMemory::profileMiss(const CacheMsg& msg) 376{ 377 m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(), 378 msg.getSize(), msg.getPrefetch()); 379} 380 381void 382CacheMemory::recordCacheContents(CacheRecorder& tr) const 383{ 384 for (int i = 0; i < m_cache_num_sets; i++) { 385 for (int j = 0; j < m_cache_assoc; j++) { 386 AccessPermission perm = m_cache[i][j]->m_Permission; 387 CacheRequestType request_type = CacheRequestType_NULL; 388 if (perm == AccessPermission_Read_Only) { 389 if (m_is_instruction_only_cache) { 390 request_type = CacheRequestType_IFETCH; 391 } else { 392 request_type = CacheRequestType_LD; 393 } 394 } else if (perm == AccessPermission_Read_Write) { 395 request_type = CacheRequestType_ST; 396 } 397 398 if (request_type != CacheRequestType_NULL) { 399#if 0 400 tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, 401 Address(0), request_type, 402 m_replacementPolicy_ptr->getLastAccess(i, j)); 403#endif 404 } 405 } 406 } 407} 408 409void 410CacheMemory::print(ostream& out) const 411{ 412 out << "Cache dump: " << m_cache_name << endl; 413 for (int i = 0; i < m_cache_num_sets; i++) { 414 for (int j = 0; j < m_cache_assoc; j++) { 415 if (m_cache[i][j] != NULL) { 416 out << " Index: " << i 417 << " way: " << j 418 << " entry: " << *m_cache[i][j] << endl; 419 } else { 420 out << " Index: " << i 421 << " way: " << j 422 << " entry: NULL" << endl; 423 } 424 } 425 } 426} 427 428void 429CacheMemory::printData(ostream& out) const 430{ 431 out << "printData() not supported" << endl; 432} 433 434void 435CacheMemory::clearStats() const 436{ 437 m_profiler_ptr->clearStats(); 438} 439 440void 441CacheMemory::printStats(ostream& out) const 442{ 443 m_profiler_ptr->printStats(out); 444} 445 446void 447CacheMemory::getMemoryValue(const Address& addr, char* value, 448 unsigned size_in_bytes) 449{ 450 AbstractCacheEntry& entry = lookup(line_address(addr)); 451 unsigned startByte = addr.getAddress() - line_address(addr).getAddress(); 452 for (unsigned i = 0; i < size_in_bytes; ++i) { 453 value[i] = entry.getDataBlk().getByte(i + startByte); 454 } 455} 456 457void 458CacheMemory::setMemoryValue(const Address& addr, char* value, 459 unsigned size_in_bytes) 460{ 461 AbstractCacheEntry& entry = lookup(line_address(addr)); 462 unsigned startByte = addr.getAddress() - line_address(addr).getAddress(); 463 assert(size_in_bytes > 0); 464 for (unsigned i = 0; i < size_in_bytes; ++i) { 465 entry.getDataBlk().setByte(i + startByte, value[i]); 466 } 467 468 // entry = lookup(line_address(addr)); 469} 470 471void 472CacheMemory::setLocked(const Address& address, int context) 473{ 474 DPRINTF(RubyCache, "Setting Lock for addr: %x to %d\n", address, context); 475 assert(address == line_address(address)); 476 Index cacheSet = addressToCacheSet(address); 477 int loc = findTagInSet(cacheSet, address); 478 assert(loc != -1); 479 m_locked[cacheSet][loc] = context; 480} 481 482void 483CacheMemory::clearLocked(const Address& address) 484{ 485 DPRINTF(RubyCache, "Clear Lock for addr: %x\n", address); 486 assert(address == line_address(address)); 487 Index cacheSet = addressToCacheSet(address); 488 int loc = findTagInSet(cacheSet, address); 489 assert(loc != -1); 490 m_locked[cacheSet][loc] = -1; 491} 492 493bool 494CacheMemory::isLocked(const Address& address, int context) 495{ 496 assert(address == line_address(address)); 497 Index cacheSet = addressToCacheSet(address); 498 int loc = findTagInSet(cacheSet, address); 499 assert(loc != -1); 500 DPRINTF(RubyCache, "Testing Lock for addr: %llx cur %d con %d\n", 501 address, m_locked[cacheSet][loc], context); 502 return m_locked[cacheSet][loc] == context; 503} 504 505