tlb.cc

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

CC
1,443
字号
    int asi;    bool real = false;    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",           priv, hpriv, red, lsu_im, part_id);    if (tl > 0) {        asi = ASI_N;        ct = Nucleus;        context = 0;    } else {        asi = ASI_P;        ct = Primary;        context = pri_context;    }    if ( hpriv || red ) {        cacheValid = true;        cacheState = tlbdata;        cacheEntry = NULL;        req->setPaddr(vaddr & PAddrImplMask);        return NoFault;    }    // If the access is unaligned trap    if (vaddr & 0x3) {        writeSfsr(false, ct, false, OtherFault, asi);        return new MemAddressNotAligned;    }    if (addr_mask)        vaddr = vaddr & VAddrAMask;    if (!validVirtualAddress(vaddr, addr_mask)) {        writeSfsr(false, ct, false, VaOutOfRange, asi);        return new InstructionAccessException;    }    if (!lsu_im) {        e = lookup(vaddr, part_id, true);        real = true;        context = 0;    } else {        e = lookup(vaddr, part_id, false, context);    }    if (e == NULL || !e->valid) {        writeTagAccess(vaddr, context);        if (real)            return new InstructionRealTranslationMiss;        else#if FULL_SYSTEM            return new FastInstructionAccessMMUMiss;#else            return new FastInstructionAccessMMUMiss(req->getVaddr());#endif    }    // were not priviledged accesing priv page    if (!priv && e->pte.priv()) {        writeTagAccess(vaddr, context);        writeSfsr(false, ct, false, PrivViolation, asi);        return new InstructionAccessException;    }    // cache translation date for next translation    cacheValid = true;    cacheState = tlbdata;    cacheEntry = e;    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |                  vaddr & e->pte.size()-1 );    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());    return NoFault;}FaultDTB::translate(RequestPtr &req, ThreadContext *tc, bool write){    /* @todo this could really use some profiling and fixing to make it faster! */    uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);    Addr vaddr = req->getVaddr();    Addr size = req->getSize();    ASI asi;    asi = (ASI)req->getAsi();    bool implicit = false;    bool hpriv = bits(tlbdata,0,0);    bool unaligned = (vaddr & size-1);    DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",            vaddr, size, asi);    if (lookupTable.size() != 64 - freeList.size())       panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(),               freeList.size());    if (asi == ASI_IMPLICIT)        implicit = true;    // Only use the fast path here if there doesn't need to be an unaligned    // trap later    if (!unaligned) {        if (hpriv && implicit) {            req->setPaddr(vaddr & PAddrImplMask);            return NoFault;        }        // Be fast if we can!        if (cacheValid &&  cacheState == tlbdata) {            if (cacheEntry[0]) {                TlbEntry *ce = cacheEntry[0];                Addr ce_va = ce->range.va;                if (cacheAsi[0] == asi &&                    ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&                    (!write || ce->pte.writable())) {                        req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());                        if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)                            req->setFlags(req->getFlags() | UNCACHEABLE);                        DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());                        return NoFault;                } // if matched            } // if cache entry valid            if (cacheEntry[1]) {                TlbEntry *ce = cacheEntry[1];                Addr ce_va = ce->range.va;                if (cacheAsi[1] == asi &&                    ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&                    (!write || ce->pte.writable())) {                        req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());                        if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)                            req->setFlags(req->getFlags() | UNCACHEABLE);                        DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());                        return NoFault;                } // if matched            } // if cache entry valid        }    }    bool red = bits(tlbdata,1,1);    bool priv = bits(tlbdata,2,2);    bool addr_mask = bits(tlbdata,3,3);    bool lsu_dm = bits(tlbdata,5,5);    int part_id = bits(tlbdata,15,8);    int tl = bits(tlbdata,18,16);    int pri_context = bits(tlbdata,47,32);    int sec_context = bits(tlbdata,63,48);    bool real = false;    ContextType ct = Primary;    int context = 0;    TlbEntry *e;    DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",           priv, hpriv, red, lsu_dm, part_id);    if (implicit) {        if (tl > 0) {            asi = ASI_N;            ct = Nucleus;            context = 0;        } else {            asi = ASI_P;            ct = Primary;            context = pri_context;        }    } else {        // We need to check for priv level/asi priv        if (!priv && !hpriv && !AsiIsUnPriv(asi)) {            // It appears that context should be Nucleus in these cases?            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);            return new PrivilegedAction;        }        if (!hpriv && AsiIsHPriv(asi)) {            writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);            return new DataAccessException;        }        if (AsiIsPrimary(asi)) {            context = pri_context;            ct = Primary;        } else if (AsiIsSecondary(asi)) {            context = sec_context;            ct = Secondary;        } else if (AsiIsNucleus(asi)) {            ct = Nucleus;            context = 0;        } else {  // ????            ct = Primary;            context = pri_context;        }    }    if (!implicit && asi != ASI_P && asi != ASI_S) {        if (AsiIsLittle(asi))            panic("Little Endian ASIs not supported\n");        //XXX It's unclear from looking at the documentation how a no fault        //load differs from a regular one, other than what happens concerning        //nfo and e bits in the TTE//        if (AsiIsNoFault(asi))//            panic("No Fault ASIs not supported\n");        if (AsiIsPartialStore(asi))            panic("Partial Store ASIs not supported\n");        if (AsiIsCmt(asi))            panic("Cmt ASI registers not implmented\n");        if (AsiIsInterrupt(asi))            goto handleIntRegAccess;        if (AsiIsMmu(asi))            goto handleMmuRegAccess;        if (AsiIsScratchPad(asi))            goto handleScratchRegAccess;        if (AsiIsQueue(asi))            goto handleQueueRegAccess;        if (AsiIsSparcError(asi))            goto handleSparcErrorRegAccess;        if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) &&                !AsiIsTwin(asi) && !AsiIsBlock(asi) && !AsiIsNoFault(asi))            panic("Accessing ASI %#X. Should we?\n", asi);    }    // If the asi is unaligned trap    if (unaligned) {        writeSfsr(vaddr, false, ct, false, OtherFault, asi);        return new MemAddressNotAligned;    }    if (addr_mask)        vaddr = vaddr & VAddrAMask;    if (!validVirtualAddress(vaddr, addr_mask)) {        writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi);        return new DataAccessException;    }    if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {        real = true;        context = 0;    };    if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {        req->setPaddr(vaddr & PAddrImplMask);        return NoFault;    }    e = lookup(vaddr, part_id, real, context);    if (e == NULL || !e->valid) {        writeTagAccess(vaddr, context);        DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");        if (real)            return new DataRealTranslationMiss;        else#if FULL_SYSTEM            return new FastDataAccessMMUMiss;#else            return new FastDataAccessMMUMiss(req->getVaddr());#endif    }    if (!priv && e->pte.priv()) {        writeTagAccess(vaddr, context);        writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);        return new DataAccessException;    }    if (write && !e->pte.writable()) {        writeTagAccess(vaddr, context);        writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);        return new FastDataAccessProtection;    }    if (e->pte.nofault() && !AsiIsNoFault(asi)) {        writeTagAccess(vaddr, context);        writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);        return new DataAccessException;    }    if (e->pte.sideffect() && AsiIsNoFault(asi)) {        writeTagAccess(vaddr, context);        writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi);        return new DataAccessException;    }    if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)        req->setFlags(req->getFlags() | UNCACHEABLE);    // cache translation date for next translation    cacheState = tlbdata;    if (!cacheValid) {        cacheEntry[1] = NULL;        cacheEntry[0] = NULL;    }    if (cacheEntry[0] != e && cacheEntry[1] != e) {        cacheEntry[1] = cacheEntry[0];        cacheEntry[0] = e;        cacheAsi[1] = cacheAsi[0];        cacheAsi[0] = asi;        if (implicit)            cacheAsi[0] = (ASI)0;    }    cacheValid = true;    req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |                  vaddr & e->pte.size()-1);    DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());    return NoFault;    /** Normal flow ends here. */handleIntRegAccess:    if (!hpriv) {        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);        if (priv)            return new DataAccessException;         else            return new PrivilegedAction;    }    if (asi == ASI_SWVR_UDB_INTR_W && !write ||                    asi == ASI_SWVR_UDB_INTR_R && write) {        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);        return new DataAccessException;    }    goto regAccessOk;handleScratchRegAccess:    if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);        return new DataAccessException;    }    goto regAccessOk;handleQueueRegAccess:    if (!priv  && !hpriv) {        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);        return new PrivilegedAction;    }    if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);        return new DataAccessException;    }    goto regAccessOk;handleSparcErrorRegAccess:    if (!hpriv) {        writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);        if (priv)            return new DataAccessException;         else            return new PrivilegedAction;    }    goto regAccessOk;regAccessOk:handleMmuRegAccess:    DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");    req->setMmapedIpr(true);    req->setPaddr(req->getVaddr());    return NoFault;};#if FULL_SYSTEMTickDTB::doMmuRegRead(ThreadContext *tc, Packet *pkt){    Addr va = pkt->getAddr();    ASI asi = (ASI)pkt->req->getAsi();    uint64_t temp;    DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",         (uint32_t)pkt->req->getAsi(), pkt->getAddr());    ITB * itb = tc->getITBPtr();    switch (asi) {      case ASI_LSU_CONTROL_REG:        assert(va == 0);        pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL));        break;      case ASI_MMU:        switch (va) {          case 0x8:            pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT));            break;          case 0x10:            pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT));            break;          default:            goto doMmuReadError;        }        break;      case ASI_QUEUE:        pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +                    (va >> 4) - 0x3c));        break;      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:        assert(va == 0);        pkt->set(c0_tsb_ps0);        break;      case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:        assert(va == 0);        pkt->set(c0_tsb_ps1);        break;      case ASI_DMMU_CTXT_ZERO_CONFIG:        assert(va == 0);        pkt->set(c0_config);        break;      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:        assert(va == 0);        pkt->set(itb->c0_tsb_ps0);        break;      case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:        assert(va == 0);        pkt->set(itb->c0_tsb_ps1);        break;      case ASI_IMMU_CTXT_ZERO_CONFIG:        assert(va == 0);        pkt->set(itb->c0_config);        break;      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:        assert(va == 0);        pkt->set(cx_tsb_ps0);        break;      case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:        assert(va == 0);        pkt->set(cx_tsb_ps1);        break;      case ASI_DMMU_CTXT_NONZERO_CONFIG:        assert(va == 0);        pkt->set(cx_config);        break;      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:        assert(va == 0);        pkt->set(itb->cx_tsb_ps0);        break;      case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:        assert(va == 0);        pkt->set(itb->cx_tsb_ps1);        break;      case ASI_IMMU_CTXT_NONZERO_CONFIG:        assert(va == 0);        pkt->set(itb->cx_config);        break;      case ASI_SPARC_ERROR_STATUS_REG:        pkt->set((uint64_t)0);        break;      case ASI_HYP_SCRATCHPAD:      case ASI_SCRATCHPAD:        pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3)));        break;      case ASI_IMMU:        switch (va) {          case 0x0:            temp = itb->tag_access;            pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);            break;          case 0x18:            pkt->set(itb->sfsr);            break;          case 0x30:            pkt->set(itb->tag_access);            break;          default:            goto doMmuReadError;

⌨️ 快捷键说明

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