CacheMemory.cc revision 10301
16782SN/A/*
28683SN/A * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
36782SN/A * All rights reserved.
46782SN/A *
56782SN/A * Redistribution and use in source and binary forms, with or without
66782SN/A * modification, are permitted provided that the following conditions are
76782SN/A * met: redistributions of source code must retain the above copyright
86782SN/A * notice, this list of conditions and the following disclaimer;
96782SN/A * redistributions in binary form must reproduce the above copyright
106782SN/A * notice, this list of conditions and the following disclaimer in the
116782SN/A * documentation and/or other materials provided with the distribution;
126782SN/A * neither the name of the copyright holders nor the names of its
136782SN/A * contributors may be used to endorse or promote products derived from
146782SN/A * this software without specific prior written permission.
156782SN/A *
166782SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176782SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186782SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196782SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206782SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216782SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226782SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236782SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246782SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256782SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266782SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276782SN/A */
286782SN/A
297056SN/A#include "base/intmath.hh"
308232SN/A#include "debug/RubyCache.hh"
318937SN/A#include "debug/RubyCacheTrace.hh"
329105SN/A#include "debug/RubyResourceStalls.hh"
339104SN/A#include "debug/RubyStats.hh"
348683SN/A#include "mem/protocol/AccessPermission.hh"
3510301Snilay@cs.wisc.edu#include "mem/ruby/structures/CacheMemory.hh"
368683SN/A#include "mem/ruby/system/System.hh"
376782SN/A
387055SN/Ausing namespace std;
397055SN/A
407039SN/Aostream&
417039SN/Aoperator<<(ostream& out, const CacheMemory& obj)
426782SN/A{
437039SN/A    obj.print(out);
447039SN/A    out << flush;
457039SN/A    return out;
466782SN/A}
476782SN/A
486876SN/ACacheMemory *
496876SN/ARubyCacheParams::create()
506782SN/A{
516876SN/A    return new CacheMemory(this);
526782SN/A}
536782SN/A
546876SN/ACacheMemory::CacheMemory(const Params *p)
559105SN/A    : SimObject(p),
569105SN/A    dataArray(p->dataArrayBanks, p->dataAccessLatency, p->start_index_bit),
579105SN/A    tagArray(p->tagArrayBanks, p->tagAccessLatency, p->start_index_bit)
586782SN/A{
596882SN/A    m_cache_size = p->size;
606876SN/A    m_latency = p->latency;
616876SN/A    m_cache_assoc = p->assoc;
626882SN/A    m_policy = p->replacement_policy;
637564SN/A    m_start_index_bit = p->start_index_bit;
648653SN/A    m_is_instruction_only_cache = p->is_icache;
659105SN/A    m_resource_stalls = p->resourceStalls;
666876SN/A}
676876SN/A
687039SN/Avoid
697039SN/ACacheMemory::init()
706876SN/A{
717039SN/A    m_cache_num_sets = (m_cache_size / m_cache_assoc) /
727039SN/A        RubySystem::getBlockSizeBytes();
736882SN/A    assert(m_cache_num_sets > 1);
747056SN/A    m_cache_num_set_bits = floorLog2(m_cache_num_sets);
756882SN/A    assert(m_cache_num_set_bits > 0);
767039SN/A
777039SN/A    if (m_policy == "PSEUDO_LRU")
787039SN/A        m_replacementPolicy_ptr =
797039SN/A            new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
806882SN/A    else if (m_policy == "LRU")
817039SN/A        m_replacementPolicy_ptr =
827039SN/A            new LRUPolicy(m_cache_num_sets, m_cache_assoc);
836882SN/A    else
847039SN/A        assert(false);
856882SN/A
867454SN/A    m_cache.resize(m_cache_num_sets);
877039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
887454SN/A        m_cache[i].resize(m_cache_assoc);
897039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
907039SN/A            m_cache[i][j] = NULL;
917039SN/A        }
926782SN/A    }
936782SN/A}
946782SN/A
956782SN/ACacheMemory::~CacheMemory()
966782SN/A{
977039SN/A    if (m_replacementPolicy_ptr != NULL)
987039SN/A        delete m_replacementPolicy_ptr;
997039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
1007039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
1017039SN/A            delete m_cache[i][j];
1027039SN/A        }
1036783SN/A    }
1046782SN/A}
1056782SN/A
1066782SN/A// convert a Address to its location in the cache
1077039SN/AIndex
1087039SN/ACacheMemory::addressToCacheSet(const Address& address) const
1096782SN/A{
1107039SN/A    assert(address == line_address(address));
1117564SN/A    return address.bitSelect(m_start_index_bit,
1127564SN/A                             m_start_index_bit + m_cache_num_set_bits - 1);
1136782SN/A}
1146782SN/A
1156782SN/A// Given a cache index: returns the index of the tag in a set.
1166782SN/A// returns -1 if the tag is not found.
1177039SN/Aint
1187039SN/ACacheMemory::findTagInSet(Index cacheSet, const Address& tag) const
1196782SN/A{
1207039SN/A    assert(tag == line_address(tag));
1217039SN/A    // search the set for the tags
1227039SN/A    m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
1237039SN/A    if (it != m_tag_index.end())
1247039SN/A        if (m_cache[cacheSet][it->second]->m_Permission !=
1257039SN/A            AccessPermission_NotPresent)
1267039SN/A            return it->second;
1277039SN/A    return -1; // Not found
1286782SN/A}
1296782SN/A
1306782SN/A// Given a cache index: returns the index of the tag in a set.
1316782SN/A// returns -1 if the tag is not found.
1327039SN/Aint
1337039SN/ACacheMemory::findTagInSetIgnorePermissions(Index cacheSet,
1347039SN/A                                           const Address& tag) const
1356782SN/A{
1367039SN/A    assert(tag == line_address(tag));
1377039SN/A    // search the set for the tags
1387039SN/A    m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
1397039SN/A    if (it != m_tag_index.end())
1407039SN/A        return it->second;
1417039SN/A    return -1; // Not found
1426782SN/A}
1436782SN/A
1447039SN/Abool
1458165SN/ACacheMemory::tryCacheAccess(const Address& address, RubyRequestType type,
1467039SN/A                            DataBlock*& data_ptr)
1476782SN/A{
1487039SN/A    assert(address == line_address(address));
1497780SN/A    DPRINTF(RubyCache, "address: %s\n", address);
1507039SN/A    Index cacheSet = addressToCacheSet(address);
1517039SN/A    int loc = findTagInSet(cacheSet, address);
1527039SN/A    if (loc != -1) {
1537039SN/A        // Do we even have a tag match?
1547039SN/A        AbstractCacheEntry* entry = m_cache[cacheSet][loc];
1559171SN/A        m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
1567039SN/A        data_ptr = &(entry->getDataBlk());
1576782SN/A
1587039SN/A        if (entry->m_Permission == AccessPermission_Read_Write) {
1597039SN/A            return true;
1607039SN/A        }
1617039SN/A        if ((entry->m_Permission == AccessPermission_Read_Only) &&
1628165SN/A            (type == RubyRequestType_LD || type == RubyRequestType_IFETCH)) {
1637039SN/A            return true;
1647039SN/A        }
1657039SN/A        // The line must not be accessible
1666782SN/A    }
1677039SN/A    data_ptr = NULL;
1687039SN/A    return false;
1696782SN/A}
1706782SN/A
1717039SN/Abool
1728165SN/ACacheMemory::testCacheAccess(const Address& address, RubyRequestType type,
1737039SN/A                             DataBlock*& data_ptr)
1746782SN/A{
1757039SN/A    assert(address == line_address(address));
1767780SN/A    DPRINTF(RubyCache, "address: %s\n", address);
1777039SN/A    Index cacheSet = addressToCacheSet(address);
1787039SN/A    int loc = findTagInSet(cacheSet, address);
1796782SN/A
1807039SN/A    if (loc != -1) {
1817039SN/A        // Do we even have a tag match?
1827039SN/A        AbstractCacheEntry* entry = m_cache[cacheSet][loc];
1839171SN/A        m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
1847039SN/A        data_ptr = &(entry->getDataBlk());
1857039SN/A
1867039SN/A        return m_cache[cacheSet][loc]->m_Permission !=
1877039SN/A            AccessPermission_NotPresent;
1887039SN/A    }
1897039SN/A
1907039SN/A    data_ptr = NULL;
1917039SN/A    return false;
1926782SN/A}
1936782SN/A
1946782SN/A// tests to see if an address is present in the cache
1957039SN/Abool
1967039SN/ACacheMemory::isTagPresent(const Address& address) const
1976782SN/A{
1987039SN/A    assert(address == line_address(address));
1997039SN/A    Index cacheSet = addressToCacheSet(address);
2007039SN/A    int loc = findTagInSet(cacheSet, address);
2016782SN/A
2027039SN/A    if (loc == -1) {
2037039SN/A        // We didn't find the tag
2047780SN/A        DPRINTF(RubyCache, "No tag match for address: %s\n", address);
2057039SN/A        return false;
2067039SN/A    }
2077780SN/A    DPRINTF(RubyCache, "address: %s found\n", address);
2087039SN/A    return true;
2096782SN/A}
2106782SN/A
2116782SN/A// Returns true if there is:
2126782SN/A//   a) a tag match on this address or there is
2136782SN/A//   b) an unused line in the same cache "way"
2147039SN/Abool
2157039SN/ACacheMemory::cacheAvail(const Address& address) const
2166782SN/A{
2177039SN/A    assert(address == line_address(address));
2186782SN/A
2197039SN/A    Index cacheSet = addressToCacheSet(address);
2206782SN/A
2217039SN/A    for (int i = 0; i < m_cache_assoc; i++) {
2227039SN/A        AbstractCacheEntry* entry = m_cache[cacheSet][i];
2237039SN/A        if (entry != NULL) {
2247039SN/A            if (entry->m_Address == address ||
2257039SN/A                entry->m_Permission == AccessPermission_NotPresent) {
2267039SN/A                // Already in the cache or we found an empty entry
2277039SN/A                return true;
2287039SN/A            }
2297039SN/A        } else {
2307039SN/A            return true;
2317039SN/A        }
2326782SN/A    }
2337039SN/A    return false;
2346782SN/A}
2356782SN/A
2367839SN/AAbstractCacheEntry*
2377039SN/ACacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
2386782SN/A{
2397039SN/A    assert(address == line_address(address));
2407039SN/A    assert(!isTagPresent(address));
2417039SN/A    assert(cacheAvail(address));
2427780SN/A    DPRINTF(RubyCache, "address: %s\n", address);
2436782SN/A
2447039SN/A    // Find the first open slot
2457039SN/A    Index cacheSet = addressToCacheSet(address);
2467454SN/A    std::vector<AbstractCacheEntry*> &set = m_cache[cacheSet];
2477039SN/A    for (int i = 0; i < m_cache_assoc; i++) {
2487039SN/A        if (!set[i] || set[i]->m_Permission == AccessPermission_NotPresent) {
2497039SN/A            set[i] = entry;  // Init entry
2507039SN/A            set[i]->m_Address = address;
2517039SN/A            set[i]->m_Permission = AccessPermission_Invalid;
2527039SN/A            DPRINTF(RubyCache, "Allocate clearing lock for addr: %x\n",
2537039SN/A                    address);
2547839SN/A            set[i]->m_locked = -1;
2557039SN/A            m_tag_index[address] = i;
2566782SN/A
2579171SN/A            m_replacementPolicy_ptr->touch(cacheSet, i, curTick());
2586782SN/A
2597839SN/A            return entry;
2607039SN/A        }
2616782SN/A    }
2627805SN/A    panic("Allocate didn't find an available entry");
2636782SN/A}
2646782SN/A
2657039SN/Avoid
2667039SN/ACacheMemory::deallocate(const Address& address)
2676782SN/A{
2687039SN/A    assert(address == line_address(address));
2697039SN/A    assert(isTagPresent(address));
2707780SN/A    DPRINTF(RubyCache, "address: %s\n", address);
2717039SN/A    Index cacheSet = addressToCacheSet(address);
2727039SN/A    int loc = findTagInSet(cacheSet, address);
2737039SN/A    if (loc != -1) {
2747039SN/A        delete m_cache[cacheSet][loc];
2757039SN/A        m_cache[cacheSet][loc] = NULL;
2767039SN/A        m_tag_index.erase(address);
2777039SN/A    }
2786782SN/A}
2796782SN/A
2806782SN/A// Returns with the physical address of the conflicting cache line
2817039SN/AAddress
2827039SN/ACacheMemory::cacheProbe(const Address& address) const
2836782SN/A{
2847039SN/A    assert(address == line_address(address));
2857039SN/A    assert(!cacheAvail(address));
2866782SN/A
2877039SN/A    Index cacheSet = addressToCacheSet(address);
2887039SN/A    return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->
2897039SN/A        m_Address;
2906782SN/A}
2916782SN/A
2926782SN/A// looks an address up in the cache
2937839SN/AAbstractCacheEntry*
2947039SN/ACacheMemory::lookup(const Address& address)
2956782SN/A{
2967039SN/A    assert(address == line_address(address));
2977039SN/A    Index cacheSet = addressToCacheSet(address);
2987039SN/A    int loc = findTagInSet(cacheSet, address);
2997839SN/A    if(loc == -1) return NULL;
3007839SN/A    return m_cache[cacheSet][loc];
3016782SN/A}
3026782SN/A
3036782SN/A// looks an address up in the cache
3047839SN/Aconst AbstractCacheEntry*
3057039SN/ACacheMemory::lookup(const Address& address) const
3066782SN/A{
3077039SN/A    assert(address == line_address(address));
3087039SN/A    Index cacheSet = addressToCacheSet(address);
3097039SN/A    int loc = findTagInSet(cacheSet, address);
3107839SN/A    if(loc == -1) return NULL;
3117839SN/A    return m_cache[cacheSet][loc];
3126782SN/A}
3136782SN/A
3146782SN/A// Sets the most recently used bit for a cache block
3157039SN/Avoid
3167039SN/ACacheMemory::setMRU(const Address& address)
3176782SN/A{
3188828SN/A    Index cacheSet = addressToCacheSet(address);
3198828SN/A    int loc = findTagInSet(cacheSet, address);
3206782SN/A
3218828SN/A    if(loc != -1)
3229171SN/A        m_replacementPolicy_ptr->touch(cacheSet, loc, curTick());
3236782SN/A}
3246782SN/A
3257039SN/Avoid
3268683SN/ACacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const
3276782SN/A{
3288683SN/A    uint64 warmedUpBlocks = 0;
3298683SN/A    uint64 totalBlocks M5_VAR_USED = (uint64)m_cache_num_sets
3308683SN/A                                                  * (uint64)m_cache_assoc;
3318683SN/A
3327039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
3337039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
3348683SN/A            if (m_cache[i][j] != NULL) {
3358683SN/A                AccessPermission perm = m_cache[i][j]->m_Permission;
3368683SN/A                RubyRequestType request_type = RubyRequestType_NULL;
3378683SN/A                if (perm == AccessPermission_Read_Only) {
3388683SN/A                    if (m_is_instruction_only_cache) {
3398683SN/A                        request_type = RubyRequestType_IFETCH;
3408683SN/A                    } else {
3418683SN/A                        request_type = RubyRequestType_LD;
3428683SN/A                    }
3438683SN/A                } else if (perm == AccessPermission_Read_Write) {
3448683SN/A                    request_type = RubyRequestType_ST;
3457039SN/A                }
3467039SN/A
3478683SN/A                if (request_type != RubyRequestType_NULL) {
3488683SN/A                    tr->addRecord(cntrl, m_cache[i][j]->m_Address.getAddress(),
3498683SN/A                                  0, request_type,
3508683SN/A                                  m_replacementPolicy_ptr->getLastAccess(i, j),
3518683SN/A                                  m_cache[i][j]->getDataBlk());
3528683SN/A                    warmedUpBlocks++;
3538683SN/A                }
3547039SN/A            }
3556782SN/A        }
3566782SN/A    }
3578683SN/A
3588937SN/A    DPRINTF(RubyCacheTrace, "%s: %lli blocks of %lli total blocks"
3598683SN/A            "recorded %.2f%% \n", name().c_str(), warmedUpBlocks,
3608683SN/A            (uint64)m_cache_num_sets * (uint64)m_cache_assoc,
3618683SN/A            (float(warmedUpBlocks)/float(totalBlocks))*100.0);
3626782SN/A}
3636782SN/A
3647039SN/Avoid
3657039SN/ACacheMemory::print(ostream& out) const
3666782SN/A{
36710080SN/A    out << "Cache dump: " << name() << endl;
3687039SN/A    for (int i = 0; i < m_cache_num_sets; i++) {
3697039SN/A        for (int j = 0; j < m_cache_assoc; j++) {
3707039SN/A            if (m_cache[i][j] != NULL) {
3717039SN/A                out << "  Index: " << i
3727039SN/A                    << " way: " << j
3737039SN/A                    << " entry: " << *m_cache[i][j] << endl;
3747039SN/A            } else {
3757039SN/A                out << "  Index: " << i
3767039SN/A                    << " way: " << j
3777039SN/A                    << " entry: NULL" << endl;
3787039SN/A            }
3797039SN/A        }
3806782SN/A    }
3816782SN/A}
3826782SN/A
3837039SN/Avoid
3847039SN/ACacheMemory::printData(ostream& out) const
3856782SN/A{
3867039SN/A    out << "printData() not supported" << endl;
3876782SN/A}
3886782SN/A
3897039SN/Avoid
3907039SN/ACacheMemory::setLocked(const Address& address, int context)
3917039SN/A{
3927039SN/A    DPRINTF(RubyCache, "Setting Lock for addr: %x to %d\n", address, context);
3937039SN/A    assert(address == line_address(address));
3947039SN/A    Index cacheSet = addressToCacheSet(address);
3957039SN/A    int loc = findTagInSet(cacheSet, address);
3967039SN/A    assert(loc != -1);
3977839SN/A    m_cache[cacheSet][loc]->m_locked = context;
3986782SN/A}
3996782SN/A
4007039SN/Avoid
4017039SN/ACacheMemory::clearLocked(const Address& address)
4026782SN/A{
4037039SN/A    DPRINTF(RubyCache, "Clear Lock for addr: %x\n", address);
4047039SN/A    assert(address == line_address(address));
4057039SN/A    Index cacheSet = addressToCacheSet(address);
4067039SN/A    int loc = findTagInSet(cacheSet, address);
4077039SN/A    assert(loc != -1);
4087839SN/A    m_cache[cacheSet][loc]->m_locked = -1;
4096782SN/A}
4106782SN/A
4116782SN/Abool
4126782SN/ACacheMemory::isLocked(const Address& address, int context)
4136782SN/A{
4147039SN/A    assert(address == line_address(address));
4157039SN/A    Index cacheSet = addressToCacheSet(address);
4167039SN/A    int loc = findTagInSet(cacheSet, address);
4177039SN/A    assert(loc != -1);
4187039SN/A    DPRINTF(RubyCache, "Testing Lock for addr: %llx cur %d con %d\n",
4197839SN/A            address, m_cache[cacheSet][loc]->m_locked, context);
4207839SN/A    return m_cache[cacheSet][loc]->m_locked == context;
4216782SN/A}
4226782SN/A
4239104SN/Avoid
4249692SN/ACacheMemory::regStats()
4259692SN/A{
4269692SN/A    m_demand_hits
4279692SN/A        .name(name() + ".demand_hits")
4289692SN/A        .desc("Number of cache demand hits")
4299692SN/A        ;
4309692SN/A
4319692SN/A    m_demand_misses
4329692SN/A        .name(name() + ".demand_misses")
4339692SN/A        .desc("Number of cache demand misses")
4349692SN/A        ;
4359692SN/A
4369692SN/A    m_demand_accesses
4379692SN/A        .name(name() + ".demand_accesses")
4389692SN/A        .desc("Number of cache demand accesses")
4399692SN/A        ;
4409692SN/A
4419692SN/A    m_demand_accesses = m_demand_hits + m_demand_misses;
4429692SN/A
4439692SN/A    m_sw_prefetches
4449692SN/A        .name(name() + ".total_sw_prefetches")
4459692SN/A        .desc("Number of software prefetches")
4469692SN/A        .flags(Stats::nozero)
4479692SN/A        ;
4489692SN/A
4499692SN/A    m_hw_prefetches
4509692SN/A        .name(name() + ".total_hw_prefetches")
4519692SN/A        .desc("Number of hardware prefetches")
4529692SN/A        .flags(Stats::nozero)
4539692SN/A        ;
4549692SN/A
4559692SN/A    m_prefetches
4569692SN/A        .name(name() + ".total_prefetches")
4579692SN/A        .desc("Number of prefetches")
4589692SN/A        .flags(Stats::nozero)
4599692SN/A        ;
4609692SN/A
4619692SN/A    m_prefetches = m_sw_prefetches + m_hw_prefetches;
4629692SN/A
4639692SN/A    m_accessModeType
4649692SN/A        .init(RubyRequestType_NUM)
4659692SN/A        .name(name() + ".access_mode")
4669692SN/A        .flags(Stats::pdf | Stats::total)
4679692SN/A        ;
4689692SN/A    for (int i = 0; i < RubyAccessMode_NUM; i++) {
4699692SN/A        m_accessModeType
4709692SN/A            .subname(i, RubyAccessMode_to_string(RubyAccessMode(i)))
4719692SN/A            .flags(Stats::nozero)
4729692SN/A            ;
4739692SN/A    }
4749692SN/A
4759692SN/A    numDataArrayReads
4769692SN/A        .name(name() + ".num_data_array_reads")
4779692SN/A        .desc("number of data array reads")
4789692SN/A        .flags(Stats::nozero)
4799692SN/A        ;
4809692SN/A
4819692SN/A    numDataArrayWrites
4829692SN/A        .name(name() + ".num_data_array_writes")
4839692SN/A        .desc("number of data array writes")
4849692SN/A        .flags(Stats::nozero)
4859692SN/A        ;
4869692SN/A
4879692SN/A    numTagArrayReads
4889692SN/A        .name(name() + ".num_tag_array_reads")
4899692SN/A        .desc("number of tag array reads")
4909692SN/A        .flags(Stats::nozero)
4919692SN/A        ;
4929692SN/A
4939692SN/A    numTagArrayWrites
4949692SN/A        .name(name() + ".num_tag_array_writes")
4959692SN/A        .desc("number of tag array writes")
4969692SN/A        .flags(Stats::nozero)
4979692SN/A        ;
4989692SN/A
4999692SN/A    numTagArrayStalls
5009692SN/A        .name(name() + ".num_tag_array_stalls")
5019692SN/A        .desc("number of stalls caused by tag array")
5029692SN/A        .flags(Stats::nozero)
5039692SN/A        ;
5049692SN/A
5059692SN/A    numDataArrayStalls
5069692SN/A        .name(name() + ".num_data_array_stalls")
5079692SN/A        .desc("number of stalls caused by data array")
5089692SN/A        .flags(Stats::nozero)
5099692SN/A        ;
5109692SN/A}
5119692SN/A
5129692SN/Avoid
5139692SN/ACacheMemory::recordRequestType(CacheRequestType requestType)
5149692SN/A{
5159104SN/A    DPRINTF(RubyStats, "Recorded statistic: %s\n",
5169104SN/A            CacheRequestType_to_string(requestType));
5179104SN/A    switch(requestType) {
5189104SN/A    case CacheRequestType_DataArrayRead:
5199104SN/A        numDataArrayReads++;
5209104SN/A        return;
5219104SN/A    case CacheRequestType_DataArrayWrite:
5229104SN/A        numDataArrayWrites++;
5239104SN/A        return;
5249104SN/A    case CacheRequestType_TagArrayRead:
5259104SN/A        numTagArrayReads++;
5269104SN/A        return;
5279104SN/A    case CacheRequestType_TagArrayWrite:
5289104SN/A        numTagArrayWrites++;
5299104SN/A        return;
5309104SN/A    default:
5319104SN/A        warn("CacheMemory access_type not found: %s",
5329104SN/A             CacheRequestType_to_string(requestType));
5339104SN/A    }
5349104SN/A}
5359104SN/A
5369105SN/Abool
5379105SN/ACacheMemory::checkResourceAvailable(CacheResourceType res, Address addr)
5389105SN/A{
5399105SN/A    if (!m_resource_stalls) {
5409105SN/A        return true;
5419105SN/A    }
5429105SN/A
5439105SN/A    if (res == CacheResourceType_TagArray) {
5449105SN/A        if (tagArray.tryAccess(addressToCacheSet(addr))) return true;
5459105SN/A        else {
5469692SN/A            DPRINTF(RubyResourceStalls,
5479692SN/A                    "Tag array stall on addr %s in set %d\n",
5489692SN/A                    addr, addressToCacheSet(addr));
5499105SN/A            numTagArrayStalls++;
5509105SN/A            return false;
5519105SN/A        }
5529105SN/A    } else if (res == CacheResourceType_DataArray) {
5539105SN/A        if (dataArray.tryAccess(addressToCacheSet(addr))) return true;
5549105SN/A        else {
5559692SN/A            DPRINTF(RubyResourceStalls,
5569692SN/A                    "Data array stall on addr %s in set %d\n",
5579692SN/A                    addr, addressToCacheSet(addr));
5589105SN/A            numDataArrayStalls++;
5599105SN/A            return false;
5609105SN/A        }
5619105SN/A    } else {
5629105SN/A        assert(false);
5639105SN/A        return true;
5649105SN/A    }
5659105SN/A}
566