CacheMemory.cc revision 14184
110717Sandreas.hansson@arm.com/* 28839Sandreas.hansson@arm.com * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood 38839Sandreas.hansson@arm.com * Copyright (c) 2013 Advanced Micro Devices, Inc. 48839Sandreas.hansson@arm.com * All rights reserved. 58839Sandreas.hansson@arm.com * 68839Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 78839Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 88839Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 98839Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 108839Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 118839Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 128839Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 135335Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its 147897Shestness@cs.utexas.edu * contributors may be used to endorse or promote products derived from 154486Sbinkertn@umich.edu * this software without specific prior written permission. 164486Sbinkertn@umich.edu * 174486Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 184486Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 194486Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 204486Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 214486Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 224486Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 234486Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 244486Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 254486Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 264486Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 274486Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 284486Sbinkertn@umich.edu */ 294486Sbinkertn@umich.edu 304486Sbinkertn@umich.edu#include "mem/ruby/structures/CacheMemory.hh" 314486Sbinkertn@umich.edu 324486Sbinkertn@umich.edu#include "base/intmath.hh" 334486Sbinkertn@umich.edu#include "base/logging.hh" 344486Sbinkertn@umich.edu#include "debug/RubyCache.hh" 354486Sbinkertn@umich.edu#include "debug/RubyCacheTrace.hh" 364486Sbinkertn@umich.edu#include "debug/RubyResourceStalls.hh" 374486Sbinkertn@umich.edu#include "debug/RubyStats.hh" 384486Sbinkertn@umich.edu#include "mem/ruby/protocol/AccessPermission.hh" 394486Sbinkertn@umich.edu#include "mem/ruby/system/RubySystem.hh" 404486Sbinkertn@umich.edu#include "mem/ruby/system/WeightedLRUPolicy.hh" 417897Shestness@cs.utexas.edu 428839Sandreas.hansson@arm.comusing namespace std; 434486Sbinkertn@umich.edu 446654Snate@binkert.orgostream& 456654Snate@binkert.orgoperator<<(ostream& out, const CacheMemory& obj) 4611988Sandreas.sandberg@arm.com{ 476654Snate@binkert.org obj.print(out); 483102SN/A out << flush; 493102SN/A return out; 506654Snate@binkert.org} 5110720Sandreas.hansson@arm.com 524776Sgblack@eecs.umich.eduCacheMemory * 5310663SAli.Saidi@ARM.comRubyCacheParams::create() 546654Snate@binkert.org{ 559793Sakash.bagdia@arm.com return new CacheMemory(this); 562667SN/A} 574776Sgblack@eecs.umich.edu 584776Sgblack@eecs.umich.eduCacheMemory::CacheMemory(const Params *p) 596654Snate@binkert.org : SimObject(p), 606023Snate@binkert.org dataArray(p->dataArrayBanks, p->dataAccessLatency, 618745Sgblack@eecs.umich.edu p->start_index_bit, p->ruby_system), 629384SAndreas.Sandberg@arm.com tagArray(p->tagArrayBanks, p->tagAccessLatency, 639384SAndreas.Sandberg@arm.com p->start_index_bit, p->ruby_system) 646654Snate@binkert.org{ 656022Sgblack@eecs.umich.edu m_cache_size = p->size; 668745Sgblack@eecs.umich.edu m_cache_assoc = p->assoc; 679384SAndreas.Sandberg@arm.com m_replacementPolicy_ptr = p->replacement_policy; 689384SAndreas.Sandberg@arm.com m_replacementPolicy_ptr->setCache(this); 696654Snate@binkert.org m_start_index_bit = p->start_index_bit; 706022Sgblack@eecs.umich.edu m_is_instruction_only_cache = p->is_icache; 718745Sgblack@eecs.umich.edu m_resource_stalls = p->resourceStalls; 729384SAndreas.Sandberg@arm.com m_block_size = p->block_size; // may be 0 at this point. Updated in init() 739384SAndreas.Sandberg@arm.com} 746654Snate@binkert.org 756022Sgblack@eecs.umich.eduvoid 768745Sgblack@eecs.umich.eduCacheMemory::init() 779384SAndreas.Sandberg@arm.com{ 789384SAndreas.Sandberg@arm.com if (m_block_size == 0) { 796654Snate@binkert.org m_block_size = RubySystem::getBlockSizeBytes(); 8010037SARM gem5 Developers } 818745Sgblack@eecs.umich.edu m_cache_num_sets = (m_cache_size / m_cache_assoc) / m_block_size; 829384SAndreas.Sandberg@arm.com assert(m_cache_num_sets > 1); 839384SAndreas.Sandberg@arm.com m_cache_num_set_bits = floorLog2(m_cache_num_sets); 846691Stjones1@inf.ed.ac.uk assert(m_cache_num_set_bits > 0); 856691Stjones1@inf.ed.ac.uk 868745Sgblack@eecs.umich.edu m_cache.resize(m_cache_num_sets, 879384SAndreas.Sandberg@arm.com std::vector<AbstractCacheEntry*>(m_cache_assoc, nullptr)); 889384SAndreas.Sandberg@arm.com} 8911723Sar4jc@virginia.edu 9011723Sar4jc@virginia.eduCacheMemory::~CacheMemory() 9111723Sar4jc@virginia.edu{ 9211723Sar4jc@virginia.edu if (m_replacementPolicy_ptr) 9311723Sar4jc@virginia.edu delete m_replacementPolicy_ptr; 944486Sbinkertn@umich.edu for (int i = 0; i < m_cache_num_sets; i++) { 955529Snate@binkert.org for (int j = 0; j < m_cache_assoc; j++) { 961366SN/A delete m_cache[i][j]; 971310SN/A } 989338SAndreas.Sandberg@arm.com } 999254SAndreas.Sandberg@arm.com} 10011988Sandreas.sandberg@arm.com 10111988Sandreas.sandberg@arm.com// convert a Address to its location in the cache 10211988Sandreas.sandberg@arm.comint64_t 10311988Sandreas.sandberg@arm.comCacheMemory::addressToCacheSet(Addr address) const 10411988Sandreas.sandberg@arm.com{ 10511988Sandreas.sandberg@arm.com assert(address == makeLineAddress(address)); 10611988Sandreas.sandberg@arm.com return bitSelect(address, m_start_index_bit, 10711988Sandreas.sandberg@arm.com m_start_index_bit + m_cache_num_set_bits - 1); 10811988Sandreas.sandberg@arm.com} 10911988Sandreas.sandberg@arm.com 1109254SAndreas.Sandberg@arm.com// Given a cache index: returns the index of the tag in a set. 1119518SAndreas.Sandberg@ARM.com// returns -1 if the tag is not found. 1129518SAndreas.Sandberg@ARM.comint 1139518SAndreas.Sandberg@ARM.comCacheMemory::findTagInSet(int64_t cacheSet, Addr tag) const 1149518SAndreas.Sandberg@ARM.com{ 1159518SAndreas.Sandberg@ARM.com assert(tag == makeLineAddress(tag)); 1169518SAndreas.Sandberg@ARM.com // search the set for the tags 1179518SAndreas.Sandberg@ARM.com auto it = m_tag_index.find(tag); 1189518SAndreas.Sandberg@ARM.com if (it != m_tag_index.end()) 1199518SAndreas.Sandberg@ARM.com if (m_cache[cacheSet][it->second]->m_Permission != 1209518SAndreas.Sandberg@ARM.com AccessPermission_NotPresent) 1219518SAndreas.Sandberg@ARM.com return it->second; 1229518SAndreas.Sandberg@ARM.com return -1; // Not found 1239518SAndreas.Sandberg@ARM.com} 1249518SAndreas.Sandberg@ARM.com 1259518SAndreas.Sandberg@ARM.com// Given a cache index: returns the index of the tag in a set. 1269518SAndreas.Sandberg@ARM.com// returns -1 if the tag is not found. 1279518SAndreas.Sandberg@ARM.comint 1289518SAndreas.Sandberg@ARM.comCacheMemory::findTagInSetIgnorePermissions(int64_t cacheSet, 1299518SAndreas.Sandberg@ARM.com Addr tag) const 1309254SAndreas.Sandberg@arm.com{ 1319254SAndreas.Sandberg@arm.com assert(tag == makeLineAddress(tag)); 1329254SAndreas.Sandberg@arm.com // search the set for the tags 1339254SAndreas.Sandberg@arm.com auto it = m_tag_index.find(tag); 1342901SN/A if (it != m_tag_index.end()) 1355712Shsul@eecs.umich.edu return it->second; 13610190Sakash.bagdia@arm.com return -1; // Not found 1375529Snate@binkert.org} 1385529Snate@binkert.org 1395529Snate@binkert.org// Given an unique cache block identifier (idx): return the valid address 1409161Sandreas.hansson@arm.com// stored by the cache block. If the block is invalid/notpresent, the 1415529Snate@binkert.org// function returns the 0 address 1425821Ssaidi@eecs.umich.eduAddr 1433170SN/ACacheMemory::getAddressAtIdx(int idx) const 14411877Sbrandon.potter@amd.com{ 14511877Sbrandon.potter@amd.com Addr tmp(0); 1465780Ssteve.reinhardt@amd.com 1475780Ssteve.reinhardt@amd.com int set = idx / m_cache_assoc; 1485780Ssteve.reinhardt@amd.com assert(set < m_cache_num_sets); 1495780Ssteve.reinhardt@amd.com 1505780Ssteve.reinhardt@amd.com int way = idx - set * m_cache_assoc; 1518784Sgblack@eecs.umich.edu assert (way < m_cache_assoc); 1528784Sgblack@eecs.umich.edu 1538784Sgblack@eecs.umich.edu AbstractCacheEntry* entry = m_cache[set][way]; 1548793Sgblack@eecs.umich.edu if (entry == NULL || 1551310SN/A entry->m_Permission == AccessPermission_Invalid || 1566654Snate@binkert.org entry->m_Permission == AccessPermission_NotPresent) { 1576022Sgblack@eecs.umich.edu return tmp; 1586022Sgblack@eecs.umich.edu } 15911150Smitch.hayenga@arm.com return entry->m_Address; 16011150Smitch.hayenga@arm.com} 1619384SAndreas.Sandberg@arm.com 1626654Snate@binkert.orgbool 1636023Snate@binkert.orgCacheMemory::tryCacheAccess(Addr address, RubyRequestType type, 1646023Snate@binkert.org DataBlock*& data_ptr) 16511150Smitch.hayenga@arm.com{ 16611150Smitch.hayenga@arm.com assert(address == makeLineAddress(address)); 1679384SAndreas.Sandberg@arm.com DPRINTF(RubyCache, "address: %#x\n", address); 1686654Snate@binkert.org int64_t cacheSet = addressToCacheSet(address); 1696022Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 1706022Sgblack@eecs.umich.edu if (loc != -1) { 17111150Smitch.hayenga@arm.com // Do we even have a tag match? 1729384SAndreas.Sandberg@arm.com AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 1736654Snate@binkert.org m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 1746022Sgblack@eecs.umich.edu data_ptr = &(entry->getDataBlk()); 1756022Sgblack@eecs.umich.edu 17611150Smitch.hayenga@arm.com if (entry->m_Permission == AccessPermission_Read_Write) { 17711150Smitch.hayenga@arm.com return true; 1789384SAndreas.Sandberg@arm.com } 1796654Snate@binkert.org if ((entry->m_Permission == AccessPermission_Read_Only) && 1806116Snate@binkert.org (type == RubyRequestType_LD || type == RubyRequestType_IFETCH)) { 1816116Snate@binkert.org return true; 18210037SARM gem5 Developers } 18310037SARM gem5 Developers // The line must not be accessible 18411150Smitch.hayenga@arm.com } 18511150Smitch.hayenga@arm.com data_ptr = NULL; 1869384SAndreas.Sandberg@arm.com return false; 1876691Stjones1@inf.ed.ac.uk} 1886691Stjones1@inf.ed.ac.uk 1896691Stjones1@inf.ed.ac.ukbool 1906691Stjones1@inf.ed.ac.ukCacheMemory::testCacheAccess(Addr address, RubyRequestType type, 19111150Smitch.hayenga@arm.com DataBlock*& data_ptr) 19211150Smitch.hayenga@arm.com{ 1939384SAndreas.Sandberg@arm.com assert(address == makeLineAddress(address)); 19411723Sar4jc@virginia.edu DPRINTF(RubyCache, "address: %#x\n", address); 19511723Sar4jc@virginia.edu int64_t cacheSet = addressToCacheSet(address); 19611723Sar4jc@virginia.edu int loc = findTagInSet(cacheSet, address); 19711723Sar4jc@virginia.edu 19811723Sar4jc@virginia.edu if (loc != -1) { 19911723Sar4jc@virginia.edu // Do we even have a tag match? 2004997Sgblack@eecs.umich.edu AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 2014997Sgblack@eecs.umich.edu m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 2026654Snate@binkert.org data_ptr = &(entry->getDataBlk()); 2034997Sgblack@eecs.umich.edu 2044997Sgblack@eecs.umich.edu return m_cache[cacheSet][loc]->m_Permission != 2051310SN/A AccessPermission_NotPresent; 2061310SN/A } 2071310SN/A 2081310SN/A data_ptr = NULL; 2099647Sdam.sunwoo@arm.com return false; 2109647Sdam.sunwoo@arm.com} 2111310SN/A 2121310SN/A// tests to see if an address is present in the cache 2131310SN/Abool 2141310SN/ACacheMemory::isTagPresent(Addr address) const 2159180Sandreas.hansson@arm.com{ 2169180Sandreas.hansson@arm.com assert(address == makeLineAddress(address)); 2171310SN/A int64_t cacheSet = addressToCacheSet(address); 2189433SAndreas.Sandberg@ARM.com int loc = findTagInSet(cacheSet, address); 2199433SAndreas.Sandberg@ARM.com 2209433SAndreas.Sandberg@ARM.com if (loc == -1) { 2211634SN/A // We didn't find the tag 2224776Sgblack@eecs.umich.edu DPRINTF(RubyCache, "No tag match for address: %#x\n", address); 2234776Sgblack@eecs.umich.edu return false; 2248839Sandreas.hansson@arm.com } 2258839Sandreas.hansson@arm.com DPRINTF(RubyCache, "address: %#x found\n", address); 2268707Sandreas.hansson@arm.com return true; 2278707Sandreas.hansson@arm.com} 2288756Sgblack@eecs.umich.edu 2298707Sandreas.hansson@arm.com// Returns true if there is: 2307876Sgblack@eecs.umich.edu// a) a tag match on this address or there is 2318839Sandreas.hansson@arm.com// b) an unused line in the same cache "way" 2328839Sandreas.hansson@arm.combool 2338745Sgblack@eecs.umich.eduCacheMemory::cacheAvail(Addr address) const 23411150Smitch.hayenga@arm.com{ 23511150Smitch.hayenga@arm.com assert(address == makeLineAddress(address)); 23611150Smitch.hayenga@arm.com 2372998SN/A int64_t cacheSet = addressToCacheSet(address); 2388863Snilay@cs.wisc.edu 2398863Snilay@cs.wisc.edu for (int i = 0; i < m_cache_assoc; i++) { 24011150Smitch.hayenga@arm.com AbstractCacheEntry* entry = m_cache[cacheSet][i]; 2418863Snilay@cs.wisc.edu if (entry != NULL) { 24211150Smitch.hayenga@arm.com if (entry->m_Address == address || 2438863Snilay@cs.wisc.edu entry->m_Permission == AccessPermission_NotPresent) { 2449793Sakash.bagdia@arm.com // Already in the cache or we found an empty entry 2459793Sakash.bagdia@arm.com return true; 2469793Sakash.bagdia@arm.com } 24711150Smitch.hayenga@arm.com } else { 2489544Sandreas.hansson@arm.com return true; 24911150Smitch.hayenga@arm.com } 2509544Sandreas.hansson@arm.com } 2518863Snilay@cs.wisc.edu return false; 25211150Smitch.hayenga@arm.com} 2538863Snilay@cs.wisc.edu 25411150Smitch.hayenga@arm.comAbstractCacheEntry* 2558863Snilay@cs.wisc.eduCacheMemory::allocate(Addr address, AbstractCacheEntry *entry, bool touch) 25611150Smitch.hayenga@arm.com{ 25711723Sar4jc@virginia.edu assert(address == makeLineAddress(address)); 25811723Sar4jc@virginia.edu assert(!isTagPresent(address)); 25911723Sar4jc@virginia.edu assert(cacheAvail(address)); 2608863Snilay@cs.wisc.edu DPRINTF(RubyCache, "address: %#x\n", address); 2618863Snilay@cs.wisc.edu 2628863Snilay@cs.wisc.edu // Find the first open slot 2638863Snilay@cs.wisc.edu int64_t cacheSet = addressToCacheSet(address); 2648863Snilay@cs.wisc.edu std::vector<AbstractCacheEntry*> &set = m_cache[cacheSet]; 2657876Sgblack@eecs.umich.edu for (int i = 0; i < m_cache_assoc; i++) { 2667876Sgblack@eecs.umich.edu if (!set[i] || set[i]->m_Permission == AccessPermission_NotPresent) { 2678839Sandreas.hansson@arm.com if (set[i] && (set[i] != entry)) { 2687404SAli.Saidi@ARM.com warn_once("This protocol contains a cache entry handling bug: " 2697876Sgblack@eecs.umich.edu "Entries in the cache should never be NotPresent! If\n" 2708839Sandreas.hansson@arm.com "this entry (%#x) is not tracked elsewhere, it will memory " 2718839Sandreas.hansson@arm.com "leak here. Fix your protocol to eliminate these!", 2728839Sandreas.hansson@arm.com address); 2738839Sandreas.hansson@arm.com } 2747876Sgblack@eecs.umich.edu set[i] = entry; // Init entry 2757876Sgblack@eecs.umich.edu set[i]->m_Address = address; 2767876Sgblack@eecs.umich.edu set[i]->m_Permission = AccessPermission_Invalid; 2777876Sgblack@eecs.umich.edu DPRINTF(RubyCache, "Allocate clearing lock for addr: %x\n", 2787876Sgblack@eecs.umich.edu address); 2797876Sgblack@eecs.umich.edu set[i]->m_locked = -1; 2802998SN/A m_tag_index[address] = i; 2817868Sgblack@eecs.umich.edu entry->setSetIndex(cacheSet); 2822998SN/A entry->setWayIndex(i); 2832998SN/A 2842998SN/A if (touch) { 2852998SN/A m_replacementPolicy_ptr->touch(cacheSet, i, curTick()); 2867876Sgblack@eecs.umich.edu } 2878796Sgblack@eecs.umich.edu 2888796Sgblack@eecs.umich.edu return entry; 2898796Sgblack@eecs.umich.edu } 2908796Sgblack@eecs.umich.edu } 29110717Sandreas.hansson@arm.com panic("Allocate didn't find an available entry"); 29210717Sandreas.hansson@arm.com} 2938796Sgblack@eecs.umich.edu 2948796Sgblack@eecs.umich.eduvoid 2958796Sgblack@eecs.umich.eduCacheMemory::deallocate(Addr address) 2968796Sgblack@eecs.umich.edu{ 2978887Sgeoffrey.blake@arm.com assert(address == makeLineAddress(address)); 2988809Sgblack@eecs.umich.edu assert(isTagPresent(address)); 2998809Sgblack@eecs.umich.edu DPRINTF(RubyCache, "address: %#x\n", address); 3008887Sgeoffrey.blake@arm.com int64_t cacheSet = addressToCacheSet(address); 3018809Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 3028809Sgblack@eecs.umich.edu if (loc != -1) { 3032998SN/A delete m_cache[cacheSet][loc]; 3047868Sgblack@eecs.umich.edu m_cache[cacheSet][loc] = NULL; 3057868Sgblack@eecs.umich.edu m_tag_index.erase(address); 30610720Sandreas.hansson@arm.com } 3077876Sgblack@eecs.umich.edu} 3082998SN/A 3098839Sandreas.hansson@arm.com// Returns with the physical address of the conflicting cache line 3107876Sgblack@eecs.umich.eduAddr 3118887Sgeoffrey.blake@arm.comCacheMemory::cacheProbe(Addr address) const 3129384SAndreas.Sandberg@arm.com{ 3139384SAndreas.Sandberg@arm.com assert(address == makeLineAddress(address)); 3149384SAndreas.Sandberg@arm.com assert(!cacheAvail(address)); 3159384SAndreas.Sandberg@arm.com 3169384SAndreas.Sandberg@arm.com int64_t cacheSet = addressToCacheSet(address); 3178887Sgeoffrey.blake@arm.com return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]-> 3188887Sgeoffrey.blake@arm.com m_Address; 319} 320 321// looks an address up in the cache 322AbstractCacheEntry* 323CacheMemory::lookup(Addr address) 324{ 325 assert(address == makeLineAddress(address)); 326 int64_t cacheSet = addressToCacheSet(address); 327 int loc = findTagInSet(cacheSet, address); 328 if (loc == -1) return NULL; 329 return m_cache[cacheSet][loc]; 330} 331 332// looks an address up in the cache 333const AbstractCacheEntry* 334CacheMemory::lookup(Addr address) const 335{ 336 assert(address == makeLineAddress(address)); 337 int64_t cacheSet = addressToCacheSet(address); 338 int loc = findTagInSet(cacheSet, address); 339 if (loc == -1) return NULL; 340 return m_cache[cacheSet][loc]; 341} 342 343// Sets the most recently used bit for a cache block 344void 345CacheMemory::setMRU(Addr address) 346{ 347 int64_t cacheSet = addressToCacheSet(address); 348 int loc = findTagInSet(cacheSet, address); 349 350 if (loc != -1) 351 m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 352} 353 354void 355CacheMemory::setMRU(const AbstractCacheEntry *e) 356{ 357 uint32_t cacheSet = e->getSetIndex(); 358 uint32_t loc = e->getWayIndex(); 359 m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 360} 361 362void 363CacheMemory::setMRU(Addr address, int occupancy) 364{ 365 int64_t cacheSet = addressToCacheSet(address); 366 int loc = findTagInSet(cacheSet, address); 367 368 if (loc != -1) { 369 if (m_replacementPolicy_ptr->useOccupancy()) { 370 (static_cast<WeightedLRUPolicy*>(m_replacementPolicy_ptr))-> 371 touch(cacheSet, loc, curTick(), occupancy); 372 } else { 373 m_replacementPolicy_ptr-> 374 touch(cacheSet, loc, curTick()); 375 } 376 } 377} 378 379int 380CacheMemory::getReplacementWeight(int64_t set, int64_t loc) 381{ 382 assert(set < m_cache_num_sets); 383 assert(loc < m_cache_assoc); 384 int ret = 0; 385 if (m_cache[set][loc] != NULL) { 386 ret = m_cache[set][loc]->getNumValidBlocks(); 387 assert(ret >= 0); 388 } 389 390 return ret; 391} 392 393void 394CacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const 395{ 396 uint64_t warmedUpBlocks = 0; 397 uint64_t totalBlocks M5_VAR_USED = (uint64_t)m_cache_num_sets * 398 (uint64_t)m_cache_assoc; 399 400 for (int i = 0; i < m_cache_num_sets; i++) { 401 for (int j = 0; j < m_cache_assoc; j++) { 402 if (m_cache[i][j] != NULL) { 403 AccessPermission perm = m_cache[i][j]->m_Permission; 404 RubyRequestType request_type = RubyRequestType_NULL; 405 if (perm == AccessPermission_Read_Only) { 406 if (m_is_instruction_only_cache) { 407 request_type = RubyRequestType_IFETCH; 408 } else { 409 request_type = RubyRequestType_LD; 410 } 411 } else if (perm == AccessPermission_Read_Write) { 412 request_type = RubyRequestType_ST; 413 } 414 415 if (request_type != RubyRequestType_NULL) { 416 tr->addRecord(cntrl, m_cache[i][j]->m_Address, 417 0, request_type, 418 m_replacementPolicy_ptr->getLastAccess(i, j), 419 m_cache[i][j]->getDataBlk()); 420 warmedUpBlocks++; 421 } 422 } 423 } 424 } 425 426 DPRINTF(RubyCacheTrace, "%s: %lli blocks of %lli total blocks" 427 "recorded %.2f%% \n", name().c_str(), warmedUpBlocks, 428 totalBlocks, (float(warmedUpBlocks) / float(totalBlocks)) * 100.0); 429} 430 431void 432CacheMemory::print(ostream& out) const 433{ 434 out << "Cache dump: " << name() << endl; 435 for (int i = 0; i < m_cache_num_sets; i++) { 436 for (int j = 0; j < m_cache_assoc; j++) { 437 if (m_cache[i][j] != NULL) { 438 out << " Index: " << i 439 << " way: " << j 440 << " entry: " << *m_cache[i][j] << endl; 441 } else { 442 out << " Index: " << i 443 << " way: " << j 444 << " entry: NULL" << endl; 445 } 446 } 447 } 448} 449 450void 451CacheMemory::printData(ostream& out) const 452{ 453 out << "printData() not supported" << endl; 454} 455 456void 457CacheMemory::setLocked(Addr address, int context) 458{ 459 DPRINTF(RubyCache, "Setting Lock for addr: %#x to %d\n", address, context); 460 assert(address == makeLineAddress(address)); 461 int64_t cacheSet = addressToCacheSet(address); 462 int loc = findTagInSet(cacheSet, address); 463 assert(loc != -1); 464 m_cache[cacheSet][loc]->setLocked(context); 465} 466 467void 468CacheMemory::clearLocked(Addr address) 469{ 470 DPRINTF(RubyCache, "Clear Lock for addr: %#x\n", address); 471 assert(address == makeLineAddress(address)); 472 int64_t cacheSet = addressToCacheSet(address); 473 int loc = findTagInSet(cacheSet, address); 474 assert(loc != -1); 475 m_cache[cacheSet][loc]->clearLocked(); 476} 477 478bool 479CacheMemory::isLocked(Addr address, int context) 480{ 481 assert(address == makeLineAddress(address)); 482 int64_t cacheSet = addressToCacheSet(address); 483 int loc = findTagInSet(cacheSet, address); 484 assert(loc != -1); 485 DPRINTF(RubyCache, "Testing Lock for addr: %#llx cur %d con %d\n", 486 address, m_cache[cacheSet][loc]->m_locked, context); 487 return m_cache[cacheSet][loc]->isLocked(context); 488} 489 490void 491CacheMemory::regStats() 492{ 493 SimObject::regStats(); 494 495 m_demand_hits 496 .name(name() + ".demand_hits") 497 .desc("Number of cache demand hits") 498 ; 499 500 m_demand_misses 501 .name(name() + ".demand_misses") 502 .desc("Number of cache demand misses") 503 ; 504 505 m_demand_accesses 506 .name(name() + ".demand_accesses") 507 .desc("Number of cache demand accesses") 508 ; 509 510 m_demand_accesses = m_demand_hits + m_demand_misses; 511 512 m_sw_prefetches 513 .name(name() + ".total_sw_prefetches") 514 .desc("Number of software prefetches") 515 .flags(Stats::nozero) 516 ; 517 518 m_hw_prefetches 519 .name(name() + ".total_hw_prefetches") 520 .desc("Number of hardware prefetches") 521 .flags(Stats::nozero) 522 ; 523 524 m_prefetches 525 .name(name() + ".total_prefetches") 526 .desc("Number of prefetches") 527 .flags(Stats::nozero) 528 ; 529 530 m_prefetches = m_sw_prefetches + m_hw_prefetches; 531 532 m_accessModeType 533 .init(RubyRequestType_NUM) 534 .name(name() + ".access_mode") 535 .flags(Stats::pdf | Stats::total) 536 ; 537 for (int i = 0; i < RubyAccessMode_NUM; i++) { 538 m_accessModeType 539 .subname(i, RubyAccessMode_to_string(RubyAccessMode(i))) 540 .flags(Stats::nozero) 541 ; 542 } 543 544 numDataArrayReads 545 .name(name() + ".num_data_array_reads") 546 .desc("number of data array reads") 547 .flags(Stats::nozero) 548 ; 549 550 numDataArrayWrites 551 .name(name() + ".num_data_array_writes") 552 .desc("number of data array writes") 553 .flags(Stats::nozero) 554 ; 555 556 numTagArrayReads 557 .name(name() + ".num_tag_array_reads") 558 .desc("number of tag array reads") 559 .flags(Stats::nozero) 560 ; 561 562 numTagArrayWrites 563 .name(name() + ".num_tag_array_writes") 564 .desc("number of tag array writes") 565 .flags(Stats::nozero) 566 ; 567 568 numTagArrayStalls 569 .name(name() + ".num_tag_array_stalls") 570 .desc("number of stalls caused by tag array") 571 .flags(Stats::nozero) 572 ; 573 574 numDataArrayStalls 575 .name(name() + ".num_data_array_stalls") 576 .desc("number of stalls caused by data array") 577 .flags(Stats::nozero) 578 ; 579} 580 581// assumption: SLICC generated files will only call this function 582// once **all** resources are granted 583void 584CacheMemory::recordRequestType(CacheRequestType requestType, Addr addr) 585{ 586 DPRINTF(RubyStats, "Recorded statistic: %s\n", 587 CacheRequestType_to_string(requestType)); 588 switch(requestType) { 589 case CacheRequestType_DataArrayRead: 590 if (m_resource_stalls) 591 dataArray.reserve(addressToCacheSet(addr)); 592 numDataArrayReads++; 593 return; 594 case CacheRequestType_DataArrayWrite: 595 if (m_resource_stalls) 596 dataArray.reserve(addressToCacheSet(addr)); 597 numDataArrayWrites++; 598 return; 599 case CacheRequestType_TagArrayRead: 600 if (m_resource_stalls) 601 tagArray.reserve(addressToCacheSet(addr)); 602 numTagArrayReads++; 603 return; 604 case CacheRequestType_TagArrayWrite: 605 if (m_resource_stalls) 606 tagArray.reserve(addressToCacheSet(addr)); 607 numTagArrayWrites++; 608 return; 609 default: 610 warn("CacheMemory access_type not found: %s", 611 CacheRequestType_to_string(requestType)); 612 } 613} 614 615bool 616CacheMemory::checkResourceAvailable(CacheResourceType res, Addr addr) 617{ 618 if (!m_resource_stalls) { 619 return true; 620 } 621 622 if (res == CacheResourceType_TagArray) { 623 if (tagArray.tryAccess(addressToCacheSet(addr))) return true; 624 else { 625 DPRINTF(RubyResourceStalls, 626 "Tag array stall on addr %#x in set %d\n", 627 addr, addressToCacheSet(addr)); 628 numTagArrayStalls++; 629 return false; 630 } 631 } else if (res == CacheResourceType_DataArray) { 632 if (dataArray.tryAccess(addressToCacheSet(addr))) return true; 633 else { 634 DPRINTF(RubyResourceStalls, 635 "Data array stall on addr %#x in set %d\n", 636 addr, addressToCacheSet(addr)); 637 numDataArrayStalls++; 638 return false; 639 } 640 } else { 641 panic("Unrecognized cache resource type."); 642 } 643} 644 645bool 646CacheMemory::isBlockInvalid(int64_t cache_set, int64_t loc) 647{ 648 return (m_cache[cache_set][loc]->m_Permission == AccessPermission_Invalid); 649} 650 651bool 652CacheMemory::isBlockNotBusy(int64_t cache_set, int64_t loc) 653{ 654 return (m_cache[cache_set][loc]->m_Permission != AccessPermission_Busy); 655} 656