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