+Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
+ RequestPtr _req, BaseTLB::Mode _mode)
+{
+ // TODO: in timing mode, instead of blocking when there are other
+ // outstanding requests, see if this request can be coalesced with
+ // another one (i.e. either coalesce or start walk)
+ WalkerState * newState = new WalkerState(this, _translation, _req);
+ newState->initState(_tc, _mode, sys->getMemoryMode() == Enums::timing);
+ if (currStates.size()) {
+ assert(newState->isTiming());
+ DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size());
+ currStates.push_back(newState);
+ return NoFault;
+ } else {
+ currStates.push_back(newState);
+ Fault fault = newState->startWalk();
+ if (!newState->isTiming()) {
+ currStates.pop_front();
+ delete newState;
+ }
+ return fault;
+ }
+}
+
+Fault
+Walker::startFunctional(ThreadContext * _tc, Addr &addr, Addr &pageSize,
+ BaseTLB::Mode _mode)
+{
+ funcState.initState(_tc, _mode);
+ return funcState.startFunctional(addr, pageSize);
+}
+
+bool
+Walker::WalkerPort::recvTiming(PacketPtr pkt)
+{
+ return walker->recvTiming(pkt);
+}
+
+bool
+Walker::recvTiming(PacketPtr pkt)
+{
+ if (pkt->isResponse() || pkt->wasNacked()) {
+ WalkerSenderState * senderState =
+ dynamic_cast<WalkerSenderState *>(pkt->senderState);
+ pkt->senderState = senderState->saved;
+ WalkerState * senderWalk = senderState->senderWalk;
+ bool walkComplete = senderWalk->recvPacket(pkt);
+ delete senderState;
+ if (walkComplete) {
+ std::list<WalkerState *>::iterator iter;
+ for (iter = currStates.begin(); iter != currStates.end(); iter++) {
+ WalkerState * walkerState = *(iter);
+ if (walkerState == senderWalk) {
+ iter = currStates.erase(iter);
+ break;
+ }
+ }
+ delete senderWalk;
+ // Since we block requests when another is outstanding, we
+ // need to check if there is a waiting request to be serviced
+ if (currStates.size()) {
+ WalkerState * newState = currStates.front();
+ if (!newState->wasStarted())
+ newState->startWalk();
+ }
+ }
+ } else {
+ DPRINTF(PageTableWalker, "Received strange packet\n");
+ }
+ return true;
+}
+
+Tick
+Walker::WalkerPort::recvAtomic(PacketPtr pkt)
+{
+ return 0;
+}
+
+void
+Walker::WalkerPort::recvFunctional(PacketPtr pkt)
+{
+ return;
+}
+
+void
+Walker::WalkerPort::recvStatusChange(Status status)
+{
+ if (status == RangeChange) {
+ if (!snoopRangeSent) {
+ snoopRangeSent = true;
+ sendStatusChange(Port::RangeChange);
+ }
+ return;
+ }
+
+ panic("Unexpected recvStatusChange.\n");
+}
+
+void
+Walker::WalkerPort::recvRetry()
+{
+ walker->recvRetry();
+}
+
+void
+Walker::recvRetry()
+{
+ std::list<WalkerState *>::iterator iter;
+ for (iter = currStates.begin(); iter != currStates.end(); iter++) {
+ WalkerState * walkerState = *(iter);
+ if (walkerState->isRetrying()) {
+ walkerState->retry();
+ }
+ }
+}
+
+bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt)
+{
+ pkt->senderState = new WalkerSenderState(sendingState, pkt->senderState);
+ return port.sendTiming(pkt);
+}
+
+Port *
+Walker::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "port")
+ return &port;
+ else
+ panic("No page table walker port named %s!\n", if_name);
+}
+
+void
+Walker::WalkerState::initState(ThreadContext * _tc,
+ BaseTLB::Mode _mode, bool _isTiming)
+{
+ assert(state == Ready);
+ started = false;
+ tc = _tc;
+ mode = _mode;
+ timing = _isTiming;
+}
+
+Fault
+Walker::WalkerState::startWalk()
+{
+ Fault fault = NoFault;
+ assert(started == false);
+ started = true;
+ setupWalk(req->getVaddr());
+ if (timing) {
+ nextState = state;
+ state = Waiting;
+ timingFault = NoFault;
+ sendPackets();
+ } else {
+ do {
+ walker->port.sendAtomic(read);
+ PacketPtr write = NULL;
+ fault = stepWalk(write);
+ assert(fault == NoFault || read == NULL);
+ state = nextState;
+ nextState = Ready;
+ if (write)
+ walker->port.sendAtomic(write);
+ } while(read);
+ state = Ready;
+ nextState = Waiting;
+ }
+ return fault;
+}
+
+Fault
+Walker::WalkerState::startFunctional(Addr &addr, Addr &pageSize)
+{
+ Fault fault = NoFault;
+ assert(started == false);
+ started = true;
+ setupWalk(addr);
+
+ do {
+ walker->port.sendFunctional(read);
+ // On a functional access (page table lookup), writes should
+ // not happen so this pointer is ignored after stepWalk
+ PacketPtr write = NULL;
+ fault = stepWalk(write);
+ assert(fault == NoFault || read == NULL);
+ state = nextState;
+ nextState = Ready;
+ } while(read);
+ pageSize = entry.size;
+ addr = entry.paddr;
+
+ return fault;
+}
+
+Fault
+Walker::WalkerState::stepWalk(PacketPtr &write)