summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/arm/table_walker.cc71
-rw-r--r--src/arch/arm/table_walker.hh12
2 files changed, 75 insertions, 8 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index 06bb10219..ddf9fe5d3 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -41,13 +41,14 @@
#include "arch/arm/table_walker.hh"
#include "arch/arm/tlb.hh"
#include "dev/io_device.hh"
+#include "cpu/base.hh"
#include "cpu/thread_context.hh"
using namespace ArmISA;
TableWalker::TableWalker(const Params *p)
- : MemObject(p), port(NULL), tlb(NULL),
- currState(NULL), doL1DescEvent(this), doL2DescEvent(this)
+ : MemObject(p), port(NULL), tlb(NULL), currState(NULL), pending(false),
+ doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
{
sctlr = 0;
}
@@ -115,6 +116,35 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
currState->isFetch = (currState->mode == TLB::Execute);
currState->isWrite = (currState->mode == TLB::Write);
+
+ if (!currState->timing)
+ return processWalk();
+
+ if (pending) {
+ pendingQueue.push_back(currState);
+ currState = NULL;
+ } else {
+ pending = true;
+ processWalk();
+ }
+
+ return NoFault;
+}
+
+void
+TableWalker::processWalkWrapper()
+{
+ assert(!currState);
+ assert(pendingQueue.size());
+ currState = pendingQueue.front();
+ pendingQueue.pop_front();
+ pending = true;
+ processWalk();
+}
+
+Fault
+TableWalker::processWalk()
+{
Addr ttbr = 0;
// If translation isn't enabled, we shouldn't be here
@@ -146,6 +176,9 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
if (currState->timing) {
currState->transState->finish(f, currState->req,
currState->tc, currState->mode);
+
+ pending = false;
+ nextWalk(currState->tc);
currState = NULL;
} else {
currState->tc = NULL;
@@ -156,7 +189,8 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
if (currState->timing) {
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
- &doL1DescEvent, (uint8_t*)&currState->l1Desc.data, (Tick)0);
+ &doL1DescEvent, (uint8_t*)&currState->l1Desc.data,
+ currState->tc->getCpuPtr()->ticks(1));
DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
stateQueueL1.size());
stateQueueL1.push_back(currState);
@@ -167,7 +201,8 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
flag = Request::UNCACHEABLE;
}
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
- NULL, (uint8_t*)&currState->l1Desc.data, (Tick)0, flag);
+ NULL, (uint8_t*)&currState->l1Desc.data,
+ currState->tc->getCpuPtr()->ticks(1), flag);
doL1Descriptor();
f = currState->fault;
}
@@ -498,10 +533,12 @@ TableWalker::doL1Descriptor()
if (currState->timing) {
currState->delayed = true;
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
- &doL2DescEvent, (uint8_t*)&currState->l2Desc.data, 0);
+ &doL2DescEvent, (uint8_t*)&currState->l2Desc.data,
+ currState->tc->getCpuPtr()->ticks(1));
} else {
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
- NULL, (uint8_t*)&currState->l2Desc.data, 0);
+ NULL, (uint8_t*)&currState->l2Desc.data,
+ currState->tc->getCpuPtr()->ticks(1));
doL2Descriptor();
}
return;
@@ -589,6 +626,9 @@ TableWalker::doL1DescriptorWrapper()
currState->transState->finish(currState->fault, currState->req,
currState->tc, currState->mode);
+ pending = false;
+ nextWalk(currState->tc);
+
currState->req = NULL;
currState->tc = NULL;
currState->delayed = false;
@@ -600,10 +640,12 @@ TableWalker::doL1DescriptorWrapper()
currState->fault = tlb->translateTiming(currState->req, currState->tc,
currState->transState, currState->mode);
+ pending = false;
+ nextWalk(currState->tc);
+
currState->req = NULL;
currState->tc = NULL;
currState->delayed = false;
-
delete currState;
} else {
// need to do L2 descriptor
@@ -633,15 +675,28 @@ TableWalker::doL2DescriptorWrapper()
currState->transState, currState->mode);
}
+
+ stateQueueL2.pop_front();
+ pending = false;
+ nextWalk(currState->tc);
+
currState->req = NULL;
currState->tc = NULL;
currState->delayed = false;
- stateQueueL2.pop_front();
delete currState;
currState = NULL;
}
+void
+TableWalker::nextWalk(ThreadContext *tc)
+{
+ if (pendingQueue.size())
+ schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick+1));
+}
+
+
+
ArmISA::TableWalker *
ArmTableWalkerParams::create()
{
diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh
index dc801dde8..fde553ff4 100644
--- a/src/arch/arm/table_walker.hh
+++ b/src/arch/arm/table_walker.hh
@@ -320,6 +320,11 @@ class TableWalker : public MemObject
* require an additional level. */
std::list<WalkerState *> stateQueueL2;
+ /** Queue of requests that have passed are waiting because the walker is
+ * currently busy. */
+ std::list<WalkerState *> pendingQueue;;
+
+
/** Port to issue translation requests from */
DmaPort *port;
@@ -331,6 +336,9 @@ class TableWalker : public MemObject
WalkerState *currState;
+ /** If a timing translation is currently in progress */
+ bool pending;
+
public:
typedef ArmTableWalkerParams Params;
TableWalker(const Params *p);
@@ -362,7 +370,11 @@ class TableWalker : public MemObject
void doL2DescriptorWrapper();
EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
+ Fault processWalk();
+ void processWalkWrapper();
+ EventWrapper<TableWalker, &TableWalker::processWalkWrapper> doProcessEvent;
+ void nextWalk(ThreadContext *tc);
};