fetch.cc:
[gem5.git] / arch / alpha / alpha_memory.cc
index 58aa13b8fc93f7e8bad5d26e7f47e627a9450be7..8f6d7a51a97a6b04acea8b6646c50e3aeb221e43 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2001-2004 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <string>
 #include <vector>
 
+#include "arch/alpha/alpha_memory.hh"
 #include "base/inifile.hh"
 #include "base/str.hh"
 #include "base/trace.hh"
 #include "cpu/exec_context.hh"
 #include "sim/builder.hh"
-#include "targetarch/alpha_memory.hh"
-#include "targetarch/ev5.hh"
 
 using namespace std;
+using namespace EV5;
 
 ///////////////////////////////////////////////////////////////////////
 //
 //  Alpha TLB
 //
+#ifdef DEBUG
+bool uncacheBit39 = false;
+bool uncacheBit40 = false;
+#endif
+
+#define MODE2MASK(X)                   (1 << (X))
+
 AlphaTLB::AlphaTLB(const string &name, int s)
     : SimObject(name), size(s), nlu(0)
 {
@@ -61,24 +68,27 @@ AlphaTLB::~AlphaTLB()
 AlphaISA::PTE *
 AlphaTLB::lookup(Addr vpn, uint8_t asn) const
 {
-    DPRINTF(TLB, "lookup %#x\n", vpn);
+    // assume not found...
+    AlphaISA::PTE *retval = NULL;
 
     PageTable::const_iterator i = lookupTable.find(vpn);
-    if (i == lookupTable.end())
-        return NULL;
-
-    while (i->first == vpn) {
-        int index = i->second;
-        AlphaISA::PTE *pte = &table[index];
-        assert(pte->valid);
-        if (vpn == pte->tag && (pte->asma || pte->asn == asn))
-            return pte;
+    if (i != lookupTable.end()) {
+        while (i->first == vpn) {
+            int index = i->second;
+            AlphaISA::PTE *pte = &table[index];
+            assert(pte->valid);
+            if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
+                retval = pte;
+                break;
+            }
 
-        ++i;
+            ++i;
+        }
     }
 
-    // not found...
-    return NULL;
+    DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
+            retval ? "hit" : "miss", retval ? retval->ppn : 0);
+    return retval;
 }
 
 
@@ -87,9 +97,23 @@ AlphaTLB::checkCacheability(MemReqPtr &req)
 {
     // in Alpha, cacheability is controlled by upper-level bits of the
     // physical address
-    if (req->paddr & PA_UNCACHED_BIT) {
-        if (PA_IPR_SPACE(req->paddr)) {
-            // IPR memory space not implemented
+
+    /*
+     * We support having the uncacheable bit in either bit 39 or bit 40.
+     * The Turbolaser platform (and EV5) support having the bit in 39, but
+     * Tsunami (which Linux assumes uses an EV6) generates accesses with
+     * the bit in 40.  So we must check for both, but we have debug flags
+     * to catch a weird case where both are used, which shouldn't happen.
+     */
+
+
+#ifdef ALPHA_TLASER
+    if (req->paddr & PAddrUncachedBit39) {
+#else
+    if (req->paddr & PAddrUncachedBit43) {
+#endif
+        // IPR memory space not implemented
+        if (PAddrIprSpace(req->paddr)) {
             if (!req->xc->misspeculating()) {
                 switch (req->paddr) {
                   case ULL(0xFFFFF00188):
@@ -104,6 +128,11 @@ AlphaTLB::checkCacheability(MemReqPtr &req)
         } else {
             // mark request as uncacheable
             req->flags |= UNCACHEABLE;
+
+#ifndef ALPHA_TLASER
+            // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
+            req->paddr &= PAddrUncachedMask;
+#endif
         }
     }
 }
@@ -111,8 +140,9 @@ AlphaTLB::checkCacheability(MemReqPtr &req)
 
 // insert a new TLB entry
 void
-AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte)
+AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte)
 {
+    AlphaISA::VAddr vaddr = addr;
     if (table[nlu].valid) {
         Addr oldvpn = table[nlu].tag;
         PageTable::iterator i = lookupTable.find(oldvpn);
@@ -133,14 +163,13 @@ AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte)
         lookupTable.erase(i);
     }
 
-    Addr vpn = VA_VPN(vaddr);
-    DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn);
+    DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
 
     table[nlu] = pte;
-    table[nlu].tag = vpn;
+    table[nlu].tag = vaddr.vpn();
     table[nlu].valid = true;
 
-    lookupTable.insert(make_pair(vpn, nlu));
+    lookupTable.insert(make_pair(vaddr.vpn(), nlu));
     nextnlu();
 }
 
@@ -173,21 +202,22 @@ AlphaTLB::flushProcesses()
 }
 
 void
-AlphaTLB::flushAddr(Addr vaddr, uint8_t asn)
+AlphaTLB::flushAddr(Addr addr, uint8_t asn)
 {
-    Addr vpn = VA_VPN(vaddr);
+    AlphaISA::VAddr vaddr = addr;
 
-    PageTable::iterator i = lookupTable.find(vpn);
+    PageTable::iterator i = lookupTable.find(vaddr.vpn());
     if (i == lookupTable.end())
         return;
 
-    while (i->first == vpn) {
+    while (i->first == vaddr.vpn()) {
         int index = i->second;
         AlphaISA::PTE *pte = &table[index];
         assert(pte->valid);
 
-        if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
-            DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn);
+        if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) {
+            DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(),
+                    pte->ppn);
 
             // invalidate this entry
             pte->valid = false;
@@ -263,7 +293,7 @@ AlphaITB::fault(Addr pc, ExecContext *xc) const
     if (!xc->misspeculating()) {
         ipr[AlphaISA::IPR_ITB_TAG] = pc;
         ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
-            ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
+            ipr[AlphaISA::IPR_IVPTBR] | (AlphaISA::VAddr(pc).vpn() << 3);
     }
 }
 
@@ -273,9 +303,9 @@ AlphaITB::translate(MemReqPtr &req) const
 {
     InternalProcReg *ipr = req->xc->regs.ipr;
 
-    if (PC_PAL(req->vaddr)) {
+    if (AlphaISA::PcPAL(req->vaddr)) {
         // strip off PAL PC marker (lsb is 1)
-        req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
+        req->paddr = (req->vaddr & ~3) & PAddrImplMask;
         hits++;
         return No_Fault;
     }
@@ -290,23 +320,37 @@ AlphaITB::translate(MemReqPtr &req) const
             return ITB_Acv_Fault;
         }
 
-        // Check for "superpage" mapping: when SP<1> is set, and
-        // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
-        if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
-               VA_SPACE(req->vaddr) == 2) {
 
+        // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
+        // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
+#ifdef ALPHA_TLASER
+        if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
+            VAddrSpaceEV5(req->vaddr) == 2) {
+#else
+        if (VAddrSpaceEV6(req->vaddr) == 0x7e) {
+#endif
             // only valid in kernel mode
-            if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
+            if (ICM_CM(ipr[AlphaISA::IPR_ICM]) !=
+                AlphaISA::mode_kernel) {
                 fault(req->vaddr, req->xc);
                 acv++;
                 return ITB_Acv_Fault;
             }
 
-            req->paddr = req->vaddr & PA_IMPL_MASK;
+            req->paddr = req->vaddr & PAddrImplMask;
+
+#ifndef ALPHA_TLASER
+            // sign extend the physical address properly
+            if (req->paddr & PAddrUncachedBit40)
+                req->paddr |= ULL(0xf0000000000);
+            else
+                req->paddr &= ULL(0xffffffffff);
+#endif
+
         } else {
             // not a physical address: need to look up pte
-            AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
-                                 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+            AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(),
+                                        DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
 
             if (!pte) {
                 fault(req->vaddr, req->xc);
@@ -314,7 +358,8 @@ AlphaITB::translate(MemReqPtr &req) const
                 return ITB_Fault_Fault;
             }
 
-            req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
+            req->paddr = (pte->ppn << AlphaISA::PageShift) +
+                (AlphaISA::VAddr(req->vaddr).offset() & ~3);
 
             // check permissions for this access
             if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
@@ -329,7 +374,7 @@ AlphaITB::translate(MemReqPtr &req) const
     }
 
     // check that the physical address is ok (catch bad physical addresses)
-    if (req->paddr & ~PA_IMPL_MASK)
+    if (req->paddr & ~PAddrImplMask)
         return Machine_Check_Fault;
 
     checkCacheability(req);
@@ -418,7 +463,7 @@ void
 AlphaDTB::fault(MemReqPtr &req, uint64_t flags) const
 {
     ExecContext *xc = req->xc;
-    Addr vaddr = req->vaddr;
+    AlphaISA::VAddr vaddr = req->vaddr;
     uint64_t *ipr = xc->regs.ipr;
 
     // Set fault address and flags.  Even though we're modeling an
@@ -429,16 +474,17 @@ AlphaDTB::fault(MemReqPtr &req, uint64_t flags) const
     if (!xc->misspeculating()
         && !(req->flags & VPTE) && !(req->flags & NO_FAULT)) {
         // set VA register with faulting address
-        ipr[AlphaISA::IPR_VA] = vaddr;
+        ipr[AlphaISA::IPR_VA] = req->vaddr;
 
         // set MM_STAT register flags
-        ipr[AlphaISA::IPR_MM_STAT] = (((OPCODE(xc->getInst()) & 0x3f) << 11)
-                               | ((RA(xc->getInst()) & 0x1f) << 6)
-                               | (flags & 0x3f));
+        ipr[AlphaISA::IPR_MM_STAT] =
+            (((Opcode(xc->getInst()) & 0x3f) << 11)
+             | ((Ra(xc->getInst()) & 0x1f) << 6)
+             | (flags & 0x3f));
 
         // set VA_FORM register with faulting formatted address
         ipr[AlphaISA::IPR_VA_FORM] =
-            ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
+            ipr[AlphaISA::IPR_MVPTBR] | (vaddr.vpn() << 3);
     }
 }
 
@@ -452,7 +498,18 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
     AlphaISA::mode_type mode =
         (AlphaISA::mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
 
-    if (PC_PAL(pc)) {
+
+    /**
+     * Check for alignment faults
+     */
+    if (req->vaddr & (req->size - 1)) {
+        fault(req, write ? MM_STAT_WR_MASK : 0);
+        DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->vaddr,
+                req->size);
+        return Alignment_Fault;
+    }
+
+    if (pc & 0x1) {
         mode = (req->flags & ALTMODE) ?
             (AlphaISA::mode_type)ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE])
             : AlphaISA::mode_kernel;
@@ -463,27 +520,41 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
     } else {
         // verify that this is a good virtual address
         if (!validVirtualAddress(req->vaddr)) {
-            fault(req, ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
-                        MM_STAT_ACV_MASK));
+            fault(req, (write ? MM_STAT_WR_MASK : 0) |
+                  MM_STAT_BAD_VA_MASK |
+                  MM_STAT_ACV_MASK);
 
             if (write) { write_acv++; } else { read_acv++; }
             return DTB_Fault_Fault;
         }
 
-        // Check for "superpage" mapping: when SP<1> is set, and
-        // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
+        // Check for "superpage" mapping
+#ifdef ALPHA_TLASER
         if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
-            VA_SPACE(req->vaddr) == 2) {
+            VAddrSpaceEV5(req->vaddr) == 2) {
+#else
+        if (VAddrSpaceEV6(req->vaddr) == 0x7e) {
+#endif
 
             // only valid in kernel mode
             if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) !=
                 AlphaISA::mode_kernel) {
-                fault(req, ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK));
+                fault(req, ((write ? MM_STAT_WR_MASK : 0) |
+                            MM_STAT_ACV_MASK));
                 if (write) { write_acv++; } else { read_acv++; }
                 return DTB_Acv_Fault;
             }
 
-            req->paddr = req->vaddr & PA_IMPL_MASK;
+            req->paddr = req->vaddr & PAddrImplMask;
+
+#ifndef ALPHA_TLASER
+            // sign extend the physical address properly
+            if (req->paddr & PAddrUncachedBit40)
+                req->paddr |= ULL(0xf0000000000);
+            else
+                req->paddr &= ULL(0xffffffffff);
+#endif
+
         } else {
             if (write)
                 write_accesses++;
@@ -491,36 +562,39 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
                 read_accesses++;
 
             // not a physical address: need to look up pte
-            AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
-                                 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+            AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(),
+                                        DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
 
             if (!pte) {
                 // page fault
-                fault(req,
-                      (write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK);
+                fault(req, (write ? MM_STAT_WR_MASK : 0) |
+                      MM_STAT_DTB_MISS_MASK);
                 if (write) { write_misses++; } else { read_misses++; }
                 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
             }
 
-            req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
+            req->paddr = (pte->ppn << AlphaISA::PageShift) +
+                AlphaISA::VAddr(req->vaddr).offset();
 
             if (write) {
                 if (!(pte->xwe & MODE2MASK(mode))) {
                     // declare the instruction access fault
-                    fault(req, (MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
-                                (pte->fonw ? MM_STAT_FONW_MASK : 0)));
+                    fault(req, MM_STAT_WR_MASK |
+                          MM_STAT_ACV_MASK |
+                          (pte->fonw ? MM_STAT_FONW_MASK : 0));
                     write_acv++;
                     return DTB_Fault_Fault;
                 }
                 if (pte->fonw) {
-                    fault(req, MM_STAT_WR_MASK | MM_STAT_FONW_MASK);
+                    fault(req, MM_STAT_WR_MASK |
+                          MM_STAT_FONW_MASK);
                     write_acv++;
                     return DTB_Fault_Fault;
                 }
             } else {
                 if (!(pte->xre & MODE2MASK(mode))) {
-                    fault(req, (MM_STAT_ACV_MASK |
-                                (pte->fonr ? MM_STAT_FONR_MASK : 0)));
+                    fault(req, MM_STAT_ACV_MASK |
+                          (pte->fonr ? MM_STAT_FONR_MASK : 0));
                     read_acv++;
                     return DTB_Acv_Fault;
                 }
@@ -539,7 +613,7 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
     }
 
     // check that the physical address is ok (catch bad physical addresses)
-    if (req->paddr & ~PA_IMPL_MASK)
+    if (req->paddr & ~PAddrImplMask)
         return Machine_Check_Fault;
 
     checkCacheability(req);