tlb.cc

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,443 行 · 第 1/3 页

CC
1,443
字号
/* * Copyright (c) 2001, 2002, 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Ali G. Saidi */#include <cstring>#include "arch/sparc/asi.hh"#include "arch/sparc/miscregfile.hh"#include "arch/sparc/tlb.hh"#include "base/bitfield.hh"#include "base/trace.hh"#include "cpu/thread_context.hh"#include "cpu/base.hh"#include "mem/packet_access.hh"#include "mem/request.hh"#include "sim/system.hh"/* @todo remove some of the magic constants.  -- ali * */namespace SparcISA {TLB::TLB(const Params *p)    : BaseTLB(p), size(p->size), usedEntries(0), lastReplaced(0),      cacheValid(false){    // To make this work you'll have to change the hypervisor and OS    if (size > 64)        fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");    tlb = new TlbEntry[size];    std::memset(tlb, 0, sizeof(TlbEntry) * size);    for (int x = 0; x < size; x++)        freeList.push_back(&tlb[x]);    c0_tsb_ps0 = 0;    c0_tsb_ps1 = 0;    c0_config = 0;    cx_tsb_ps0 = 0;    cx_tsb_ps1 = 0;    cx_config = 0;    sfsr = 0;    tag_access = 0;}voidTLB::clearUsedBits(){    MapIter i;    for (i = lookupTable.begin(); i != lookupTable.end(); i++) {        TlbEntry *t = i->second;        if (!t->pte.locked()) {            t->used = false;            usedEntries--;        }    }}voidTLB::insert(Addr va, int partition_id, int context_id, bool real,        const PageTableEntry& PTE, int entry){    MapIter i;    TlbEntry *new_entry = NULL;//    TlbRange tr;    int x;    cacheValid = false;    va &= ~(PTE.size()-1); /*   tr.va = va;    tr.size = PTE.size() - 1;    tr.contextId = context_id;    tr.partitionId = partition_id;    tr.real = real;*/    DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",            va, PTE.paddr(), partition_id, context_id, (int)real, entry);    // Demap any entry that conflicts    for (x = 0; x < size; x++) {        if (tlb[x].range.real == real &&            tlb[x].range.partitionId == partition_id &&            tlb[x].range.va < va + PTE.size() - 1 &&            tlb[x].range.va + tlb[x].range.size >= va &&            (real || tlb[x].range.contextId == context_id ))        {            if (tlb[x].valid) {                freeList.push_front(&tlb[x]);                DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);                tlb[x].valid = false;                if (tlb[x].used) {                    tlb[x].used = false;                    usedEntries--;                }                lookupTable.erase(tlb[x].range);            }        }    }/*    i = lookupTable.find(tr);    if (i != lookupTable.end()) {        i->second->valid = false;        if (i->second->used) {            i->second->used = false;            usedEntries--;        }        freeList.push_front(i->second);        DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",                i->second);        lookupTable.erase(i);    }*/    if (entry != -1) {        assert(entry < size && entry >= 0);        new_entry = &tlb[entry];    } else {        if (!freeList.empty()) {            new_entry = freeList.front();        } else {            x = lastReplaced;            do {                ++x;                if (x == size)                    x = 0;                if (x == lastReplaced)                    goto insertAllLocked;            } while (tlb[x].pte.locked());            lastReplaced = x;            new_entry = &tlb[x];        }        /*        for (x = 0; x < size; x++) {            if (!tlb[x].valid || !tlb[x].used)  {                new_entry = &tlb[x];                break;            }        }*/    }insertAllLocked:    // Update the last ently if their all locked    if (!new_entry) {        new_entry = &tlb[size-1];    }    freeList.remove(new_entry);    if (new_entry->valid && new_entry->used)        usedEntries--;    if (new_entry->valid)        lookupTable.erase(new_entry->range);    assert(PTE.valid());    new_entry->range.va = va;    new_entry->range.size = PTE.size() - 1;    new_entry->range.partitionId = partition_id;    new_entry->range.contextId = context_id;    new_entry->range.real = real;    new_entry->pte = PTE;    new_entry->used = true;;    new_entry->valid = true;    usedEntries++;    i = lookupTable.insert(new_entry->range, new_entry);    assert(i != lookupTable.end());    // If all entries have there used bit set, clear it on them all, but the    // one we just inserted    if (usedEntries == size) {        clearUsedBits();        new_entry->used = true;        usedEntries++;    }}TlbEntry*TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool        update_used){    MapIter i;    TlbRange tr;    TlbEntry *t;    DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",            va, partition_id, context_id, real);    // Assemble full address structure    tr.va = va;    tr.size = 1;    tr.contextId = context_id;    tr.partitionId = partition_id;    tr.real = real;    // Try to find the entry    i = lookupTable.find(tr);    if (i == lookupTable.end()) {        DPRINTF(TLB, "TLB: No valid entry found\n");        return NULL;    }    // Mark the entries used bit and clear other used bits in needed    t = i->second;    DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),            t->pte.size());    // Update the used bits only if this is a real access (not a fake one from    // virttophys()    if (!t->used && update_used) {        t->used = true;        usedEntries++;        if (usedEntries == size) {            clearUsedBits();            t->used = true;            usedEntries++;        }    }    return t;}voidTLB::dumpAll(){    MapIter i;    for (int x = 0; x < size; x++) {        if (tlb[x].valid) {           DPRINTFN("%4d:  %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",                   x, tlb[x].range.partitionId, tlb[x].range.contextId,                   tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,                   tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());        }    }}voidTLB::demapPage(Addr va, int partition_id, bool real, int context_id){    TlbRange tr;    MapIter i;    DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",            va, partition_id, context_id, real);    cacheValid = false;    // Assemble full address structure    tr.va = va;    tr.size = 1;    tr.contextId = context_id;    tr.partitionId = partition_id;    tr.real = real;    // Demap any entry that conflicts    i = lookupTable.find(tr);    if (i != lookupTable.end()) {        DPRINTF(IPR, "TLB: Demapped page\n");        i->second->valid = false;        if (i->second->used) {            i->second->used = false;            usedEntries--;        }        freeList.push_front(i->second);        lookupTable.erase(i);    }}voidTLB::demapContext(int partition_id, int context_id){    int x;    DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",            partition_id, context_id);    cacheValid = false;    for (x = 0; x < size; x++) {        if (tlb[x].range.contextId == context_id &&            tlb[x].range.partitionId == partition_id) {            if (tlb[x].valid == true) {                freeList.push_front(&tlb[x]);            }            tlb[x].valid = false;            if (tlb[x].used) {                tlb[x].used = false;                usedEntries--;            }            lookupTable.erase(tlb[x].range);        }    }}voidTLB::demapAll(int partition_id){    int x;    DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);    cacheValid = false;    for (x = 0; x < size; x++) {        if (tlb[x].valid && !tlb[x].pte.locked() &&                tlb[x].range.partitionId == partition_id) {            freeList.push_front(&tlb[x]);            tlb[x].valid = false;            if (tlb[x].used) {                tlb[x].used = false;                usedEntries--;            }            lookupTable.erase(tlb[x].range);        }    }}voidTLB::invalidateAll(){    int x;    cacheValid = false;    lookupTable.clear();    for (x = 0; x < size; x++) {        if (tlb[x].valid == true)            freeList.push_back(&tlb[x]);        tlb[x].valid = false;        tlb[x].used = false;    }    usedEntries = 0;}uint64_tTLB::TteRead(int entry) {    if (entry >= size)        panic("entry: %d\n", entry);    assert(entry < size);    if (tlb[entry].valid)        return tlb[entry].pte();    else        return (uint64_t)-1ll;}uint64_tTLB::TagRead(int entry) {    assert(entry < size);    uint64_t tag;    if (!tlb[entry].valid)        return (uint64_t)-1ll;    tag = tlb[entry].range.contextId;    tag |= tlb[entry].range.va;    tag |= (uint64_t)tlb[entry].range.partitionId << 61;    tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;    tag |= (uint64_t)~tlb[entry].pte._size() << 56;    return tag;}boolTLB::validVirtualAddress(Addr va, bool am){    if (am)        return true;    if (va >= StartVAddrHole && va <= EndVAddrHole)        return false;    return true;}voidTLB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi){    if (sfsr & 0x1)        sfsr = 0x3;    else        sfsr = 1;    if (write)        sfsr |= 1 << 2;    sfsr |= ct << 4;    if (se)        sfsr |= 1 << 6;    sfsr |= ft << 7;    sfsr |= asi << 16;}voidTLB::writeTagAccess(Addr va, int context){    DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n",            va, context, mbits(va, 63,13) | mbits(context,12,0));    tag_access = mbits(va, 63,13) | mbits(context,12,0);}voidITB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi){    DPRINTF(TLB, "TLB: ITB Fault:  w=%d ct=%d ft=%d asi=%d\n",             (int)write, ct, ft, asi);    TLB::writeSfsr(write, ct, se, ft, asi);}voidDTB::writeSfsr(Addr a, bool write, ContextType ct,        bool se, FaultTypes ft, int asi){    DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",            a, (int)write, ct, ft, asi);    TLB::writeSfsr(write, ct, se, ft, asi);    sfar = a;}FaultITB::translate(RequestPtr &req, ThreadContext *tc){    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);    Addr vaddr = req->getVaddr();    TlbEntry *e;    assert(req->getAsi() == ASI_IMPLICIT);    DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",            vaddr, req->getSize());    // Be fast if we can!    if (cacheValid && cacheState == tlbdata) {        if (cacheEntry) {            if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&                cacheEntry->range.va + cacheEntry->range.size >= vaddr) {                    req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |                                  vaddr & cacheEntry->pte.size()-1 );                    return NoFault;            }        } else {            req->setPaddr(vaddr & PAddrImplMask);            return NoFault;        }    }    bool hpriv = bits(tlbdata,0,0);    bool red = bits(tlbdata,1,1);    bool priv = bits(tlbdata,2,2);    bool addr_mask = bits(tlbdata,3,3);    bool lsu_im = bits(tlbdata,4,4);    int part_id = bits(tlbdata,15,8);    int tl = bits(tlbdata,18,16);    int pri_context = bits(tlbdata,47,32);    int context;    ContextType ct;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?