114039Sstacze01@arm.com/*
214039Sstacze01@arm.com * Copyright (c) 2014, 2018-2019 ARM Limited
314039Sstacze01@arm.com * All rights reserved
414039Sstacze01@arm.com *
514039Sstacze01@arm.com * The license below extends only to copyright in the software and shall
614039Sstacze01@arm.com * not be construed as granting a license to any other intellectual
714039Sstacze01@arm.com * property including but not limited to intellectual property relating
814039Sstacze01@arm.com * to a hardware implementation of the functionality of the software
914039Sstacze01@arm.com * licensed hereunder.  You may use the software subject to the license
1014039Sstacze01@arm.com * terms below provided that you ensure that this notice is replicated
1114039Sstacze01@arm.com * unmodified and in its entirety in all distributions of the software,
1214039Sstacze01@arm.com * modified or unmodified, in source code or in binary form.
1314039Sstacze01@arm.com *
1414039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without
1514039Sstacze01@arm.com * modification, are permitted provided that the following conditions are
1614039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright
1714039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer;
1814039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright
1914039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the
2014039Sstacze01@arm.com * documentation and/or other materials provided with the distribution;
2114039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its
2214039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from
2314039Sstacze01@arm.com * this software without specific prior written permission.
2414039Sstacze01@arm.com *
2514039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2614039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2714039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2814039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2914039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3014039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3114039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3214039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3314039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3414039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3514039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3614039Sstacze01@arm.com *
3714039Sstacze01@arm.com * Authors: Stan Czerniawski
3814039Sstacze01@arm.com *          Damian Richardson
3914039Sstacze01@arm.com */
4014039Sstacze01@arm.com
4114039Sstacze01@arm.com#include "dev/arm/smmu_v3_caches.hh"
4214039Sstacze01@arm.com
4314039Sstacze01@arm.com#include <numeric>
4414039Sstacze01@arm.com
4514039Sstacze01@arm.com#include "base/bitfield.hh"
4614039Sstacze01@arm.com#include "base/intmath.hh"
4714039Sstacze01@arm.com#include "base/logging.hh"
4814039Sstacze01@arm.com#include "sim/stats.hh"
4914039Sstacze01@arm.com
5014039Sstacze01@arm.com
5114039Sstacze01@arm.com// taken from hex expansion of pi
5214039Sstacze01@arm.com#define SMMUTLB_SEED     0xEA752DFE
5314039Sstacze01@arm.com#define ARMARCHTLB_SEED  0x8B021FA1
5414039Sstacze01@arm.com#define IPACACHE_SEED    0xE5A0CC0F
5514039Sstacze01@arm.com#define CONFIGCACHE_SEED 0xB56F74E8
5614039Sstacze01@arm.com#define WALKCACHE_SEED   0x18ACF3D6
5714039Sstacze01@arm.com
5814039Sstacze01@arm.com/*
5914039Sstacze01@arm.com * BaseCache
6014039Sstacze01@arm.com *
6114039Sstacze01@arm.com * TODO: move more code into this base class to reduce duplication.
6214039Sstacze01@arm.com */
6314039Sstacze01@arm.com
6414039Sstacze01@arm.comSMMUv3BaseCache::SMMUv3BaseCache(const std::string &policy_name, uint32_t seed) :
6514039Sstacze01@arm.com    replacementPolicy(decodePolicyName(policy_name)),
6614039Sstacze01@arm.com    nextToReplace(0),
6714039Sstacze01@arm.com    random(seed),
6814039Sstacze01@arm.com    useStamp(0)
6914039Sstacze01@arm.com{}
7014039Sstacze01@arm.com
7114039Sstacze01@arm.comint
7214039Sstacze01@arm.comSMMUv3BaseCache::decodePolicyName(const std::string &policy_name)
7314039Sstacze01@arm.com{
7414039Sstacze01@arm.com    if (policy_name == "rr") {
7514039Sstacze01@arm.com        return SMMU_CACHE_REPL_ROUND_ROBIN;
7614039Sstacze01@arm.com    } else if (policy_name == "rand") {
7714039Sstacze01@arm.com        return SMMU_CACHE_REPL_RANDOM;
7814039Sstacze01@arm.com    } else if (policy_name == "lru") {
7914039Sstacze01@arm.com        return SMMU_CACHE_REPL_LRU;
8014039Sstacze01@arm.com    } else {
8114039Sstacze01@arm.com        panic("Unknown cache replacement policy '%s'\n", policy_name);
8214039Sstacze01@arm.com    }
8314039Sstacze01@arm.com}
8414039Sstacze01@arm.com
8514039Sstacze01@arm.comvoid
8614039Sstacze01@arm.comSMMUv3BaseCache::regStats(const std::string &name)
8714039Sstacze01@arm.com{
8814039Sstacze01@arm.com    using namespace Stats;
8914039Sstacze01@arm.com
9014039Sstacze01@arm.com
9114039Sstacze01@arm.com    averageLookups
9214039Sstacze01@arm.com        .name(name + ".averageLookups")
9314039Sstacze01@arm.com        .desc("Average number lookups per second")
9414039Sstacze01@arm.com        .flags(pdf);
9514039Sstacze01@arm.com
9614039Sstacze01@arm.com    totalLookups
9714039Sstacze01@arm.com        .name(name + ".totalLookups")
9814039Sstacze01@arm.com        .desc("Total number of lookups")
9914039Sstacze01@arm.com        .flags(pdf);
10014039Sstacze01@arm.com
10114039Sstacze01@arm.com    averageLookups = totalLookups / simSeconds;
10214039Sstacze01@arm.com
10314039Sstacze01@arm.com
10414039Sstacze01@arm.com    averageMisses
10514039Sstacze01@arm.com        .name(name + ".averageMisses")
10614039Sstacze01@arm.com        .desc("Average number misses per second")
10714039Sstacze01@arm.com        .flags(pdf);
10814039Sstacze01@arm.com
10914039Sstacze01@arm.com    totalMisses
11014039Sstacze01@arm.com        .name(name + ".totalMisses")
11114039Sstacze01@arm.com        .desc("Total number of misses")
11214039Sstacze01@arm.com        .flags(pdf);
11314039Sstacze01@arm.com
11414039Sstacze01@arm.com    averageMisses = totalMisses / simSeconds;
11514039Sstacze01@arm.com
11614039Sstacze01@arm.com
11714039Sstacze01@arm.com    averageUpdates
11814039Sstacze01@arm.com        .name(name + ".averageUpdates")
11914039Sstacze01@arm.com        .desc("Average number updates per second")
12014039Sstacze01@arm.com        .flags(pdf);
12114039Sstacze01@arm.com
12214039Sstacze01@arm.com    totalUpdates
12314039Sstacze01@arm.com        .name(name + ".totalUpdates")
12414039Sstacze01@arm.com        .desc("Total number of updates")
12514039Sstacze01@arm.com        .flags(pdf);
12614039Sstacze01@arm.com
12714039Sstacze01@arm.com    averageUpdates = totalUpdates / simSeconds;
12814039Sstacze01@arm.com
12914039Sstacze01@arm.com
13014039Sstacze01@arm.com    averageHitRate
13114039Sstacze01@arm.com        .name(name + ".averageHitRate")
13214039Sstacze01@arm.com        .desc("Average hit rate")
13314039Sstacze01@arm.com        .flags(pdf);
13414039Sstacze01@arm.com
13514039Sstacze01@arm.com    averageHitRate = (totalLookups - totalMisses) / totalLookups;
13614039Sstacze01@arm.com
13714039Sstacze01@arm.com    insertions
13814039Sstacze01@arm.com        .name(name + ".insertions")
13914039Sstacze01@arm.com        .desc("Number of insertions (not replacements)")
14014039Sstacze01@arm.com        .flags(pdf);
14114039Sstacze01@arm.com}
14214039Sstacze01@arm.com
14314039Sstacze01@arm.com
14414039Sstacze01@arm.com
14514039Sstacze01@arm.com/*
14614039Sstacze01@arm.com * SMMUTLB
14714039Sstacze01@arm.com */
14814039Sstacze01@arm.com
14914039Sstacze01@arm.comSMMUTLB::SMMUTLB(unsigned numEntries, unsigned _associativity,
15014039Sstacze01@arm.com                 const std::string &policy)
15114039Sstacze01@arm.com:
15214039Sstacze01@arm.com    SMMUv3BaseCache(policy, SMMUTLB_SEED),
15314039Sstacze01@arm.com    associativity(_associativity)
15414039Sstacze01@arm.com{
15514039Sstacze01@arm.com    if (associativity == 0)
15614039Sstacze01@arm.com        associativity = numEntries; // fully associative
15714039Sstacze01@arm.com
15814039Sstacze01@arm.com    if (numEntries == 0)
15914039Sstacze01@arm.com        fatal("SMMUTLB must have at least one entry\n");
16014039Sstacze01@arm.com
16114039Sstacze01@arm.com    if (associativity > numEntries)
16214039Sstacze01@arm.com        fatal("SMMUTLB associativity cannot be higher than "
16314039Sstacze01@arm.com              "its number of entries\n");
16414039Sstacze01@arm.com
16514039Sstacze01@arm.com    unsigned num_sets = numEntries / associativity;
16614039Sstacze01@arm.com
16714039Sstacze01@arm.com    if (num_sets*associativity != numEntries)
16814039Sstacze01@arm.com        fatal("Number of SMMUTLB entries must be divisible "
16914039Sstacze01@arm.com              "by its associativity\n");
17014039Sstacze01@arm.com
17114039Sstacze01@arm.com    Entry e;
17214039Sstacze01@arm.com    e.valid = false;
17314039Sstacze01@arm.com
17414039Sstacze01@arm.com    Set set(associativity, e);
17514039Sstacze01@arm.com    sets.resize(num_sets, set);
17614039Sstacze01@arm.com}
17714039Sstacze01@arm.com
17814039Sstacze01@arm.comconst SMMUTLB::Entry*
17914039Sstacze01@arm.comSMMUTLB::lookup(uint32_t sid, uint32_t ssid,
18014039Sstacze01@arm.com                Addr va, bool updStats)
18114039Sstacze01@arm.com{
18214039Sstacze01@arm.com    const Entry *result = NULL;
18314039Sstacze01@arm.com
18414039Sstacze01@arm.com    Set &set = sets[pickSetIdx(va)];
18514039Sstacze01@arm.com
18614039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
18714039Sstacze01@arm.com        const Entry &e = set[i];
18814039Sstacze01@arm.com
18914039Sstacze01@arm.com        if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
19014039Sstacze01@arm.com            e.sid==sid && e.ssid==ssid)
19114039Sstacze01@arm.com        {
19214039Sstacze01@arm.com            if (result != NULL)
19314039Sstacze01@arm.com                panic("SMMUTLB: duplicate entry found!\n");
19414039Sstacze01@arm.com
19514039Sstacze01@arm.com            result = &e;
19614039Sstacze01@arm.com            break;
19714039Sstacze01@arm.com        }
19814039Sstacze01@arm.com    }
19914039Sstacze01@arm.com
20014039Sstacze01@arm.com    if (updStats) {
20114039Sstacze01@arm.com        if (result)
20214039Sstacze01@arm.com            result->lastUsed = useStamp++;
20314039Sstacze01@arm.com
20414039Sstacze01@arm.com        totalLookups++;
20514039Sstacze01@arm.com        if (result == NULL)
20614039Sstacze01@arm.com            totalMisses++;
20714039Sstacze01@arm.com    }
20814039Sstacze01@arm.com
20914039Sstacze01@arm.com    return result;
21014039Sstacze01@arm.com}
21114039Sstacze01@arm.com
21214039Sstacze01@arm.comconst SMMUTLB::Entry*
21314039Sstacze01@arm.comSMMUTLB::lookupAnyVA(uint32_t sid, uint32_t ssid, bool updStats)
21414039Sstacze01@arm.com{
21514039Sstacze01@arm.com    const Entry *result = NULL;
21614039Sstacze01@arm.com
21714039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
21814039Sstacze01@arm.com        Set &set = sets[s];
21914039Sstacze01@arm.com
22014039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
22114039Sstacze01@arm.com            const Entry &e = set[i];
22214039Sstacze01@arm.com
22314039Sstacze01@arm.com            if (e.valid && e.sid==sid && e.ssid==ssid) {
22414039Sstacze01@arm.com                result = &e;
22514039Sstacze01@arm.com                break;
22614039Sstacze01@arm.com            }
22714039Sstacze01@arm.com        }
22814039Sstacze01@arm.com    }
22914039Sstacze01@arm.com
23014039Sstacze01@arm.com    if (updStats) {
23114039Sstacze01@arm.com        totalLookups++;
23214039Sstacze01@arm.com        if (result == NULL)
23314039Sstacze01@arm.com            totalMisses++;
23414039Sstacze01@arm.com    }
23514039Sstacze01@arm.com
23614039Sstacze01@arm.com    return result;
23714039Sstacze01@arm.com}
23814039Sstacze01@arm.com
23914039Sstacze01@arm.comvoid
24014039Sstacze01@arm.comSMMUTLB::store(const Entry &incoming, AllocPolicy alloc)
24114039Sstacze01@arm.com{
24214039Sstacze01@arm.com    if (!incoming.valid)
24314039Sstacze01@arm.com        panic("Tried to store an invalid entry\n");
24414039Sstacze01@arm.com
24514039Sstacze01@arm.com    incoming.lastUsed = 0;
24614039Sstacze01@arm.com
24714039Sstacze01@arm.com    const Entry *existing =
24814039Sstacze01@arm.com        lookup(incoming.sid, incoming.ssid, incoming.va, false);
24914039Sstacze01@arm.com
25014039Sstacze01@arm.com    if (existing) {
25114039Sstacze01@arm.com        *const_cast<Entry *> (existing) = incoming;
25214039Sstacze01@arm.com    } else {
25314039Sstacze01@arm.com        Set &set = sets[pickSetIdx(incoming.va)];
25414039Sstacze01@arm.com        set[pickEntryIdxToReplace(set, alloc)] = incoming;
25514039Sstacze01@arm.com    }
25614039Sstacze01@arm.com
25714039Sstacze01@arm.com    totalUpdates++;
25814039Sstacze01@arm.com}
25914039Sstacze01@arm.com
26014039Sstacze01@arm.comvoid
26114132Sgiacomo.travaglini@arm.comSMMUTLB::invalidateSSID(uint32_t sid, uint32_t ssid)
26214132Sgiacomo.travaglini@arm.com{
26314132Sgiacomo.travaglini@arm.com    Set &set = sets[pickSetIdx(sid, ssid)];
26414132Sgiacomo.travaglini@arm.com
26514132Sgiacomo.travaglini@arm.com    for (size_t i = 0; i < set.size(); i++) {
26614132Sgiacomo.travaglini@arm.com        Entry &e = set[i];
26714132Sgiacomo.travaglini@arm.com
26814132Sgiacomo.travaglini@arm.com        if (e.sid == sid && e.ssid == ssid)
26914132Sgiacomo.travaglini@arm.com            e.valid = false;
27014132Sgiacomo.travaglini@arm.com    }
27114132Sgiacomo.travaglini@arm.com}
27214132Sgiacomo.travaglini@arm.com
27314132Sgiacomo.travaglini@arm.comvoid
27414132Sgiacomo.travaglini@arm.comSMMUTLB::invalidateSID(uint32_t sid)
27514132Sgiacomo.travaglini@arm.com{
27614132Sgiacomo.travaglini@arm.com    for (size_t s = 0; s < sets.size(); s++) {
27714132Sgiacomo.travaglini@arm.com        Set &set = sets[s];
27814132Sgiacomo.travaglini@arm.com
27914132Sgiacomo.travaglini@arm.com        for (size_t i = 0; i < set.size(); i++) {
28014132Sgiacomo.travaglini@arm.com            Entry &e = set[i];
28114132Sgiacomo.travaglini@arm.com
28214132Sgiacomo.travaglini@arm.com            if (e.sid == sid)
28314132Sgiacomo.travaglini@arm.com                e.valid = false;
28414132Sgiacomo.travaglini@arm.com        }
28514132Sgiacomo.travaglini@arm.com    }
28614132Sgiacomo.travaglini@arm.com}
28714132Sgiacomo.travaglini@arm.com
28814132Sgiacomo.travaglini@arm.comvoid
28914039Sstacze01@arm.comSMMUTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
29014039Sstacze01@arm.com{
29114039Sstacze01@arm.com    Set &set = sets[pickSetIdx(va)];
29214039Sstacze01@arm.com
29314039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
29414039Sstacze01@arm.com        Entry &e = set[i];
29514039Sstacze01@arm.com
29614039Sstacze01@arm.com        if ((e.va & e.vaMask) == (va & e.vaMask) &&
29714039Sstacze01@arm.com            e.asid==asid && e.vmid==vmid)
29814039Sstacze01@arm.com        {
29914039Sstacze01@arm.com            e.valid = false;
30014039Sstacze01@arm.com        }
30114039Sstacze01@arm.com    }
30214039Sstacze01@arm.com}
30314039Sstacze01@arm.com
30414039Sstacze01@arm.comvoid
30514039Sstacze01@arm.comSMMUTLB::invalidateVAA(Addr va, uint16_t vmid)
30614039Sstacze01@arm.com{
30714039Sstacze01@arm.com    Set &set = sets[pickSetIdx(va)];
30814039Sstacze01@arm.com
30914039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
31014039Sstacze01@arm.com        Entry &e = set[i];
31114039Sstacze01@arm.com
31214039Sstacze01@arm.com        if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid)
31314039Sstacze01@arm.com            e.valid = false;
31414039Sstacze01@arm.com    }
31514039Sstacze01@arm.com}
31614039Sstacze01@arm.com
31714039Sstacze01@arm.comvoid
31814039Sstacze01@arm.comSMMUTLB::invalidateASID(uint16_t asid, uint16_t vmid)
31914039Sstacze01@arm.com{
32014039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
32114039Sstacze01@arm.com        Set &set = sets[s];
32214039Sstacze01@arm.com
32314039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
32414039Sstacze01@arm.com            Entry &e = set[i];
32514039Sstacze01@arm.com
32614039Sstacze01@arm.com            if (e.asid==asid && e.vmid==vmid)
32714039Sstacze01@arm.com                e.valid = false;
32814039Sstacze01@arm.com        }
32914039Sstacze01@arm.com    }
33014039Sstacze01@arm.com}
33114039Sstacze01@arm.com
33214039Sstacze01@arm.comvoid
33314039Sstacze01@arm.comSMMUTLB::invalidateVMID(uint16_t vmid)
33414039Sstacze01@arm.com{
33514039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
33614039Sstacze01@arm.com        Set &set = sets[s];
33714039Sstacze01@arm.com
33814039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
33914039Sstacze01@arm.com            Entry &e = set[i];
34014039Sstacze01@arm.com
34114039Sstacze01@arm.com            if (e.vmid == vmid)
34214039Sstacze01@arm.com                e.valid = false;
34314039Sstacze01@arm.com        }
34414039Sstacze01@arm.com    }
34514039Sstacze01@arm.com}
34614039Sstacze01@arm.com
34714039Sstacze01@arm.comvoid
34814039Sstacze01@arm.comSMMUTLB::invalidateAll()
34914039Sstacze01@arm.com{
35014039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
35114039Sstacze01@arm.com        Set &set = sets[s];
35214039Sstacze01@arm.com
35314039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++)
35414039Sstacze01@arm.com            set[i].valid = false;
35514039Sstacze01@arm.com    }
35614039Sstacze01@arm.com}
35714039Sstacze01@arm.com
35814039Sstacze01@arm.comsize_t
35914039Sstacze01@arm.comSMMUTLB::pickSetIdx(Addr va) const
36014039Sstacze01@arm.com{
36114039Sstacze01@arm.com    return (va >> 12) % sets.size();
36214039Sstacze01@arm.com}
36314039Sstacze01@arm.com
36414039Sstacze01@arm.comsize_t
36514132Sgiacomo.travaglini@arm.comSMMUTLB::pickSetIdx(uint32_t sid, uint32_t ssid) const
36614132Sgiacomo.travaglini@arm.com{
36714132Sgiacomo.travaglini@arm.com    return (sid^ssid) % sets.size();
36814132Sgiacomo.travaglini@arm.com}
36914132Sgiacomo.travaglini@arm.com
37014132Sgiacomo.travaglini@arm.comsize_t
37114039Sstacze01@arm.comSMMUTLB::pickEntryIdxToReplace(const Set &set, AllocPolicy alloc)
37214039Sstacze01@arm.com{
37314039Sstacze01@arm.com    if (alloc == ALLOC_LAST_WAY)
37414039Sstacze01@arm.com        return associativity - 1;
37514039Sstacze01@arm.com
37614039Sstacze01@arm.com    uint32_t lru_tick = UINT32_MAX;
37714039Sstacze01@arm.com    size_t lru_idx = 0;
37814039Sstacze01@arm.com    size_t max_idx =
37914039Sstacze01@arm.com        alloc==ALLOC_ANY_BUT_LAST_WAY ?
38014039Sstacze01@arm.com            set.size()-1 : set.size();
38114039Sstacze01@arm.com
38214039Sstacze01@arm.com    for (size_t i = 0; i < max_idx; i++) {
38314039Sstacze01@arm.com        if (!set[i].valid) {
38414039Sstacze01@arm.com            insertions++;
38514039Sstacze01@arm.com            return i;
38614039Sstacze01@arm.com        }
38714039Sstacze01@arm.com
38814039Sstacze01@arm.com        if (set[i].lastUsed < lru_tick) {
38914039Sstacze01@arm.com            lru_idx = i;
39014039Sstacze01@arm.com            lru_tick = set[i].lastUsed;
39114039Sstacze01@arm.com        }
39214039Sstacze01@arm.com    }
39314039Sstacze01@arm.com
39414039Sstacze01@arm.com    switch (replacementPolicy) {
39514039Sstacze01@arm.com    case SMMU_CACHE_REPL_ROUND_ROBIN:
39614039Sstacze01@arm.com        switch (alloc) {
39714039Sstacze01@arm.com        case ALLOC_ANY_WAY:
39814039Sstacze01@arm.com            return nextToReplace = ((nextToReplace+1) % associativity);
39914039Sstacze01@arm.com        case ALLOC_ANY_BUT_LAST_WAY:
40014039Sstacze01@arm.com            return nextToReplace = ((nextToReplace+1) % (associativity-1));
40114039Sstacze01@arm.com        default:
40214039Sstacze01@arm.com            panic("Unknown allocation mode %d\n", alloc);
40314039Sstacze01@arm.com        }
40414039Sstacze01@arm.com
40514039Sstacze01@arm.com    case SMMU_CACHE_REPL_RANDOM:
40614039Sstacze01@arm.com        switch (alloc) {
40714039Sstacze01@arm.com        case ALLOC_ANY_WAY:
40814039Sstacze01@arm.com            return random.random<size_t>(0, associativity-1);
40914039Sstacze01@arm.com        case ALLOC_ANY_BUT_LAST_WAY:
41014039Sstacze01@arm.com            return random.random<size_t>(0, associativity-2);
41114039Sstacze01@arm.com        default:
41214039Sstacze01@arm.com            panic("Unknown allocation mode %d\n", alloc);
41314039Sstacze01@arm.com        }
41414039Sstacze01@arm.com
41514039Sstacze01@arm.com    case SMMU_CACHE_REPL_LRU:
41614039Sstacze01@arm.com        return lru_idx;
41714039Sstacze01@arm.com
41814039Sstacze01@arm.com    default:
41914039Sstacze01@arm.com        panic("Unknown replacement policy %d\n", replacementPolicy);
42014039Sstacze01@arm.com    }
42114039Sstacze01@arm.com}
42214039Sstacze01@arm.com
42314039Sstacze01@arm.com
42414039Sstacze01@arm.com
42514039Sstacze01@arm.com/*
42614039Sstacze01@arm.com * ARMArchTLB
42714039Sstacze01@arm.com */
42814039Sstacze01@arm.com
42914039Sstacze01@arm.comARMArchTLB::ARMArchTLB(unsigned numEntries, unsigned _associativity,
43014039Sstacze01@arm.com                       const std::string &policy)
43114039Sstacze01@arm.com:
43214039Sstacze01@arm.com    SMMUv3BaseCache(policy, ARMARCHTLB_SEED),
43314039Sstacze01@arm.com    associativity(_associativity)
43414039Sstacze01@arm.com{
43514039Sstacze01@arm.com    if (associativity == 0)
43614039Sstacze01@arm.com        associativity = numEntries; // fully associative
43714039Sstacze01@arm.com
43814039Sstacze01@arm.com    if (numEntries == 0)
43914039Sstacze01@arm.com        fatal("ARMArchTLB must have at least one entry\n");
44014039Sstacze01@arm.com
44114039Sstacze01@arm.com    if (associativity > numEntries)
44214039Sstacze01@arm.com        fatal("ARMArchTLB associativity cannot be higher than "
44314039Sstacze01@arm.com              "its number of entries\n");
44414039Sstacze01@arm.com
44514039Sstacze01@arm.com    unsigned num_sets = numEntries / associativity;
44614039Sstacze01@arm.com
44714039Sstacze01@arm.com    if (num_sets*associativity != numEntries)
44814039Sstacze01@arm.com        fatal("Number of ARMArchTLB entries must be divisible "
44914039Sstacze01@arm.com              "by its associativity\n");
45014039Sstacze01@arm.com
45114039Sstacze01@arm.com    Entry e;
45214039Sstacze01@arm.com    e.valid = false;
45314039Sstacze01@arm.com
45414039Sstacze01@arm.com    Set set(associativity, e);
45514039Sstacze01@arm.com    sets.resize(num_sets, set);
45614039Sstacze01@arm.com}
45714039Sstacze01@arm.com
45814039Sstacze01@arm.comconst ARMArchTLB::Entry *
45914039Sstacze01@arm.comARMArchTLB::lookup(Addr va, uint16_t asid, uint16_t vmid, bool updStats)
46014039Sstacze01@arm.com{
46114039Sstacze01@arm.com    const Entry *result = NULL;
46214039Sstacze01@arm.com
46314039Sstacze01@arm.com    Set &set = sets[pickSetIdx(va, asid, vmid)];
46414039Sstacze01@arm.com
46514039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
46614039Sstacze01@arm.com        const Entry &e = set[i];
46714039Sstacze01@arm.com
46814039Sstacze01@arm.com        if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
46914039Sstacze01@arm.com            e.asid==asid && e.vmid==vmid)
47014039Sstacze01@arm.com        {
47114039Sstacze01@arm.com            if (result != NULL)
47214039Sstacze01@arm.com                panic("ARMArchTLB: duplicate entry found!\n");
47314039Sstacze01@arm.com
47414039Sstacze01@arm.com            result = &e;
47514039Sstacze01@arm.com            break;
47614039Sstacze01@arm.com        }
47714039Sstacze01@arm.com    }
47814039Sstacze01@arm.com
47914039Sstacze01@arm.com    if (updStats) {
48014039Sstacze01@arm.com        if (result)
48114039Sstacze01@arm.com            result->lastUsed = useStamp++;
48214039Sstacze01@arm.com
48314039Sstacze01@arm.com        totalLookups++;
48414039Sstacze01@arm.com        if (result == NULL)
48514039Sstacze01@arm.com            totalMisses++;
48614039Sstacze01@arm.com    }
48714039Sstacze01@arm.com
48814039Sstacze01@arm.com    return result;
48914039Sstacze01@arm.com}
49014039Sstacze01@arm.com
49114039Sstacze01@arm.comvoid
49214039Sstacze01@arm.comARMArchTLB::store(const Entry &incoming)
49314039Sstacze01@arm.com{
49414039Sstacze01@arm.com    if (!incoming.valid)
49514039Sstacze01@arm.com        panic("Tried to store an invalid entry\n");
49614039Sstacze01@arm.com
49714039Sstacze01@arm.com    incoming.lastUsed = 0;
49814039Sstacze01@arm.com
49914039Sstacze01@arm.com    const Entry *existing =
50014039Sstacze01@arm.com        lookup(incoming.va, incoming.asid, incoming.vmid, false);
50114039Sstacze01@arm.com
50214039Sstacze01@arm.com    if (existing) {
50314039Sstacze01@arm.com        *const_cast<Entry *> (existing) = incoming;
50414039Sstacze01@arm.com    } else {
50514039Sstacze01@arm.com        Set &set = sets[pickSetIdx(incoming.va, incoming.asid, incoming.vmid)];
50614039Sstacze01@arm.com        set[pickEntryIdxToReplace(set)] = incoming;
50714039Sstacze01@arm.com    }
50814039Sstacze01@arm.com
50914039Sstacze01@arm.com    totalUpdates++;
51014039Sstacze01@arm.com}
51114039Sstacze01@arm.com
51214039Sstacze01@arm.comvoid
51314039Sstacze01@arm.comARMArchTLB::invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
51414039Sstacze01@arm.com{
51514039Sstacze01@arm.com    Set &set = sets[pickSetIdx(va, asid, vmid)];
51614039Sstacze01@arm.com
51714039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
51814039Sstacze01@arm.com        Entry &e = set[i];
51914039Sstacze01@arm.com
52014039Sstacze01@arm.com        if ((e.va & e.vaMask) == (va & e.vaMask) &&
52114039Sstacze01@arm.com            e.asid==asid && e.vmid==vmid)
52214039Sstacze01@arm.com        {
52314039Sstacze01@arm.com            e.valid = false;
52414039Sstacze01@arm.com        }
52514039Sstacze01@arm.com    }
52614039Sstacze01@arm.com}
52714039Sstacze01@arm.com
52814039Sstacze01@arm.comvoid
52914039Sstacze01@arm.comARMArchTLB::invalidateVAA(Addr va, uint16_t vmid)
53014039Sstacze01@arm.com{
53114039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
53214039Sstacze01@arm.com        Set &set = sets[s];
53314039Sstacze01@arm.com
53414039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
53514039Sstacze01@arm.com            Entry &e = set[i];
53614039Sstacze01@arm.com
53714039Sstacze01@arm.com            if ((e.va & e.vaMask) == (va & e.vaMask) && e.vmid==vmid)
53814039Sstacze01@arm.com                e.valid = false;
53914039Sstacze01@arm.com        }
54014039Sstacze01@arm.com    }
54114039Sstacze01@arm.com}
54214039Sstacze01@arm.com
54314039Sstacze01@arm.comvoid
54414039Sstacze01@arm.comARMArchTLB::invalidateASID(uint16_t asid, uint16_t vmid)
54514039Sstacze01@arm.com{
54614039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
54714039Sstacze01@arm.com        Set &set = sets[s];
54814039Sstacze01@arm.com
54914039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
55014039Sstacze01@arm.com            Entry &e = set[i];
55114039Sstacze01@arm.com
55214039Sstacze01@arm.com            if (e.asid==asid && e.vmid==vmid)
55314039Sstacze01@arm.com                e.valid = false;
55414039Sstacze01@arm.com        }
55514039Sstacze01@arm.com    }
55614039Sstacze01@arm.com}
55714039Sstacze01@arm.com
55814039Sstacze01@arm.comvoid
55914039Sstacze01@arm.comARMArchTLB::invalidateVMID(uint16_t vmid)
56014039Sstacze01@arm.com{
56114039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
56214039Sstacze01@arm.com        Set &set = sets[s];
56314039Sstacze01@arm.com
56414039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
56514039Sstacze01@arm.com            Entry &e = set[i];
56614039Sstacze01@arm.com
56714039Sstacze01@arm.com            if (e.vmid == vmid)
56814039Sstacze01@arm.com                e.valid = false;
56914039Sstacze01@arm.com        }
57014039Sstacze01@arm.com    }
57114039Sstacze01@arm.com}
57214039Sstacze01@arm.com
57314039Sstacze01@arm.comvoid
57414039Sstacze01@arm.comARMArchTLB::invalidateAll()
57514039Sstacze01@arm.com{
57614039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
57714039Sstacze01@arm.com        Set &set = sets[s];
57814039Sstacze01@arm.com
57914039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++)
58014039Sstacze01@arm.com            set[i].valid = false;
58114039Sstacze01@arm.com    }
58214039Sstacze01@arm.com}
58314039Sstacze01@arm.com
58414039Sstacze01@arm.comsize_t
58514039Sstacze01@arm.comARMArchTLB::pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const
58614039Sstacze01@arm.com{
58714039Sstacze01@arm.com    return ((va >> 12) ^ asid ^ vmid) % sets.size();
58814039Sstacze01@arm.com}
58914039Sstacze01@arm.com
59014039Sstacze01@arm.comsize_t
59114039Sstacze01@arm.comARMArchTLB::pickEntryIdxToReplace(const Set &set)
59214039Sstacze01@arm.com{
59314039Sstacze01@arm.com    size_t lru_idx = 0;
59414039Sstacze01@arm.com    uint32_t lru_tick = UINT32_MAX;
59514039Sstacze01@arm.com
59614039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
59714039Sstacze01@arm.com        if (!set[i].valid) {
59814039Sstacze01@arm.com            insertions++;
59914039Sstacze01@arm.com            return i;
60014039Sstacze01@arm.com        }
60114039Sstacze01@arm.com
60214039Sstacze01@arm.com        if (set[i].lastUsed < lru_tick) {
60314039Sstacze01@arm.com            lru_idx = i;
60414039Sstacze01@arm.com            lru_tick = set[i].lastUsed;
60514039Sstacze01@arm.com        }
60614039Sstacze01@arm.com    }
60714039Sstacze01@arm.com
60814039Sstacze01@arm.com    switch (replacementPolicy) {
60914039Sstacze01@arm.com    case SMMU_CACHE_REPL_ROUND_ROBIN:
61014039Sstacze01@arm.com        return nextToReplace = ((nextToReplace+1) % associativity);
61114039Sstacze01@arm.com
61214039Sstacze01@arm.com    case SMMU_CACHE_REPL_RANDOM:
61314039Sstacze01@arm.com        return random.random<size_t>(0, associativity-1);
61414039Sstacze01@arm.com
61514039Sstacze01@arm.com    case SMMU_CACHE_REPL_LRU:
61614039Sstacze01@arm.com        return lru_idx;
61714039Sstacze01@arm.com
61814039Sstacze01@arm.com    default:
61914039Sstacze01@arm.com        panic("Unknown replacement policy %d\n", replacementPolicy);
62014039Sstacze01@arm.com    }
62114039Sstacze01@arm.com
62214039Sstacze01@arm.com}
62314039Sstacze01@arm.com
62414039Sstacze01@arm.com/*
62514039Sstacze01@arm.com * IPACache
62614039Sstacze01@arm.com */
62714039Sstacze01@arm.com
62814039Sstacze01@arm.comIPACache::IPACache(unsigned numEntries, unsigned _associativity,
62914039Sstacze01@arm.com                   const std::string &policy)
63014039Sstacze01@arm.com:
63114039Sstacze01@arm.com    SMMUv3BaseCache(policy, IPACACHE_SEED),
63214039Sstacze01@arm.com    associativity(_associativity)
63314039Sstacze01@arm.com{
63414039Sstacze01@arm.com    if (associativity == 0)
63514039Sstacze01@arm.com        associativity = numEntries; // fully associative
63614039Sstacze01@arm.com
63714039Sstacze01@arm.com    if (numEntries == 0)
63814039Sstacze01@arm.com        fatal("IPACache must have at least one entry\n");
63914039Sstacze01@arm.com
64014039Sstacze01@arm.com    if (associativity > numEntries)
64114039Sstacze01@arm.com        fatal("IPACache associativity cannot be higher than "
64214039Sstacze01@arm.com              "its number of entries\n");
64314039Sstacze01@arm.com
64414039Sstacze01@arm.com    unsigned num_sets = numEntries / associativity;
64514039Sstacze01@arm.com
64614039Sstacze01@arm.com    if (num_sets*associativity != numEntries)
64714039Sstacze01@arm.com        fatal("Number of IPACache entries must be divisible "
64814039Sstacze01@arm.com              "by its associativity\n");
64914039Sstacze01@arm.com
65014039Sstacze01@arm.com    Entry e;
65114039Sstacze01@arm.com    e.valid = false;
65214039Sstacze01@arm.com
65314039Sstacze01@arm.com    Set set(associativity, e);
65414039Sstacze01@arm.com    sets.resize(num_sets, set);
65514039Sstacze01@arm.com}
65614039Sstacze01@arm.com
65714039Sstacze01@arm.comconst IPACache::Entry*
65814039Sstacze01@arm.comIPACache::lookup(Addr ipa, uint16_t vmid, bool updStats)
65914039Sstacze01@arm.com{
66014039Sstacze01@arm.com    const Entry *result = NULL;
66114039Sstacze01@arm.com
66214039Sstacze01@arm.com    Set &set = sets[pickSetIdx(ipa, vmid)];
66314039Sstacze01@arm.com
66414039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
66514039Sstacze01@arm.com        const Entry &e = set[i];
66614039Sstacze01@arm.com
66714039Sstacze01@arm.com        if (e.valid && (e.ipa & e.ipaMask) == (ipa & e.ipaMask) &&
66814039Sstacze01@arm.com            e.vmid==vmid)
66914039Sstacze01@arm.com        {
67014039Sstacze01@arm.com            if (result != NULL)
67114039Sstacze01@arm.com                panic("IPACache: duplicate entry found!\n");
67214039Sstacze01@arm.com
67314039Sstacze01@arm.com            result = &e;
67414039Sstacze01@arm.com            break;
67514039Sstacze01@arm.com        }
67614039Sstacze01@arm.com    }
67714039Sstacze01@arm.com
67814039Sstacze01@arm.com    if (updStats) {
67914039Sstacze01@arm.com        if (result)
68014039Sstacze01@arm.com            result->lastUsed = useStamp++;
68114039Sstacze01@arm.com
68214039Sstacze01@arm.com        totalLookups++;
68314039Sstacze01@arm.com        if (result == NULL)
68414039Sstacze01@arm.com            totalMisses++;
68514039Sstacze01@arm.com    }
68614039Sstacze01@arm.com
68714039Sstacze01@arm.com    return result;
68814039Sstacze01@arm.com}
68914039Sstacze01@arm.com
69014039Sstacze01@arm.comvoid
69114039Sstacze01@arm.comIPACache::store(const Entry &incoming)
69214039Sstacze01@arm.com{
69314039Sstacze01@arm.com    if (!incoming.valid)
69414039Sstacze01@arm.com        panic("Tried to store an invalid entry\n");
69514039Sstacze01@arm.com
69614039Sstacze01@arm.com    incoming.lastUsed = 0;
69714039Sstacze01@arm.com
69814039Sstacze01@arm.com    const Entry *existing = lookup(incoming.ipa, incoming.vmid, false);
69914039Sstacze01@arm.com
70014039Sstacze01@arm.com    if (existing) {
70114039Sstacze01@arm.com        *const_cast<Entry *> (existing) = incoming;
70214039Sstacze01@arm.com    } else {
70314039Sstacze01@arm.com        Set &set = sets[pickSetIdx(incoming.ipa, incoming.vmid)];
70414039Sstacze01@arm.com        set[pickEntryIdxToReplace(set)] = incoming;
70514039Sstacze01@arm.com    }
70614039Sstacze01@arm.com
70714039Sstacze01@arm.com    totalUpdates++;
70814039Sstacze01@arm.com}
70914039Sstacze01@arm.com
71014039Sstacze01@arm.comvoid
71114039Sstacze01@arm.comIPACache::invalidateIPA(Addr ipa, uint16_t vmid)
71214039Sstacze01@arm.com{
71314039Sstacze01@arm.com    Set &set = sets[pickSetIdx(ipa, vmid)];
71414039Sstacze01@arm.com
71514039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
71614039Sstacze01@arm.com        Entry &e = set[i];
71714039Sstacze01@arm.com
71814039Sstacze01@arm.com        if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask) && e.vmid==vmid)
71914039Sstacze01@arm.com            e.valid = false;
72014039Sstacze01@arm.com    }
72114039Sstacze01@arm.com}
72214039Sstacze01@arm.com
72314039Sstacze01@arm.comvoid
72414039Sstacze01@arm.comIPACache::invalidateIPAA(Addr ipa)
72514039Sstacze01@arm.com{
72614039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
72714039Sstacze01@arm.com        Set &set = sets[s];
72814039Sstacze01@arm.com
72914039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
73014039Sstacze01@arm.com            Entry &e = set[i];
73114039Sstacze01@arm.com
73214039Sstacze01@arm.com            if ((e.ipa & e.ipaMask) == (ipa & e.ipaMask))
73314039Sstacze01@arm.com                e.valid = false;
73414039Sstacze01@arm.com        }
73514039Sstacze01@arm.com    }
73614039Sstacze01@arm.com}
73714039Sstacze01@arm.com
73814039Sstacze01@arm.comvoid
73914039Sstacze01@arm.comIPACache::invalidateVMID(uint16_t vmid)
74014039Sstacze01@arm.com{
74114039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
74214039Sstacze01@arm.com        Set &set = sets[s];
74314039Sstacze01@arm.com
74414039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
74514039Sstacze01@arm.com            Entry &e = set[i];
74614039Sstacze01@arm.com
74714039Sstacze01@arm.com            if (e.vmid == vmid)
74814039Sstacze01@arm.com                e.valid = false;
74914039Sstacze01@arm.com        }
75014039Sstacze01@arm.com    }
75114039Sstacze01@arm.com}
75214039Sstacze01@arm.com
75314039Sstacze01@arm.comvoid
75414039Sstacze01@arm.comIPACache::invalidateAll()
75514039Sstacze01@arm.com{
75614039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
75714039Sstacze01@arm.com        Set &set = sets[s];
75814039Sstacze01@arm.com
75914039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++)
76014039Sstacze01@arm.com            set[i].valid = false;
76114039Sstacze01@arm.com    }
76214039Sstacze01@arm.com}
76314039Sstacze01@arm.com
76414039Sstacze01@arm.comsize_t
76514039Sstacze01@arm.comIPACache::pickSetIdx(Addr va, uint16_t vmid) const
76614039Sstacze01@arm.com{
76714039Sstacze01@arm.com    return ((va >> 12) ^ vmid) % sets.size();
76814039Sstacze01@arm.com}
76914039Sstacze01@arm.com
77014039Sstacze01@arm.comsize_t
77114039Sstacze01@arm.comIPACache::pickEntryIdxToReplace(const Set &set)
77214039Sstacze01@arm.com{
77314039Sstacze01@arm.com    size_t lru_idx = 0;
77414039Sstacze01@arm.com    uint32_t lru_tick = UINT32_MAX;
77514039Sstacze01@arm.com
77614039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
77714039Sstacze01@arm.com        if (!set[i].valid) {
77814039Sstacze01@arm.com            insertions++;
77914039Sstacze01@arm.com            return i;
78014039Sstacze01@arm.com        }
78114039Sstacze01@arm.com
78214039Sstacze01@arm.com        if (set[i].lastUsed < lru_tick) {
78314039Sstacze01@arm.com            lru_idx = i;
78414039Sstacze01@arm.com            lru_tick = set[i].lastUsed;
78514039Sstacze01@arm.com        }
78614039Sstacze01@arm.com    }
78714039Sstacze01@arm.com
78814039Sstacze01@arm.com    switch (replacementPolicy) {
78914039Sstacze01@arm.com    case SMMU_CACHE_REPL_ROUND_ROBIN:
79014039Sstacze01@arm.com        return nextToReplace = ((nextToReplace+1) % associativity);
79114039Sstacze01@arm.com
79214039Sstacze01@arm.com    case SMMU_CACHE_REPL_RANDOM:
79314039Sstacze01@arm.com        return random.random<size_t>(0, associativity-1);
79414039Sstacze01@arm.com
79514039Sstacze01@arm.com    case SMMU_CACHE_REPL_LRU:
79614039Sstacze01@arm.com        return lru_idx;
79714039Sstacze01@arm.com
79814039Sstacze01@arm.com    default:
79914039Sstacze01@arm.com        panic("Unknown replacement policy %d\n", replacementPolicy);
80014039Sstacze01@arm.com    }
80114039Sstacze01@arm.com
80214039Sstacze01@arm.com}
80314039Sstacze01@arm.com
80414039Sstacze01@arm.com/*
80514039Sstacze01@arm.com * ConfigCache
80614039Sstacze01@arm.com */
80714039Sstacze01@arm.com
80814039Sstacze01@arm.comConfigCache::ConfigCache(unsigned numEntries, unsigned _associativity,
80914039Sstacze01@arm.com                         const std::string &policy)
81014039Sstacze01@arm.com:
81114039Sstacze01@arm.com    SMMUv3BaseCache(policy, CONFIGCACHE_SEED),
81214039Sstacze01@arm.com    associativity(_associativity)
81314039Sstacze01@arm.com{
81414039Sstacze01@arm.com    if (associativity == 0)
81514039Sstacze01@arm.com        associativity = numEntries; // fully associative
81614039Sstacze01@arm.com
81714039Sstacze01@arm.com    if (numEntries == 0)
81814039Sstacze01@arm.com        fatal("ConfigCache must have at least one entry\n");
81914039Sstacze01@arm.com
82014039Sstacze01@arm.com    if (associativity > numEntries)
82114039Sstacze01@arm.com        fatal("ConfigCache associativity cannot be higher than "
82214039Sstacze01@arm.com              "its number of entries\n");
82314039Sstacze01@arm.com
82414039Sstacze01@arm.com    unsigned num_sets = numEntries / associativity;
82514039Sstacze01@arm.com
82614039Sstacze01@arm.com    if (num_sets*associativity != numEntries)
82714039Sstacze01@arm.com        fatal("Number of ConfigCache entries must be divisible "
82814039Sstacze01@arm.com              "by its associativity\n");
82914039Sstacze01@arm.com
83014039Sstacze01@arm.com    Entry e;
83114039Sstacze01@arm.com    e.valid = false;
83214039Sstacze01@arm.com
83314039Sstacze01@arm.com    Set set(associativity, e);
83414039Sstacze01@arm.com    sets.resize(num_sets, set);
83514039Sstacze01@arm.com}
83614039Sstacze01@arm.com
83714039Sstacze01@arm.comconst ConfigCache::Entry *
83814039Sstacze01@arm.comConfigCache::lookup(uint32_t sid, uint32_t ssid, bool updStats)
83914039Sstacze01@arm.com{
84014039Sstacze01@arm.com    const Entry *result = NULL;
84114039Sstacze01@arm.com
84214039Sstacze01@arm.com    Set &set = sets[pickSetIdx(sid, ssid)];
84314039Sstacze01@arm.com
84414039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
84514039Sstacze01@arm.com        const Entry &e = set[i];
84614039Sstacze01@arm.com
84714039Sstacze01@arm.com        if (e.valid && e.sid==sid && e.ssid==ssid)
84814039Sstacze01@arm.com        {
84914039Sstacze01@arm.com            if (result != NULL)
85014039Sstacze01@arm.com                panic("ConfigCache: duplicate entry found!\n");
85114039Sstacze01@arm.com
85214039Sstacze01@arm.com            result = &e;
85314039Sstacze01@arm.com            break;
85414039Sstacze01@arm.com        }
85514039Sstacze01@arm.com    }
85614039Sstacze01@arm.com
85714039Sstacze01@arm.com    if (updStats) {
85814039Sstacze01@arm.com        if (result)
85914039Sstacze01@arm.com            result->lastUsed = useStamp++;
86014039Sstacze01@arm.com
86114039Sstacze01@arm.com        totalLookups++;
86214039Sstacze01@arm.com        if (result == NULL)
86314039Sstacze01@arm.com            totalMisses++;
86414039Sstacze01@arm.com    }
86514039Sstacze01@arm.com
86614039Sstacze01@arm.com    return result;
86714039Sstacze01@arm.com}
86814039Sstacze01@arm.com
86914039Sstacze01@arm.comvoid
87014039Sstacze01@arm.comConfigCache::store(const Entry &incoming)
87114039Sstacze01@arm.com{
87214039Sstacze01@arm.com    if (!incoming.valid)
87314039Sstacze01@arm.com        panic("Tried to store an invalid entry\n");
87414039Sstacze01@arm.com
87514039Sstacze01@arm.com    incoming.lastUsed = 0;
87614039Sstacze01@arm.com
87714039Sstacze01@arm.com    const Entry *existing = lookup(incoming.sid, incoming.ssid, false);
87814039Sstacze01@arm.com
87914039Sstacze01@arm.com    if (existing) {
88014039Sstacze01@arm.com        *const_cast<Entry *> (existing) = incoming;
88114039Sstacze01@arm.com    } else {
88214039Sstacze01@arm.com        Set &set = sets[pickSetIdx(incoming.sid, incoming.ssid)];
88314039Sstacze01@arm.com        set[pickEntryIdxToReplace(set)] = incoming;
88414039Sstacze01@arm.com    }
88514039Sstacze01@arm.com
88614039Sstacze01@arm.com    totalUpdates++;
88714039Sstacze01@arm.com}
88814039Sstacze01@arm.com
88914039Sstacze01@arm.comvoid
89014039Sstacze01@arm.comConfigCache::invalidateSSID(uint32_t sid, uint32_t ssid)
89114039Sstacze01@arm.com{
89214039Sstacze01@arm.com    Set &set = sets[pickSetIdx(sid, ssid)];
89314039Sstacze01@arm.com
89414039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
89514039Sstacze01@arm.com        Entry &e = set[i];
89614039Sstacze01@arm.com
89714039Sstacze01@arm.com        if (e.sid==sid && e.ssid==ssid)
89814039Sstacze01@arm.com            e.valid = false;
89914039Sstacze01@arm.com    }
90014039Sstacze01@arm.com}
90114039Sstacze01@arm.com
90214039Sstacze01@arm.comvoid
90314039Sstacze01@arm.comConfigCache::invalidateSID(uint32_t sid)
90414039Sstacze01@arm.com{
90514039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
90614039Sstacze01@arm.com        Set &set = sets[s];
90714039Sstacze01@arm.com
90814039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
90914039Sstacze01@arm.com            Entry &e = set[i];
91014039Sstacze01@arm.com
91114039Sstacze01@arm.com            if (e.sid == sid)
91214039Sstacze01@arm.com                e.valid = false;
91314039Sstacze01@arm.com        }
91414039Sstacze01@arm.com    }
91514039Sstacze01@arm.com}
91614039Sstacze01@arm.com
91714039Sstacze01@arm.comvoid
91814039Sstacze01@arm.comConfigCache::invalidateAll()
91914039Sstacze01@arm.com{
92014039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
92114039Sstacze01@arm.com        Set &set = sets[s];
92214039Sstacze01@arm.com
92314039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++)
92414039Sstacze01@arm.com            set[i].valid = false;
92514039Sstacze01@arm.com    }
92614039Sstacze01@arm.com}
92714039Sstacze01@arm.com
92814039Sstacze01@arm.comsize_t
92914039Sstacze01@arm.comConfigCache::pickSetIdx(uint32_t sid, uint32_t ssid) const
93014039Sstacze01@arm.com{
93114039Sstacze01@arm.com    return (sid^ssid) % sets.size();
93214039Sstacze01@arm.com}
93314039Sstacze01@arm.com
93414039Sstacze01@arm.comsize_t
93514039Sstacze01@arm.comConfigCache::pickEntryIdxToReplace(const Set &set)
93614039Sstacze01@arm.com{
93714039Sstacze01@arm.com    size_t lru_idx = 0;
93814039Sstacze01@arm.com    uint32_t lru_tick = UINT32_MAX;
93914039Sstacze01@arm.com
94014039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
94114039Sstacze01@arm.com        if (!set[i].valid) {
94214039Sstacze01@arm.com            insertions++;
94314039Sstacze01@arm.com            return i;
94414039Sstacze01@arm.com        }
94514039Sstacze01@arm.com
94614039Sstacze01@arm.com        if (set[i].lastUsed < lru_tick) {
94714039Sstacze01@arm.com            lru_idx = i;
94814039Sstacze01@arm.com            lru_tick = set[i].lastUsed;
94914039Sstacze01@arm.com        }
95014039Sstacze01@arm.com    }
95114039Sstacze01@arm.com
95214039Sstacze01@arm.com    switch (replacementPolicy) {
95314039Sstacze01@arm.com    case SMMU_CACHE_REPL_ROUND_ROBIN:
95414039Sstacze01@arm.com        return nextToReplace = ((nextToReplace+1) % associativity);
95514039Sstacze01@arm.com
95614039Sstacze01@arm.com    case SMMU_CACHE_REPL_RANDOM:
95714039Sstacze01@arm.com        return random.random<size_t>(0, associativity-1);
95814039Sstacze01@arm.com
95914039Sstacze01@arm.com    case SMMU_CACHE_REPL_LRU:
96014039Sstacze01@arm.com        return lru_idx;
96114039Sstacze01@arm.com
96214039Sstacze01@arm.com    default:
96314039Sstacze01@arm.com        panic("Unknown replacement policy %d\n", replacementPolicy);
96414039Sstacze01@arm.com    }
96514039Sstacze01@arm.com
96614039Sstacze01@arm.com}
96714039Sstacze01@arm.com
96814039Sstacze01@arm.com/*
96914039Sstacze01@arm.com * WalkCache
97014039Sstacze01@arm.com */
97114039Sstacze01@arm.com
97214039Sstacze01@arm.comWalkCache::WalkCache(const std::array<unsigned, 2*WALK_CACHE_LEVELS> &_sizes,
97314039Sstacze01@arm.com                     unsigned _associativity, const std::string &policy) :
97414039Sstacze01@arm.com    SMMUv3BaseCache(policy, WALKCACHE_SEED),
97514039Sstacze01@arm.com    associativity(_associativity),
97614039Sstacze01@arm.com    sizes()
97714039Sstacze01@arm.com{
97814039Sstacze01@arm.com    unsigned numEntries = std::accumulate(&_sizes[0],
97914039Sstacze01@arm.com                                          &_sizes[2*WALK_CACHE_LEVELS], 0);
98014039Sstacze01@arm.com
98114039Sstacze01@arm.com    if (associativity == 0)
98214039Sstacze01@arm.com        associativity = numEntries; // fully associative
98314039Sstacze01@arm.com
98414039Sstacze01@arm.com    if (numEntries == 0)
98514039Sstacze01@arm.com        fatal("WalkCache must have at least one entry\n");
98614039Sstacze01@arm.com
98714039Sstacze01@arm.com    for (size_t i = 0; i < 2*WALK_CACHE_LEVELS; i++){
98814039Sstacze01@arm.com        if (_sizes[i] % associativity != 0)
98914039Sstacze01@arm.com              fatal("Number of WalkCache entries at each level must be "
99014039Sstacze01@arm.com                    "divisible by WalkCache associativity\n");
99114039Sstacze01@arm.com
99214039Sstacze01@arm.com        sizes[i] = _sizes[i] /  associativity;
99314039Sstacze01@arm.com        offsets[i] = i==0 ? 0 : offsets[i-1] + sizes[i-1];
99414039Sstacze01@arm.com    }
99514039Sstacze01@arm.com
99614039Sstacze01@arm.com    if (associativity > numEntries)
99714039Sstacze01@arm.com        fatal("WalkCache associativity cannot be higher than "
99814039Sstacze01@arm.com              "its number of entries\n");
99914039Sstacze01@arm.com
100014039Sstacze01@arm.com    unsigned num_sets = numEntries / associativity;
100114039Sstacze01@arm.com
100214039Sstacze01@arm.com    if (num_sets*associativity != numEntries)
100314039Sstacze01@arm.com        fatal("Number of WalkCache entries must be divisible "
100414039Sstacze01@arm.com              "by its associativity\n");
100514039Sstacze01@arm.com
100614039Sstacze01@arm.com    Entry e;
100714039Sstacze01@arm.com    e.valid = false;
100814039Sstacze01@arm.com
100914039Sstacze01@arm.com    Set set(associativity, e);
101014039Sstacze01@arm.com    sets.resize(num_sets, set);
101114039Sstacze01@arm.com}
101214039Sstacze01@arm.com
101314039Sstacze01@arm.comconst WalkCache::Entry*
101414039Sstacze01@arm.comWalkCache::lookup(Addr va, Addr vaMask,
101514039Sstacze01@arm.com                  uint16_t asid, uint16_t vmid,
101614039Sstacze01@arm.com                  unsigned stage, unsigned level,
101714039Sstacze01@arm.com                  bool updStats)
101814039Sstacze01@arm.com{
101914039Sstacze01@arm.com    const Entry *result = NULL;
102014039Sstacze01@arm.com
102114039Sstacze01@arm.com    Set &set = sets[pickSetIdx(va, vaMask, stage, level)];
102214039Sstacze01@arm.com
102314039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
102414039Sstacze01@arm.com        const Entry &e = set[i];
102514039Sstacze01@arm.com
102614039Sstacze01@arm.com        if (e.valid && (e.va & e.vaMask) == (va & e.vaMask) &&
102714039Sstacze01@arm.com            e.asid==asid && e.vmid==vmid && e.stage==stage && e.level==level)
102814039Sstacze01@arm.com        {
102914039Sstacze01@arm.com            if (result != NULL)
103014039Sstacze01@arm.com                panic("WalkCache: duplicate entry found!\n");
103114039Sstacze01@arm.com
103214039Sstacze01@arm.com            result = &e;
103314039Sstacze01@arm.com            break;
103414039Sstacze01@arm.com        }
103514039Sstacze01@arm.com    }
103614039Sstacze01@arm.com
103714039Sstacze01@arm.com    if (updStats) {
103814039Sstacze01@arm.com        if (result)
103914039Sstacze01@arm.com            result->lastUsed = useStamp++;
104014039Sstacze01@arm.com
104114039Sstacze01@arm.com        totalLookups++;
104214039Sstacze01@arm.com        if (result == NULL)
104314039Sstacze01@arm.com            totalMisses++;
104414039Sstacze01@arm.com
104514039Sstacze01@arm.com        lookupsByStageLevel[stage-1][level]++;
104614039Sstacze01@arm.com        totalLookupsByStageLevel[stage-1][level]++;
104714039Sstacze01@arm.com        if (result == NULL) {
104814039Sstacze01@arm.com            missesByStageLevel[stage-1][level]++;
104914039Sstacze01@arm.com            totalMissesByStageLevel[stage-1][level]++;
105014039Sstacze01@arm.com        }
105114039Sstacze01@arm.com    }
105214039Sstacze01@arm.com
105314039Sstacze01@arm.com    return result;
105414039Sstacze01@arm.com}
105514039Sstacze01@arm.com
105614039Sstacze01@arm.comvoid
105714039Sstacze01@arm.comWalkCache::store(const Entry &incoming)
105814039Sstacze01@arm.com{
105914039Sstacze01@arm.com    if (!incoming.valid)
106014039Sstacze01@arm.com        panic("Tried to store an invalid entry\n");
106114039Sstacze01@arm.com
106214039Sstacze01@arm.com    assert(incoming.stage==1 || incoming.stage==2);
106314039Sstacze01@arm.com    assert(incoming.level<=WALK_CACHE_LEVELS);
106414039Sstacze01@arm.com
106514039Sstacze01@arm.com    incoming.lastUsed = 0;
106614039Sstacze01@arm.com
106714039Sstacze01@arm.com    const Entry *existing = lookup(incoming.va, incoming.vaMask,
106814039Sstacze01@arm.com                                   incoming.asid, incoming.vmid,
106914039Sstacze01@arm.com                                   incoming.stage, incoming.level, false);
107014039Sstacze01@arm.com
107114039Sstacze01@arm.com    if (existing) {
107214039Sstacze01@arm.com        *const_cast<Entry *> (existing) = incoming;
107314039Sstacze01@arm.com    } else {
107414039Sstacze01@arm.com        Set &set = sets[pickSetIdx(incoming.va, incoming.vaMask,
107514039Sstacze01@arm.com                                   incoming.stage, incoming.level)];
107614039Sstacze01@arm.com        set[pickEntryIdxToReplace(set, incoming.stage, incoming.level)] =
107714039Sstacze01@arm.com            incoming;
107814039Sstacze01@arm.com    }
107914039Sstacze01@arm.com
108014039Sstacze01@arm.com    totalUpdates++;
108114039Sstacze01@arm.com    updatesByStageLevel[incoming.stage-1][incoming.level]++;
108214039Sstacze01@arm.com    totalUpdatesByStageLevel[incoming.stage-1][incoming.level]++;
108314039Sstacze01@arm.com}
108414039Sstacze01@arm.com
108514039Sstacze01@arm.comvoid
108614221Sadrian.herrera@arm.comWalkCache::invalidateVA(Addr va, uint16_t asid, uint16_t vmid,
108714221Sadrian.herrera@arm.com                        const bool leaf_only)
108814039Sstacze01@arm.com{
108914221Sadrian.herrera@arm.com    for (size_t s = 0; s < sets.size(); s++) {
109014221Sadrian.herrera@arm.com        Set &set = sets[s];
109114221Sadrian.herrera@arm.com
109214221Sadrian.herrera@arm.com        for (size_t i = 0; i < set.size(); i++) {
109314221Sadrian.herrera@arm.com            Entry &e = set[i];
109414221Sadrian.herrera@arm.com
109514221Sadrian.herrera@arm.com            if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask)
109614221Sadrian.herrera@arm.com                && e.asid == asid && e.vmid == vmid)
109714221Sadrian.herrera@arm.com            {
109814221Sadrian.herrera@arm.com                e.valid = false;
109914221Sadrian.herrera@arm.com            }
110014221Sadrian.herrera@arm.com        }
110114221Sadrian.herrera@arm.com    }
110214039Sstacze01@arm.com}
110314039Sstacze01@arm.com
110414039Sstacze01@arm.comvoid
110514221Sadrian.herrera@arm.comWalkCache::invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only)
110614039Sstacze01@arm.com{
110714221Sadrian.herrera@arm.com    for (size_t s = 0; s < sets.size(); s++) {
110814221Sadrian.herrera@arm.com        Set &set = sets[s];
110914221Sadrian.herrera@arm.com
111014221Sadrian.herrera@arm.com        for (size_t i = 0; i < set.size(); i++) {
111114221Sadrian.herrera@arm.com            Entry &e = set[i];
111214221Sadrian.herrera@arm.com
111314221Sadrian.herrera@arm.com            if ((!leaf_only || e.leaf) && (e.va & e.vaMask) == (va & e.vaMask)
111414221Sadrian.herrera@arm.com                && e.vmid == vmid)
111514221Sadrian.herrera@arm.com            {
111614221Sadrian.herrera@arm.com                e.valid = false;
111714221Sadrian.herrera@arm.com            }
111814221Sadrian.herrera@arm.com        }
111914221Sadrian.herrera@arm.com    }
112014039Sstacze01@arm.com}
112114039Sstacze01@arm.com
112214039Sstacze01@arm.comvoid
112314039Sstacze01@arm.comWalkCache::invalidateASID(uint16_t asid, uint16_t vmid)
112414039Sstacze01@arm.com{
112514222Sjan-peter.larsson@arm.com    for (size_t s = 0; s < sets.size(); s++) {
112614222Sjan-peter.larsson@arm.com        Set &set = sets[s];
112714222Sjan-peter.larsson@arm.com
112814222Sjan-peter.larsson@arm.com        for (size_t i = 0; i < set.size(); i++) {
112914222Sjan-peter.larsson@arm.com            Entry &e = set[i];
113014222Sjan-peter.larsson@arm.com
113114222Sjan-peter.larsson@arm.com            if (e.asid==asid && e.vmid==vmid)
113214222Sjan-peter.larsson@arm.com                e.valid = false;
113314222Sjan-peter.larsson@arm.com        }
113414222Sjan-peter.larsson@arm.com    }
113514039Sstacze01@arm.com}
113614039Sstacze01@arm.com
113714039Sstacze01@arm.comvoid
113814039Sstacze01@arm.comWalkCache::invalidateVMID(uint16_t vmid)
113914039Sstacze01@arm.com{
114014039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
114114039Sstacze01@arm.com        Set &set = sets[s];
114214039Sstacze01@arm.com
114314039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++) {
114414039Sstacze01@arm.com            Entry &e = set[i];
114514039Sstacze01@arm.com
114614039Sstacze01@arm.com            if (e.vmid == vmid)
114714039Sstacze01@arm.com                e.valid = false;
114814039Sstacze01@arm.com        }
114914039Sstacze01@arm.com    }
115014039Sstacze01@arm.com}
115114039Sstacze01@arm.com
115214039Sstacze01@arm.comvoid
115314039Sstacze01@arm.comWalkCache::invalidateAll()
115414039Sstacze01@arm.com{
115514039Sstacze01@arm.com    for (size_t s = 0; s < sets.size(); s++) {
115614039Sstacze01@arm.com        Set &set = sets[s];
115714039Sstacze01@arm.com
115814039Sstacze01@arm.com        for (size_t i = 0; i < set.size(); i++)
115914039Sstacze01@arm.com            set[i].valid = false;
116014039Sstacze01@arm.com    }
116114039Sstacze01@arm.com}
116214039Sstacze01@arm.com
116314039Sstacze01@arm.comsize_t
116414039Sstacze01@arm.comWalkCache::pickSetIdx(Addr va, Addr vaMask,
116514039Sstacze01@arm.com                      unsigned stage, unsigned level) const
116614039Sstacze01@arm.com{
116714039Sstacze01@arm.com    (void) stage;
116814039Sstacze01@arm.com
116914039Sstacze01@arm.com    int size, offset;
117014039Sstacze01@arm.com
117114039Sstacze01@arm.com    switch (stage) {
117214039Sstacze01@arm.com        case 1:
117314039Sstacze01@arm.com            assert (level<=3);
117414039Sstacze01@arm.com            size = sizes[0*WALK_CACHE_LEVELS + level];
117514039Sstacze01@arm.com            offset = offsets[0*WALK_CACHE_LEVELS + level];
117614039Sstacze01@arm.com            break;
117714039Sstacze01@arm.com
117814039Sstacze01@arm.com        case 2:
117914039Sstacze01@arm.com            assert (level<=3);
118014039Sstacze01@arm.com            size = sizes[1*WALK_CACHE_LEVELS + level];
118114039Sstacze01@arm.com            offset = offsets[1*WALK_CACHE_LEVELS + level];
118214039Sstacze01@arm.com            break;
118314039Sstacze01@arm.com
118414039Sstacze01@arm.com        default:
118514039Sstacze01@arm.com            panic("bad stage");
118614039Sstacze01@arm.com    }
118714039Sstacze01@arm.com
118814039Sstacze01@arm.com    return ((va >> findLsbSet(vaMask)) % size) + offset;
118914039Sstacze01@arm.com}
119014039Sstacze01@arm.com
119114039Sstacze01@arm.comsize_t
119214039Sstacze01@arm.comWalkCache::pickEntryIdxToReplace(const Set &set,
119314039Sstacze01@arm.com                                 unsigned stage, unsigned level)
119414039Sstacze01@arm.com{
119514039Sstacze01@arm.com    size_t lru_idx = 0;
119614039Sstacze01@arm.com    uint32_t lru_tick = UINT32_MAX;
119714039Sstacze01@arm.com
119814039Sstacze01@arm.com    for (size_t i = 0; i < set.size(); i++) {
119914039Sstacze01@arm.com        if (!set[i].valid) {
120014039Sstacze01@arm.com            insertions++;
120114039Sstacze01@arm.com            insertionsByStageLevel[stage-1][level]++;
120214039Sstacze01@arm.com            return i;
120314039Sstacze01@arm.com        }
120414039Sstacze01@arm.com
120514039Sstacze01@arm.com        if (set[i].lastUsed < lru_tick) {
120614039Sstacze01@arm.com            lru_idx = i;
120714039Sstacze01@arm.com            lru_tick = set[i].lastUsed;
120814039Sstacze01@arm.com        }
120914039Sstacze01@arm.com    }
121014039Sstacze01@arm.com
121114039Sstacze01@arm.com    switch (replacementPolicy) {
121214039Sstacze01@arm.com    case SMMU_CACHE_REPL_ROUND_ROBIN:
121314039Sstacze01@arm.com        return nextToReplace = ((nextToReplace+1) % associativity);
121414039Sstacze01@arm.com
121514039Sstacze01@arm.com    case SMMU_CACHE_REPL_RANDOM:
121614039Sstacze01@arm.com        return random.random<size_t>(0, associativity-1);
121714039Sstacze01@arm.com
121814039Sstacze01@arm.com    case SMMU_CACHE_REPL_LRU:
121914039Sstacze01@arm.com        return lru_idx;
122014039Sstacze01@arm.com
122114039Sstacze01@arm.com    default:
122214039Sstacze01@arm.com        panic("Unknown replacement policy %d\n", replacementPolicy);
122314039Sstacze01@arm.com    }
122414039Sstacze01@arm.com
122514039Sstacze01@arm.com}
122614039Sstacze01@arm.com
122714039Sstacze01@arm.comvoid
122814039Sstacze01@arm.comWalkCache::regStats(const std::string &name)
122914039Sstacze01@arm.com{
123014039Sstacze01@arm.com    using namespace Stats;
123114039Sstacze01@arm.com
123214039Sstacze01@arm.com    SMMUv3BaseCache::regStats(name);
123314039Sstacze01@arm.com
123414039Sstacze01@arm.com    for (int s = 0; s < 2; s++) {
123514039Sstacze01@arm.com        for (int l = 0; l < WALK_CACHE_LEVELS; l++) {
123614039Sstacze01@arm.com            averageLookupsByStageLevel[s][l]
123714039Sstacze01@arm.com                .name(csprintf("%s.averageLookupsS%dL%d", name, s+1, l))
123814039Sstacze01@arm.com                .desc("Average number lookups per second")
123914039Sstacze01@arm.com                .flags(pdf);
124014039Sstacze01@arm.com
124114039Sstacze01@arm.com            totalLookupsByStageLevel[s][l]
124214039Sstacze01@arm.com                .name(csprintf("%s.totalLookupsS%dL%d", name, s+1, l))
124314039Sstacze01@arm.com                .desc("Total number of lookups")
124414039Sstacze01@arm.com                .flags(pdf);
124514039Sstacze01@arm.com
124614039Sstacze01@arm.com            averageLookupsByStageLevel[s][l] =
124714039Sstacze01@arm.com                totalLookupsByStageLevel[s][l] / simSeconds;
124814039Sstacze01@arm.com
124914039Sstacze01@arm.com
125014039Sstacze01@arm.com            averageMissesByStageLevel[s][l]
125114039Sstacze01@arm.com                .name(csprintf("%s.averageMissesS%dL%d", name, s+1, l))
125214039Sstacze01@arm.com                .desc("Average number misses per second")
125314039Sstacze01@arm.com                .flags(pdf);
125414039Sstacze01@arm.com
125514039Sstacze01@arm.com            totalMissesByStageLevel[s][l]
125614039Sstacze01@arm.com                .name(csprintf("%s.totalMissesS%dL%d", name, s+1, l))
125714039Sstacze01@arm.com                .desc("Total number of misses")
125814039Sstacze01@arm.com                .flags(pdf);
125914039Sstacze01@arm.com
126014039Sstacze01@arm.com            averageMissesByStageLevel[s][l] =
126114039Sstacze01@arm.com                totalMissesByStageLevel[s][l] / simSeconds;
126214039Sstacze01@arm.com
126314039Sstacze01@arm.com
126414039Sstacze01@arm.com            averageUpdatesByStageLevel[s][l]
126514039Sstacze01@arm.com                .name(csprintf("%s.averageUpdatesS%dL%d", name, s+1, l))
126614039Sstacze01@arm.com                .desc("Average number updates per second")
126714039Sstacze01@arm.com                .flags(pdf);
126814039Sstacze01@arm.com
126914039Sstacze01@arm.com            totalUpdatesByStageLevel[s][l]
127014039Sstacze01@arm.com                .name(csprintf("%s.totalUpdatesS%dL%d", name, s+1, l))
127114039Sstacze01@arm.com                .desc("Total number of updates")
127214039Sstacze01@arm.com                .flags(pdf);
127314039Sstacze01@arm.com
127414039Sstacze01@arm.com            averageUpdatesByStageLevel[s][l] =
127514039Sstacze01@arm.com                totalUpdatesByStageLevel[s][l] / simSeconds;
127614039Sstacze01@arm.com
127714039Sstacze01@arm.com
127814039Sstacze01@arm.com            averageHitRateByStageLevel[s][l]
127914039Sstacze01@arm.com                .name(csprintf("%s.averageHitRateS%dL%d", name, s+1, l))
128014039Sstacze01@arm.com                .desc("Average hit rate")
128114039Sstacze01@arm.com                .flags(pdf);
128214039Sstacze01@arm.com
128314039Sstacze01@arm.com            averageHitRateByStageLevel[s][l] =
128414039Sstacze01@arm.com                (totalLookupsByStageLevel[s][l] -
128514039Sstacze01@arm.com                 totalMissesByStageLevel[s][l])
128614039Sstacze01@arm.com                / totalLookupsByStageLevel[s][l];
128714039Sstacze01@arm.com
128814039Sstacze01@arm.com            insertionsByStageLevel[s][l]
128914039Sstacze01@arm.com                .name(csprintf("%s.insertionsS%dL%d", name, s+1, l))
129014039Sstacze01@arm.com                .desc("Number of insertions (not replacements)")
129114039Sstacze01@arm.com                .flags(pdf);
129214039Sstacze01@arm.com        }
129314039Sstacze01@arm.com    }
129414039Sstacze01@arm.com}
1295