111308Santhony.gutierrez@amd.com/*
211308Santhony.gutierrez@amd.com * Copyright (c) 2011-2015 Advanced Micro Devices, Inc.
311308Santhony.gutierrez@amd.com * All rights reserved.
411308Santhony.gutierrez@amd.com *
511308Santhony.gutierrez@amd.com * For use for simulation and test purposes only
611308Santhony.gutierrez@amd.com *
711308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
811308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are met:
911308Santhony.gutierrez@amd.com *
1011308Santhony.gutierrez@amd.com * 1. Redistributions of source code must retain the above copyright notice,
1111308Santhony.gutierrez@amd.com * this list of conditions and the following disclaimer.
1211308Santhony.gutierrez@amd.com *
1311308Santhony.gutierrez@amd.com * 2. Redistributions in binary form must reproduce the above copyright notice,
1411308Santhony.gutierrez@amd.com * this list of conditions and the following disclaimer in the documentation
1511308Santhony.gutierrez@amd.com * and/or other materials provided with the distribution.
1611308Santhony.gutierrez@amd.com *
1711308Santhony.gutierrez@amd.com * 3. Neither the name of the copyright holder nor the names of its contributors
1811308Santhony.gutierrez@amd.com * may be used to endorse or promote products derived from this software
1911308Santhony.gutierrez@amd.com * without specific prior written permission.
2011308Santhony.gutierrez@amd.com *
2111308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2211308Santhony.gutierrez@amd.com * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2311308Santhony.gutierrez@amd.com * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2411308Santhony.gutierrez@amd.com * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2511308Santhony.gutierrez@amd.com * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2611308Santhony.gutierrez@amd.com * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2711308Santhony.gutierrez@amd.com * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2811308Santhony.gutierrez@amd.com * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2911308Santhony.gutierrez@amd.com * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3011308Santhony.gutierrez@amd.com * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3111308Santhony.gutierrez@amd.com * POSSIBILITY OF SUCH DAMAGE.
3211308Santhony.gutierrez@amd.com *
3311308Santhony.gutierrez@amd.com * Author: Lisa Hsu
3411308Santhony.gutierrez@amd.com */
3511308Santhony.gutierrez@amd.com
3611308Santhony.gutierrez@amd.com#include "gpu-compute/gpu_tlb.hh"
3711308Santhony.gutierrez@amd.com
3811308Santhony.gutierrez@amd.com#include <cmath>
3911308Santhony.gutierrez@amd.com#include <cstring>
4011308Santhony.gutierrez@amd.com
4111308Santhony.gutierrez@amd.com#include "arch/x86/faults.hh"
4211308Santhony.gutierrez@amd.com#include "arch/x86/insts/microldstop.hh"
4311308Santhony.gutierrez@amd.com#include "arch/x86/pagetable.hh"
4411308Santhony.gutierrez@amd.com#include "arch/x86/pagetable_walker.hh"
4511308Santhony.gutierrez@amd.com#include "arch/x86/regs/misc.hh"
4611308Santhony.gutierrez@amd.com#include "arch/x86/x86_traits.hh"
4711308Santhony.gutierrez@amd.com#include "base/bitfield.hh"
4813449Sgabeblack@google.com#include "base/logging.hh"
4911308Santhony.gutierrez@amd.com#include "base/output.hh"
5011308Santhony.gutierrez@amd.com#include "base/trace.hh"
5111308Santhony.gutierrez@amd.com#include "cpu/base.hh"
5211308Santhony.gutierrez@amd.com#include "cpu/thread_context.hh"
5311308Santhony.gutierrez@amd.com#include "debug/GPUPrefetch.hh"
5411308Santhony.gutierrez@amd.com#include "debug/GPUTLB.hh"
5511308Santhony.gutierrez@amd.com#include "mem/packet_access.hh"
5611308Santhony.gutierrez@amd.com#include "mem/page_table.hh"
5711308Santhony.gutierrez@amd.com#include "mem/request.hh"
5811308Santhony.gutierrez@amd.com#include "sim/process.hh"
5911308Santhony.gutierrez@amd.com
6011308Santhony.gutierrez@amd.comnamespace X86ISA
6111308Santhony.gutierrez@amd.com{
6211308Santhony.gutierrez@amd.com
6311308Santhony.gutierrez@amd.com    GpuTLB::GpuTLB(const Params *p)
6413892Sgabeblack@google.com        : ClockedObject(p), configAddress(0), size(p->size),
6512085Sspwilson2@wisc.edu          cleanupEvent([this]{ cleanup(); }, name(), false,
6612085Sspwilson2@wisc.edu                       Event::Maximum_Pri),
6712085Sspwilson2@wisc.edu          exitEvent([this]{ exitCallback(); }, name())
6811308Santhony.gutierrez@amd.com    {
6911308Santhony.gutierrez@amd.com        assoc = p->assoc;
7011308Santhony.gutierrez@amd.com        assert(assoc <= size);
7111308Santhony.gutierrez@amd.com        numSets = size/assoc;
7211308Santhony.gutierrez@amd.com        allocationPolicy = p->allocationPolicy;
7311308Santhony.gutierrez@amd.com        hasMemSidePort = false;
7411308Santhony.gutierrez@amd.com        accessDistance = p->accessDistance;
7511308Santhony.gutierrez@amd.com        clock = p->clk_domain->clockPeriod();
7611308Santhony.gutierrez@amd.com
7712717Sbrandon.potter@amd.com        tlb.assign(size, TlbEntry());
7811308Santhony.gutierrez@amd.com
7911308Santhony.gutierrez@amd.com        freeList.resize(numSets);
8011308Santhony.gutierrez@amd.com        entryList.resize(numSets);
8111308Santhony.gutierrez@amd.com
8211308Santhony.gutierrez@amd.com        for (int set = 0; set < numSets; ++set) {
8311308Santhony.gutierrez@amd.com            for (int way = 0; way < assoc; ++way) {
8411704Santhony.gutierrez@amd.com                int x = set * assoc + way;
8511704Santhony.gutierrez@amd.com                freeList[set].push_back(&tlb.at(x));
8611308Santhony.gutierrez@amd.com            }
8711308Santhony.gutierrez@amd.com        }
8811308Santhony.gutierrez@amd.com
8911308Santhony.gutierrez@amd.com        FA = (size == assoc);
9011308Santhony.gutierrez@amd.com
9111308Santhony.gutierrez@amd.com        /**
9211308Santhony.gutierrez@amd.com         * @warning: the set-associative version assumes you have a
9311308Santhony.gutierrez@amd.com         * fixed page size of 4KB.
9411308Santhony.gutierrez@amd.com         * If the page size is greather than 4KB (as defined in the
9511308Santhony.gutierrez@amd.com         * TheISA::PageBytes), then there are various issues w/ the current
9611308Santhony.gutierrez@amd.com         * implementation (you'd have the same 8KB page being replicated in
9711308Santhony.gutierrez@amd.com         * different sets etc)
9811308Santhony.gutierrez@amd.com         */
9911308Santhony.gutierrez@amd.com        setMask = numSets - 1;
10011308Santhony.gutierrez@amd.com
10111308Santhony.gutierrez@amd.com        maxCoalescedReqs = p->maxOutstandingReqs;
10211308Santhony.gutierrez@amd.com
10311308Santhony.gutierrez@amd.com        // Do not allow maxCoalescedReqs to be more than the TLB associativity
10411308Santhony.gutierrez@amd.com        if (maxCoalescedReqs > assoc) {
10511308Santhony.gutierrez@amd.com            maxCoalescedReqs = assoc;
10611308Santhony.gutierrez@amd.com            cprintf("Forcing maxCoalescedReqs to %d (TLB assoc.) \n", assoc);
10711308Santhony.gutierrez@amd.com        }
10811308Santhony.gutierrez@amd.com
10911308Santhony.gutierrez@amd.com        outstandingReqs = 0;
11011308Santhony.gutierrez@amd.com        hitLatency = p->hitLatency;
11111308Santhony.gutierrez@amd.com        missLatency1 = p->missLatency1;
11211308Santhony.gutierrez@amd.com        missLatency2 = p->missLatency2;
11311308Santhony.gutierrez@amd.com
11411308Santhony.gutierrez@amd.com        // create the slave ports based on the number of connected ports
11511308Santhony.gutierrez@amd.com        for (size_t i = 0; i < p->port_slave_connection_count; ++i) {
11611308Santhony.gutierrez@amd.com            cpuSidePort.push_back(new CpuSidePort(csprintf("%s-port%d",
11711308Santhony.gutierrez@amd.com                                  name(), i), this, i));
11811308Santhony.gutierrez@amd.com        }
11911308Santhony.gutierrez@amd.com
12011308Santhony.gutierrez@amd.com        // create the master ports based on the number of connected ports
12111308Santhony.gutierrez@amd.com        for (size_t i = 0; i < p->port_master_connection_count; ++i) {
12211308Santhony.gutierrez@amd.com            memSidePort.push_back(new MemSidePort(csprintf("%s-port%d",
12311308Santhony.gutierrez@amd.com                                  name(), i), this, i));
12411308Santhony.gutierrez@amd.com        }
12511308Santhony.gutierrez@amd.com    }
12611308Santhony.gutierrez@amd.com
12711308Santhony.gutierrez@amd.com    // fixme: this is never called?
12811308Santhony.gutierrez@amd.com    GpuTLB::~GpuTLB()
12911308Santhony.gutierrez@amd.com    {
13011308Santhony.gutierrez@amd.com        // make sure all the hash-maps are empty
13111308Santhony.gutierrez@amd.com        assert(translationReturnEvent.empty());
13211308Santhony.gutierrez@amd.com    }
13311308Santhony.gutierrez@amd.com
13413784Sgabeblack@google.com    Port &
13513784Sgabeblack@google.com    GpuTLB::getPort(const std::string &if_name, PortID idx)
13611308Santhony.gutierrez@amd.com    {
13711308Santhony.gutierrez@amd.com        if (if_name == "slave") {
13811308Santhony.gutierrez@amd.com            if (idx >= static_cast<PortID>(cpuSidePort.size())) {
13913784Sgabeblack@google.com                panic("TLBCoalescer::getPort: unknown index %d\n", idx);
14011308Santhony.gutierrez@amd.com            }
14111308Santhony.gutierrez@amd.com
14211308Santhony.gutierrez@amd.com            return *cpuSidePort[idx];
14313784Sgabeblack@google.com        } else if (if_name == "master") {
14411308Santhony.gutierrez@amd.com            if (idx >= static_cast<PortID>(memSidePort.size())) {
14513784Sgabeblack@google.com                panic("TLBCoalescer::getPort: unknown index %d\n", idx);
14611308Santhony.gutierrez@amd.com            }
14711308Santhony.gutierrez@amd.com
14811308Santhony.gutierrez@amd.com            hasMemSidePort = true;
14911308Santhony.gutierrez@amd.com
15011308Santhony.gutierrez@amd.com            return *memSidePort[idx];
15111308Santhony.gutierrez@amd.com        } else {
15213784Sgabeblack@google.com            panic("TLBCoalescer::getPort: unknown port %s\n", if_name);
15311308Santhony.gutierrez@amd.com        }
15411308Santhony.gutierrez@amd.com    }
15511308Santhony.gutierrez@amd.com
15612717Sbrandon.potter@amd.com    TlbEntry*
15712717Sbrandon.potter@amd.com    GpuTLB::insert(Addr vpn, TlbEntry &entry)
15811308Santhony.gutierrez@amd.com    {
15912717Sbrandon.potter@amd.com        TlbEntry *newEntry = nullptr;
16011308Santhony.gutierrez@amd.com
16111308Santhony.gutierrez@amd.com        /**
16211308Santhony.gutierrez@amd.com         * vpn holds the virtual page address
16311308Santhony.gutierrez@amd.com         * The least significant bits are simply masked
16411308Santhony.gutierrez@amd.com         */
16511308Santhony.gutierrez@amd.com        int set = (vpn >> TheISA::PageShift) & setMask;
16611308Santhony.gutierrez@amd.com
16711308Santhony.gutierrez@amd.com        if (!freeList[set].empty()) {
16811308Santhony.gutierrez@amd.com            newEntry = freeList[set].front();
16911308Santhony.gutierrez@amd.com            freeList[set].pop_front();
17011308Santhony.gutierrez@amd.com        } else {
17111308Santhony.gutierrez@amd.com            newEntry = entryList[set].back();
17211308Santhony.gutierrez@amd.com            entryList[set].pop_back();
17311308Santhony.gutierrez@amd.com        }
17411308Santhony.gutierrez@amd.com
17511308Santhony.gutierrez@amd.com        *newEntry = entry;
17611308Santhony.gutierrez@amd.com        newEntry->vaddr = vpn;
17711308Santhony.gutierrez@amd.com        entryList[set].push_front(newEntry);
17811308Santhony.gutierrez@amd.com
17911308Santhony.gutierrez@amd.com        return newEntry;
18011308Santhony.gutierrez@amd.com    }
18111308Santhony.gutierrez@amd.com
18211308Santhony.gutierrez@amd.com    GpuTLB::EntryList::iterator
18311308Santhony.gutierrez@amd.com    GpuTLB::lookupIt(Addr va, bool update_lru)
18411308Santhony.gutierrez@amd.com    {
18511308Santhony.gutierrez@amd.com        int set = (va >> TheISA::PageShift) & setMask;
18611308Santhony.gutierrez@amd.com
18711308Santhony.gutierrez@amd.com        if (FA) {
18811308Santhony.gutierrez@amd.com            assert(!set);
18911308Santhony.gutierrez@amd.com        }
19011308Santhony.gutierrez@amd.com
19111308Santhony.gutierrez@amd.com        auto entry = entryList[set].begin();
19211308Santhony.gutierrez@amd.com        for (; entry != entryList[set].end(); ++entry) {
19311308Santhony.gutierrez@amd.com            int page_size = (*entry)->size();
19411308Santhony.gutierrez@amd.com
19511308Santhony.gutierrez@amd.com            if ((*entry)->vaddr <= va && (*entry)->vaddr + page_size > va) {
19611308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Matched vaddr %#x to entry starting at %#x "
19711308Santhony.gutierrez@amd.com                        "with size %#x.\n", va, (*entry)->vaddr, page_size);
19811308Santhony.gutierrez@amd.com
19911308Santhony.gutierrez@amd.com                if (update_lru) {
20011308Santhony.gutierrez@amd.com                    entryList[set].push_front(*entry);
20111308Santhony.gutierrez@amd.com                    entryList[set].erase(entry);
20211308Santhony.gutierrez@amd.com                    entry = entryList[set].begin();
20311308Santhony.gutierrez@amd.com                }
20411308Santhony.gutierrez@amd.com
20511308Santhony.gutierrez@amd.com                break;
20611308Santhony.gutierrez@amd.com            }
20711308Santhony.gutierrez@amd.com        }
20811308Santhony.gutierrez@amd.com
20911308Santhony.gutierrez@amd.com        return entry;
21011308Santhony.gutierrez@amd.com    }
21111308Santhony.gutierrez@amd.com
21212717Sbrandon.potter@amd.com    TlbEntry*
21311308Santhony.gutierrez@amd.com    GpuTLB::lookup(Addr va, bool update_lru)
21411308Santhony.gutierrez@amd.com    {
21511308Santhony.gutierrez@amd.com        int set = (va >> TheISA::PageShift) & setMask;
21611308Santhony.gutierrez@amd.com
21711308Santhony.gutierrez@amd.com        auto entry = lookupIt(va, update_lru);
21811308Santhony.gutierrez@amd.com
21911308Santhony.gutierrez@amd.com        if (entry == entryList[set].end())
22011308Santhony.gutierrez@amd.com            return nullptr;
22111308Santhony.gutierrez@amd.com        else
22211308Santhony.gutierrez@amd.com            return *entry;
22311308Santhony.gutierrez@amd.com    }
22411308Santhony.gutierrez@amd.com
22511308Santhony.gutierrez@amd.com    void
22611308Santhony.gutierrez@amd.com    GpuTLB::invalidateAll()
22711308Santhony.gutierrez@amd.com    {
22811308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Invalidating all entries.\n");
22911308Santhony.gutierrez@amd.com
23011308Santhony.gutierrez@amd.com        for (int i = 0; i < numSets; ++i) {
23111308Santhony.gutierrez@amd.com            while (!entryList[i].empty()) {
23212717Sbrandon.potter@amd.com                TlbEntry *entry = entryList[i].front();
23311308Santhony.gutierrez@amd.com                entryList[i].pop_front();
23411308Santhony.gutierrez@amd.com                freeList[i].push_back(entry);
23511308Santhony.gutierrez@amd.com            }
23611308Santhony.gutierrez@amd.com        }
23711308Santhony.gutierrez@amd.com    }
23811308Santhony.gutierrez@amd.com
23911308Santhony.gutierrez@amd.com    void
24011308Santhony.gutierrez@amd.com    GpuTLB::setConfigAddress(uint32_t addr)
24111308Santhony.gutierrez@amd.com    {
24211308Santhony.gutierrez@amd.com        configAddress = addr;
24311308Santhony.gutierrez@amd.com    }
24411308Santhony.gutierrez@amd.com
24511308Santhony.gutierrez@amd.com    void
24611308Santhony.gutierrez@amd.com    GpuTLB::invalidateNonGlobal()
24711308Santhony.gutierrez@amd.com    {
24811308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Invalidating all non global entries.\n");
24911308Santhony.gutierrez@amd.com
25011308Santhony.gutierrez@amd.com        for (int i = 0; i < numSets; ++i) {
25111308Santhony.gutierrez@amd.com            for (auto entryIt = entryList[i].begin();
25211308Santhony.gutierrez@amd.com                 entryIt != entryList[i].end();) {
25311308Santhony.gutierrez@amd.com                if (!(*entryIt)->global) {
25411308Santhony.gutierrez@amd.com                    freeList[i].push_back(*entryIt);
25511308Santhony.gutierrez@amd.com                    entryList[i].erase(entryIt++);
25611308Santhony.gutierrez@amd.com                } else {
25711308Santhony.gutierrez@amd.com                    ++entryIt;
25811308Santhony.gutierrez@amd.com                }
25911308Santhony.gutierrez@amd.com            }
26011308Santhony.gutierrez@amd.com        }
26111308Santhony.gutierrez@amd.com    }
26211308Santhony.gutierrez@amd.com
26311308Santhony.gutierrez@amd.com    void
26411308Santhony.gutierrez@amd.com    GpuTLB::demapPage(Addr va, uint64_t asn)
26511308Santhony.gutierrez@amd.com    {
26611308Santhony.gutierrez@amd.com
26711308Santhony.gutierrez@amd.com        int set = (va >> TheISA::PageShift) & setMask;
26811308Santhony.gutierrez@amd.com        auto entry = lookupIt(va, false);
26911308Santhony.gutierrez@amd.com
27011308Santhony.gutierrez@amd.com        if (entry != entryList[set].end()) {
27111308Santhony.gutierrez@amd.com            freeList[set].push_back(*entry);
27211308Santhony.gutierrez@amd.com            entryList[set].erase(entry);
27311308Santhony.gutierrez@amd.com        }
27411308Santhony.gutierrez@amd.com    }
27511308Santhony.gutierrez@amd.com
27611308Santhony.gutierrez@amd.com    Fault
27712749Sgiacomo.travaglini@arm.com    GpuTLB::translateInt(const RequestPtr &req, ThreadContext *tc)
27811308Santhony.gutierrez@amd.com    {
27911308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Addresses references internal memory.\n");
28011308Santhony.gutierrez@amd.com        Addr vaddr = req->getVaddr();
28111308Santhony.gutierrez@amd.com        Addr prefix = (vaddr >> 3) & IntAddrPrefixMask;
28211308Santhony.gutierrez@amd.com
28311308Santhony.gutierrez@amd.com        if (prefix == IntAddrPrefixCPUID) {
28411308Santhony.gutierrez@amd.com            panic("CPUID memory space not yet implemented!\n");
28511308Santhony.gutierrez@amd.com        } else if (prefix == IntAddrPrefixMSR) {
28611308Santhony.gutierrez@amd.com            vaddr = vaddr >> 3;
28711308Santhony.gutierrez@amd.com            req->setFlags(Request::MMAPPED_IPR);
28811308Santhony.gutierrez@amd.com            Addr regNum = 0;
28911308Santhony.gutierrez@amd.com
29011308Santhony.gutierrez@amd.com            switch (vaddr & ~IntAddrPrefixMask) {
29111308Santhony.gutierrez@amd.com              case 0x10:
29211308Santhony.gutierrez@amd.com                regNum = MISCREG_TSC;
29311308Santhony.gutierrez@amd.com                break;
29411308Santhony.gutierrez@amd.com              case 0x1B:
29511308Santhony.gutierrez@amd.com                regNum = MISCREG_APIC_BASE;
29611308Santhony.gutierrez@amd.com                break;
29711308Santhony.gutierrez@amd.com              case 0xFE:
29811308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRRCAP;
29911308Santhony.gutierrez@amd.com                break;
30011308Santhony.gutierrez@amd.com              case 0x174:
30111308Santhony.gutierrez@amd.com                regNum = MISCREG_SYSENTER_CS;
30211308Santhony.gutierrez@amd.com                break;
30311308Santhony.gutierrez@amd.com              case 0x175:
30411308Santhony.gutierrez@amd.com                regNum = MISCREG_SYSENTER_ESP;
30511308Santhony.gutierrez@amd.com                break;
30611308Santhony.gutierrez@amd.com              case 0x176:
30711308Santhony.gutierrez@amd.com                regNum = MISCREG_SYSENTER_EIP;
30811308Santhony.gutierrez@amd.com                break;
30911308Santhony.gutierrez@amd.com              case 0x179:
31011308Santhony.gutierrez@amd.com                regNum = MISCREG_MCG_CAP;
31111308Santhony.gutierrez@amd.com                break;
31211308Santhony.gutierrez@amd.com              case 0x17A:
31311308Santhony.gutierrez@amd.com                regNum = MISCREG_MCG_STATUS;
31411308Santhony.gutierrez@amd.com                break;
31511308Santhony.gutierrez@amd.com              case 0x17B:
31611308Santhony.gutierrez@amd.com                regNum = MISCREG_MCG_CTL;
31711308Santhony.gutierrez@amd.com                break;
31811308Santhony.gutierrez@amd.com              case 0x1D9:
31911308Santhony.gutierrez@amd.com                regNum = MISCREG_DEBUG_CTL_MSR;
32011308Santhony.gutierrez@amd.com                break;
32111308Santhony.gutierrez@amd.com              case 0x1DB:
32211308Santhony.gutierrez@amd.com                regNum = MISCREG_LAST_BRANCH_FROM_IP;
32311308Santhony.gutierrez@amd.com                break;
32411308Santhony.gutierrez@amd.com              case 0x1DC:
32511308Santhony.gutierrez@amd.com                regNum = MISCREG_LAST_BRANCH_TO_IP;
32611308Santhony.gutierrez@amd.com                break;
32711308Santhony.gutierrez@amd.com              case 0x1DD:
32811308Santhony.gutierrez@amd.com                regNum = MISCREG_LAST_EXCEPTION_FROM_IP;
32911308Santhony.gutierrez@amd.com                break;
33011308Santhony.gutierrez@amd.com              case 0x1DE:
33111308Santhony.gutierrez@amd.com                regNum = MISCREG_LAST_EXCEPTION_TO_IP;
33211308Santhony.gutierrez@amd.com                break;
33311308Santhony.gutierrez@amd.com              case 0x200:
33411308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_0;
33511308Santhony.gutierrez@amd.com                break;
33611308Santhony.gutierrez@amd.com              case 0x201:
33711308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_0;
33811308Santhony.gutierrez@amd.com                break;
33911308Santhony.gutierrez@amd.com              case 0x202:
34011308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_1;
34111308Santhony.gutierrez@amd.com                break;
34211308Santhony.gutierrez@amd.com              case 0x203:
34311308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_1;
34411308Santhony.gutierrez@amd.com                break;
34511308Santhony.gutierrez@amd.com              case 0x204:
34611308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_2;
34711308Santhony.gutierrez@amd.com                break;
34811308Santhony.gutierrez@amd.com              case 0x205:
34911308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_2;
35011308Santhony.gutierrez@amd.com                break;
35111308Santhony.gutierrez@amd.com              case 0x206:
35211308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_3;
35311308Santhony.gutierrez@amd.com                break;
35411308Santhony.gutierrez@amd.com              case 0x207:
35511308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_3;
35611308Santhony.gutierrez@amd.com                break;
35711308Santhony.gutierrez@amd.com              case 0x208:
35811308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_4;
35911308Santhony.gutierrez@amd.com                break;
36011308Santhony.gutierrez@amd.com              case 0x209:
36111308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_4;
36211308Santhony.gutierrez@amd.com                break;
36311308Santhony.gutierrez@amd.com              case 0x20A:
36411308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_5;
36511308Santhony.gutierrez@amd.com                break;
36611308Santhony.gutierrez@amd.com              case 0x20B:
36711308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_5;
36811308Santhony.gutierrez@amd.com                break;
36911308Santhony.gutierrez@amd.com              case 0x20C:
37011308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_6;
37111308Santhony.gutierrez@amd.com                break;
37211308Santhony.gutierrez@amd.com              case 0x20D:
37311308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_6;
37411308Santhony.gutierrez@amd.com                break;
37511308Santhony.gutierrez@amd.com              case 0x20E:
37611308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_BASE_7;
37711308Santhony.gutierrez@amd.com                break;
37811308Santhony.gutierrez@amd.com              case 0x20F:
37911308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_PHYS_MASK_7;
38011308Santhony.gutierrez@amd.com                break;
38111308Santhony.gutierrez@amd.com              case 0x250:
38211308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_64K_00000;
38311308Santhony.gutierrez@amd.com                break;
38411308Santhony.gutierrez@amd.com              case 0x258:
38511308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_16K_80000;
38611308Santhony.gutierrez@amd.com                break;
38711308Santhony.gutierrez@amd.com              case 0x259:
38811308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_16K_A0000;
38911308Santhony.gutierrez@amd.com                break;
39011308Santhony.gutierrez@amd.com              case 0x268:
39111308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_C0000;
39211308Santhony.gutierrez@amd.com                break;
39311308Santhony.gutierrez@amd.com              case 0x269:
39411308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_C8000;
39511308Santhony.gutierrez@amd.com                break;
39611308Santhony.gutierrez@amd.com              case 0x26A:
39711308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_D0000;
39811308Santhony.gutierrez@amd.com                break;
39911308Santhony.gutierrez@amd.com              case 0x26B:
40011308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_D8000;
40111308Santhony.gutierrez@amd.com                break;
40211308Santhony.gutierrez@amd.com              case 0x26C:
40311308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_E0000;
40411308Santhony.gutierrez@amd.com                break;
40511308Santhony.gutierrez@amd.com              case 0x26D:
40611308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_E8000;
40711308Santhony.gutierrez@amd.com                break;
40811308Santhony.gutierrez@amd.com              case 0x26E:
40911308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_F0000;
41011308Santhony.gutierrez@amd.com                break;
41111308Santhony.gutierrez@amd.com              case 0x26F:
41211308Santhony.gutierrez@amd.com                regNum = MISCREG_MTRR_FIX_4K_F8000;
41311308Santhony.gutierrez@amd.com                break;
41411308Santhony.gutierrez@amd.com              case 0x277:
41511308Santhony.gutierrez@amd.com                regNum = MISCREG_PAT;
41611308Santhony.gutierrez@amd.com                break;
41711308Santhony.gutierrez@amd.com              case 0x2FF:
41811308Santhony.gutierrez@amd.com                regNum = MISCREG_DEF_TYPE;
41911308Santhony.gutierrez@amd.com                break;
42011308Santhony.gutierrez@amd.com              case 0x400:
42111308Santhony.gutierrez@amd.com                regNum = MISCREG_MC0_CTL;
42211308Santhony.gutierrez@amd.com                break;
42311308Santhony.gutierrez@amd.com              case 0x404:
42411308Santhony.gutierrez@amd.com                regNum = MISCREG_MC1_CTL;
42511308Santhony.gutierrez@amd.com                break;
42611308Santhony.gutierrez@amd.com              case 0x408:
42711308Santhony.gutierrez@amd.com                regNum = MISCREG_MC2_CTL;
42811308Santhony.gutierrez@amd.com                break;
42911308Santhony.gutierrez@amd.com              case 0x40C:
43011308Santhony.gutierrez@amd.com                regNum = MISCREG_MC3_CTL;
43111308Santhony.gutierrez@amd.com                break;
43211308Santhony.gutierrez@amd.com              case 0x410:
43311308Santhony.gutierrez@amd.com                regNum = MISCREG_MC4_CTL;
43411308Santhony.gutierrez@amd.com                break;
43511308Santhony.gutierrez@amd.com              case 0x414:
43611308Santhony.gutierrez@amd.com                regNum = MISCREG_MC5_CTL;
43711308Santhony.gutierrez@amd.com                break;
43811308Santhony.gutierrez@amd.com              case 0x418:
43911308Santhony.gutierrez@amd.com                regNum = MISCREG_MC6_CTL;
44011308Santhony.gutierrez@amd.com                break;
44111308Santhony.gutierrez@amd.com              case 0x41C:
44211308Santhony.gutierrez@amd.com                regNum = MISCREG_MC7_CTL;
44311308Santhony.gutierrez@amd.com                break;
44411308Santhony.gutierrez@amd.com              case 0x401:
44511308Santhony.gutierrez@amd.com                regNum = MISCREG_MC0_STATUS;
44611308Santhony.gutierrez@amd.com                break;
44711308Santhony.gutierrez@amd.com              case 0x405:
44811308Santhony.gutierrez@amd.com                regNum = MISCREG_MC1_STATUS;
44911308Santhony.gutierrez@amd.com                break;
45011308Santhony.gutierrez@amd.com              case 0x409:
45111308Santhony.gutierrez@amd.com                regNum = MISCREG_MC2_STATUS;
45211308Santhony.gutierrez@amd.com                break;
45311308Santhony.gutierrez@amd.com              case 0x40D:
45411308Santhony.gutierrez@amd.com                regNum = MISCREG_MC3_STATUS;
45511308Santhony.gutierrez@amd.com                break;
45611308Santhony.gutierrez@amd.com              case 0x411:
45711308Santhony.gutierrez@amd.com                regNum = MISCREG_MC4_STATUS;
45811308Santhony.gutierrez@amd.com                break;
45911308Santhony.gutierrez@amd.com              case 0x415:
46011308Santhony.gutierrez@amd.com                regNum = MISCREG_MC5_STATUS;
46111308Santhony.gutierrez@amd.com                break;
46211308Santhony.gutierrez@amd.com              case 0x419:
46311308Santhony.gutierrez@amd.com                regNum = MISCREG_MC6_STATUS;
46411308Santhony.gutierrez@amd.com                break;
46511308Santhony.gutierrez@amd.com              case 0x41D:
46611308Santhony.gutierrez@amd.com                regNum = MISCREG_MC7_STATUS;
46711308Santhony.gutierrez@amd.com                break;
46811308Santhony.gutierrez@amd.com              case 0x402:
46911308Santhony.gutierrez@amd.com                regNum = MISCREG_MC0_ADDR;
47011308Santhony.gutierrez@amd.com                break;
47111308Santhony.gutierrez@amd.com              case 0x406:
47211308Santhony.gutierrez@amd.com                regNum = MISCREG_MC1_ADDR;
47311308Santhony.gutierrez@amd.com                break;
47411308Santhony.gutierrez@amd.com              case 0x40A:
47511308Santhony.gutierrez@amd.com                regNum = MISCREG_MC2_ADDR;
47611308Santhony.gutierrez@amd.com                break;
47711308Santhony.gutierrez@amd.com              case 0x40E:
47811308Santhony.gutierrez@amd.com                regNum = MISCREG_MC3_ADDR;
47911308Santhony.gutierrez@amd.com                break;
48011308Santhony.gutierrez@amd.com              case 0x412:
48111308Santhony.gutierrez@amd.com                regNum = MISCREG_MC4_ADDR;
48211308Santhony.gutierrez@amd.com                break;
48311308Santhony.gutierrez@amd.com              case 0x416:
48411308Santhony.gutierrez@amd.com                regNum = MISCREG_MC5_ADDR;
48511308Santhony.gutierrez@amd.com                break;
48611308Santhony.gutierrez@amd.com              case 0x41A:
48711308Santhony.gutierrez@amd.com                regNum = MISCREG_MC6_ADDR;
48811308Santhony.gutierrez@amd.com                break;
48911308Santhony.gutierrez@amd.com              case 0x41E:
49011308Santhony.gutierrez@amd.com                regNum = MISCREG_MC7_ADDR;
49111308Santhony.gutierrez@amd.com                break;
49211308Santhony.gutierrez@amd.com              case 0x403:
49311308Santhony.gutierrez@amd.com                regNum = MISCREG_MC0_MISC;
49411308Santhony.gutierrez@amd.com                break;
49511308Santhony.gutierrez@amd.com              case 0x407:
49611308Santhony.gutierrez@amd.com                regNum = MISCREG_MC1_MISC;
49711308Santhony.gutierrez@amd.com                break;
49811308Santhony.gutierrez@amd.com              case 0x40B:
49911308Santhony.gutierrez@amd.com                regNum = MISCREG_MC2_MISC;
50011308Santhony.gutierrez@amd.com                break;
50111308Santhony.gutierrez@amd.com              case 0x40F:
50211308Santhony.gutierrez@amd.com                regNum = MISCREG_MC3_MISC;
50311308Santhony.gutierrez@amd.com                break;
50411308Santhony.gutierrez@amd.com              case 0x413:
50511308Santhony.gutierrez@amd.com                regNum = MISCREG_MC4_MISC;
50611308Santhony.gutierrez@amd.com                break;
50711308Santhony.gutierrez@amd.com              case 0x417:
50811308Santhony.gutierrez@amd.com                regNum = MISCREG_MC5_MISC;
50911308Santhony.gutierrez@amd.com                break;
51011308Santhony.gutierrez@amd.com              case 0x41B:
51111308Santhony.gutierrez@amd.com                regNum = MISCREG_MC6_MISC;
51211308Santhony.gutierrez@amd.com                break;
51311308Santhony.gutierrez@amd.com              case 0x41F:
51411308Santhony.gutierrez@amd.com                regNum = MISCREG_MC7_MISC;
51511308Santhony.gutierrez@amd.com                break;
51611308Santhony.gutierrez@amd.com              case 0xC0000080:
51711308Santhony.gutierrez@amd.com                regNum = MISCREG_EFER;
51811308Santhony.gutierrez@amd.com                break;
51911308Santhony.gutierrez@amd.com              case 0xC0000081:
52011308Santhony.gutierrez@amd.com                regNum = MISCREG_STAR;
52111308Santhony.gutierrez@amd.com                break;
52211308Santhony.gutierrez@amd.com              case 0xC0000082:
52311308Santhony.gutierrez@amd.com                regNum = MISCREG_LSTAR;
52411308Santhony.gutierrez@amd.com                break;
52511308Santhony.gutierrez@amd.com              case 0xC0000083:
52611308Santhony.gutierrez@amd.com                regNum = MISCREG_CSTAR;
52711308Santhony.gutierrez@amd.com                break;
52811308Santhony.gutierrez@amd.com              case 0xC0000084:
52911308Santhony.gutierrez@amd.com                regNum = MISCREG_SF_MASK;
53011308Santhony.gutierrez@amd.com                break;
53111308Santhony.gutierrez@amd.com              case 0xC0000100:
53211308Santhony.gutierrez@amd.com                regNum = MISCREG_FS_BASE;
53311308Santhony.gutierrez@amd.com                break;
53411308Santhony.gutierrez@amd.com              case 0xC0000101:
53511308Santhony.gutierrez@amd.com                regNum = MISCREG_GS_BASE;
53611308Santhony.gutierrez@amd.com                break;
53711308Santhony.gutierrez@amd.com              case 0xC0000102:
53811308Santhony.gutierrez@amd.com                regNum = MISCREG_KERNEL_GS_BASE;
53911308Santhony.gutierrez@amd.com                break;
54011308Santhony.gutierrez@amd.com              case 0xC0000103:
54111308Santhony.gutierrez@amd.com                regNum = MISCREG_TSC_AUX;
54211308Santhony.gutierrez@amd.com                break;
54311308Santhony.gutierrez@amd.com              case 0xC0010000:
54411308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_SEL0;
54511308Santhony.gutierrez@amd.com                break;
54611308Santhony.gutierrez@amd.com              case 0xC0010001:
54711308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_SEL1;
54811308Santhony.gutierrez@amd.com                break;
54911308Santhony.gutierrez@amd.com              case 0xC0010002:
55011308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_SEL2;
55111308Santhony.gutierrez@amd.com                break;
55211308Santhony.gutierrez@amd.com              case 0xC0010003:
55311308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_SEL3;
55411308Santhony.gutierrez@amd.com                break;
55511308Santhony.gutierrez@amd.com              case 0xC0010004:
55611308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_CTR0;
55711308Santhony.gutierrez@amd.com                break;
55811308Santhony.gutierrez@amd.com              case 0xC0010005:
55911308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_CTR1;
56011308Santhony.gutierrez@amd.com                break;
56111308Santhony.gutierrez@amd.com              case 0xC0010006:
56211308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_CTR2;
56311308Santhony.gutierrez@amd.com                break;
56411308Santhony.gutierrez@amd.com              case 0xC0010007:
56511308Santhony.gutierrez@amd.com                regNum = MISCREG_PERF_EVT_CTR3;
56611308Santhony.gutierrez@amd.com                break;
56711308Santhony.gutierrez@amd.com              case 0xC0010010:
56811308Santhony.gutierrez@amd.com                regNum = MISCREG_SYSCFG;
56911308Santhony.gutierrez@amd.com                break;
57011308Santhony.gutierrez@amd.com              case 0xC0010016:
57111308Santhony.gutierrez@amd.com                regNum = MISCREG_IORR_BASE0;
57211308Santhony.gutierrez@amd.com                break;
57311308Santhony.gutierrez@amd.com              case 0xC0010017:
57411308Santhony.gutierrez@amd.com                regNum = MISCREG_IORR_BASE1;
57511308Santhony.gutierrez@amd.com                break;
57611308Santhony.gutierrez@amd.com              case 0xC0010018:
57711308Santhony.gutierrez@amd.com                regNum = MISCREG_IORR_MASK0;
57811308Santhony.gutierrez@amd.com                break;
57911308Santhony.gutierrez@amd.com              case 0xC0010019:
58011308Santhony.gutierrez@amd.com                regNum = MISCREG_IORR_MASK1;
58111308Santhony.gutierrez@amd.com                break;
58211308Santhony.gutierrez@amd.com              case 0xC001001A:
58311308Santhony.gutierrez@amd.com                regNum = MISCREG_TOP_MEM;
58411308Santhony.gutierrez@amd.com                break;
58511308Santhony.gutierrez@amd.com              case 0xC001001D:
58611308Santhony.gutierrez@amd.com                regNum = MISCREG_TOP_MEM2;
58711308Santhony.gutierrez@amd.com                break;
58811308Santhony.gutierrez@amd.com              case 0xC0010114:
58911308Santhony.gutierrez@amd.com                regNum = MISCREG_VM_CR;
59011308Santhony.gutierrez@amd.com                break;
59111308Santhony.gutierrez@amd.com              case 0xC0010115:
59211308Santhony.gutierrez@amd.com                regNum = MISCREG_IGNNE;
59311308Santhony.gutierrez@amd.com                break;
59411308Santhony.gutierrez@amd.com              case 0xC0010116:
59511308Santhony.gutierrez@amd.com                regNum = MISCREG_SMM_CTL;
59611308Santhony.gutierrez@amd.com                break;
59711308Santhony.gutierrez@amd.com              case 0xC0010117:
59811308Santhony.gutierrez@amd.com                regNum = MISCREG_VM_HSAVE_PA;
59911308Santhony.gutierrez@amd.com                break;
60011308Santhony.gutierrez@amd.com              default:
60111308Santhony.gutierrez@amd.com                return std::make_shared<GeneralProtection>(0);
60211308Santhony.gutierrez@amd.com            }
60311308Santhony.gutierrez@amd.com            //The index is multiplied by the size of a MiscReg so that
60411308Santhony.gutierrez@amd.com            //any memory dependence calculations will not see these as
60511308Santhony.gutierrez@amd.com            //overlapping.
60613557Sgabeblack@google.com            req->setPaddr(regNum * sizeof(RegVal));
60711308Santhony.gutierrez@amd.com            return NoFault;
60811308Santhony.gutierrez@amd.com        } else if (prefix == IntAddrPrefixIO) {
60911308Santhony.gutierrez@amd.com            // TODO If CPL > IOPL or in virtual mode, check the I/O permission
61011308Santhony.gutierrez@amd.com            // bitmap in the TSS.
61111308Santhony.gutierrez@amd.com
61211308Santhony.gutierrez@amd.com            Addr IOPort = vaddr & ~IntAddrPrefixMask;
61311308Santhony.gutierrez@amd.com            // Make sure the address fits in the expected 16 bit IO address
61411308Santhony.gutierrez@amd.com            // space.
61511308Santhony.gutierrez@amd.com            assert(!(IOPort & ~0xFFFF));
61611308Santhony.gutierrez@amd.com
61711308Santhony.gutierrez@amd.com            if (IOPort == 0xCF8 && req->getSize() == 4) {
61811308Santhony.gutierrez@amd.com                req->setFlags(Request::MMAPPED_IPR);
61913557Sgabeblack@google.com                req->setPaddr(MISCREG_PCI_CONFIG_ADDRESS * sizeof(RegVal));
62011308Santhony.gutierrez@amd.com            } else if ((IOPort & ~mask(2)) == 0xCFC) {
62111308Santhony.gutierrez@amd.com                req->setFlags(Request::UNCACHEABLE);
62211308Santhony.gutierrez@amd.com
62311308Santhony.gutierrez@amd.com                Addr configAddress =
62411308Santhony.gutierrez@amd.com                    tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS);
62511308Santhony.gutierrez@amd.com
62611308Santhony.gutierrez@amd.com                if (bits(configAddress, 31, 31)) {
62711308Santhony.gutierrez@amd.com                    req->setPaddr(PhysAddrPrefixPciConfig |
62811308Santhony.gutierrez@amd.com                                  mbits(configAddress, 30, 2) |
62911308Santhony.gutierrez@amd.com                                  (IOPort & mask(2)));
63011308Santhony.gutierrez@amd.com                } else {
63111308Santhony.gutierrez@amd.com                    req->setPaddr(PhysAddrPrefixIO | IOPort);
63211308Santhony.gutierrez@amd.com                }
63311308Santhony.gutierrez@amd.com            } else {
63411308Santhony.gutierrez@amd.com                req->setFlags(Request::UNCACHEABLE);
63511308Santhony.gutierrez@amd.com                req->setPaddr(PhysAddrPrefixIO | IOPort);
63611308Santhony.gutierrez@amd.com            }
63711308Santhony.gutierrez@amd.com            return NoFault;
63811308Santhony.gutierrez@amd.com        } else {
63911308Santhony.gutierrez@amd.com            panic("Access to unrecognized internal address space %#x.\n",
64011308Santhony.gutierrez@amd.com                  prefix);
64111308Santhony.gutierrez@amd.com        }
64211308Santhony.gutierrez@amd.com    }
64311308Santhony.gutierrez@amd.com
64411308Santhony.gutierrez@amd.com    /**
64511308Santhony.gutierrez@amd.com     * TLB_lookup will only perform a TLB lookup returning true on a TLB hit
64611308Santhony.gutierrez@amd.com     * and false on a TLB miss.
64711308Santhony.gutierrez@amd.com     * Many of the checks about different modes have been converted to
64811308Santhony.gutierrez@amd.com     * assertions, since these parts of the code are not really used.
64911308Santhony.gutierrez@amd.com     * On a hit it will update the LRU stack.
65011308Santhony.gutierrez@amd.com     */
65111308Santhony.gutierrez@amd.com    bool
65212749Sgiacomo.travaglini@arm.com    GpuTLB::tlbLookup(const RequestPtr &req,
65312749Sgiacomo.travaglini@arm.com                      ThreadContext *tc, bool update_stats)
65411308Santhony.gutierrez@amd.com    {
65511308Santhony.gutierrez@amd.com        bool tlb_hit = false;
65611308Santhony.gutierrez@amd.com    #ifndef NDEBUG
65711308Santhony.gutierrez@amd.com        uint32_t flags = req->getFlags();
65811308Santhony.gutierrez@amd.com        int seg = flags & SegmentFlagMask;
65911308Santhony.gutierrez@amd.com    #endif
66011308Santhony.gutierrez@amd.com
66111308Santhony.gutierrez@amd.com        assert(seg != SEGMENT_REG_MS);
66211308Santhony.gutierrez@amd.com        Addr vaddr = req->getVaddr();
66311308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "TLB Lookup for vaddr %#x.\n", vaddr);
66411308Santhony.gutierrez@amd.com        HandyM5Reg m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
66511308Santhony.gutierrez@amd.com
66611308Santhony.gutierrez@amd.com        if (m5Reg.prot) {
66711308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "In protected mode.\n");
66811308Santhony.gutierrez@amd.com            // make sure we are in 64-bit mode
66911308Santhony.gutierrez@amd.com            assert(m5Reg.mode == LongMode);
67011308Santhony.gutierrez@amd.com
67111308Santhony.gutierrez@amd.com            // If paging is enabled, do the translation.
67211308Santhony.gutierrez@amd.com            if (m5Reg.paging) {
67311308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Paging enabled.\n");
67411308Santhony.gutierrez@amd.com                //update LRU stack on a hit
67512717Sbrandon.potter@amd.com                TlbEntry *entry = lookup(vaddr, true);
67611308Santhony.gutierrez@amd.com
67711308Santhony.gutierrez@amd.com                if (entry)
67811308Santhony.gutierrez@amd.com                    tlb_hit = true;
67911308Santhony.gutierrez@amd.com
68011308Santhony.gutierrez@amd.com                if (!update_stats) {
68111308Santhony.gutierrez@amd.com                    // functional tlb access for memory initialization
68211308Santhony.gutierrez@amd.com                    // i.e., memory seeding or instr. seeding -> don't update
68311308Santhony.gutierrez@amd.com                    // TLB and stats
68411308Santhony.gutierrez@amd.com                    return tlb_hit;
68511308Santhony.gutierrez@amd.com                }
68611308Santhony.gutierrez@amd.com
68711308Santhony.gutierrez@amd.com                localNumTLBAccesses++;
68811308Santhony.gutierrez@amd.com
68911308Santhony.gutierrez@amd.com                if (!entry) {
69011308Santhony.gutierrez@amd.com                    localNumTLBMisses++;
69111308Santhony.gutierrez@amd.com                } else {
69211308Santhony.gutierrez@amd.com                    localNumTLBHits++;
69311308Santhony.gutierrez@amd.com                }
69411308Santhony.gutierrez@amd.com            }
69511308Santhony.gutierrez@amd.com        }
69611308Santhony.gutierrez@amd.com
69711308Santhony.gutierrez@amd.com        return tlb_hit;
69811308Santhony.gutierrez@amd.com    }
69911308Santhony.gutierrez@amd.com
70011308Santhony.gutierrez@amd.com    Fault
70112749Sgiacomo.travaglini@arm.com    GpuTLB::translate(const RequestPtr &req, ThreadContext *tc,
70211308Santhony.gutierrez@amd.com                      Translation *translation, Mode mode,
70311308Santhony.gutierrez@amd.com                      bool &delayedResponse, bool timing, int &latency)
70411308Santhony.gutierrez@amd.com    {
70511308Santhony.gutierrez@amd.com        uint32_t flags = req->getFlags();
70611308Santhony.gutierrez@amd.com        int seg = flags & SegmentFlagMask;
70711308Santhony.gutierrez@amd.com        bool storeCheck = flags & (StoreCheck << FlagShift);
70811308Santhony.gutierrez@amd.com
70911308Santhony.gutierrez@amd.com        // If this is true, we're dealing with a request
71011308Santhony.gutierrez@amd.com        // to a non-memory address space.
71111308Santhony.gutierrez@amd.com        if (seg == SEGMENT_REG_MS) {
71211308Santhony.gutierrez@amd.com            return translateInt(req, tc);
71311308Santhony.gutierrez@amd.com        }
71411308Santhony.gutierrez@amd.com
71511308Santhony.gutierrez@amd.com        delayedResponse = false;
71611308Santhony.gutierrez@amd.com        Addr vaddr = req->getVaddr();
71711308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Translating vaddr %#x.\n", vaddr);
71811308Santhony.gutierrez@amd.com
71911308Santhony.gutierrez@amd.com        HandyM5Reg m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
72011308Santhony.gutierrez@amd.com
72111308Santhony.gutierrez@amd.com        // If protected mode has been enabled...
72211308Santhony.gutierrez@amd.com        if (m5Reg.prot) {
72311308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "In protected mode.\n");
72411308Santhony.gutierrez@amd.com            // If we're not in 64-bit mode, do protection/limit checks
72511308Santhony.gutierrez@amd.com            if (m5Reg.mode != LongMode) {
72611308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Not in long mode. Checking segment "
72711308Santhony.gutierrez@amd.com                        "protection.\n");
72811308Santhony.gutierrez@amd.com
72911308Santhony.gutierrez@amd.com                // Check for a null segment selector.
73011308Santhony.gutierrez@amd.com                if (!(seg == SEGMENT_REG_TSG || seg == SYS_SEGMENT_REG_IDTR ||
73111308Santhony.gutierrez@amd.com                    seg == SEGMENT_REG_HS || seg == SEGMENT_REG_LS)
73211308Santhony.gutierrez@amd.com                    && !tc->readMiscRegNoEffect(MISCREG_SEG_SEL(seg))) {
73311308Santhony.gutierrez@amd.com                    return std::make_shared<GeneralProtection>(0);
73411308Santhony.gutierrez@amd.com                }
73511308Santhony.gutierrez@amd.com
73611308Santhony.gutierrez@amd.com                bool expandDown = false;
73711308Santhony.gutierrez@amd.com                SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
73811308Santhony.gutierrez@amd.com
73911308Santhony.gutierrez@amd.com                if (seg >= SEGMENT_REG_ES && seg <= SEGMENT_REG_HS) {
74011308Santhony.gutierrez@amd.com                    if (!attr.writable && (mode == BaseTLB::Write ||
74111308Santhony.gutierrez@amd.com                        storeCheck))
74211308Santhony.gutierrez@amd.com                        return std::make_shared<GeneralProtection>(0);
74311308Santhony.gutierrez@amd.com
74411308Santhony.gutierrez@amd.com                    if (!attr.readable && mode == BaseTLB::Read)
74511308Santhony.gutierrez@amd.com                        return std::make_shared<GeneralProtection>(0);
74611308Santhony.gutierrez@amd.com
74711308Santhony.gutierrez@amd.com                    expandDown = attr.expandDown;
74811308Santhony.gutierrez@amd.com
74911308Santhony.gutierrez@amd.com                }
75011308Santhony.gutierrez@amd.com
75111308Santhony.gutierrez@amd.com                Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg));
75211308Santhony.gutierrez@amd.com                Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg));
75311308Santhony.gutierrez@amd.com                // This assumes we're not in 64 bit mode. If we were, the
75411308Santhony.gutierrez@amd.com                // default address size is 64 bits, overridable to 32.
75511308Santhony.gutierrez@amd.com                int size = 32;
75611308Santhony.gutierrez@amd.com                bool sizeOverride = (flags & (AddrSizeFlagBit << FlagShift));
75711308Santhony.gutierrez@amd.com                SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR);
75811308Santhony.gutierrez@amd.com
75911308Santhony.gutierrez@amd.com                if ((csAttr.defaultSize && sizeOverride) ||
76011308Santhony.gutierrez@amd.com                    (!csAttr.defaultSize && !sizeOverride)) {
76111308Santhony.gutierrez@amd.com                    size = 16;
76211308Santhony.gutierrez@amd.com                }
76311308Santhony.gutierrez@amd.com
76411308Santhony.gutierrez@amd.com                Addr offset = bits(vaddr - base, size - 1, 0);
76511308Santhony.gutierrez@amd.com                Addr endOffset = offset + req->getSize() - 1;
76611308Santhony.gutierrez@amd.com
76711308Santhony.gutierrez@amd.com                if (expandDown) {
76811308Santhony.gutierrez@amd.com                    DPRINTF(GPUTLB, "Checking an expand down segment.\n");
76911308Santhony.gutierrez@amd.com                    warn_once("Expand down segments are untested.\n");
77011308Santhony.gutierrez@amd.com
77111308Santhony.gutierrez@amd.com                    if (offset <= limit || endOffset <= limit)
77211308Santhony.gutierrez@amd.com                        return std::make_shared<GeneralProtection>(0);
77311308Santhony.gutierrez@amd.com                } else {
77411308Santhony.gutierrez@amd.com                    if (offset > limit || endOffset > limit)
77511308Santhony.gutierrez@amd.com                        return std::make_shared<GeneralProtection>(0);
77611308Santhony.gutierrez@amd.com                }
77711308Santhony.gutierrez@amd.com            }
77811308Santhony.gutierrez@amd.com
77911308Santhony.gutierrez@amd.com            // If paging is enabled, do the translation.
78011308Santhony.gutierrez@amd.com            if (m5Reg.paging) {
78111308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Paging enabled.\n");
78211308Santhony.gutierrez@amd.com                // The vaddr already has the segment base applied.
78312717Sbrandon.potter@amd.com                TlbEntry *entry = lookup(vaddr);
78411308Santhony.gutierrez@amd.com                localNumTLBAccesses++;
78511308Santhony.gutierrez@amd.com
78611308Santhony.gutierrez@amd.com                if (!entry) {
78711308Santhony.gutierrez@amd.com                    localNumTLBMisses++;
78811308Santhony.gutierrez@amd.com                    if (timing) {
78911308Santhony.gutierrez@amd.com                        latency = missLatency1;
79011308Santhony.gutierrez@amd.com                    }
79111308Santhony.gutierrez@amd.com
79211308Santhony.gutierrez@amd.com                    if (FullSystem) {
79311308Santhony.gutierrez@amd.com                        fatal("GpuTLB doesn't support full-system mode\n");
79411308Santhony.gutierrez@amd.com                    } else {
79511308Santhony.gutierrez@amd.com                        DPRINTF(GPUTLB, "Handling a TLB miss for address %#x "
79611308Santhony.gutierrez@amd.com                                "at pc %#x.\n", vaddr, tc->instAddr());
79711308Santhony.gutierrez@amd.com
79811308Santhony.gutierrez@amd.com                        Process *p = tc->getProcessPtr();
79912461Sgabeblack@google.com                        const EmulationPageTable::Entry *pte =
80012461Sgabeblack@google.com                            p->pTable->lookup(vaddr);
80111308Santhony.gutierrez@amd.com
80212461Sgabeblack@google.com                        if (!pte && mode != BaseTLB::Execute) {
80311308Santhony.gutierrez@amd.com                            // penalize a "page fault" more
80412455Sgabeblack@google.com                            if (timing)
80511308Santhony.gutierrez@amd.com                                latency += missLatency2;
80611308Santhony.gutierrez@amd.com
80711308Santhony.gutierrez@amd.com                            if (p->fixupStackFault(vaddr))
80812461Sgabeblack@google.com                                pte = p->pTable->lookup(vaddr);
80911308Santhony.gutierrez@amd.com                        }
81011308Santhony.gutierrez@amd.com
81112461Sgabeblack@google.com                        if (!pte) {
81211308Santhony.gutierrez@amd.com                            return std::make_shared<PageFault>(vaddr, true,
81311308Santhony.gutierrez@amd.com                                                               mode, true,
81411308Santhony.gutierrez@amd.com                                                               false);
81511308Santhony.gutierrez@amd.com                        } else {
81611308Santhony.gutierrez@amd.com                            Addr alignedVaddr = p->pTable->pageAlign(vaddr);
81711308Santhony.gutierrez@amd.com
81811308Santhony.gutierrez@amd.com                            DPRINTF(GPUTLB, "Mapping %#x to %#x\n",
81912461Sgabeblack@google.com                                    alignedVaddr, pte->paddr);
82011308Santhony.gutierrez@amd.com
82112717Sbrandon.potter@amd.com                            TlbEntry gpuEntry(p->pid(), alignedVaddr,
82212717Sbrandon.potter@amd.com                                              pte->paddr, false, false);
82312455Sgabeblack@google.com                            entry = insert(alignedVaddr, gpuEntry);
82411308Santhony.gutierrez@amd.com                        }
82511308Santhony.gutierrez@amd.com
82611308Santhony.gutierrez@amd.com                        DPRINTF(GPUTLB, "Miss was serviced.\n");
82711308Santhony.gutierrez@amd.com                    }
82811308Santhony.gutierrez@amd.com                } else {
82911308Santhony.gutierrez@amd.com                    localNumTLBHits++;
83011308Santhony.gutierrez@amd.com
83111308Santhony.gutierrez@amd.com                    if (timing) {
83211308Santhony.gutierrez@amd.com                        latency = hitLatency;
83311308Santhony.gutierrez@amd.com                    }
83411308Santhony.gutierrez@amd.com                }
83511308Santhony.gutierrez@amd.com
83611308Santhony.gutierrez@amd.com                // Do paging protection checks.
83711308Santhony.gutierrez@amd.com                bool inUser = (m5Reg.cpl == 3 &&
83811308Santhony.gutierrez@amd.com                               !(flags & (CPL0FlagBit << FlagShift)));
83911308Santhony.gutierrez@amd.com
84011308Santhony.gutierrez@amd.com                CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
84111308Santhony.gutierrez@amd.com                bool badWrite = (!entry->writable && (inUser || cr0.wp));
84211308Santhony.gutierrez@amd.com
84311308Santhony.gutierrez@amd.com                if ((inUser && !entry->user) || (mode == BaseTLB::Write &&
84411308Santhony.gutierrez@amd.com                     badWrite)) {
84511308Santhony.gutierrez@amd.com                    // The page must have been present to get into the TLB in
84611308Santhony.gutierrez@amd.com                    // the first place. We'll assume the reserved bits are
84711308Santhony.gutierrez@amd.com                    // fine even though we're not checking them.
84811308Santhony.gutierrez@amd.com                    return std::make_shared<PageFault>(vaddr, true, mode,
84911308Santhony.gutierrez@amd.com                                                       inUser, false);
85011308Santhony.gutierrez@amd.com                }
85111308Santhony.gutierrez@amd.com
85211308Santhony.gutierrez@amd.com                if (storeCheck && badWrite) {
85311308Santhony.gutierrez@amd.com                    // This would fault if this were a write, so return a page
85411308Santhony.gutierrez@amd.com                    // fault that reflects that happening.
85511308Santhony.gutierrez@amd.com                    return std::make_shared<PageFault>(vaddr, true,
85611308Santhony.gutierrez@amd.com                                                       BaseTLB::Write,
85711308Santhony.gutierrez@amd.com                                                       inUser, false);
85811308Santhony.gutierrez@amd.com                }
85911308Santhony.gutierrez@amd.com
86011308Santhony.gutierrez@amd.com
86111308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Entry found with paddr %#x, doing protection "
86211308Santhony.gutierrez@amd.com                        "checks.\n", entry->paddr);
86311308Santhony.gutierrez@amd.com
86411308Santhony.gutierrez@amd.com                int page_size = entry->size();
86511308Santhony.gutierrez@amd.com                Addr paddr = entry->paddr | (vaddr & (page_size - 1));
86611308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Translated %#x -> %#x.\n", vaddr, paddr);
86711308Santhony.gutierrez@amd.com                req->setPaddr(paddr);
86811308Santhony.gutierrez@amd.com
86911308Santhony.gutierrez@amd.com                if (entry->uncacheable)
87011308Santhony.gutierrez@amd.com                    req->setFlags(Request::UNCACHEABLE);
87111308Santhony.gutierrez@amd.com            } else {
87211308Santhony.gutierrez@amd.com                //Use the address which already has segmentation applied.
87311308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Paging disabled.\n");
87411308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
87511308Santhony.gutierrez@amd.com                req->setPaddr(vaddr);
87611308Santhony.gutierrez@amd.com            }
87711308Santhony.gutierrez@amd.com        } else {
87811308Santhony.gutierrez@amd.com            // Real mode
87911308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "In real mode.\n");
88011308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
88111308Santhony.gutierrez@amd.com            req->setPaddr(vaddr);
88211308Santhony.gutierrez@amd.com        }
88311308Santhony.gutierrez@amd.com
88411308Santhony.gutierrez@amd.com        // Check for an access to the local APIC
88511308Santhony.gutierrez@amd.com        if (FullSystem) {
88611308Santhony.gutierrez@amd.com            LocalApicBase localApicBase =
88711308Santhony.gutierrez@amd.com                tc->readMiscRegNoEffect(MISCREG_APIC_BASE);
88811308Santhony.gutierrez@amd.com
88911308Santhony.gutierrez@amd.com            Addr baseAddr = localApicBase.base * PageBytes;
89011308Santhony.gutierrez@amd.com            Addr paddr = req->getPaddr();
89111308Santhony.gutierrez@amd.com
89211308Santhony.gutierrez@amd.com            if (baseAddr <= paddr && baseAddr + PageBytes > paddr) {
89311308Santhony.gutierrez@amd.com                // Force the access to be uncacheable.
89411308Santhony.gutierrez@amd.com                req->setFlags(Request::UNCACHEABLE);
89511308Santhony.gutierrez@amd.com                req->setPaddr(x86LocalAPICAddress(tc->contextId(),
89611308Santhony.gutierrez@amd.com                                                  paddr - baseAddr));
89711308Santhony.gutierrez@amd.com            }
89811308Santhony.gutierrez@amd.com        }
89911308Santhony.gutierrez@amd.com
90011308Santhony.gutierrez@amd.com        return NoFault;
90111308Santhony.gutierrez@amd.com    };
90211308Santhony.gutierrez@amd.com
90311308Santhony.gutierrez@amd.com    Fault
90412749Sgiacomo.travaglini@arm.com    GpuTLB::translateAtomic(const RequestPtr &req, ThreadContext *tc,
90512749Sgiacomo.travaglini@arm.com                            Mode mode, int &latency)
90611308Santhony.gutierrez@amd.com    {
90711308Santhony.gutierrez@amd.com        bool delayedResponse;
90811308Santhony.gutierrez@amd.com
90911308Santhony.gutierrez@amd.com        return GpuTLB::translate(req, tc, nullptr, mode, delayedResponse, false,
91011308Santhony.gutierrez@amd.com                                 latency);
91111308Santhony.gutierrez@amd.com    }
91211308Santhony.gutierrez@amd.com
91311308Santhony.gutierrez@amd.com    void
91412749Sgiacomo.travaglini@arm.com    GpuTLB::translateTiming(const RequestPtr &req, ThreadContext *tc,
91511308Santhony.gutierrez@amd.com            Translation *translation, Mode mode, int &latency)
91611308Santhony.gutierrez@amd.com    {
91711308Santhony.gutierrez@amd.com        bool delayedResponse;
91811308Santhony.gutierrez@amd.com        assert(translation);
91911308Santhony.gutierrez@amd.com
92011308Santhony.gutierrez@amd.com        Fault fault = GpuTLB::translate(req, tc, translation, mode,
92111308Santhony.gutierrez@amd.com                                        delayedResponse, true, latency);
92211308Santhony.gutierrez@amd.com
92311308Santhony.gutierrez@amd.com        if (!delayedResponse)
92411308Santhony.gutierrez@amd.com            translation->finish(fault, req, tc, mode);
92511308Santhony.gutierrez@amd.com    }
92611308Santhony.gutierrez@amd.com
92711308Santhony.gutierrez@amd.com    Walker*
92811308Santhony.gutierrez@amd.com    GpuTLB::getWalker()
92911308Santhony.gutierrez@amd.com    {
93011308Santhony.gutierrez@amd.com        return walker;
93111308Santhony.gutierrez@amd.com    }
93211308Santhony.gutierrez@amd.com
93311308Santhony.gutierrez@amd.com
93411308Santhony.gutierrez@amd.com    void
93511308Santhony.gutierrez@amd.com    GpuTLB::serialize(CheckpointOut &cp) const
93611308Santhony.gutierrez@amd.com    {
93711308Santhony.gutierrez@amd.com    }
93811308Santhony.gutierrez@amd.com
93911308Santhony.gutierrez@amd.com    void
94011308Santhony.gutierrez@amd.com    GpuTLB::unserialize(CheckpointIn &cp)
94111308Santhony.gutierrez@amd.com    {
94211308Santhony.gutierrez@amd.com    }
94311308Santhony.gutierrez@amd.com
94411308Santhony.gutierrez@amd.com    void
94511308Santhony.gutierrez@amd.com    GpuTLB::regStats()
94611308Santhony.gutierrez@amd.com    {
94713892Sgabeblack@google.com        ClockedObject::regStats();
94811523Sdavid.guillen@arm.com
94911308Santhony.gutierrez@amd.com        localNumTLBAccesses
95011308Santhony.gutierrez@amd.com            .name(name() + ".local_TLB_accesses")
95111308Santhony.gutierrez@amd.com            .desc("Number of TLB accesses")
95211308Santhony.gutierrez@amd.com            ;
95311308Santhony.gutierrez@amd.com
95411308Santhony.gutierrez@amd.com        localNumTLBHits
95511308Santhony.gutierrez@amd.com            .name(name() + ".local_TLB_hits")
95611308Santhony.gutierrez@amd.com            .desc("Number of TLB hits")
95711308Santhony.gutierrez@amd.com            ;
95811308Santhony.gutierrez@amd.com
95911308Santhony.gutierrez@amd.com        localNumTLBMisses
96011308Santhony.gutierrez@amd.com            .name(name() + ".local_TLB_misses")
96111308Santhony.gutierrez@amd.com            .desc("Number of TLB misses")
96211308Santhony.gutierrez@amd.com            ;
96311308Santhony.gutierrez@amd.com
96411308Santhony.gutierrez@amd.com        localTLBMissRate
96511308Santhony.gutierrez@amd.com            .name(name() + ".local_TLB_miss_rate")
96611308Santhony.gutierrez@amd.com            .desc("TLB miss rate")
96711308Santhony.gutierrez@amd.com            ;
96811308Santhony.gutierrez@amd.com
96911308Santhony.gutierrez@amd.com        accessCycles
97011308Santhony.gutierrez@amd.com            .name(name() + ".access_cycles")
97111308Santhony.gutierrez@amd.com            .desc("Cycles spent accessing this TLB level")
97211308Santhony.gutierrez@amd.com            ;
97311308Santhony.gutierrez@amd.com
97411308Santhony.gutierrez@amd.com        pageTableCycles
97511308Santhony.gutierrez@amd.com            .name(name() + ".page_table_cycles")
97611308Santhony.gutierrez@amd.com            .desc("Cycles spent accessing the page table")
97711308Santhony.gutierrez@amd.com            ;
97811308Santhony.gutierrez@amd.com
97911308Santhony.gutierrez@amd.com        localTLBMissRate = 100 * localNumTLBMisses / localNumTLBAccesses;
98011308Santhony.gutierrez@amd.com
98111308Santhony.gutierrez@amd.com        numUniquePages
98211308Santhony.gutierrez@amd.com            .name(name() + ".unique_pages")
98311308Santhony.gutierrez@amd.com            .desc("Number of unique pages touched")
98411308Santhony.gutierrez@amd.com            ;
98511308Santhony.gutierrez@amd.com
98611308Santhony.gutierrez@amd.com        localCycles
98711308Santhony.gutierrez@amd.com            .name(name() + ".local_cycles")
98811308Santhony.gutierrez@amd.com            .desc("Number of cycles spent in queue for all incoming reqs")
98911308Santhony.gutierrez@amd.com            ;
99011308Santhony.gutierrez@amd.com
99111308Santhony.gutierrez@amd.com        localLatency
99211308Santhony.gutierrez@amd.com            .name(name() + ".local_latency")
99311308Santhony.gutierrez@amd.com            .desc("Avg. latency over incoming coalesced reqs")
99411308Santhony.gutierrez@amd.com            ;
99511308Santhony.gutierrez@amd.com
99611308Santhony.gutierrez@amd.com        localLatency = localCycles / localNumTLBAccesses;
99711308Santhony.gutierrez@amd.com
99811308Santhony.gutierrez@amd.com        globalNumTLBAccesses
99911308Santhony.gutierrez@amd.com            .name(name() + ".global_TLB_accesses")
100011308Santhony.gutierrez@amd.com            .desc("Number of TLB accesses")
100111308Santhony.gutierrez@amd.com            ;
100211308Santhony.gutierrez@amd.com
100311308Santhony.gutierrez@amd.com        globalNumTLBHits
100411308Santhony.gutierrez@amd.com            .name(name() + ".global_TLB_hits")
100511308Santhony.gutierrez@amd.com            .desc("Number of TLB hits")
100611308Santhony.gutierrez@amd.com            ;
100711308Santhony.gutierrez@amd.com
100811308Santhony.gutierrez@amd.com        globalNumTLBMisses
100911308Santhony.gutierrez@amd.com            .name(name() + ".global_TLB_misses")
101011308Santhony.gutierrez@amd.com            .desc("Number of TLB misses")
101111308Santhony.gutierrez@amd.com            ;
101211308Santhony.gutierrez@amd.com
101311308Santhony.gutierrez@amd.com        globalTLBMissRate
101411308Santhony.gutierrez@amd.com            .name(name() + ".global_TLB_miss_rate")
101511308Santhony.gutierrez@amd.com            .desc("TLB miss rate")
101611308Santhony.gutierrez@amd.com            ;
101711308Santhony.gutierrez@amd.com
101811308Santhony.gutierrez@amd.com        globalTLBMissRate = 100 * globalNumTLBMisses / globalNumTLBAccesses;
101911308Santhony.gutierrez@amd.com
102011308Santhony.gutierrez@amd.com        avgReuseDistance
102111308Santhony.gutierrez@amd.com            .name(name() + ".avg_reuse_distance")
102211308Santhony.gutierrez@amd.com            .desc("avg. reuse distance over all pages (in ticks)")
102311308Santhony.gutierrez@amd.com            ;
102411308Santhony.gutierrez@amd.com
102511308Santhony.gutierrez@amd.com    }
102611308Santhony.gutierrez@amd.com
102711308Santhony.gutierrez@amd.com    /**
102811308Santhony.gutierrez@amd.com     * Do the TLB lookup for this coalesced request and schedule
102911308Santhony.gutierrez@amd.com     * another event <TLB access latency> cycles later.
103011308Santhony.gutierrez@amd.com     */
103111308Santhony.gutierrez@amd.com
103211308Santhony.gutierrez@amd.com    void
103311308Santhony.gutierrez@amd.com    GpuTLB::issueTLBLookup(PacketPtr pkt)
103411308Santhony.gutierrez@amd.com    {
103511308Santhony.gutierrez@amd.com        assert(pkt);
103611308Santhony.gutierrez@amd.com        assert(pkt->senderState);
103711308Santhony.gutierrez@amd.com
103811308Santhony.gutierrez@amd.com        Addr virt_page_addr = roundDown(pkt->req->getVaddr(),
103911308Santhony.gutierrez@amd.com                                        TheISA::PageBytes);
104011308Santhony.gutierrez@amd.com
104111308Santhony.gutierrez@amd.com        TranslationState *sender_state =
104211308Santhony.gutierrez@amd.com                safe_cast<TranslationState*>(pkt->senderState);
104311308Santhony.gutierrez@amd.com
104411308Santhony.gutierrez@amd.com        bool update_stats = !sender_state->prefetch;
104511308Santhony.gutierrez@amd.com        ThreadContext * tmp_tc = sender_state->tc;
104611308Santhony.gutierrez@amd.com
104711308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Translation req. for virt. page addr %#x\n",
104811308Santhony.gutierrez@amd.com                virt_page_addr);
104911308Santhony.gutierrez@amd.com
105011308Santhony.gutierrez@amd.com        int req_cnt = sender_state->reqCnt.back();
105111308Santhony.gutierrez@amd.com
105211308Santhony.gutierrez@amd.com        if (update_stats) {
105311308Santhony.gutierrez@amd.com            accessCycles -= (curTick() * req_cnt);
105411308Santhony.gutierrez@amd.com            localCycles -= curTick();
105511308Santhony.gutierrez@amd.com            updatePageFootprint(virt_page_addr);
105611308Santhony.gutierrez@amd.com            globalNumTLBAccesses += req_cnt;
105711308Santhony.gutierrez@amd.com        }
105811308Santhony.gutierrez@amd.com
105911308Santhony.gutierrez@amd.com        tlbOutcome lookup_outcome = TLB_MISS;
106012749Sgiacomo.travaglini@arm.com        const RequestPtr &tmp_req = pkt->req;
106111308Santhony.gutierrez@amd.com
106211308Santhony.gutierrez@amd.com        // Access the TLB and figure out if it's a hit or a miss.
106311308Santhony.gutierrez@amd.com        bool success = tlbLookup(tmp_req, tmp_tc, update_stats);
106411308Santhony.gutierrez@amd.com
106511308Santhony.gutierrez@amd.com        if (success) {
106611308Santhony.gutierrez@amd.com            lookup_outcome = TLB_HIT;
106711308Santhony.gutierrez@amd.com            // Put the entry in SenderState
106812717Sbrandon.potter@amd.com            TlbEntry *entry = lookup(tmp_req->getVaddr(), false);
106911308Santhony.gutierrez@amd.com            assert(entry);
107011308Santhony.gutierrez@amd.com
107112717Sbrandon.potter@amd.com            auto p = sender_state->tc->getProcessPtr();
107211308Santhony.gutierrez@amd.com            sender_state->tlbEntry =
107312717Sbrandon.potter@amd.com                new TlbEntry(p->pid(), entry->vaddr, entry->paddr,
107412717Sbrandon.potter@amd.com                             false, false);
107511308Santhony.gutierrez@amd.com
107611308Santhony.gutierrez@amd.com            if (update_stats) {
107711308Santhony.gutierrez@amd.com                // the reqCnt has an entry per level, so its size tells us
107811308Santhony.gutierrez@amd.com                // which level we are in
107911308Santhony.gutierrez@amd.com                sender_state->hitLevel = sender_state->reqCnt.size();
108011308Santhony.gutierrez@amd.com                globalNumTLBHits += req_cnt;
108111308Santhony.gutierrez@amd.com            }
108211308Santhony.gutierrez@amd.com        } else {
108311308Santhony.gutierrez@amd.com            if (update_stats)
108411308Santhony.gutierrez@amd.com                globalNumTLBMisses += req_cnt;
108511308Santhony.gutierrez@amd.com        }
108611308Santhony.gutierrez@amd.com
108711308Santhony.gutierrez@amd.com        /*
108811308Santhony.gutierrez@amd.com         * We now know the TLB lookup outcome (if it's a hit or a miss), as well
108911308Santhony.gutierrez@amd.com         * as the TLB access latency.
109011308Santhony.gutierrez@amd.com         *
109111308Santhony.gutierrez@amd.com         * We create and schedule a new TLBEvent which will help us take the
109211308Santhony.gutierrez@amd.com         * appropriate actions (e.g., update TLB on a hit, send request to lower
109311308Santhony.gutierrez@amd.com         * level TLB on a miss, or start a page walk if this was the last-level
109411308Santhony.gutierrez@amd.com         * TLB)
109511308Santhony.gutierrez@amd.com         */
109611308Santhony.gutierrez@amd.com        TLBEvent *tlb_event =
109711308Santhony.gutierrez@amd.com            new TLBEvent(this, virt_page_addr, lookup_outcome, pkt);
109811308Santhony.gutierrez@amd.com
109911308Santhony.gutierrez@amd.com        if (translationReturnEvent.count(virt_page_addr)) {
110011308Santhony.gutierrez@amd.com            panic("Virtual Page Address %#x already has a return event\n",
110111308Santhony.gutierrez@amd.com                  virt_page_addr);
110211308Santhony.gutierrez@amd.com        }
110311308Santhony.gutierrez@amd.com
110411308Santhony.gutierrez@amd.com        translationReturnEvent[virt_page_addr] = tlb_event;
110511308Santhony.gutierrez@amd.com        assert(tlb_event);
110611308Santhony.gutierrez@amd.com
110711308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "schedule translationReturnEvent @ curTick %d\n",
110811308Santhony.gutierrez@amd.com                curTick() + this->ticks(hitLatency));
110911308Santhony.gutierrez@amd.com
111011308Santhony.gutierrez@amd.com        schedule(tlb_event, curTick() + this->ticks(hitLatency));
111111308Santhony.gutierrez@amd.com    }
111211308Santhony.gutierrez@amd.com
111311308Santhony.gutierrez@amd.com    GpuTLB::TLBEvent::TLBEvent(GpuTLB* _tlb, Addr _addr, tlbOutcome tlb_outcome,
111411308Santhony.gutierrez@amd.com                               PacketPtr _pkt)
111511308Santhony.gutierrez@amd.com        : Event(CPU_Tick_Pri), tlb(_tlb), virtPageAddr(_addr),
111611308Santhony.gutierrez@amd.com        outcome(tlb_outcome), pkt(_pkt)
111711308Santhony.gutierrez@amd.com    {
111811308Santhony.gutierrez@amd.com    }
111911308Santhony.gutierrez@amd.com
112011308Santhony.gutierrez@amd.com    /**
112111308Santhony.gutierrez@amd.com     * Do Paging protection checks. If we encounter a page fault, then
112211308Santhony.gutierrez@amd.com     * an assertion is fired.
112311308Santhony.gutierrez@amd.com     */
112411308Santhony.gutierrez@amd.com    void
112511308Santhony.gutierrez@amd.com    GpuTLB::pagingProtectionChecks(ThreadContext *tc, PacketPtr pkt,
112612717Sbrandon.potter@amd.com            TlbEntry * tlb_entry, Mode mode)
112711308Santhony.gutierrez@amd.com    {
112811308Santhony.gutierrez@amd.com        HandyM5Reg m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
112911308Santhony.gutierrez@amd.com        uint32_t flags = pkt->req->getFlags();
113011308Santhony.gutierrez@amd.com        bool storeCheck = flags & (StoreCheck << FlagShift);
113111308Santhony.gutierrez@amd.com
113211308Santhony.gutierrez@amd.com        // Do paging protection checks.
113311308Santhony.gutierrez@amd.com        bool inUser = (m5Reg.cpl == 3 && !(flags & (CPL0FlagBit << FlagShift)));
113411308Santhony.gutierrez@amd.com        CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
113511308Santhony.gutierrez@amd.com
113611308Santhony.gutierrez@amd.com        bool badWrite = (!tlb_entry->writable && (inUser || cr0.wp));
113711308Santhony.gutierrez@amd.com
113811308Santhony.gutierrez@amd.com        if ((inUser && !tlb_entry->user) ||
113911308Santhony.gutierrez@amd.com            (mode == BaseTLB::Write && badWrite)) {
114013449Sgabeblack@google.com            // The page must have been present to get into the TLB in
114113449Sgabeblack@google.com            // the first place. We'll assume the reserved bits are
114213449Sgabeblack@google.com            // fine even though we're not checking them.
114313449Sgabeblack@google.com            panic("Page fault detected");
114411308Santhony.gutierrez@amd.com        }
114511308Santhony.gutierrez@amd.com
114611308Santhony.gutierrez@amd.com        if (storeCheck && badWrite) {
114713449Sgabeblack@google.com            // This would fault if this were a write, so return a page
114813449Sgabeblack@google.com            // fault that reflects that happening.
114913449Sgabeblack@google.com            panic("Page fault detected");
115011308Santhony.gutierrez@amd.com        }
115111308Santhony.gutierrez@amd.com    }
115211308Santhony.gutierrez@amd.com
115311308Santhony.gutierrez@amd.com    /**
115411308Santhony.gutierrez@amd.com     * handleTranslationReturn is called on a TLB hit,
115511308Santhony.gutierrez@amd.com     * when a TLB miss returns or when a page fault returns.
115611308Santhony.gutierrez@amd.com     * The latter calls handelHit with TLB miss as tlbOutcome.
115711308Santhony.gutierrez@amd.com     */
115811308Santhony.gutierrez@amd.com    void
115911308Santhony.gutierrez@amd.com    GpuTLB::handleTranslationReturn(Addr virt_page_addr, tlbOutcome tlb_outcome,
116011308Santhony.gutierrez@amd.com            PacketPtr pkt)
116111308Santhony.gutierrez@amd.com    {
116211308Santhony.gutierrez@amd.com
116311308Santhony.gutierrez@amd.com        assert(pkt);
116411308Santhony.gutierrez@amd.com        Addr vaddr = pkt->req->getVaddr();
116511308Santhony.gutierrez@amd.com
116611308Santhony.gutierrez@amd.com        TranslationState *sender_state =
116711308Santhony.gutierrez@amd.com            safe_cast<TranslationState*>(pkt->senderState);
116811308Santhony.gutierrez@amd.com
116911308Santhony.gutierrez@amd.com        ThreadContext *tc = sender_state->tc;
117011308Santhony.gutierrez@amd.com        Mode mode = sender_state->tlbMode;
117111308Santhony.gutierrez@amd.com
117212717Sbrandon.potter@amd.com        TlbEntry *local_entry, *new_entry;
117311308Santhony.gutierrez@amd.com
117411308Santhony.gutierrez@amd.com        if (tlb_outcome == TLB_HIT) {
117511308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Translation Done - TLB Hit for addr %#x\n", vaddr);
117611308Santhony.gutierrez@amd.com            local_entry = sender_state->tlbEntry;
117711308Santhony.gutierrez@amd.com        } else {
117811308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Translation Done - TLB Miss for addr %#x\n",
117911308Santhony.gutierrez@amd.com                    vaddr);
118011308Santhony.gutierrez@amd.com
118111308Santhony.gutierrez@amd.com            // We are returning either from a page walk or from a hit at a lower
118211308Santhony.gutierrez@amd.com            // TLB level. The senderState should be "carrying" a pointer to the
118311308Santhony.gutierrez@amd.com            // correct TLBEntry.
118411308Santhony.gutierrez@amd.com            new_entry = sender_state->tlbEntry;
118511308Santhony.gutierrez@amd.com            assert(new_entry);
118611308Santhony.gutierrez@amd.com            local_entry = new_entry;
118711308Santhony.gutierrez@amd.com
118811308Santhony.gutierrez@amd.com            if (allocationPolicy) {
118911308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "allocating entry w/ addr %#x\n",
119011308Santhony.gutierrez@amd.com                        virt_page_addr);
119111308Santhony.gutierrez@amd.com
119211308Santhony.gutierrez@amd.com                local_entry = insert(virt_page_addr, *new_entry);
119311308Santhony.gutierrez@amd.com            }
119411308Santhony.gutierrez@amd.com
119511308Santhony.gutierrez@amd.com            assert(local_entry);
119611308Santhony.gutierrez@amd.com        }
119711308Santhony.gutierrez@amd.com
119811308Santhony.gutierrez@amd.com        /**
119911308Santhony.gutierrez@amd.com         * At this point the packet carries an up-to-date tlbEntry pointer
120011308Santhony.gutierrez@amd.com         * in its senderState.
120111308Santhony.gutierrez@amd.com         * Next step is to do the paging protection checks.
120211308Santhony.gutierrez@amd.com         */
120311308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Entry found with vaddr %#x,  doing protection checks "
120411308Santhony.gutierrez@amd.com                "while paddr was %#x.\n", local_entry->vaddr,
120511308Santhony.gutierrez@amd.com                local_entry->paddr);
120611308Santhony.gutierrez@amd.com
120711308Santhony.gutierrez@amd.com        pagingProtectionChecks(tc, pkt, local_entry, mode);
120811308Santhony.gutierrez@amd.com        int page_size = local_entry->size();
120911308Santhony.gutierrez@amd.com        Addr paddr = local_entry->paddr | (vaddr & (page_size - 1));
121011308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Translated %#x -> %#x.\n", vaddr, paddr);
121111308Santhony.gutierrez@amd.com
121211308Santhony.gutierrez@amd.com        // Since this packet will be sent through the cpu side slave port,
121311308Santhony.gutierrez@amd.com        // it must be converted to a response pkt if it is not one already
121411308Santhony.gutierrez@amd.com        if (pkt->isRequest()) {
121511308Santhony.gutierrez@amd.com            pkt->makeTimingResponse();
121611308Santhony.gutierrez@amd.com        }
121711308Santhony.gutierrez@amd.com
121811308Santhony.gutierrez@amd.com        pkt->req->setPaddr(paddr);
121911308Santhony.gutierrez@amd.com
122011308Santhony.gutierrez@amd.com        if (local_entry->uncacheable) {
122111308Santhony.gutierrez@amd.com             pkt->req->setFlags(Request::UNCACHEABLE);
122211308Santhony.gutierrez@amd.com        }
122311308Santhony.gutierrez@amd.com
122411308Santhony.gutierrez@amd.com        //send packet back to coalescer
122511308Santhony.gutierrez@amd.com        cpuSidePort[0]->sendTimingResp(pkt);
122611308Santhony.gutierrez@amd.com        //schedule cleanup event
122711308Santhony.gutierrez@amd.com        cleanupQueue.push(virt_page_addr);
122811308Santhony.gutierrez@amd.com
122911308Santhony.gutierrez@amd.com        // schedule this only once per cycle.
123011308Santhony.gutierrez@amd.com        // The check is required because we might have multiple translations
123111308Santhony.gutierrez@amd.com        // returning the same cycle
123211308Santhony.gutierrez@amd.com        // this is a maximum priority event and must be on the same cycle
123311308Santhony.gutierrez@amd.com        // as the cleanup event in TLBCoalescer to avoid a race with
123411308Santhony.gutierrez@amd.com        // IssueProbeEvent caused by TLBCoalescer::MemSidePort::recvReqRetry
123511308Santhony.gutierrez@amd.com        if (!cleanupEvent.scheduled())
123611308Santhony.gutierrez@amd.com            schedule(cleanupEvent, curTick());
123711308Santhony.gutierrez@amd.com    }
123811308Santhony.gutierrez@amd.com
123911308Santhony.gutierrez@amd.com    /**
124011308Santhony.gutierrez@amd.com     * Here we take the appropriate actions based on the result of the
124111308Santhony.gutierrez@amd.com     * TLB lookup.
124211308Santhony.gutierrez@amd.com     */
124311308Santhony.gutierrez@amd.com    void
124411308Santhony.gutierrez@amd.com    GpuTLB::translationReturn(Addr virtPageAddr, tlbOutcome outcome,
124511308Santhony.gutierrez@amd.com                              PacketPtr pkt)
124611308Santhony.gutierrez@amd.com    {
124711308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Triggered TLBEvent for addr %#x\n", virtPageAddr);
124811308Santhony.gutierrez@amd.com
124911308Santhony.gutierrez@amd.com        assert(translationReturnEvent[virtPageAddr]);
125011308Santhony.gutierrez@amd.com        assert(pkt);
125111308Santhony.gutierrez@amd.com
125211308Santhony.gutierrez@amd.com        TranslationState *tmp_sender_state =
125311308Santhony.gutierrez@amd.com            safe_cast<TranslationState*>(pkt->senderState);
125411308Santhony.gutierrez@amd.com
125511308Santhony.gutierrez@amd.com        int req_cnt = tmp_sender_state->reqCnt.back();
125611308Santhony.gutierrez@amd.com        bool update_stats = !tmp_sender_state->prefetch;
125711308Santhony.gutierrez@amd.com
125811308Santhony.gutierrez@amd.com
125911308Santhony.gutierrez@amd.com        if (outcome == TLB_HIT) {
126011308Santhony.gutierrez@amd.com            handleTranslationReturn(virtPageAddr, TLB_HIT, pkt);
126111308Santhony.gutierrez@amd.com
126211308Santhony.gutierrez@amd.com            if (update_stats) {
126311308Santhony.gutierrez@amd.com                accessCycles += (req_cnt * curTick());
126411308Santhony.gutierrez@amd.com                localCycles += curTick();
126511308Santhony.gutierrez@amd.com            }
126611308Santhony.gutierrez@amd.com
126711308Santhony.gutierrez@amd.com        } else if (outcome == TLB_MISS) {
126811308Santhony.gutierrez@amd.com
126911308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "This is a TLB miss\n");
127011308Santhony.gutierrez@amd.com            if (update_stats) {
127111308Santhony.gutierrez@amd.com                accessCycles += (req_cnt*curTick());
127211308Santhony.gutierrez@amd.com                localCycles += curTick();
127311308Santhony.gutierrez@amd.com            }
127411308Santhony.gutierrez@amd.com
127511308Santhony.gutierrez@amd.com            if (hasMemSidePort) {
127611308Santhony.gutierrez@amd.com                // the one cyle added here represent the delay from when we get
127711308Santhony.gutierrez@amd.com                // the reply back till when we propagate it to the coalescer
127811308Santhony.gutierrez@amd.com                // above.
127911308Santhony.gutierrez@amd.com                if (update_stats) {
128011308Santhony.gutierrez@amd.com                    accessCycles += (req_cnt * 1);
128111308Santhony.gutierrez@amd.com                    localCycles += 1;
128211308Santhony.gutierrez@amd.com                }
128311308Santhony.gutierrez@amd.com
128411308Santhony.gutierrez@amd.com                /**
128511308Santhony.gutierrez@amd.com                 * There is a TLB below. Send the coalesced request.
128611308Santhony.gutierrez@amd.com                 * We actually send the very first packet of all the
128711308Santhony.gutierrez@amd.com                 * pending packets for this virtual page address.
128811308Santhony.gutierrez@amd.com                 */
128911308Santhony.gutierrez@amd.com                if (!memSidePort[0]->sendTimingReq(pkt)) {
129011308Santhony.gutierrez@amd.com                    DPRINTF(GPUTLB, "Failed sending translation request to "
129111308Santhony.gutierrez@amd.com                            "lower level TLB for addr %#x\n", virtPageAddr);
129211308Santhony.gutierrez@amd.com
129311308Santhony.gutierrez@amd.com                    memSidePort[0]->retries.push_back(pkt);
129411308Santhony.gutierrez@amd.com                } else {
129511308Santhony.gutierrez@amd.com                    DPRINTF(GPUTLB, "Sent translation request to lower level "
129611308Santhony.gutierrez@amd.com                            "TLB for addr %#x\n", virtPageAddr);
129711308Santhony.gutierrez@amd.com                }
129811308Santhony.gutierrez@amd.com            } else {
129911308Santhony.gutierrez@amd.com                //this is the last level TLB. Start a page walk
130011308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Last level TLB - start a page walk for "
130111308Santhony.gutierrez@amd.com                        "addr %#x\n", virtPageAddr);
130211308Santhony.gutierrez@amd.com
130311308Santhony.gutierrez@amd.com                if (update_stats)
130411308Santhony.gutierrez@amd.com                    pageTableCycles -= (req_cnt*curTick());
130511308Santhony.gutierrez@amd.com
130611308Santhony.gutierrez@amd.com                TLBEvent *tlb_event = translationReturnEvent[virtPageAddr];
130711308Santhony.gutierrez@amd.com                assert(tlb_event);
130811308Santhony.gutierrez@amd.com                tlb_event->updateOutcome(PAGE_WALK);
130911308Santhony.gutierrez@amd.com                schedule(tlb_event, curTick() + ticks(missLatency2));
131011308Santhony.gutierrez@amd.com            }
131111308Santhony.gutierrez@amd.com        } else if (outcome == PAGE_WALK) {
131211308Santhony.gutierrez@amd.com            if (update_stats)
131311308Santhony.gutierrez@amd.com                pageTableCycles += (req_cnt*curTick());
131411308Santhony.gutierrez@amd.com
131511308Santhony.gutierrez@amd.com            // Need to access the page table and update the TLB
131611308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Doing a page walk for address %#x\n",
131711308Santhony.gutierrez@amd.com                    virtPageAddr);
131811308Santhony.gutierrez@amd.com
131911308Santhony.gutierrez@amd.com            TranslationState *sender_state =
132011308Santhony.gutierrez@amd.com                safe_cast<TranslationState*>(pkt->senderState);
132111308Santhony.gutierrez@amd.com
132211308Santhony.gutierrez@amd.com            Process *p = sender_state->tc->getProcessPtr();
132311308Santhony.gutierrez@amd.com            Addr vaddr = pkt->req->getVaddr();
132411308Santhony.gutierrez@amd.com    #ifndef NDEBUG
132511308Santhony.gutierrez@amd.com            Addr alignedVaddr = p->pTable->pageAlign(vaddr);
132611308Santhony.gutierrez@amd.com            assert(alignedVaddr == virtPageAddr);
132711308Santhony.gutierrez@amd.com    #endif
132812461Sgabeblack@google.com            const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr);
132912461Sgabeblack@google.com            if (!pte && sender_state->tlbMode != BaseTLB::Execute &&
133012455Sgabeblack@google.com                    p->fixupStackFault(vaddr)) {
133112461Sgabeblack@google.com                pte = p->pTable->lookup(vaddr);
133211308Santhony.gutierrez@amd.com            }
133311308Santhony.gutierrez@amd.com
133412461Sgabeblack@google.com            if (pte) {
133512455Sgabeblack@google.com                DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
133612461Sgabeblack@google.com                        pte->paddr);
133711308Santhony.gutierrez@amd.com
133812455Sgabeblack@google.com                sender_state->tlbEntry =
133912717Sbrandon.potter@amd.com                    new TlbEntry(p->pid(), virtPageAddr, pte->paddr, false,
134012717Sbrandon.potter@amd.com                                 false);
134112455Sgabeblack@google.com            } else {
134212717Sbrandon.potter@amd.com                sender_state->tlbEntry = nullptr;
134312455Sgabeblack@google.com            }
134411308Santhony.gutierrez@amd.com
134511308Santhony.gutierrez@amd.com            handleTranslationReturn(virtPageAddr, TLB_MISS, pkt);
134611308Santhony.gutierrez@amd.com        } else if (outcome == MISS_RETURN) {
134711308Santhony.gutierrez@amd.com            /** we add an extra cycle in the return path of the translation
134811308Santhony.gutierrez@amd.com             * requests in between the various TLB levels.
134911308Santhony.gutierrez@amd.com             */
135011308Santhony.gutierrez@amd.com            handleTranslationReturn(virtPageAddr, TLB_MISS, pkt);
135111308Santhony.gutierrez@amd.com        } else {
135213449Sgabeblack@google.com            panic("Unexpected TLB outcome %d", outcome);
135311308Santhony.gutierrez@amd.com        }
135411308Santhony.gutierrez@amd.com    }
135511308Santhony.gutierrez@amd.com
135611308Santhony.gutierrez@amd.com    void
135711308Santhony.gutierrez@amd.com    GpuTLB::TLBEvent::process()
135811308Santhony.gutierrez@amd.com    {
135911308Santhony.gutierrez@amd.com        tlb->translationReturn(virtPageAddr, outcome, pkt);
136011308Santhony.gutierrez@amd.com    }
136111308Santhony.gutierrez@amd.com
136211308Santhony.gutierrez@amd.com    const char*
136311308Santhony.gutierrez@amd.com    GpuTLB::TLBEvent::description() const
136411308Santhony.gutierrez@amd.com    {
136511308Santhony.gutierrez@amd.com        return "trigger translationDoneEvent";
136611308Santhony.gutierrez@amd.com    }
136711308Santhony.gutierrez@amd.com
136811308Santhony.gutierrez@amd.com    void
136911308Santhony.gutierrez@amd.com    GpuTLB::TLBEvent::updateOutcome(tlbOutcome _outcome)
137011308Santhony.gutierrez@amd.com    {
137111308Santhony.gutierrez@amd.com        outcome = _outcome;
137211308Santhony.gutierrez@amd.com    }
137311308Santhony.gutierrez@amd.com
137411308Santhony.gutierrez@amd.com    Addr
137511308Santhony.gutierrez@amd.com    GpuTLB::TLBEvent::getTLBEventVaddr()
137611308Santhony.gutierrez@amd.com    {
137711308Santhony.gutierrez@amd.com        return virtPageAddr;
137811308Santhony.gutierrez@amd.com    }
137911308Santhony.gutierrez@amd.com
138011308Santhony.gutierrez@amd.com    /*
138111308Santhony.gutierrez@amd.com     * recvTiming receives a coalesced timing request from a TLBCoalescer
138211308Santhony.gutierrez@amd.com     * and it calls issueTLBLookup()
138311308Santhony.gutierrez@amd.com     * It only rejects the packet if we have exceeded the max
138411308Santhony.gutierrez@amd.com     * outstanding number of requests for the TLB
138511308Santhony.gutierrez@amd.com     */
138611308Santhony.gutierrez@amd.com    bool
138711308Santhony.gutierrez@amd.com    GpuTLB::CpuSidePort::recvTimingReq(PacketPtr pkt)
138811308Santhony.gutierrez@amd.com    {
138911308Santhony.gutierrez@amd.com        if (tlb->outstandingReqs < tlb->maxCoalescedReqs) {
139011308Santhony.gutierrez@amd.com            tlb->issueTLBLookup(pkt);
139111308Santhony.gutierrez@amd.com            // update number of outstanding translation requests
139211308Santhony.gutierrez@amd.com            tlb->outstandingReqs++;
139311308Santhony.gutierrez@amd.com            return true;
139411308Santhony.gutierrez@amd.com         } else {
139511308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Reached maxCoalescedReqs number %d\n",
139611308Santhony.gutierrez@amd.com                    tlb->outstandingReqs);
139711308Santhony.gutierrez@amd.com            return false;
139811308Santhony.gutierrez@amd.com         }
139911308Santhony.gutierrez@amd.com    }
140011308Santhony.gutierrez@amd.com
140111308Santhony.gutierrez@amd.com    /**
140211308Santhony.gutierrez@amd.com     * handleFuncTranslationReturn is called on a TLB hit,
140311308Santhony.gutierrez@amd.com     * when a TLB miss returns or when a page fault returns.
140411308Santhony.gutierrez@amd.com     * It updates LRU, inserts the TLB entry on a miss
140511308Santhony.gutierrez@amd.com     * depending on the allocation policy and does the required
140611308Santhony.gutierrez@amd.com     * protection checks. It does NOT create a new packet to
140711308Santhony.gutierrez@amd.com     * update the packet's addr; this is done in hsail-gpu code.
140811308Santhony.gutierrez@amd.com     */
140911308Santhony.gutierrez@amd.com    void
141011308Santhony.gutierrez@amd.com    GpuTLB::handleFuncTranslationReturn(PacketPtr pkt, tlbOutcome tlb_outcome)
141111308Santhony.gutierrez@amd.com    {
141211308Santhony.gutierrez@amd.com        TranslationState *sender_state =
141311308Santhony.gutierrez@amd.com            safe_cast<TranslationState*>(pkt->senderState);
141411308Santhony.gutierrez@amd.com
141511308Santhony.gutierrez@amd.com        ThreadContext *tc = sender_state->tc;
141611308Santhony.gutierrez@amd.com        Mode mode = sender_state->tlbMode;
141711308Santhony.gutierrez@amd.com        Addr vaddr = pkt->req->getVaddr();
141811308Santhony.gutierrez@amd.com
141912717Sbrandon.potter@amd.com        TlbEntry *local_entry, *new_entry;
142011308Santhony.gutierrez@amd.com
142111308Santhony.gutierrez@amd.com        if (tlb_outcome == TLB_HIT) {
142211308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Functional Translation Done - TLB hit for addr "
142311308Santhony.gutierrez@amd.com                    "%#x\n", vaddr);
142411308Santhony.gutierrez@amd.com
142511308Santhony.gutierrez@amd.com            local_entry = sender_state->tlbEntry;
142611308Santhony.gutierrez@amd.com        } else {
142711308Santhony.gutierrez@amd.com            DPRINTF(GPUTLB, "Functional Translation Done - TLB miss for addr "
142811308Santhony.gutierrez@amd.com                    "%#x\n", vaddr);
142911308Santhony.gutierrez@amd.com
143011308Santhony.gutierrez@amd.com            // We are returning either from a page walk or from a hit at a lower
143111308Santhony.gutierrez@amd.com            // TLB level. The senderState should be "carrying" a pointer to the
143211308Santhony.gutierrez@amd.com            // correct TLBEntry.
143311308Santhony.gutierrez@amd.com            new_entry = sender_state->tlbEntry;
143411308Santhony.gutierrez@amd.com            assert(new_entry);
143511308Santhony.gutierrez@amd.com            local_entry = new_entry;
143611308Santhony.gutierrez@amd.com
143711308Santhony.gutierrez@amd.com            if (allocationPolicy) {
143811308Santhony.gutierrez@amd.com                Addr virt_page_addr = roundDown(vaddr, TheISA::PageBytes);
143911308Santhony.gutierrez@amd.com
144011308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "allocating entry w/ addr %#x\n",
144111308Santhony.gutierrez@amd.com                        virt_page_addr);
144211308Santhony.gutierrez@amd.com
144311308Santhony.gutierrez@amd.com                local_entry = insert(virt_page_addr, *new_entry);
144411308Santhony.gutierrez@amd.com            }
144511308Santhony.gutierrez@amd.com
144611308Santhony.gutierrez@amd.com            assert(local_entry);
144711308Santhony.gutierrez@amd.com        }
144811308Santhony.gutierrez@amd.com
144911308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Entry found with vaddr %#x, doing protection checks "
145011308Santhony.gutierrez@amd.com                "while paddr was %#x.\n", local_entry->vaddr,
145111308Santhony.gutierrez@amd.com                local_entry->paddr);
145211308Santhony.gutierrez@amd.com
145312717Sbrandon.potter@amd.com        /**
145412717Sbrandon.potter@amd.com         * Do paging checks if it's a normal functional access.  If it's for a
145512717Sbrandon.potter@amd.com         * prefetch, then sometimes you can try to prefetch something that
145612717Sbrandon.potter@amd.com         * won't pass protection. We don't actually want to fault becuase there
145712717Sbrandon.potter@amd.com         * is no demand access to deem this a violation.  Just put it in the
145812717Sbrandon.potter@amd.com         * TLB and it will fault if indeed a future demand access touches it in
145912717Sbrandon.potter@amd.com         * violation.
146012717Sbrandon.potter@amd.com         *
146112717Sbrandon.potter@amd.com         * This feature could be used to explore security issues around
146212717Sbrandon.potter@amd.com         * speculative memory accesses.
146312717Sbrandon.potter@amd.com         */
146412717Sbrandon.potter@amd.com        if (!sender_state->prefetch && sender_state->tlbEntry)
146511308Santhony.gutierrez@amd.com            pagingProtectionChecks(tc, pkt, local_entry, mode);
146611308Santhony.gutierrez@amd.com
146711308Santhony.gutierrez@amd.com        int page_size = local_entry->size();
146811308Santhony.gutierrez@amd.com        Addr paddr = local_entry->paddr | (vaddr & (page_size - 1));
146911308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "Translated %#x -> %#x.\n", vaddr, paddr);
147011308Santhony.gutierrez@amd.com
147111308Santhony.gutierrez@amd.com        pkt->req->setPaddr(paddr);
147211308Santhony.gutierrez@amd.com
147311308Santhony.gutierrez@amd.com        if (local_entry->uncacheable)
147411308Santhony.gutierrez@amd.com             pkt->req->setFlags(Request::UNCACHEABLE);
147511308Santhony.gutierrez@amd.com    }
147611308Santhony.gutierrez@amd.com
147711308Santhony.gutierrez@amd.com    // This is used for atomic translations. Need to
147811308Santhony.gutierrez@amd.com    // make it all happen during the same cycle.
147911308Santhony.gutierrez@amd.com    void
148011308Santhony.gutierrez@amd.com    GpuTLB::CpuSidePort::recvFunctional(PacketPtr pkt)
148111308Santhony.gutierrez@amd.com    {
148211308Santhony.gutierrez@amd.com        TranslationState *sender_state =
148311308Santhony.gutierrez@amd.com            safe_cast<TranslationState*>(pkt->senderState);
148411308Santhony.gutierrez@amd.com
148511308Santhony.gutierrez@amd.com        ThreadContext *tc = sender_state->tc;
148611308Santhony.gutierrez@amd.com        bool update_stats = !sender_state->prefetch;
148711308Santhony.gutierrez@amd.com
148811308Santhony.gutierrez@amd.com        Addr virt_page_addr = roundDown(pkt->req->getVaddr(),
148911308Santhony.gutierrez@amd.com                                        TheISA::PageBytes);
149011308Santhony.gutierrez@amd.com
149111308Santhony.gutierrez@amd.com        if (update_stats)
149211308Santhony.gutierrez@amd.com            tlb->updatePageFootprint(virt_page_addr);
149311308Santhony.gutierrez@amd.com
149411308Santhony.gutierrez@amd.com        // do the TLB lookup without updating the stats
149511308Santhony.gutierrez@amd.com        bool success = tlb->tlbLookup(pkt->req, tc, update_stats);
149611308Santhony.gutierrez@amd.com        tlbOutcome tlb_outcome = success ? TLB_HIT : TLB_MISS;
149711308Santhony.gutierrez@amd.com
149811308Santhony.gutierrez@amd.com        // functional mode means no coalescing
149911308Santhony.gutierrez@amd.com        // global metrics are the same as the local metrics
150011308Santhony.gutierrez@amd.com        if (update_stats) {
150111308Santhony.gutierrez@amd.com            tlb->globalNumTLBAccesses++;
150211308Santhony.gutierrez@amd.com
150311308Santhony.gutierrez@amd.com            if (success) {
150411308Santhony.gutierrez@amd.com                sender_state->hitLevel = sender_state->reqCnt.size();
150511308Santhony.gutierrez@amd.com                tlb->globalNumTLBHits++;
150611308Santhony.gutierrez@amd.com            }
150711308Santhony.gutierrez@amd.com        }
150811308Santhony.gutierrez@amd.com
150911308Santhony.gutierrez@amd.com        if (!success) {
151011308Santhony.gutierrez@amd.com            if (update_stats)
151111308Santhony.gutierrez@amd.com                tlb->globalNumTLBMisses++;
151211308Santhony.gutierrez@amd.com            if (tlb->hasMemSidePort) {
151311308Santhony.gutierrez@amd.com                // there is a TLB below -> propagate down the TLB hierarchy
151411308Santhony.gutierrez@amd.com                tlb->memSidePort[0]->sendFunctional(pkt);
151511308Santhony.gutierrez@amd.com                // If no valid translation from a prefetch, then just return
151611308Santhony.gutierrez@amd.com                if (sender_state->prefetch && !pkt->req->hasPaddr())
151711308Santhony.gutierrez@amd.com                    return;
151811308Santhony.gutierrez@amd.com            } else {
151911308Santhony.gutierrez@amd.com                // Need to access the page table and update the TLB
152011308Santhony.gutierrez@amd.com                DPRINTF(GPUTLB, "Doing a page walk for address %#x\n",
152111308Santhony.gutierrez@amd.com                        virt_page_addr);
152211308Santhony.gutierrez@amd.com
152311308Santhony.gutierrez@amd.com                Process *p = tc->getProcessPtr();
152411308Santhony.gutierrez@amd.com
152511308Santhony.gutierrez@amd.com                Addr vaddr = pkt->req->getVaddr();
152611308Santhony.gutierrez@amd.com    #ifndef NDEBUG
152711308Santhony.gutierrez@amd.com                Addr alignedVaddr = p->pTable->pageAlign(vaddr);
152811308Santhony.gutierrez@amd.com                assert(alignedVaddr == virt_page_addr);
152911308Santhony.gutierrez@amd.com    #endif
153011308Santhony.gutierrez@amd.com
153112461Sgabeblack@google.com                const EmulationPageTable::Entry *pte =
153212461Sgabeblack@google.com                        p->pTable->lookup(vaddr);
153312461Sgabeblack@google.com                if (!pte && sender_state->tlbMode != BaseTLB::Execute &&
153412455Sgabeblack@google.com                        p->fixupStackFault(vaddr)) {
153512461Sgabeblack@google.com                    pte = p->pTable->lookup(vaddr);
153611308Santhony.gutierrez@amd.com                }
153711308Santhony.gutierrez@amd.com
153811308Santhony.gutierrez@amd.com                if (!sender_state->prefetch) {
153911308Santhony.gutierrez@amd.com                    // no PageFaults are permitted after
154011308Santhony.gutierrez@amd.com                    // the second page table lookup
154112663Santhony.gutierrez@amd.com                    assert(pte);
154211308Santhony.gutierrez@amd.com
154311308Santhony.gutierrez@amd.com                    DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
154412461Sgabeblack@google.com                            pte->paddr);
154511308Santhony.gutierrez@amd.com
154612455Sgabeblack@google.com                    sender_state->tlbEntry =
154712717Sbrandon.potter@amd.com                        new TlbEntry(p->pid(), virt_page_addr,
154812717Sbrandon.potter@amd.com                                     pte->paddr, false, false);
154911308Santhony.gutierrez@amd.com                } else {
155011308Santhony.gutierrez@amd.com                    // If this was a prefetch, then do the normal thing if it
155111308Santhony.gutierrez@amd.com                    // was a successful translation.  Otherwise, send an empty
155211308Santhony.gutierrez@amd.com                    // TLB entry back so that it can be figured out as empty and
155311308Santhony.gutierrez@amd.com                    // handled accordingly.
155412461Sgabeblack@google.com                    if (pte) {
155511308Santhony.gutierrez@amd.com                        DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
155612461Sgabeblack@google.com                                pte->paddr);
155711308Santhony.gutierrez@amd.com
155812455Sgabeblack@google.com                        sender_state->tlbEntry =
155912717Sbrandon.potter@amd.com                            new TlbEntry(p->pid(), virt_page_addr,
156012717Sbrandon.potter@amd.com                                         pte->paddr, false, false);
156111308Santhony.gutierrez@amd.com                    } else {
156211308Santhony.gutierrez@amd.com                        DPRINTF(GPUPrefetch, "Prefetch failed %#x\n",
156311308Santhony.gutierrez@amd.com                                alignedVaddr);
156411308Santhony.gutierrez@amd.com
156512717Sbrandon.potter@amd.com                        sender_state->tlbEntry = nullptr;
156611308Santhony.gutierrez@amd.com
156711308Santhony.gutierrez@amd.com                        return;
156811308Santhony.gutierrez@amd.com                    }
156911308Santhony.gutierrez@amd.com                }
157011308Santhony.gutierrez@amd.com            }
157111308Santhony.gutierrez@amd.com        } else {
157211308Santhony.gutierrez@amd.com            DPRINTF(GPUPrefetch, "Functional Hit for vaddr %#x\n",
157311308Santhony.gutierrez@amd.com                    tlb->lookup(pkt->req->getVaddr()));
157411308Santhony.gutierrez@amd.com
157512717Sbrandon.potter@amd.com            TlbEntry *entry = tlb->lookup(pkt->req->getVaddr(),
157611308Santhony.gutierrez@amd.com                                             update_stats);
157711308Santhony.gutierrez@amd.com
157811308Santhony.gutierrez@amd.com            assert(entry);
157911308Santhony.gutierrez@amd.com
158012717Sbrandon.potter@amd.com            auto p = sender_state->tc->getProcessPtr();
158111308Santhony.gutierrez@amd.com            sender_state->tlbEntry =
158212717Sbrandon.potter@amd.com                new TlbEntry(p->pid(), entry->vaddr, entry->paddr,
158312717Sbrandon.potter@amd.com                             false, false);
158411308Santhony.gutierrez@amd.com        }
158511308Santhony.gutierrez@amd.com        // This is the function that would populate pkt->req with the paddr of
158611308Santhony.gutierrez@amd.com        // the translation. But if no translation happens (i.e Prefetch fails)
158711308Santhony.gutierrez@amd.com        // then the early returns in the above code wiill keep this function
158811308Santhony.gutierrez@amd.com        // from executing.
158911308Santhony.gutierrez@amd.com        tlb->handleFuncTranslationReturn(pkt, tlb_outcome);
159011308Santhony.gutierrez@amd.com    }
159111308Santhony.gutierrez@amd.com
159211308Santhony.gutierrez@amd.com    void
159311308Santhony.gutierrez@amd.com    GpuTLB::CpuSidePort::recvReqRetry()
159411308Santhony.gutierrez@amd.com    {
159511308Santhony.gutierrez@amd.com        // The CPUSidePort never sends anything but replies. No retries
159611308Santhony.gutierrez@amd.com        // expected.
159713449Sgabeblack@google.com        panic("recvReqRetry called");
159811308Santhony.gutierrez@amd.com    }
159911308Santhony.gutierrez@amd.com
160011308Santhony.gutierrez@amd.com    AddrRangeList
160111308Santhony.gutierrez@amd.com    GpuTLB::CpuSidePort::getAddrRanges() const
160211308Santhony.gutierrez@amd.com    {
160311308Santhony.gutierrez@amd.com        // currently not checked by the master
160411308Santhony.gutierrez@amd.com        AddrRangeList ranges;
160511308Santhony.gutierrez@amd.com
160611308Santhony.gutierrez@amd.com        return ranges;
160711308Santhony.gutierrez@amd.com    }
160811308Santhony.gutierrez@amd.com
160911308Santhony.gutierrez@amd.com    /**
161011308Santhony.gutierrez@amd.com     * MemSidePort receives the packet back.
161111308Santhony.gutierrez@amd.com     * We need to call the handleTranslationReturn
161211308Santhony.gutierrez@amd.com     * and propagate up the hierarchy.
161311308Santhony.gutierrez@amd.com     */
161411308Santhony.gutierrez@amd.com    bool
161511308Santhony.gutierrez@amd.com    GpuTLB::MemSidePort::recvTimingResp(PacketPtr pkt)
161611308Santhony.gutierrez@amd.com    {
161711308Santhony.gutierrez@amd.com        Addr virt_page_addr = roundDown(pkt->req->getVaddr(),
161811308Santhony.gutierrez@amd.com                                        TheISA::PageBytes);
161911308Santhony.gutierrez@amd.com
162011308Santhony.gutierrez@amd.com        DPRINTF(GPUTLB, "MemSidePort recvTiming for virt_page_addr %#x\n",
162111308Santhony.gutierrez@amd.com                virt_page_addr);
162211308Santhony.gutierrez@amd.com
162311308Santhony.gutierrez@amd.com        TLBEvent *tlb_event = tlb->translationReturnEvent[virt_page_addr];
162411308Santhony.gutierrez@amd.com        assert(tlb_event);
162511308Santhony.gutierrez@amd.com        assert(virt_page_addr == tlb_event->getTLBEventVaddr());
162611308Santhony.gutierrez@amd.com
162711308Santhony.gutierrez@amd.com        tlb_event->updateOutcome(MISS_RETURN);
162811308Santhony.gutierrez@amd.com        tlb->schedule(tlb_event, curTick()+tlb->ticks(1));
162911308Santhony.gutierrez@amd.com
163011308Santhony.gutierrez@amd.com        return true;
163111308Santhony.gutierrez@amd.com    }
163211308Santhony.gutierrez@amd.com
163311308Santhony.gutierrez@amd.com    void
163411308Santhony.gutierrez@amd.com    GpuTLB::MemSidePort::recvReqRetry()
163511308Santhony.gutierrez@amd.com    {
163611308Santhony.gutierrez@amd.com        // No retries should reach the TLB. The retries
163711308Santhony.gutierrez@amd.com        // should only reach the TLBCoalescer.
163813449Sgabeblack@google.com        panic("recvReqRetry called");
163911308Santhony.gutierrez@amd.com    }
164011308Santhony.gutierrez@amd.com
164111308Santhony.gutierrez@amd.com    void
164211308Santhony.gutierrez@amd.com    GpuTLB::cleanup()
164311308Santhony.gutierrez@amd.com    {
164411308Santhony.gutierrez@amd.com        while (!cleanupQueue.empty()) {
164511308Santhony.gutierrez@amd.com            Addr cleanup_addr = cleanupQueue.front();
164611308Santhony.gutierrez@amd.com            cleanupQueue.pop();
164711308Santhony.gutierrez@amd.com
164811308Santhony.gutierrez@amd.com            // delete TLBEvent
164911308Santhony.gutierrez@amd.com            TLBEvent * old_tlb_event = translationReturnEvent[cleanup_addr];
165011308Santhony.gutierrez@amd.com            delete old_tlb_event;
165111308Santhony.gutierrez@amd.com            translationReturnEvent.erase(cleanup_addr);
165211308Santhony.gutierrez@amd.com
165311308Santhony.gutierrez@amd.com            // update number of outstanding requests
165411308Santhony.gutierrez@amd.com            outstandingReqs--;
165511308Santhony.gutierrez@amd.com        }
165611308Santhony.gutierrez@amd.com
165711308Santhony.gutierrez@amd.com        /** the higher level coalescer should retry if it has
165811308Santhony.gutierrez@amd.com         * any pending requests.
165911308Santhony.gutierrez@amd.com         */
166011308Santhony.gutierrez@amd.com        for (int i = 0; i < cpuSidePort.size(); ++i) {
166111308Santhony.gutierrez@amd.com            cpuSidePort[i]->sendRetryReq();
166211308Santhony.gutierrez@amd.com        }
166311308Santhony.gutierrez@amd.com    }
166411308Santhony.gutierrez@amd.com
166511308Santhony.gutierrez@amd.com    void
166611308Santhony.gutierrez@amd.com    GpuTLB::updatePageFootprint(Addr virt_page_addr)
166711308Santhony.gutierrez@amd.com    {
166811308Santhony.gutierrez@amd.com
166911308Santhony.gutierrez@amd.com        std::pair<AccessPatternTable::iterator, bool> ret;
167011308Santhony.gutierrez@amd.com
167111308Santhony.gutierrez@amd.com        AccessInfo tmp_access_info;
167211308Santhony.gutierrez@amd.com        tmp_access_info.lastTimeAccessed = 0;
167311308Santhony.gutierrez@amd.com        tmp_access_info.accessesPerPage = 0;
167411308Santhony.gutierrez@amd.com        tmp_access_info.totalReuseDistance = 0;
167511308Santhony.gutierrez@amd.com        tmp_access_info.sumDistance = 0;
167611308Santhony.gutierrez@amd.com        tmp_access_info.meanDistance = 0;
167711308Santhony.gutierrez@amd.com
167811308Santhony.gutierrez@amd.com        ret = TLBFootprint.insert(AccessPatternTable::value_type(virt_page_addr,
167911308Santhony.gutierrez@amd.com                                  tmp_access_info));
168011308Santhony.gutierrez@amd.com
168111308Santhony.gutierrez@amd.com        bool first_page_access = ret.second;
168211308Santhony.gutierrez@amd.com
168311308Santhony.gutierrez@amd.com        if (first_page_access) {
168411308Santhony.gutierrez@amd.com            numUniquePages++;
168511308Santhony.gutierrez@amd.com        } else  {
168611308Santhony.gutierrez@amd.com            int accessed_before;
168711308Santhony.gutierrez@amd.com            accessed_before  = curTick() - ret.first->second.lastTimeAccessed;
168811308Santhony.gutierrez@amd.com            ret.first->second.totalReuseDistance += accessed_before;
168911308Santhony.gutierrez@amd.com        }
169011308Santhony.gutierrez@amd.com
169111308Santhony.gutierrez@amd.com        ret.first->second.accessesPerPage++;
169211308Santhony.gutierrez@amd.com        ret.first->second.lastTimeAccessed = curTick();
169311308Santhony.gutierrez@amd.com
169411308Santhony.gutierrez@amd.com        if (accessDistance) {
169511308Santhony.gutierrez@amd.com            ret.first->second.localTLBAccesses
169611308Santhony.gutierrez@amd.com                .push_back(localNumTLBAccesses.value());
169711308Santhony.gutierrez@amd.com        }
169811308Santhony.gutierrez@amd.com    }
169911308Santhony.gutierrez@amd.com
170011308Santhony.gutierrez@amd.com    void
170111308Santhony.gutierrez@amd.com    GpuTLB::exitCallback()
170211308Santhony.gutierrez@amd.com    {
170311308Santhony.gutierrez@amd.com        std::ostream *page_stat_file = nullptr;
170411308Santhony.gutierrez@amd.com
170511308Santhony.gutierrez@amd.com        if (accessDistance) {
170611308Santhony.gutierrez@amd.com
170711308Santhony.gutierrez@amd.com            // print per page statistics to a separate file (.csv format)
170811308Santhony.gutierrez@amd.com            // simout is the gem5 output directory (default is m5out or the one
170911308Santhony.gutierrez@amd.com            // specified with -d
171011364Sandreas.hansson@arm.com            page_stat_file = simout.create(name().c_str())->stream();
171111308Santhony.gutierrez@amd.com
171211308Santhony.gutierrez@amd.com            // print header
171311308Santhony.gutierrez@amd.com            *page_stat_file << "page,max_access_distance,mean_access_distance, "
171411308Santhony.gutierrez@amd.com                            << "stddev_distance" << std::endl;
171511308Santhony.gutierrez@amd.com        }
171611308Santhony.gutierrez@amd.com
171711308Santhony.gutierrez@amd.com        // update avg. reuse distance footprint
171811308Santhony.gutierrez@amd.com        AccessPatternTable::iterator iter, iter_begin, iter_end;
171911308Santhony.gutierrez@amd.com        unsigned int sum_avg_reuse_distance_per_page = 0;
172011308Santhony.gutierrez@amd.com
172111308Santhony.gutierrez@amd.com        // iterate through all pages seen by this TLB
172211308Santhony.gutierrez@amd.com        for (iter = TLBFootprint.begin(); iter != TLBFootprint.end(); iter++) {
172311308Santhony.gutierrez@amd.com            sum_avg_reuse_distance_per_page += iter->second.totalReuseDistance /
172411308Santhony.gutierrez@amd.com                                               iter->second.accessesPerPage;
172511308Santhony.gutierrez@amd.com
172611308Santhony.gutierrez@amd.com            if (accessDistance) {
172711308Santhony.gutierrez@amd.com                unsigned int tmp = iter->second.localTLBAccesses[0];
172811308Santhony.gutierrez@amd.com                unsigned int prev = tmp;
172911308Santhony.gutierrez@amd.com
173011308Santhony.gutierrez@amd.com                for (int i = 0; i < iter->second.localTLBAccesses.size(); ++i) {
173111308Santhony.gutierrez@amd.com                    if (i) {
173211308Santhony.gutierrez@amd.com                        tmp = prev + 1;
173311308Santhony.gutierrez@amd.com                    }
173411308Santhony.gutierrez@amd.com
173511308Santhony.gutierrez@amd.com                    prev = iter->second.localTLBAccesses[i];
173611308Santhony.gutierrez@amd.com                    // update the localTLBAccesses value
173711308Santhony.gutierrez@amd.com                    // with the actual differece
173811308Santhony.gutierrez@amd.com                    iter->second.localTLBAccesses[i] -= tmp;
173911308Santhony.gutierrez@amd.com                    // compute the sum of AccessDistance per page
174011308Santhony.gutierrez@amd.com                    // used later for mean
174111308Santhony.gutierrez@amd.com                    iter->second.sumDistance +=
174211308Santhony.gutierrez@amd.com                        iter->second.localTLBAccesses[i];
174311308Santhony.gutierrez@amd.com                }
174411308Santhony.gutierrez@amd.com
174511308Santhony.gutierrez@amd.com                iter->second.meanDistance =
174611308Santhony.gutierrez@amd.com                    iter->second.sumDistance / iter->second.accessesPerPage;
174711308Santhony.gutierrez@amd.com
174811308Santhony.gutierrez@amd.com                // compute std_dev and max  (we need a second round because we
174911308Santhony.gutierrez@amd.com                // need to know the mean value
175011308Santhony.gutierrez@amd.com                unsigned int max_distance = 0;
175111308Santhony.gutierrez@amd.com                unsigned int stddev_distance = 0;
175211308Santhony.gutierrez@amd.com
175311308Santhony.gutierrez@amd.com                for (int i = 0; i < iter->second.localTLBAccesses.size(); ++i) {
175411308Santhony.gutierrez@amd.com                    unsigned int tmp_access_distance =
175511308Santhony.gutierrez@amd.com                        iter->second.localTLBAccesses[i];
175611308Santhony.gutierrez@amd.com
175711308Santhony.gutierrez@amd.com                    if (tmp_access_distance > max_distance) {
175811308Santhony.gutierrez@amd.com                        max_distance = tmp_access_distance;
175911308Santhony.gutierrez@amd.com                    }
176011308Santhony.gutierrez@amd.com
176111308Santhony.gutierrez@amd.com                    unsigned int diff =
176211308Santhony.gutierrez@amd.com                        tmp_access_distance - iter->second.meanDistance;
176311308Santhony.gutierrez@amd.com                    stddev_distance += pow(diff, 2);
176411308Santhony.gutierrez@amd.com
176511308Santhony.gutierrez@amd.com                }
176611308Santhony.gutierrez@amd.com
176711308Santhony.gutierrez@amd.com                stddev_distance =
176811308Santhony.gutierrez@amd.com                    sqrt(stddev_distance/iter->second.accessesPerPage);
176911308Santhony.gutierrez@amd.com
177011308Santhony.gutierrez@amd.com                if (page_stat_file) {
177111308Santhony.gutierrez@amd.com                    *page_stat_file << std::hex << iter->first << ",";
177211308Santhony.gutierrez@amd.com                    *page_stat_file << std::dec << max_distance << ",";
177311308Santhony.gutierrez@amd.com                    *page_stat_file << std::dec << iter->second.meanDistance
177411308Santhony.gutierrez@amd.com                                    << ",";
177511308Santhony.gutierrez@amd.com                    *page_stat_file << std::dec << stddev_distance;
177611308Santhony.gutierrez@amd.com                    *page_stat_file << std::endl;
177711308Santhony.gutierrez@amd.com                }
177811308Santhony.gutierrez@amd.com
177911308Santhony.gutierrez@amd.com                // erase the localTLBAccesses array
178011308Santhony.gutierrez@amd.com                iter->second.localTLBAccesses.clear();
178111308Santhony.gutierrez@amd.com            }
178211308Santhony.gutierrez@amd.com        }
178311308Santhony.gutierrez@amd.com
178411308Santhony.gutierrez@amd.com        if (!TLBFootprint.empty()) {
178511308Santhony.gutierrez@amd.com            avgReuseDistance =
178611308Santhony.gutierrez@amd.com                sum_avg_reuse_distance_per_page / TLBFootprint.size();
178711308Santhony.gutierrez@amd.com        }
178811308Santhony.gutierrez@amd.com
178911308Santhony.gutierrez@amd.com        //clear the TLBFootprint map
179011308Santhony.gutierrez@amd.com        TLBFootprint.clear();
179111308Santhony.gutierrez@amd.com    }
179211308Santhony.gutierrez@amd.com} // namespace X86ISA
179311308Santhony.gutierrez@amd.com
179411308Santhony.gutierrez@amd.comX86ISA::GpuTLB*
179511308Santhony.gutierrez@amd.comX86GPUTLBParams::create()
179611308Santhony.gutierrez@amd.com{
179711308Santhony.gutierrez@amd.com    return new X86ISA::GpuTLB(this);
179811308Santhony.gutierrez@amd.com}
179911308Santhony.gutierrez@amd.com
1800