ARM: Support table walks in timing mode.
authorDam Sunwoo <dam.sunwoo@arm.com>
Wed, 2 Jun 2010 17:58:18 +0000 (12:58 -0500)
committerDam Sunwoo <dam.sunwoo@arm.com>
Wed, 2 Jun 2010 17:58:18 +0000 (12:58 -0500)
src/arch/arm/table_walker.cc
src/arch/arm/table_walker.hh
src/arch/arm/tlb.cc

index 85d5b00cf67c610b872f474cd45c7716b0650607..ecdb8a53ec689343bd665c60a342bd15a3fbd344 100644 (file)
@@ -80,7 +80,7 @@ TableWalker::getPort(const std::string &if_name, int idx)
 }
 
 Fault
-TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode,
+TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode,
             TLB::Translation *_trans, bool _timing)
 {
     // Right now 1 CPU == 1 TLB == 1 TLB walker
@@ -95,6 +95,7 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode m
     fault = NoFault;
     contextId = _cid;
     timing = _timing;
+    mode = _mode;
 
     /** @todo These should be cached or grabbed from cached copies in
      the TLB, all these miscreg reads are expensive */
@@ -378,8 +379,10 @@ TableWalker::doL1Descriptor()
     switch (l1Desc.type()) {
       case L1Descriptor::Ignore:
       case L1Descriptor::Reserved:
-        tc = NULL;
-        req = NULL;
+        if (!delayed) {
+            tc = NULL;
+            req = NULL;
+        }
         DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
         if (isFetch)
             fault = new PrefetchAbort(vaddr, ArmFault::Translation0);
@@ -422,8 +425,10 @@ TableWalker::doL1Descriptor()
         DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
                 l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF );
 
-        tc = NULL;
-        req = NULL;
+        if (!timing) {
+            tc = NULL;
+            req = NULL;
+        }
         tlb->insert(vaddr, te);
 
         return;
@@ -437,13 +442,16 @@ TableWalker::doL1Descriptor()
         fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
                 isFetch, isWrite, l1Desc.domain(), false);
         if (fault) {
-           tc = NULL;
-           req = NULL;
-           return;
+            if (!timing) {
+                tc = NULL;
+                req = NULL;
+            }
+            return;
         }
 
 
         if (timing) {
+            delayed = true;
             port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
                     &doL2DescEvent, (uint8_t*)&l2Desc.data, 0);
         } else {
@@ -465,8 +473,10 @@ TableWalker::doL2Descriptor()
 
     if (l2Desc.invalid()) {
         DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
-        tc = NULL;
-        req = NULL;
+        if (!delayed) {
+            tc = NULL;
+            req = NULL;
+        }
         if (isFetch)
             fault = new PrefetchAbort(vaddr, ArmFault::Translation1);
         else
@@ -502,11 +512,61 @@ TableWalker::doL2Descriptor()
     te.domain = l1Desc.domain();
     memAttrs(te, l2Desc.texcb(), l2Desc.shareable());
 
-    tc = NULL;
-    req = NULL;
+    if (!delayed) {
+        tc = NULL;
+        req = NULL;
+    }
     tlb->insert(vaddr, te);
 }
 
+void
+TableWalker::doL1DescriptorWrapper()
+{
+    delayed = false;
+
+    DPRINTF(TLBVerbose, "calling doL1Descriptor\n");
+    doL1Descriptor();
+
+    // Check if fault was generated
+    if (fault != NoFault) {
+        transState->finish(fault, req, tc, mode);
+
+        req = NULL;
+        tc = NULL;
+        delayed = false;
+    }
+    else if (!delayed) {
+        DPRINTF(TLBVerbose, "calling translateTiming again\n");
+        fault = tlb->translateTiming(req, tc, transState, mode);
+
+        req = NULL;
+        tc = NULL;
+        delayed = false;
+    }
+}
+
+void
+TableWalker::doL2DescriptorWrapper()
+{
+    assert(delayed);
+
+    DPRINTF(TLBVerbose, "calling doL2Descriptor\n");
+    doL2Descriptor();
+
+    // Check if fault was generated
+    if (fault != NoFault) {
+        transState->finish(fault, req, tc, mode);
+    }
+    else {
+        DPRINTF(TLBVerbose, "calling translateTiming again\n");
+        fault = tlb->translateTiming(req, tc, transState, mode);
+    }
+
+    req = NULL;
+    tc = NULL;
+    delayed = false;
+}
+
 ArmISA::TableWalker *
 ArmTableWalkerParams::create()
 {
index f6d3bee06cc328317a296d5546405f5c6c6d1b38..fbb9133e16f973cc6aa4f6b87e877b6b8043c884 100644 (file)
@@ -289,6 +289,12 @@ class TableWalker : public MemObject
     L1Descriptor l1Desc;
     L2Descriptor l2Desc;
 
+    /** Save mode for use in delayed response */
+    BaseTLB::Mode mode;
+
+    /** Whether L1/L2 descriptor response is delayed in timing mode */
+    bool delayed;
+
   public:
     typedef ArmTableWalkerParams Params;
     TableWalker(const Params *p);
@@ -312,10 +318,12 @@ class TableWalker : public MemObject
   private:
 
     void doL1Descriptor();
-    EventWrapper<TableWalker, &TableWalker::doL1Descriptor> doL1DescEvent;
+    void doL1DescriptorWrapper();
+    EventWrapper<TableWalker, &TableWalker::doL1DescriptorWrapper> doL1DescEvent;
 
     void doL2Descriptor();
-    EventWrapper<TableWalker, &TableWalker::doL2Descriptor> doL2DescEvent;
+    void doL2DescriptorWrapper();
+    EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
 
 
 };
index 7f02061b0d130fc00711d2768e0dfc4e076e3a7c..422ac68f48343485de2450c7dd0ae94316383520 100644 (file)
@@ -408,8 +408,11 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
                 vaddr, context_id);
         fault = tableWalker->walk(req, tc, context_id, mode, translation,
                 timing);
-        if (timing)
+        if (timing) {
             delay = true;
+            // for timing mode, return and wait for table walk
+            return fault;
+        }
         if (fault)
             return fault;