16782SN/A/*
28683SN/A * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
310973Sdavid.hashe@amd.com * Copyright (c) 2013 Advanced Micro Devices, Inc.
46782SN/A * All rights reserved.
56782SN/A *
66782SN/A * Redistribution and use in source and binary forms, with or without
76782SN/A * modification, are permitted provided that the following conditions are
86782SN/A * met: redistributions of source code must retain the above copyright
96782SN/A * notice, this list of conditions and the following disclaimer;
106782SN/A * redistributions in binary form must reproduce the above copyright
116782SN/A * notice, this list of conditions and the following disclaimer in the
126782SN/A * documentation and/or other materials provided with the distribution;
136782SN/A * neither the name of the copyright holders nor the names of its
146782SN/A * contributors may be used to endorse or promote products derived from
156782SN/A * this software without specific prior written permission.
166782SN/A *
176782SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186782SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196782SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206782SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216782SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226782SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236782SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246782SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256782SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266782SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276782SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286782SN/A */
296782SN/A
3011793Sbrandon.potter@amd.com#include "mem/ruby/structures/CacheMemory.hh"
3111793Sbrandon.potter@amd.com
327056SN/A#include "base/intmath.hh"
3313449Sgabeblack@google.com#include "base/logging.hh"
348232SN/A#include "debug/RubyCache.hh"
358937SN/A#include "debug/RubyCacheTrace.hh"
369105SN/A#include "debug/RubyResourceStalls.hh"
379104SN/A#include "debug/RubyStats.hh"
3814184Sgabeblack@google.com#include "mem/ruby/protocol/AccessPermission.hh"
3911108Sdavid.hashe@amd.com#include "mem/ruby/system/RubySystem.hh"
4011308Santhony.gutierrez@amd.com#include "mem/ruby/system/WeightedLRUPolicy.hh"
416782SN/A
427055SN/Ausing namespace std;
437055SN/A
447039SN/Aostream&
457039SN/Aoperator<<(ostream& out, const CacheMemory& obj)
466782SN/A{
477039SN/A    obj.print(out);
487039SN/A    out << flush;
497039SN/A    return out;
506782SN/A}
516782SN/A
526876SN/ACacheMemory *
536876SN/ARubyCacheParams::create()
546782SN/A{
556876SN/A    return new CacheMemory(this);
566782SN/A}
576782SN/A
586876SN/ACacheMemory::CacheMemory(const Params *p)
599105SN/A    : SimObject(p),
6010919Sbrandon.potter@amd.com    dataArray(p->dataArrayBanks, p->dataAccessLatency,
6110919Sbrandon.potter@amd.com              p->start_index_bit, p->ruby_system),
6210919Sbrandon.potter@amd.com    tagArray(p->tagArrayBanks, p->tagAccessLatency,
6310919Sbrandon.potter@amd.com             p->start_index_bit, p->ruby_system)
646782SN/A{
656882SN/A    m_cache_size = p->size;
666876SN/A    m_cache_assoc = p->assoc;
6710970Sdavid.hashe@amd.com    m_replacementPolicy_ptr = p->replacement_policy;
6810980Sdavid.hashe@amd.com    m_replacementPolicy_ptr->setCache(this);
697564SN/A    m_start_index_bit = p->start_index_bit;
708653SN/A    m_is_instruction_only_cache = p->is_icache;
719105SN/A    m_resource_stalls = p->resourceStalls;
7211308Santhony.gutierrez@amd.com    m_block_size = p->block_size;  // may be 0 at this point. Updated in init()
736876SN/A}
746876SN/A
757039SN/Avoid
767039SN/ACacheMemory::init()
776876SN/A{
7811308Santhony.gutierrez@amd.com    if (m_block_size == 0) {
7911308Santhony.gutierrez@amd.com        m_block_size = RubySystem::getBlockSizeBytes();
8011308Santhony.gutierrez@amd.com    }
8111308Santhony.gutierrez@amd.com    m_cache_num_sets = (m_cache_size / m_cache_assoc) / m_block_size;
826882SN/A    assert(m_cache_num_sets > 1);
837056SN/A    m_cache_num_set_bits = floorLog2(m_cache_num_sets);
846882SN/A    assert(m_cache_num_set_bits > 0);
857039SN/A
8611308Santhony.gutierrez@amd.com    m_cache.resize(m_cache_num_sets,
8711308Santhony.gutierrez@amd.com                    std::vector<AbstractCacheEntry*>(m_cache_assoc, nullptr));
886782SN/A}
896782SN/A
906782SN/ACacheMemory::~CacheMemory()
916782SN/A{
9211308Santhony.gutierrez@amd.com    if (m_replacementPolicy_ptr)
937039SN/A        delete m_replacementPolicy_ptr;
947039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
957039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
967039SN/A            delete m_cache[i][j];
977039SN/A        }
986783SN/A    }
996782SN/A}
1006782SN/A
1016782SN/A// convert a Address to its location in the cache
10211061Snilay@cs.wisc.eduint64_t
10311025Snilay@cs.wisc.eduCacheMemory::addressToCacheSet(Addr address) const
1046782SN/A{
10511025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
10611025Snilay@cs.wisc.edu    return bitSelect(address, m_start_index_bit,
10711025Snilay@cs.wisc.edu                     m_start_index_bit + m_cache_num_set_bits - 1);
1086782SN/A}
1096782SN/A
1106782SN/A// Given a cache index: returns the index of the tag in a set.
1116782SN/A// returns -1 if the tag is not found.
1127039SN/Aint
11311061Snilay@cs.wisc.eduCacheMemory::findTagInSet(int64_t cacheSet, Addr tag) const
1146782SN/A{
11511025Snilay@cs.wisc.edu    assert(tag == makeLineAddress(tag));
1167039SN/A    // search the set for the tags
11711168Sandreas.hansson@arm.com    auto it = m_tag_index.find(tag);
1187039SN/A    if (it != m_tag_index.end())
1197039SN/A        if (m_cache[cacheSet][it->second]->m_Permission !=
1207039SN/A            AccessPermission_NotPresent)
1217039SN/A            return it->second;
1227039SN/A    return -1; // Not found
1236782SN/A}
1246782SN/A
1256782SN/A// Given a cache index: returns the index of the tag in a set.
1266782SN/A// returns -1 if the tag is not found.
1277039SN/Aint
12811061Snilay@cs.wisc.eduCacheMemory::findTagInSetIgnorePermissions(int64_t cacheSet,
12911025Snilay@cs.wisc.edu                                           Addr tag) const
1306782SN/A{
13111025Snilay@cs.wisc.edu    assert(tag == makeLineAddress(tag));
1327039SN/A    // search the set for the tags
13311168Sandreas.hansson@arm.com    auto it = m_tag_index.find(tag);
1347039SN/A    if (it != m_tag_index.end())
1357039SN/A        return it->second;
1367039SN/A    return -1; // Not found
1376782SN/A}
1386782SN/A
13910973Sdavid.hashe@amd.com// Given an unique cache block identifier (idx): return the valid address
14010973Sdavid.hashe@amd.com// stored by the cache block.  If the block is invalid/notpresent, the
14110973Sdavid.hashe@amd.com// function returns the 0 address
14211025Snilay@cs.wisc.eduAddr
14310973Sdavid.hashe@amd.comCacheMemory::getAddressAtIdx(int idx) const
14410973Sdavid.hashe@amd.com{
14511025Snilay@cs.wisc.edu    Addr tmp(0);
14610973Sdavid.hashe@amd.com
14710973Sdavid.hashe@amd.com    int set = idx / m_cache_assoc;
14810973Sdavid.hashe@amd.com    assert(set < m_cache_num_sets);
14910973Sdavid.hashe@amd.com
15010973Sdavid.hashe@amd.com    int way = idx - set * m_cache_assoc;
15110973Sdavid.hashe@amd.com    assert (way < m_cache_assoc);
15210973Sdavid.hashe@amd.com
15310973Sdavid.hashe@amd.com    AbstractCacheEntry* entry = m_cache[set][way];
15410973Sdavid.hashe@amd.com    if (entry == NULL ||
15510973Sdavid.hashe@amd.com        entry->m_Permission == AccessPermission_Invalid ||
15610973Sdavid.hashe@amd.com        entry->m_Permission == AccessPermission_NotPresent) {
15710973Sdavid.hashe@amd.com        return tmp;
15810973Sdavid.hashe@amd.com    }
15910973Sdavid.hashe@amd.com    return entry->m_Address;
16010973Sdavid.hashe@amd.com}
16110973Sdavid.hashe@amd.com
16211049Snilay@cs.wisc.edubool
16311049Snilay@cs.wisc.eduCacheMemory::tryCacheAccess(Addr address, RubyRequestType type,
16411049Snilay@cs.wisc.edu                            DataBlock*& data_ptr)
16511049Snilay@cs.wisc.edu{
16611049Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
16711118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "address: %#x\n", address);
16811061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
16911049Snilay@cs.wisc.edu    int loc = findTagInSet(cacheSet, address);
17011049Snilay@cs.wisc.edu    if (loc != -1) {
17111049Snilay@cs.wisc.edu        // Do we even have a tag match?
17211049Snilay@cs.wisc.edu        AbstractCacheEntry* entry = m_cache[cacheSet][loc];
17311049Snilay@cs.wisc.edu        m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
17411049Snilay@cs.wisc.edu        data_ptr = &(entry->getDataBlk());
17511049Snilay@cs.wisc.edu
17611049Snilay@cs.wisc.edu        if (entry->m_Permission == AccessPermission_Read_Write) {
17711049Snilay@cs.wisc.edu            return true;
17811049Snilay@cs.wisc.edu        }
17911049Snilay@cs.wisc.edu        if ((entry->m_Permission == AccessPermission_Read_Only) &&
18011049Snilay@cs.wisc.edu            (type == RubyRequestType_LD || type == RubyRequestType_IFETCH)) {
18111049Snilay@cs.wisc.edu            return true;
18211049Snilay@cs.wisc.edu        }
18311049Snilay@cs.wisc.edu        // The line must not be accessible
18411049Snilay@cs.wisc.edu    }
18511049Snilay@cs.wisc.edu    data_ptr = NULL;
18611049Snilay@cs.wisc.edu    return false;
18711049Snilay@cs.wisc.edu}
18811049Snilay@cs.wisc.edu
18911049Snilay@cs.wisc.edubool
19011049Snilay@cs.wisc.eduCacheMemory::testCacheAccess(Addr address, RubyRequestType type,
19111049Snilay@cs.wisc.edu                             DataBlock*& data_ptr)
19211049Snilay@cs.wisc.edu{
19311049Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
19411118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "address: %#x\n", address);
19511061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
19611049Snilay@cs.wisc.edu    int loc = findTagInSet(cacheSet, address);
19711049Snilay@cs.wisc.edu
19811049Snilay@cs.wisc.edu    if (loc != -1) {
19911049Snilay@cs.wisc.edu        // Do we even have a tag match?
20011049Snilay@cs.wisc.edu        AbstractCacheEntry* entry = m_cache[cacheSet][loc];
20111049Snilay@cs.wisc.edu        m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
20211049Snilay@cs.wisc.edu        data_ptr = &(entry->getDataBlk());
20311049Snilay@cs.wisc.edu
20411049Snilay@cs.wisc.edu        return m_cache[cacheSet][loc]->m_Permission !=
20511049Snilay@cs.wisc.edu            AccessPermission_NotPresent;
20611049Snilay@cs.wisc.edu    }
20711049Snilay@cs.wisc.edu
20811049Snilay@cs.wisc.edu    data_ptr = NULL;
20911049Snilay@cs.wisc.edu    return false;
21011049Snilay@cs.wisc.edu}
21111049Snilay@cs.wisc.edu
2126782SN/A// tests to see if an address is present in the cache
2137039SN/Abool
21411025Snilay@cs.wisc.eduCacheMemory::isTagPresent(Addr address) const
2156782SN/A{
21611025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
21711061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
2187039SN/A    int loc = findTagInSet(cacheSet, address);
2196782SN/A
2207039SN/A    if (loc == -1) {
2217039SN/A        // We didn't find the tag
22211118Snilay@cs.wisc.edu        DPRINTF(RubyCache, "No tag match for address: %#x\n", address);
2237039SN/A        return false;
2247039SN/A    }
22511118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "address: %#x found\n", address);
2267039SN/A    return true;
2276782SN/A}
2286782SN/A
2296782SN/A// Returns true if there is:
2306782SN/A//   a) a tag match on this address or there is
2316782SN/A//   b) an unused line in the same cache "way"
2327039SN/Abool
23311025Snilay@cs.wisc.eduCacheMemory::cacheAvail(Addr address) const
2346782SN/A{
23511025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
2366782SN/A
23711061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
2386782SN/A
2397039SN/A    for (int i = 0; i < m_cache_assoc; i++) {
2407039SN/A        AbstractCacheEntry* entry = m_cache[cacheSet][i];
2417039SN/A        if (entry != NULL) {
2427039SN/A            if (entry->m_Address == address ||
2437039SN/A                entry->m_Permission == AccessPermission_NotPresent) {
2447039SN/A                // Already in the cache or we found an empty entry
2457039SN/A                return true;
2467039SN/A            }
2477039SN/A        } else {
2487039SN/A            return true;
2497039SN/A        }
2506782SN/A    }
2517039SN/A    return false;
2526782SN/A}
2536782SN/A
2547839SN/AAbstractCacheEntry*
25511086Snilay@cs.wisc.eduCacheMemory::allocate(Addr address, AbstractCacheEntry *entry, bool touch)
2566782SN/A{
25711025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
2587039SN/A    assert(!isTagPresent(address));
2597039SN/A    assert(cacheAvail(address));
26011118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "address: %#x\n", address);
2616782SN/A
2627039SN/A    // Find the first open slot
26311061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
2647454SN/A    std::vector<AbstractCacheEntry*> &set = m_cache[cacheSet];
2657039SN/A    for (int i = 0; i < m_cache_assoc; i++) {
2667039SN/A        if (!set[i] || set[i]->m_Permission == AccessPermission_NotPresent) {
26711145Sjthestness@gmail.com            if (set[i] && (set[i] != entry)) {
26811145Sjthestness@gmail.com                warn_once("This protocol contains a cache entry handling bug: "
26911145Sjthestness@gmail.com                    "Entries in the cache should never be NotPresent! If\n"
27011145Sjthestness@gmail.com                    "this entry (%#x) is not tracked elsewhere, it will memory "
27111145Sjthestness@gmail.com                    "leak here. Fix your protocol to eliminate these!",
27211145Sjthestness@gmail.com                    address);
27311145Sjthestness@gmail.com            }
2747039SN/A            set[i] = entry;  // Init entry
2757039SN/A            set[i]->m_Address = address;
2767039SN/A            set[i]->m_Permission = AccessPermission_Invalid;
2777039SN/A            DPRINTF(RubyCache, "Allocate clearing lock for addr: %x\n",
2787039SN/A                    address);
2797839SN/A            set[i]->m_locked = -1;
2807039SN/A            m_tag_index[address] = i;
28111086Snilay@cs.wisc.edu            entry->setSetIndex(cacheSet);
28211086Snilay@cs.wisc.edu            entry->setWayIndex(i);
2836782SN/A
28410974Sdavid.hashe@amd.com            if (touch) {
28510974Sdavid.hashe@amd.com                m_replacementPolicy_ptr->touch(cacheSet, i, curTick());
28610974Sdavid.hashe@amd.com            }
2876782SN/A
2887839SN/A            return entry;
2897039SN/A        }
2906782SN/A    }
2917805SN/A    panic("Allocate didn't find an available entry");
2926782SN/A}
2936782SN/A
2947039SN/Avoid
29511025Snilay@cs.wisc.eduCacheMemory::deallocate(Addr address)
2966782SN/A{
29711025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
2987039SN/A    assert(isTagPresent(address));
29911118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "address: %#x\n", address);
30011061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
3017039SN/A    int loc = findTagInSet(cacheSet, address);
3027039SN/A    if (loc != -1) {
3037039SN/A        delete m_cache[cacheSet][loc];
3047039SN/A        m_cache[cacheSet][loc] = NULL;
3057039SN/A        m_tag_index.erase(address);
3067039SN/A    }
3076782SN/A}
3086782SN/A
3096782SN/A// Returns with the physical address of the conflicting cache line
31011025Snilay@cs.wisc.eduAddr
31111025Snilay@cs.wisc.eduCacheMemory::cacheProbe(Addr address) const
3126782SN/A{
31311025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
3147039SN/A    assert(!cacheAvail(address));
3156782SN/A
31611061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
3177039SN/A    return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->
3187039SN/A        m_Address;
3196782SN/A}
3206782SN/A
3216782SN/A// looks an address up in the cache
3227839SN/AAbstractCacheEntry*
32311025Snilay@cs.wisc.eduCacheMemory::lookup(Addr address)
3246782SN/A{
32511025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
32611061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
3277039SN/A    int loc = findTagInSet(cacheSet, address);
32811321Ssteve.reinhardt@amd.com    if (loc == -1) return NULL;
3297839SN/A    return m_cache[cacheSet][loc];
3306782SN/A}
3316782SN/A
3326782SN/A// looks an address up in the cache
3337839SN/Aconst AbstractCacheEntry*
33411025Snilay@cs.wisc.eduCacheMemory::lookup(Addr address) const
3356782SN/A{
33611025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
33711061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
3387039SN/A    int loc = findTagInSet(cacheSet, address);
33911321Ssteve.reinhardt@amd.com    if (loc == -1) return NULL;
3407839SN/A    return m_cache[cacheSet][loc];
3416782SN/A}
3426782SN/A
3436782SN/A// Sets the most recently used bit for a cache block
3447039SN/Avoid
34511025Snilay@cs.wisc.eduCacheMemory::setMRU(Addr address)
3466782SN/A{
34711061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
3488828SN/A    int loc = findTagInSet(cacheSet, address);
3496782SN/A
35011321Ssteve.reinhardt@amd.com    if (loc != -1)
3519171SN/A        m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
3526782SN/A}
3536782SN/A
3547039SN/Avoid
35511087Snilay@cs.wisc.eduCacheMemory::setMRU(const AbstractCacheEntry *e)
35611087Snilay@cs.wisc.edu{
35711087Snilay@cs.wisc.edu    uint32_t cacheSet = e->getSetIndex();
35811087Snilay@cs.wisc.edu    uint32_t loc = e->getWayIndex();
35911087Snilay@cs.wisc.edu    m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
36011087Snilay@cs.wisc.edu}
36111087Snilay@cs.wisc.edu
36211087Snilay@cs.wisc.eduvoid
36311308Santhony.gutierrez@amd.comCacheMemory::setMRU(Addr address, int occupancy)
36411308Santhony.gutierrez@amd.com{
36511308Santhony.gutierrez@amd.com    int64_t cacheSet = addressToCacheSet(address);
36611308Santhony.gutierrez@amd.com    int loc = findTagInSet(cacheSet, address);
36711308Santhony.gutierrez@amd.com
36811321Ssteve.reinhardt@amd.com    if (loc != -1) {
36911308Santhony.gutierrez@amd.com        if (m_replacementPolicy_ptr->useOccupancy()) {
37011308Santhony.gutierrez@amd.com            (static_cast<WeightedLRUPolicy*>(m_replacementPolicy_ptr))->
37111308Santhony.gutierrez@amd.com                touch(cacheSet, loc, curTick(), occupancy);
37211308Santhony.gutierrez@amd.com        } else {
37311308Santhony.gutierrez@amd.com            m_replacementPolicy_ptr->
37411308Santhony.gutierrez@amd.com                touch(cacheSet, loc, curTick());
37511308Santhony.gutierrez@amd.com        }
37611308Santhony.gutierrez@amd.com    }
37711308Santhony.gutierrez@amd.com}
37811308Santhony.gutierrez@amd.com
37911308Santhony.gutierrez@amd.comint
38011308Santhony.gutierrez@amd.comCacheMemory::getReplacementWeight(int64_t set, int64_t loc)
38111308Santhony.gutierrez@amd.com{
38211308Santhony.gutierrez@amd.com    assert(set < m_cache_num_sets);
38311308Santhony.gutierrez@amd.com    assert(loc < m_cache_assoc);
38411308Santhony.gutierrez@amd.com    int ret = 0;
38511321Ssteve.reinhardt@amd.com    if (m_cache[set][loc] != NULL) {
38611308Santhony.gutierrez@amd.com        ret = m_cache[set][loc]->getNumValidBlocks();
38711308Santhony.gutierrez@amd.com        assert(ret >= 0);
38811308Santhony.gutierrez@amd.com    }
38911308Santhony.gutierrez@amd.com
39011308Santhony.gutierrez@amd.com    return ret;
39111308Santhony.gutierrez@amd.com}
39211308Santhony.gutierrez@amd.com
39311308Santhony.gutierrez@amd.comvoid
3948683SN/ACacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const
3956782SN/A{
39611061Snilay@cs.wisc.edu    uint64_t warmedUpBlocks = 0;
39711061Snilay@cs.wisc.edu    uint64_t totalBlocks M5_VAR_USED = (uint64_t)m_cache_num_sets *
39811061Snilay@cs.wisc.edu                                       (uint64_t)m_cache_assoc;
3998683SN/A
4007039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
4017039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
4028683SN/A            if (m_cache[i][j] != NULL) {
4038683SN/A                AccessPermission perm = m_cache[i][j]->m_Permission;
4048683SN/A                RubyRequestType request_type = RubyRequestType_NULL;
4058683SN/A                if (perm == AccessPermission_Read_Only) {
4068683SN/A                    if (m_is_instruction_only_cache) {
4078683SN/A                        request_type = RubyRequestType_IFETCH;
4088683SN/A                    } else {
4098683SN/A                        request_type = RubyRequestType_LD;
4108683SN/A                    }
4118683SN/A                } else if (perm == AccessPermission_Read_Write) {
4128683SN/A                    request_type = RubyRequestType_ST;
4137039SN/A                }
4147039SN/A
4158683SN/A                if (request_type != RubyRequestType_NULL) {
41611025Snilay@cs.wisc.edu                    tr->addRecord(cntrl, m_cache[i][j]->m_Address,
4178683SN/A                                  0, request_type,
4188683SN/A                                  m_replacementPolicy_ptr->getLastAccess(i, j),
4198683SN/A                                  m_cache[i][j]->getDataBlk());
4208683SN/A                    warmedUpBlocks++;
4218683SN/A                }
4227039SN/A            }
4236782SN/A        }
4246782SN/A    }
4258683SN/A
4268937SN/A    DPRINTF(RubyCacheTrace, "%s: %lli blocks of %lli total blocks"
4278683SN/A            "recorded %.2f%% \n", name().c_str(), warmedUpBlocks,
42811061Snilay@cs.wisc.edu            totalBlocks, (float(warmedUpBlocks) / float(totalBlocks)) * 100.0);
4296782SN/A}
4306782SN/A
4317039SN/Avoid
4327039SN/ACacheMemory::print(ostream& out) const
4336782SN/A{
43410080SN/A    out << "Cache dump: " << name() << endl;
4357039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
4367039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
4377039SN/A            if (m_cache[i][j] != NULL) {
4387039SN/A                out << "  Index: " << i
4397039SN/A                    << " way: " << j
4407039SN/A                    << " entry: " << *m_cache[i][j] << endl;
4417039SN/A            } else {
4427039SN/A                out << "  Index: " << i
4437039SN/A                    << " way: " << j
4447039SN/A                    << " entry: NULL" << endl;
4457039SN/A            }
4467039SN/A        }
4476782SN/A    }
4486782SN/A}
4496782SN/A
4507039SN/Avoid
4517039SN/ACacheMemory::printData(ostream& out) const
4526782SN/A{
4537039SN/A    out << "printData() not supported" << endl;
4546782SN/A}
4556782SN/A
4567039SN/Avoid
45711025Snilay@cs.wisc.eduCacheMemory::setLocked(Addr address, int context)
4587039SN/A{
45911118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "Setting Lock for addr: %#x to %d\n", address, context);
46011025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
46111061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
4627039SN/A    int loc = findTagInSet(cacheSet, address);
4637039SN/A    assert(loc != -1);
46411059Snilay@cs.wisc.edu    m_cache[cacheSet][loc]->setLocked(context);
4656782SN/A}
4666782SN/A
4677039SN/Avoid
46811025Snilay@cs.wisc.eduCacheMemory::clearLocked(Addr address)
4696782SN/A{
47011118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "Clear Lock for addr: %#x\n", address);
47111025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
47211061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
4737039SN/A    int loc = findTagInSet(cacheSet, address);
4747039SN/A    assert(loc != -1);
47511059Snilay@cs.wisc.edu    m_cache[cacheSet][loc]->clearLocked();
4766782SN/A}
4776782SN/A
4786782SN/Abool
47911025Snilay@cs.wisc.eduCacheMemory::isLocked(Addr address, int context)
4806782SN/A{
48111025Snilay@cs.wisc.edu    assert(address == makeLineAddress(address));
48211061Snilay@cs.wisc.edu    int64_t cacheSet = addressToCacheSet(address);
4837039SN/A    int loc = findTagInSet(cacheSet, address);
4847039SN/A    assert(loc != -1);
48511118Snilay@cs.wisc.edu    DPRINTF(RubyCache, "Testing Lock for addr: %#llx cur %d con %d\n",
4867839SN/A            address, m_cache[cacheSet][loc]->m_locked, context);
48711059Snilay@cs.wisc.edu    return m_cache[cacheSet][loc]->isLocked(context);
4886782SN/A}
4896782SN/A
4909104SN/Avoid
4919692SN/ACacheMemory::regStats()
4929692SN/A{
49311523Sdavid.guillen@arm.com    SimObject::regStats();
49411523Sdavid.guillen@arm.com
4959692SN/A    m_demand_hits
4969692SN/A        .name(name() + ".demand_hits")
4979692SN/A        .desc("Number of cache demand hits")
4989692SN/A        ;
4999692SN/A
5009692SN/A    m_demand_misses
5019692SN/A        .name(name() + ".demand_misses")
5029692SN/A        .desc("Number of cache demand misses")
5039692SN/A        ;
5049692SN/A
5059692SN/A    m_demand_accesses
5069692SN/A        .name(name() + ".demand_accesses")
5079692SN/A        .desc("Number of cache demand accesses")
5089692SN/A        ;
5099692SN/A
5109692SN/A    m_demand_accesses = m_demand_hits + m_demand_misses;
5119692SN/A
5129692SN/A    m_sw_prefetches
5139692SN/A        .name(name() + ".total_sw_prefetches")
5149692SN/A        .desc("Number of software prefetches")
5159692SN/A        .flags(Stats::nozero)
5169692SN/A        ;
5179692SN/A
5189692SN/A    m_hw_prefetches
5199692SN/A        .name(name() + ".total_hw_prefetches")
5209692SN/A        .desc("Number of hardware prefetches")
5219692SN/A        .flags(Stats::nozero)
5229692SN/A        ;
5239692SN/A
5249692SN/A    m_prefetches
5259692SN/A        .name(name() + ".total_prefetches")
5269692SN/A        .desc("Number of prefetches")
5279692SN/A        .flags(Stats::nozero)
5289692SN/A        ;
5299692SN/A
5309692SN/A    m_prefetches = m_sw_prefetches + m_hw_prefetches;
5319692SN/A
5329692SN/A    m_accessModeType
5339692SN/A        .init(RubyRequestType_NUM)
5349692SN/A        .name(name() + ".access_mode")
5359692SN/A        .flags(Stats::pdf | Stats::total)
5369692SN/A        ;
5379692SN/A    for (int i = 0; i < RubyAccessMode_NUM; i++) {
5389692SN/A        m_accessModeType
5399692SN/A            .subname(i, RubyAccessMode_to_string(RubyAccessMode(i)))
5409692SN/A            .flags(Stats::nozero)
5419692SN/A            ;
5429692SN/A    }
5439692SN/A
5449692SN/A    numDataArrayReads
5459692SN/A        .name(name() + ".num_data_array_reads")
5469692SN/A        .desc("number of data array reads")
5479692SN/A        .flags(Stats::nozero)
5489692SN/A        ;
5499692SN/A
5509692SN/A    numDataArrayWrites
5519692SN/A        .name(name() + ".num_data_array_writes")
5529692SN/A        .desc("number of data array writes")
5539692SN/A        .flags(Stats::nozero)
5549692SN/A        ;
5559692SN/A
5569692SN/A    numTagArrayReads
5579692SN/A        .name(name() + ".num_tag_array_reads")
5589692SN/A        .desc("number of tag array reads")
5599692SN/A        .flags(Stats::nozero)
5609692SN/A        ;
5619692SN/A
5629692SN/A    numTagArrayWrites
5639692SN/A        .name(name() + ".num_tag_array_writes")
5649692SN/A        .desc("number of tag array writes")
5659692SN/A        .flags(Stats::nozero)
5669692SN/A        ;
5679692SN/A
5689692SN/A    numTagArrayStalls
5699692SN/A        .name(name() + ".num_tag_array_stalls")
5709692SN/A        .desc("number of stalls caused by tag array")
5719692SN/A        .flags(Stats::nozero)
5729692SN/A        ;
5739692SN/A
5749692SN/A    numDataArrayStalls
5759692SN/A        .name(name() + ".num_data_array_stalls")
5769692SN/A        .desc("number of stalls caused by data array")
5779692SN/A        .flags(Stats::nozero)
5789692SN/A        ;
5799692SN/A}
5809692SN/A
58110978Sdavid.hashe@amd.com// assumption: SLICC generated files will only call this function
58210978Sdavid.hashe@amd.com// once **all** resources are granted
5839692SN/Avoid
58411025Snilay@cs.wisc.eduCacheMemory::recordRequestType(CacheRequestType requestType, Addr addr)
5859692SN/A{
5869104SN/A    DPRINTF(RubyStats, "Recorded statistic: %s\n",
5879104SN/A            CacheRequestType_to_string(requestType));
5889104SN/A    switch(requestType) {
5899104SN/A    case CacheRequestType_DataArrayRead:
59010978Sdavid.hashe@amd.com        if (m_resource_stalls)
59110978Sdavid.hashe@amd.com            dataArray.reserve(addressToCacheSet(addr));
5929104SN/A        numDataArrayReads++;
5939104SN/A        return;
5949104SN/A    case CacheRequestType_DataArrayWrite:
59510978Sdavid.hashe@amd.com        if (m_resource_stalls)
59610978Sdavid.hashe@amd.com            dataArray.reserve(addressToCacheSet(addr));
5979104SN/A        numDataArrayWrites++;
5989104SN/A        return;
5999104SN/A    case CacheRequestType_TagArrayRead:
60010978Sdavid.hashe@amd.com        if (m_resource_stalls)
60110978Sdavid.hashe@amd.com            tagArray.reserve(addressToCacheSet(addr));
6029104SN/A        numTagArrayReads++;
6039104SN/A        return;
6049104SN/A    case CacheRequestType_TagArrayWrite:
60510978Sdavid.hashe@amd.com        if (m_resource_stalls)
60610978Sdavid.hashe@amd.com            tagArray.reserve(addressToCacheSet(addr));
6079104SN/A        numTagArrayWrites++;
6089104SN/A        return;
6099104SN/A    default:
6109104SN/A        warn("CacheMemory access_type not found: %s",
6119104SN/A             CacheRequestType_to_string(requestType));
6129104SN/A    }
6139104SN/A}
6149104SN/A
6159105SN/Abool
61611025Snilay@cs.wisc.eduCacheMemory::checkResourceAvailable(CacheResourceType res, Addr addr)
6179105SN/A{
6189105SN/A    if (!m_resource_stalls) {
6199105SN/A        return true;
6209105SN/A    }
6219105SN/A
6229105SN/A    if (res == CacheResourceType_TagArray) {
6239105SN/A        if (tagArray.tryAccess(addressToCacheSet(addr))) return true;
6249105SN/A        else {
6259692SN/A            DPRINTF(RubyResourceStalls,
62611118Snilay@cs.wisc.edu                    "Tag array stall on addr %#x in set %d\n",
6279692SN/A                    addr, addressToCacheSet(addr));
6289105SN/A            numTagArrayStalls++;
6299105SN/A            return false;
6309105SN/A        }
6319105SN/A    } else if (res == CacheResourceType_DataArray) {
6329105SN/A        if (dataArray.tryAccess(addressToCacheSet(addr))) return true;
6339105SN/A        else {
6349692SN/A            DPRINTF(RubyResourceStalls,
63511118Snilay@cs.wisc.edu                    "Data array stall on addr %#x in set %d\n",
6369692SN/A                    addr, addressToCacheSet(addr));
6379105SN/A            numDataArrayStalls++;
6389105SN/A            return false;
6399105SN/A        }
6409105SN/A    } else {
64113449Sgabeblack@google.com        panic("Unrecognized cache resource type.");
6429105SN/A    }
6439105SN/A}
64410980Sdavid.hashe@amd.com
64510980Sdavid.hashe@amd.combool
64611061Snilay@cs.wisc.eduCacheMemory::isBlockInvalid(int64_t cache_set, int64_t loc)
64710980Sdavid.hashe@amd.com{
64810980Sdavid.hashe@amd.com  return (m_cache[cache_set][loc]->m_Permission == AccessPermission_Invalid);
64910980Sdavid.hashe@amd.com}
65010980Sdavid.hashe@amd.com
65110980Sdavid.hashe@amd.combool
65211061Snilay@cs.wisc.eduCacheMemory::isBlockNotBusy(int64_t cache_set, int64_t loc)
65310980Sdavid.hashe@amd.com{
65410980Sdavid.hashe@amd.com  return (m_cache[cache_set][loc]->m_Permission != AccessPermission_Busy);
65510980Sdavid.hashe@amd.com}
656