CacheMemory.cc revision 14184
19022Sgblack@eecs.umich.edu/* 29022Sgblack@eecs.umich.edu * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood 39022Sgblack@eecs.umich.edu * Copyright (c) 2013 Advanced Micro Devices, Inc. 49022Sgblack@eecs.umich.edu * All rights reserved. 59022Sgblack@eecs.umich.edu * 69022Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 79022Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 89022Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 99022Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 109022Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 119022Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 129022Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 139022Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 149022Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 159022Sgblack@eecs.umich.edu * this software without specific prior written permission. 169022Sgblack@eecs.umich.edu * 179022Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 189022Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 199022Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 209022Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 219022Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 229022Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 239022Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 249022Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 259022Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 269022Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 279022Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 289022Sgblack@eecs.umich.edu */ 299022Sgblack@eecs.umich.edu 309022Sgblack@eecs.umich.edu#include "mem/ruby/structures/CacheMemory.hh" 319022Sgblack@eecs.umich.edu 329023Sgblack@eecs.umich.edu#include "base/intmath.hh" 339023Sgblack@eecs.umich.edu#include "base/logging.hh" 349023Sgblack@eecs.umich.edu#include "debug/RubyCache.hh" 359023Sgblack@eecs.umich.edu#include "debug/RubyCacheTrace.hh" 369023Sgblack@eecs.umich.edu#include "debug/RubyResourceStalls.hh" 379023Sgblack@eecs.umich.edu#include "debug/RubyStats.hh" 389022Sgblack@eecs.umich.edu#include "mem/ruby/protocol/AccessPermission.hh" 399022Sgblack@eecs.umich.edu#include "mem/ruby/system/RubySystem.hh" 409022Sgblack@eecs.umich.edu#include "mem/ruby/system/WeightedLRUPolicy.hh" 419023Sgblack@eecs.umich.edu 429023Sgblack@eecs.umich.eduusing namespace std; 439023Sgblack@eecs.umich.edu 449023Sgblack@eecs.umich.eduostream& 459023Sgblack@eecs.umich.eduoperator<<(ostream& out, const CacheMemory& obj) 469023Sgblack@eecs.umich.edu{ 479023Sgblack@eecs.umich.edu obj.print(out); 489023Sgblack@eecs.umich.edu out << flush; 499023Sgblack@eecs.umich.edu return out; 509023Sgblack@eecs.umich.edu} 519023Sgblack@eecs.umich.edu 529023Sgblack@eecs.umich.eduCacheMemory * 539023Sgblack@eecs.umich.eduRubyCacheParams::create() 549023Sgblack@eecs.umich.edu{ 559023Sgblack@eecs.umich.edu return new CacheMemory(this); 569023Sgblack@eecs.umich.edu} 579023Sgblack@eecs.umich.edu 589023Sgblack@eecs.umich.eduCacheMemory::CacheMemory(const Params *p) 599023Sgblack@eecs.umich.edu : SimObject(p), 609023Sgblack@eecs.umich.edu dataArray(p->dataArrayBanks, p->dataAccessLatency, 619023Sgblack@eecs.umich.edu p->start_index_bit, p->ruby_system), 629023Sgblack@eecs.umich.edu tagArray(p->tagArrayBanks, p->tagAccessLatency, 639023Sgblack@eecs.umich.edu p->start_index_bit, p->ruby_system) 649023Sgblack@eecs.umich.edu{ 659023Sgblack@eecs.umich.edu m_cache_size = p->size; 669023Sgblack@eecs.umich.edu m_cache_assoc = p->assoc; 679023Sgblack@eecs.umich.edu m_replacementPolicy_ptr = p->replacement_policy; 689023Sgblack@eecs.umich.edu m_replacementPolicy_ptr->setCache(this); 699023Sgblack@eecs.umich.edu m_start_index_bit = p->start_index_bit; 709023Sgblack@eecs.umich.edu m_is_instruction_only_cache = p->is_icache; 719023Sgblack@eecs.umich.edu m_resource_stalls = p->resourceStalls; 729023Sgblack@eecs.umich.edu m_block_size = p->block_size; // may be 0 at this point. Updated in init() 739023Sgblack@eecs.umich.edu} 749023Sgblack@eecs.umich.edu 759023Sgblack@eecs.umich.eduvoid 769023Sgblack@eecs.umich.eduCacheMemory::init() 779023Sgblack@eecs.umich.edu{ 789023Sgblack@eecs.umich.edu if (m_block_size == 0) { 799023Sgblack@eecs.umich.edu m_block_size = RubySystem::getBlockSizeBytes(); 809023Sgblack@eecs.umich.edu } 819023Sgblack@eecs.umich.edu m_cache_num_sets = (m_cache_size / m_cache_assoc) / m_block_size; 829023Sgblack@eecs.umich.edu assert(m_cache_num_sets > 1); 839023Sgblack@eecs.umich.edu m_cache_num_set_bits = floorLog2(m_cache_num_sets); 849023Sgblack@eecs.umich.edu assert(m_cache_num_set_bits > 0); 859023Sgblack@eecs.umich.edu 869023Sgblack@eecs.umich.edu m_cache.resize(m_cache_num_sets, 879023Sgblack@eecs.umich.edu std::vector<AbstractCacheEntry*>(m_cache_assoc, nullptr)); 889023Sgblack@eecs.umich.edu} 899023Sgblack@eecs.umich.edu 909023Sgblack@eecs.umich.eduCacheMemory::~CacheMemory() 919023Sgblack@eecs.umich.edu{ 929023Sgblack@eecs.umich.edu if (m_replacementPolicy_ptr) 939023Sgblack@eecs.umich.edu delete m_replacementPolicy_ptr; 949023Sgblack@eecs.umich.edu for (int i = 0; i < m_cache_num_sets; i++) { 959023Sgblack@eecs.umich.edu for (int j = 0; j < m_cache_assoc; j++) { 969023Sgblack@eecs.umich.edu delete m_cache[i][j]; 979023Sgblack@eecs.umich.edu } 989023Sgblack@eecs.umich.edu } 999023Sgblack@eecs.umich.edu} 1009023Sgblack@eecs.umich.edu 1019023Sgblack@eecs.umich.edu// convert a Address to its location in the cache 1029023Sgblack@eecs.umich.eduint64_t 1039023Sgblack@eecs.umich.eduCacheMemory::addressToCacheSet(Addr address) const 1049023Sgblack@eecs.umich.edu{ 1059023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 1069023Sgblack@eecs.umich.edu return bitSelect(address, m_start_index_bit, 1079023Sgblack@eecs.umich.edu m_start_index_bit + m_cache_num_set_bits - 1); 1089023Sgblack@eecs.umich.edu} 1099023Sgblack@eecs.umich.edu 1109023Sgblack@eecs.umich.edu// Given a cache index: returns the index of the tag in a set. 1119023Sgblack@eecs.umich.edu// returns -1 if the tag is not found. 1129023Sgblack@eecs.umich.eduint 1139023Sgblack@eecs.umich.eduCacheMemory::findTagInSet(int64_t cacheSet, Addr tag) const 1149023Sgblack@eecs.umich.edu{ 1159023Sgblack@eecs.umich.edu assert(tag == makeLineAddress(tag)); 1169023Sgblack@eecs.umich.edu // search the set for the tags 1179023Sgblack@eecs.umich.edu auto it = m_tag_index.find(tag); 1189023Sgblack@eecs.umich.edu if (it != m_tag_index.end()) 1199023Sgblack@eecs.umich.edu if (m_cache[cacheSet][it->second]->m_Permission != 1209023Sgblack@eecs.umich.edu AccessPermission_NotPresent) 1219023Sgblack@eecs.umich.edu return it->second; 1229023Sgblack@eecs.umich.edu return -1; // Not found 1239023Sgblack@eecs.umich.edu} 1249023Sgblack@eecs.umich.edu 1259023Sgblack@eecs.umich.edu// Given a cache index: returns the index of the tag in a set. 1269023Sgblack@eecs.umich.edu// returns -1 if the tag is not found. 1279023Sgblack@eecs.umich.eduint 1289023Sgblack@eecs.umich.eduCacheMemory::findTagInSetIgnorePermissions(int64_t cacheSet, 1299023Sgblack@eecs.umich.edu Addr tag) const 1309023Sgblack@eecs.umich.edu{ 1319023Sgblack@eecs.umich.edu assert(tag == makeLineAddress(tag)); 1329023Sgblack@eecs.umich.edu // search the set for the tags 1339023Sgblack@eecs.umich.edu auto it = m_tag_index.find(tag); 1349023Sgblack@eecs.umich.edu if (it != m_tag_index.end()) 1359023Sgblack@eecs.umich.edu return it->second; 1369023Sgblack@eecs.umich.edu return -1; // Not found 1379023Sgblack@eecs.umich.edu} 1389023Sgblack@eecs.umich.edu 1399023Sgblack@eecs.umich.edu// Given an unique cache block identifier (idx): return the valid address 1409023Sgblack@eecs.umich.edu// stored by the cache block. If the block is invalid/notpresent, the 1419023Sgblack@eecs.umich.edu// function returns the 0 address 1429023Sgblack@eecs.umich.eduAddr 1439023Sgblack@eecs.umich.eduCacheMemory::getAddressAtIdx(int idx) const 1449023Sgblack@eecs.umich.edu{ 1459023Sgblack@eecs.umich.edu Addr tmp(0); 1469023Sgblack@eecs.umich.edu 1479023Sgblack@eecs.umich.edu int set = idx / m_cache_assoc; 1489023Sgblack@eecs.umich.edu assert(set < m_cache_num_sets); 1499023Sgblack@eecs.umich.edu 1509023Sgblack@eecs.umich.edu int way = idx - set * m_cache_assoc; 1519023Sgblack@eecs.umich.edu assert (way < m_cache_assoc); 1529023Sgblack@eecs.umich.edu 1539023Sgblack@eecs.umich.edu AbstractCacheEntry* entry = m_cache[set][way]; 1549023Sgblack@eecs.umich.edu if (entry == NULL || 1559023Sgblack@eecs.umich.edu entry->m_Permission == AccessPermission_Invalid || 1569023Sgblack@eecs.umich.edu entry->m_Permission == AccessPermission_NotPresent) { 1579023Sgblack@eecs.umich.edu return tmp; 1589023Sgblack@eecs.umich.edu } 1599023Sgblack@eecs.umich.edu return entry->m_Address; 1609023Sgblack@eecs.umich.edu} 1619023Sgblack@eecs.umich.edu 1629023Sgblack@eecs.umich.edubool 1639023Sgblack@eecs.umich.eduCacheMemory::tryCacheAccess(Addr address, RubyRequestType type, 1649023Sgblack@eecs.umich.edu DataBlock*& data_ptr) 1659023Sgblack@eecs.umich.edu{ 1669023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 1679023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "address: %#x\n", address); 1689023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 1699023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 1709023Sgblack@eecs.umich.edu if (loc != -1) { 1719023Sgblack@eecs.umich.edu // Do we even have a tag match? 1729023Sgblack@eecs.umich.edu AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 1739023Sgblack@eecs.umich.edu m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 1749023Sgblack@eecs.umich.edu data_ptr = &(entry->getDataBlk()); 1759023Sgblack@eecs.umich.edu 1769023Sgblack@eecs.umich.edu if (entry->m_Permission == AccessPermission_Read_Write) { 1779023Sgblack@eecs.umich.edu return true; 1789023Sgblack@eecs.umich.edu } 1799023Sgblack@eecs.umich.edu if ((entry->m_Permission == AccessPermission_Read_Only) && 1809023Sgblack@eecs.umich.edu (type == RubyRequestType_LD || type == RubyRequestType_IFETCH)) { 1819023Sgblack@eecs.umich.edu return true; 1829023Sgblack@eecs.umich.edu } 1839023Sgblack@eecs.umich.edu // The line must not be accessible 1849023Sgblack@eecs.umich.edu } 1859023Sgblack@eecs.umich.edu data_ptr = NULL; 1869023Sgblack@eecs.umich.edu return false; 1879023Sgblack@eecs.umich.edu} 1889023Sgblack@eecs.umich.edu 1899023Sgblack@eecs.umich.edubool 1909023Sgblack@eecs.umich.eduCacheMemory::testCacheAccess(Addr address, RubyRequestType type, 1919023Sgblack@eecs.umich.edu DataBlock*& data_ptr) 1929023Sgblack@eecs.umich.edu{ 1939023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 1949023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "address: %#x\n", address); 1959023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 1969023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 1979023Sgblack@eecs.umich.edu 1989023Sgblack@eecs.umich.edu if (loc != -1) { 1999023Sgblack@eecs.umich.edu // Do we even have a tag match? 2009023Sgblack@eecs.umich.edu AbstractCacheEntry* entry = m_cache[cacheSet][loc]; 2019023Sgblack@eecs.umich.edu m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 2029023Sgblack@eecs.umich.edu data_ptr = &(entry->getDataBlk()); 2039023Sgblack@eecs.umich.edu 2049023Sgblack@eecs.umich.edu return m_cache[cacheSet][loc]->m_Permission != 2059023Sgblack@eecs.umich.edu AccessPermission_NotPresent; 2069023Sgblack@eecs.umich.edu } 2079023Sgblack@eecs.umich.edu 2089023Sgblack@eecs.umich.edu data_ptr = NULL; 2099023Sgblack@eecs.umich.edu return false; 2109023Sgblack@eecs.umich.edu} 2119023Sgblack@eecs.umich.edu 2129023Sgblack@eecs.umich.edu// tests to see if an address is present in the cache 2139023Sgblack@eecs.umich.edubool 2149023Sgblack@eecs.umich.eduCacheMemory::isTagPresent(Addr address) const 2159023Sgblack@eecs.umich.edu{ 2169023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 2179023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 2189023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 2199023Sgblack@eecs.umich.edu 2209023Sgblack@eecs.umich.edu if (loc == -1) { 2219023Sgblack@eecs.umich.edu // We didn't find the tag 2229023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "No tag match for address: %#x\n", address); 2239023Sgblack@eecs.umich.edu return false; 2249023Sgblack@eecs.umich.edu } 2259023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "address: %#x found\n", address); 2269023Sgblack@eecs.umich.edu return true; 2279023Sgblack@eecs.umich.edu} 2289023Sgblack@eecs.umich.edu 2299023Sgblack@eecs.umich.edu// Returns true if there is: 2309023Sgblack@eecs.umich.edu// a) a tag match on this address or there is 2319023Sgblack@eecs.umich.edu// b) an unused line in the same cache "way" 2329023Sgblack@eecs.umich.edubool 2339023Sgblack@eecs.umich.eduCacheMemory::cacheAvail(Addr address) const 2349023Sgblack@eecs.umich.edu{ 2359023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 2369023Sgblack@eecs.umich.edu 2379023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 2389023Sgblack@eecs.umich.edu 2399023Sgblack@eecs.umich.edu for (int i = 0; i < m_cache_assoc; i++) { 2409023Sgblack@eecs.umich.edu AbstractCacheEntry* entry = m_cache[cacheSet][i]; 2419023Sgblack@eecs.umich.edu if (entry != NULL) { 2429023Sgblack@eecs.umich.edu if (entry->m_Address == address || 2439023Sgblack@eecs.umich.edu entry->m_Permission == AccessPermission_NotPresent) { 2449023Sgblack@eecs.umich.edu // Already in the cache or we found an empty entry 2459023Sgblack@eecs.umich.edu return true; 2469023Sgblack@eecs.umich.edu } 2479023Sgblack@eecs.umich.edu } else { 2489023Sgblack@eecs.umich.edu return true; 2499023Sgblack@eecs.umich.edu } 2509023Sgblack@eecs.umich.edu } 2519023Sgblack@eecs.umich.edu return false; 2529023Sgblack@eecs.umich.edu} 2539023Sgblack@eecs.umich.edu 2549023Sgblack@eecs.umich.eduAbstractCacheEntry* 2559023Sgblack@eecs.umich.eduCacheMemory::allocate(Addr address, AbstractCacheEntry *entry, bool touch) 2569023Sgblack@eecs.umich.edu{ 2579023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 2589023Sgblack@eecs.umich.edu assert(!isTagPresent(address)); 2599023Sgblack@eecs.umich.edu assert(cacheAvail(address)); 2609023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "address: %#x\n", address); 2619023Sgblack@eecs.umich.edu 2629023Sgblack@eecs.umich.edu // Find the first open slot 2639023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 2649023Sgblack@eecs.umich.edu std::vector<AbstractCacheEntry*> &set = m_cache[cacheSet]; 2659023Sgblack@eecs.umich.edu for (int i = 0; i < m_cache_assoc; i++) { 2669023Sgblack@eecs.umich.edu if (!set[i] || set[i]->m_Permission == AccessPermission_NotPresent) { 2679023Sgblack@eecs.umich.edu if (set[i] && (set[i] != entry)) { 2689023Sgblack@eecs.umich.edu warn_once("This protocol contains a cache entry handling bug: " 2699023Sgblack@eecs.umich.edu "Entries in the cache should never be NotPresent! If\n" 2709023Sgblack@eecs.umich.edu "this entry (%#x) is not tracked elsewhere, it will memory " 2719023Sgblack@eecs.umich.edu "leak here. Fix your protocol to eliminate these!", 2729023Sgblack@eecs.umich.edu address); 2739023Sgblack@eecs.umich.edu } 2749023Sgblack@eecs.umich.edu set[i] = entry; // Init entry 2759023Sgblack@eecs.umich.edu set[i]->m_Address = address; 2769023Sgblack@eecs.umich.edu set[i]->m_Permission = AccessPermission_Invalid; 2779023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "Allocate clearing lock for addr: %x\n", 2789023Sgblack@eecs.umich.edu address); 2799023Sgblack@eecs.umich.edu set[i]->m_locked = -1; 2809023Sgblack@eecs.umich.edu m_tag_index[address] = i; 2819023Sgblack@eecs.umich.edu entry->setSetIndex(cacheSet); 2829023Sgblack@eecs.umich.edu entry->setWayIndex(i); 2839023Sgblack@eecs.umich.edu 2849023Sgblack@eecs.umich.edu if (touch) { 2859023Sgblack@eecs.umich.edu m_replacementPolicy_ptr->touch(cacheSet, i, curTick()); 2869023Sgblack@eecs.umich.edu } 2879023Sgblack@eecs.umich.edu 2889023Sgblack@eecs.umich.edu return entry; 2899023Sgblack@eecs.umich.edu } 2909023Sgblack@eecs.umich.edu } 2919023Sgblack@eecs.umich.edu panic("Allocate didn't find an available entry"); 2929023Sgblack@eecs.umich.edu} 2939023Sgblack@eecs.umich.edu 2949023Sgblack@eecs.umich.eduvoid 2959023Sgblack@eecs.umich.eduCacheMemory::deallocate(Addr address) 2969023Sgblack@eecs.umich.edu{ 2979023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 2989023Sgblack@eecs.umich.edu assert(isTagPresent(address)); 2999023Sgblack@eecs.umich.edu DPRINTF(RubyCache, "address: %#x\n", address); 3009023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 3019023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 3029023Sgblack@eecs.umich.edu if (loc != -1) { 3039023Sgblack@eecs.umich.edu delete m_cache[cacheSet][loc]; 3049023Sgblack@eecs.umich.edu m_cache[cacheSet][loc] = NULL; 3059023Sgblack@eecs.umich.edu m_tag_index.erase(address); 3069023Sgblack@eecs.umich.edu } 3079023Sgblack@eecs.umich.edu} 3089023Sgblack@eecs.umich.edu 3099023Sgblack@eecs.umich.edu// Returns with the physical address of the conflicting cache line 3109023Sgblack@eecs.umich.eduAddr 3119023Sgblack@eecs.umich.eduCacheMemory::cacheProbe(Addr address) const 3129023Sgblack@eecs.umich.edu{ 3139023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 3149023Sgblack@eecs.umich.edu assert(!cacheAvail(address)); 3159023Sgblack@eecs.umich.edu 3169023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 3179023Sgblack@eecs.umich.edu return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]-> 3189023Sgblack@eecs.umich.edu m_Address; 3199023Sgblack@eecs.umich.edu} 3209023Sgblack@eecs.umich.edu 3219023Sgblack@eecs.umich.edu// looks an address up in the cache 3229023Sgblack@eecs.umich.eduAbstractCacheEntry* 3239023Sgblack@eecs.umich.eduCacheMemory::lookup(Addr address) 3249023Sgblack@eecs.umich.edu{ 3259023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 3269023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 3279023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 3289023Sgblack@eecs.umich.edu if (loc == -1) return NULL; 3299023Sgblack@eecs.umich.edu return m_cache[cacheSet][loc]; 3309023Sgblack@eecs.umich.edu} 3319023Sgblack@eecs.umich.edu 3329023Sgblack@eecs.umich.edu// looks an address up in the cache 3339023Sgblack@eecs.umich.educonst AbstractCacheEntry* 3349023Sgblack@eecs.umich.eduCacheMemory::lookup(Addr address) const 3359023Sgblack@eecs.umich.edu{ 3369023Sgblack@eecs.umich.edu assert(address == makeLineAddress(address)); 3379023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 3389023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 3399023Sgblack@eecs.umich.edu if (loc == -1) return NULL; 3409023Sgblack@eecs.umich.edu return m_cache[cacheSet][loc]; 3419023Sgblack@eecs.umich.edu} 3429023Sgblack@eecs.umich.edu 3439023Sgblack@eecs.umich.edu// Sets the most recently used bit for a cache block 3449023Sgblack@eecs.umich.eduvoid 3459023Sgblack@eecs.umich.eduCacheMemory::setMRU(Addr address) 3469023Sgblack@eecs.umich.edu{ 3479023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 3489023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 3499023Sgblack@eecs.umich.edu 3509023Sgblack@eecs.umich.edu if (loc != -1) 3519023Sgblack@eecs.umich.edu m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 3529023Sgblack@eecs.umich.edu} 3539023Sgblack@eecs.umich.edu 3549023Sgblack@eecs.umich.eduvoid 3559023Sgblack@eecs.umich.eduCacheMemory::setMRU(const AbstractCacheEntry *e) 3569023Sgblack@eecs.umich.edu{ 3579023Sgblack@eecs.umich.edu uint32_t cacheSet = e->getSetIndex(); 3589023Sgblack@eecs.umich.edu uint32_t loc = e->getWayIndex(); 3599023Sgblack@eecs.umich.edu m_replacementPolicy_ptr->touch(cacheSet, loc, curTick()); 3609023Sgblack@eecs.umich.edu} 3619023Sgblack@eecs.umich.edu 3629023Sgblack@eecs.umich.eduvoid 3639023Sgblack@eecs.umich.eduCacheMemory::setMRU(Addr address, int occupancy) 3649023Sgblack@eecs.umich.edu{ 3659023Sgblack@eecs.umich.edu int64_t cacheSet = addressToCacheSet(address); 3669023Sgblack@eecs.umich.edu int loc = findTagInSet(cacheSet, address); 3679023Sgblack@eecs.umich.edu 3689023Sgblack@eecs.umich.edu if (loc != -1) { 3699023Sgblack@eecs.umich.edu if (m_replacementPolicy_ptr->useOccupancy()) { 3709023Sgblack@eecs.umich.edu (static_cast<WeightedLRUPolicy*>(m_replacementPolicy_ptr))-> 3719023Sgblack@eecs.umich.edu touch(cacheSet, loc, curTick(), occupancy); 3729023Sgblack@eecs.umich.edu } else { 3739023Sgblack@eecs.umich.edu m_replacementPolicy_ptr-> 3749023Sgblack@eecs.umich.edu touch(cacheSet, loc, curTick()); 3759023Sgblack@eecs.umich.edu } 3769023Sgblack@eecs.umich.edu } 3779023Sgblack@eecs.umich.edu} 3789023Sgblack@eecs.umich.edu 3799023Sgblack@eecs.umich.eduint 3809023Sgblack@eecs.umich.eduCacheMemory::getReplacementWeight(int64_t set, int64_t loc) 3819023Sgblack@eecs.umich.edu{ 3829023Sgblack@eecs.umich.edu assert(set < m_cache_num_sets); 3839023Sgblack@eecs.umich.edu assert(loc < m_cache_assoc); 3849023Sgblack@eecs.umich.edu int ret = 0; 3859023Sgblack@eecs.umich.edu if (m_cache[set][loc] != NULL) { 3869023Sgblack@eecs.umich.edu ret = m_cache[set][loc]->getNumValidBlocks(); 3879023Sgblack@eecs.umich.edu assert(ret >= 0); 3889023Sgblack@eecs.umich.edu } 3899023Sgblack@eecs.umich.edu 3909023Sgblack@eecs.umich.edu return ret; 3919023Sgblack@eecs.umich.edu} 3929023Sgblack@eecs.umich.edu 3939023Sgblack@eecs.umich.eduvoid 3949023Sgblack@eecs.umich.eduCacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const 3959023Sgblack@eecs.umich.edu{ 3969023Sgblack@eecs.umich.edu uint64_t warmedUpBlocks = 0; 3979023Sgblack@eecs.umich.edu uint64_t totalBlocks M5_VAR_USED = (uint64_t)m_cache_num_sets * 3989023Sgblack@eecs.umich.edu (uint64_t)m_cache_assoc; 3999023Sgblack@eecs.umich.edu 4009023Sgblack@eecs.umich.edu for (int i = 0; i < m_cache_num_sets; i++) { 4019023Sgblack@eecs.umich.edu for (int j = 0; j < m_cache_assoc; j++) { 4029023Sgblack@eecs.umich.edu if (m_cache[i][j] != NULL) { 4039023Sgblack@eecs.umich.edu AccessPermission perm = m_cache[i][j]->m_Permission; 4049023Sgblack@eecs.umich.edu RubyRequestType request_type = RubyRequestType_NULL; 4059023Sgblack@eecs.umich.edu if (perm == AccessPermission_Read_Only) { 4069023Sgblack@eecs.umich.edu if (m_is_instruction_only_cache) { 4079023Sgblack@eecs.umich.edu request_type = RubyRequestType_IFETCH; 4089023Sgblack@eecs.umich.edu } else { 4099023Sgblack@eecs.umich.edu request_type = RubyRequestType_LD; 4109022Sgblack@eecs.umich.edu } 4119022Sgblack@eecs.umich.edu } else if (perm == AccessPermission_Read_Write) { 4129022Sgblack@eecs.umich.edu request_type = RubyRequestType_ST; 4139022Sgblack@eecs.umich.edu } 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