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