ARM: Don't return the result of a table walk the same cycle it's completed.

The L1 cache may have been accessed to provide this data, which confuses
it, if it ends up being accesses twice in one cycle. Instead wait 1 tick
which will force the timing simple CPU to forward to its next clock cycle
when the translation completes.

Also prevent multiple outstanding table walks from occuring at once.
This commit is contained in:
Ali Saidi 2010-11-08 13:58:24 -06:00
parent 5fcf442f4f
commit e6c31ceb2b
2 changed files with 75 additions and 8 deletions

View file

@ -41,13 +41,14 @@
#include "arch/arm/table_walker.hh" #include "arch/arm/table_walker.hh"
#include "arch/arm/tlb.hh" #include "arch/arm/tlb.hh"
#include "dev/io_device.hh" #include "dev/io_device.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh" #include "cpu/thread_context.hh"
using namespace ArmISA; using namespace ArmISA;
TableWalker::TableWalker(const Params *p) TableWalker::TableWalker(const Params *p)
: MemObject(p), port(NULL), tlb(NULL), : MemObject(p), port(NULL), tlb(NULL), currState(NULL), pending(false),
currState(NULL), doL1DescEvent(this), doL2DescEvent(this) doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
{ {
sctlr = 0; sctlr = 0;
} }
@ -115,6 +116,35 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
currState->isFetch = (currState->mode == TLB::Execute); currState->isFetch = (currState->mode == TLB::Execute);
currState->isWrite = (currState->mode == TLB::Write); 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; Addr ttbr = 0;
// If translation isn't enabled, we shouldn't be here // 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) { if (currState->timing) {
currState->transState->finish(f, currState->req, currState->transState->finish(f, currState->req,
currState->tc, currState->mode); currState->tc, currState->mode);
pending = false;
nextWalk(currState->tc);
currState = NULL; currState = NULL;
} else { } else {
currState->tc = NULL; currState->tc = NULL;
@ -156,7 +189,8 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
if (currState->timing) { if (currState->timing) {
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 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", DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
stateQueueL1.size()); stateQueueL1.size());
stateQueueL1.push_back(currState); stateQueueL1.push_back(currState);
@ -167,7 +201,8 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
flag = Request::UNCACHEABLE; flag = Request::UNCACHEABLE;
} }
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 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(); doL1Descriptor();
f = currState->fault; f = currState->fault;
} }
@ -498,10 +533,12 @@ TableWalker::doL1Descriptor()
if (currState->timing) { if (currState->timing) {
currState->delayed = true; currState->delayed = true;
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 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 { } else {
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 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(); doL2Descriptor();
} }
return; return;
@ -589,6 +626,9 @@ TableWalker::doL1DescriptorWrapper()
currState->transState->finish(currState->fault, currState->req, currState->transState->finish(currState->fault, currState->req,
currState->tc, currState->mode); currState->tc, currState->mode);
pending = false;
nextWalk(currState->tc);
currState->req = NULL; currState->req = NULL;
currState->tc = NULL; currState->tc = NULL;
currState->delayed = false; currState->delayed = false;
@ -600,10 +640,12 @@ TableWalker::doL1DescriptorWrapper()
currState->fault = tlb->translateTiming(currState->req, currState->tc, currState->fault = tlb->translateTiming(currState->req, currState->tc,
currState->transState, currState->mode); currState->transState, currState->mode);
pending = false;
nextWalk(currState->tc);
currState->req = NULL; currState->req = NULL;
currState->tc = NULL; currState->tc = NULL;
currState->delayed = false; currState->delayed = false;
delete currState; delete currState;
} else { } else {
// need to do L2 descriptor // need to do L2 descriptor
@ -633,15 +675,28 @@ TableWalker::doL2DescriptorWrapper()
currState->transState, currState->mode); currState->transState, currState->mode);
} }
stateQueueL2.pop_front();
pending = false;
nextWalk(currState->tc);
currState->req = NULL; currState->req = NULL;
currState->tc = NULL; currState->tc = NULL;
currState->delayed = false; currState->delayed = false;
stateQueueL2.pop_front();
delete currState; delete currState;
currState = NULL; currState = NULL;
} }
void
TableWalker::nextWalk(ThreadContext *tc)
{
if (pendingQueue.size())
schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick+1));
}
ArmISA::TableWalker * ArmISA::TableWalker *
ArmTableWalkerParams::create() ArmTableWalkerParams::create()
{ {

View file

@ -320,6 +320,11 @@ class TableWalker : public MemObject
* require an additional level. */ * require an additional level. */
std::list<WalkerState *> stateQueueL2; 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 */ /** Port to issue translation requests from */
DmaPort *port; DmaPort *port;
@ -331,6 +336,9 @@ class TableWalker : public MemObject
WalkerState *currState; WalkerState *currState;
/** If a timing translation is currently in progress */
bool pending;
public: public:
typedef ArmTableWalkerParams Params; typedef ArmTableWalkerParams Params;
TableWalker(const Params *p); TableWalker(const Params *p);
@ -362,7 +370,11 @@ class TableWalker : public MemObject
void doL2DescriptorWrapper(); void doL2DescriptorWrapper();
EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent; EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
Fault processWalk();
void processWalkWrapper();
EventWrapper<TableWalker, &TableWalker::processWalkWrapper> doProcessEvent;
void nextWalk(ThreadContext *tc);
}; };