cxx_class = 'ArmISA::TableWalker'
port = MasterPort("Port for TableWalker to do walk the translation with")
sys = Param.System(Parent.any, "system object parameter")
- min_backoff = Param.Tick(0, "Minimum backoff delay after failed send")
- max_backoff = Param.Tick(100000, "Minimum backoff delay after failed send")
-
class ArmTLB(SimObject):
type = 'ArmTLB'
using namespace ArmISA;
TableWalker::TableWalker(const Params *p)
- : MemObject(p), port(this, params()->sys, params()->min_backoff,
- params()->max_backoff), drainEvent(NULL),
+ : MemObject(p), port(this, params()->sys), drainEvent(NULL),
tlb(NULL), currState(NULL), pending(false),
masterId(p->sys->getMasterId(name())),
doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
* A snooping DMA port merely calls the construtor of the DMA
* port.
*/
- SnoopingDmaPort(MemObject *dev, System *s, Tick min_backoff,
- Tick max_backoff) :
- DmaPort(dev, s, min_backoff, max_backoff)
+ SnoopingDmaPort(MemObject *dev, System *s) :
+ DmaPort(dev, s)
{ }
};
Walker::WalkerState::recvPacket(PacketPtr pkt)
{
assert(pkt->isResponse());
- if (!pkt->wasNacked()) {
- assert(inflight);
- assert(state == Waiting);
- assert(!read);
- inflight--;
- if (pkt->isRead()) {
- state = nextState;
- nextState = Ready;
- PacketPtr write = NULL;
- read = pkt;
- timingFault = stepWalk(write);
- state = Waiting;
- assert(timingFault == NoFault || read == NULL);
- if (write) {
- writes.push_back(write);
- }
- sendPackets();
- } else {
- sendPackets();
- }
- if (inflight == 0 && read == NULL && writes.size() == 0) {
- state = Ready;
- nextState = Waiting;
- if (timingFault == NoFault) {
- /*
- * Finish the translation. Now that we now the right entry is
- * in the TLB, this should work with no memory accesses.
- * There could be new faults unrelated to the table walk like
- * permissions violations, so we'll need the return value as
- * well.
- */
- bool delayedResponse;
- Fault fault = walker->tlb->translate(req, tc, NULL, mode,
- delayedResponse, true);
- assert(!delayedResponse);
- // Let the CPU continue.
- translation->finish(fault, req, tc, mode);
- } else {
- // There was a fault during the walk. Let the CPU know.
- translation->finish(timingFault, req, tc, mode);
- }
- return true;
+ assert(inflight);
+ assert(state == Waiting);
+ assert(!read);
+ inflight--;
+ if (pkt->isRead()) {
+ state = nextState;
+ nextState = Ready;
+ PacketPtr write = NULL;
+ read = pkt;
+ timingFault = stepWalk(write);
+ state = Waiting;
+ assert(timingFault == NoFault || read == NULL);
+ if (write) {
+ writes.push_back(write);
}
+ sendPackets();
} else {
- DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n");
- pkt->reinitNacked();
- if (!walker->sendTiming(this, pkt)) {
- inflight--;
- retrying = true;
- if (pkt->isWrite()) {
- writes.push_back(pkt);
- } else {
- assert(!read);
- read = pkt;
- }
+ sendPackets();
+ }
+ if (inflight == 0 && read == NULL && writes.size() == 0) {
+ state = Ready;
+ nextState = Waiting;
+ if (timingFault == NoFault) {
+ /*
+ * Finish the translation. Now that we now the right entry is
+ * in the TLB, this should work with no memory accesses.
+ * There could be new faults unrelated to the table walk like
+ * permissions violations, so we'll need the return value as
+ * well.
+ */
+ bool delayedResponse;
+ Fault fault = walker->tlb->translate(req, tc, NULL, mode,
+ delayedResponse, true);
+ assert(!delayedResponse);
+ // Let the CPU continue.
+ translation->finish(fault, req, tc, mode);
+ } else {
+ // There was a fault during the walk. Let the CPU know.
+ translation->finish(timingFault, req, tc, mode);
}
+ return true;
}
+
return false;
}
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
- assert(!pkt->wasNacked());
-
// Only change the status if it's still waiting on the icache access
// to return.
if (fetchStatus[tid] != IcacheWaitResponse ||
//iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
- assert(!pkt->wasNacked());
-
// If this is a split access, wait until all packets are received.
if (TheISA::HasUnalignedMemAcc && !state->complete()) {
delete pkt->req;
bool
TimingSimpleCPU::IcachePort::recvTimingResp(PacketPtr pkt)
{
- if (!pkt->wasNacked()) {
- DPRINTF(SimpleCPU, "Received timing response %#x\n", pkt->getAddr());
- // delay processing of returned data until next CPU clock edge
- Tick next_tick = cpu->nextCycle(curTick());
-
- if (next_tick == curTick())
- cpu->completeIfetch(pkt);
- else
- tickEvent.schedule(pkt, next_tick);
+ DPRINTF(SimpleCPU, "Received timing response %#x\n", pkt->getAddr());
+ // delay processing of returned data until next CPU clock edge
+ Tick next_tick = cpu->nextCycle();
- return true;
- } else {
- assert(cpu->_status == IcacheWaitResponse);
- pkt->reinitNacked();
- if (!sendTimingReq(pkt)) {
- cpu->_status = IcacheRetry;
- cpu->ifetch_pkt = pkt;
- }
- }
+ if (next_tick == curTick())
+ cpu->completeIfetch(pkt);
+ else
+ tickEvent.schedule(pkt, next_tick);
return true;
}
bool
TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt)
{
- if (!pkt->wasNacked()) {
- // delay processing of returned data until next CPU clock edge
- Tick next_tick = cpu->nextCycle(curTick());
+ // delay processing of returned data until next CPU clock edge
+ Tick next_tick = cpu->nextCycle();
- if (next_tick == curTick()) {
- cpu->completeDataAccess(pkt);
+ if (next_tick == curTick()) {
+ cpu->completeDataAccess(pkt);
+ } else {
+ if (!tickEvent.scheduled()) {
+ tickEvent.schedule(pkt, next_tick);
} else {
- if (!tickEvent.scheduled()) {
- tickEvent.schedule(pkt, next_tick);
- } else {
- // In the case of a split transaction and a cache that is
- // faster than a CPU we could get two responses before
- // next_tick expires
- if (!retryEvent.scheduled())
- cpu->schedule(retryEvent, next_tick);
- return false;
- }
- }
-
- return true;
- } else {
- assert(cpu->_status == DcacheWaitResponse);
- pkt->reinitNacked();
- if (!sendTimingReq(pkt)) {
- cpu->_status = DcacheRetry;
- cpu->dcache_pkt = pkt;
+ // In the case of a split transaction and a cache that is
+ // faster than a CPU we could get two responses before
+ // next_tick expires
+ if (!retryEvent.scheduled())
+ cpu->schedule(retryEvent, next_tick);
+ return false;
}
}
type = 'DmaDevice'
abstract = True
dma = MasterPort("DMA port")
- min_backoff_delay = Param.Latency('4ns',
- "min time between a nack packet being received and the next request made by the device")
- max_backoff_delay = Param.Latency('10us',
- "max time between a nack packet being received and the next request made by the device")
-
class IsaFake(BasicPioDevice):
CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
- : cePort(_ce, _ce->sys, _ce->params()->min_backoff_delay,
- _ce->params()->max_backoff_delay),
+ : cePort(_ce, _ce->sys),
ce(_ce), channelId(cid), busy(false), underReset(false),
refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
latAfterCompletion(ce->params()->latAfterCompletion),
#include "dev/dma_device.hh"
#include "sim/system.hh"
-DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff)
+DmaPort::DmaPort(MemObject *dev, System *s)
: MasterPort(dev->name() + ".dma", dev), device(dev), sys(s),
masterId(s->getMasterId(dev->name())),
pendingCount(0), drainEvent(NULL),
- backoffTime(0), minBackoffDelay(min_backoff),
- maxBackoffDelay(max_backoff), inRetry(false),
- backoffEvent(this)
+ inRetry(false)
{ }
bool
DmaPort::recvTimingResp(PacketPtr pkt)
{
- if (pkt->wasNacked()) {
- DPRINTF(DMA, "Received nacked %s addr %#x\n",
- pkt->cmdString(), pkt->getAddr());
-
- if (backoffTime < minBackoffDelay)
- backoffTime = minBackoffDelay;
- else if (backoffTime < maxBackoffDelay)
- backoffTime <<= 1;
-
- device->reschedule(backoffEvent, curTick() + backoffTime, true);
-
- DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
-
- pkt->reinitNacked();
- queueDma(pkt, true);
- } else if (pkt->senderState) {
+ if (pkt->senderState) {
DmaReqState *state;
- backoffTime >>= 2;
DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
}
DmaDevice::DmaDevice(const Params *p)
- : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay,
- params()->max_backoff_delay)
+ : PioDevice(p), dmaPort(this, sys)
{ }
void
inRetry = true;
DPRINTF(DMA, "-- Failed, queued\n");
}
- } while (!backoffTime && result && transmitList.size());
+ } while (result && transmitList.size());
- if (transmitList.size() && backoffTime && !inRetry) {
- DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime);
- if (!backoffEvent.scheduled())
- device->schedule(backoffEvent, backoffTime + curTick());
- }
- DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
- transmitList.size(), backoffTime, inRetry,
- backoffEvent.scheduled());
+ DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
+ transmitList.size(), inRetry);
}
void
Enums::MemoryMode state = sys->getMemoryMode();
if (state == Enums::timing) {
- if (backoffEvent.scheduled() || inRetry) {
- DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n");
+ if (inRetry) {
+ DPRINTF(DMA, "Can't send immediately, waiting for retry\n");
return;
}
inRetry = true;
DPRINTF(DMA, "-- Failed: queued\n");
}
- } while (result && !backoffTime && transmitList.size());
-
- if (transmitList.size() && backoffTime && !inRetry &&
- !backoffEvent.scheduled()) {
- DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
- backoffTime+curTick());
- device->schedule(backoffEvent, backoffTime + curTick());
- }
+ } while (result && transmitList.size());
} else if (state == Enums::atomic) {
transmitList.pop_front();
* here.*/
Event *drainEvent;
- /** time to wait between sending another packet, increases as NACKs are
- * recived, decreases as responses are recived. */
- Tick backoffTime;
-
- /** Minimum time that device should back off for after failed sendTiming */
- Tick minBackoffDelay;
-
- /** Maximum time that device should back off for after failed sendTiming */
- Tick maxBackoffDelay;
-
/** If the port is currently waiting for a retry before it can send whatever
* it is that it's sending. */
bool inRetry;
void queueDma(PacketPtr pkt, bool front = false);
void sendDma();
- /** event to give us a kick every time we backoff time is reached. */
- EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent;
-
public:
- DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff);
+
+ DmaPort(MemObject *dev, System *s);
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data, Tick delay, Request::Flags flag = 0);
DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
bus_pkt->cmdString(), bus_pkt->getAddr(), old_state);
- assert(!bus_pkt->wasNacked());
-
// If packet was a forward, the response (if any) is already
// in place in the bus_pkt == pkt structure, so we don't need
// to do anything. Otherwise, use the separate bus_pkt to
assert(mshr);
- if (pkt->wasNacked()) {
- //pkt->reinitFromRequest();
- warn("NACKs from devices not connected to the same bus "
- "not implemented\n");
- return;
- }
if (is_error) {
DPRINTF(Cache, "Cache received packet with error for address %x, "
"cmd: %s\n", pkt->getAddr(), pkt->cmdString());
bool
Cache<TagStore>::MemSidePort::recvTimingResp(PacketPtr pkt)
{
- // this needs to be fixed so that the cache updates the mshr and sends the
- // packet back out on the link, but it probably won't happen so until this
- // gets fixed, just panic when it does
- if (pkt->wasNacked())
- panic("Need to implement cache resending nacked packets!\n");
-
cache->handleResponse(pkt);
return true;
}
MessageResp, "MessageReq" },
/* IntResp -- for interrupts */
{ SET2(IsWrite, IsResponse), InvalidCmd, "MessageResp" },
- /* NetworkNackError -- nacked at network layer (not by protocol) */
- { SET2(IsResponse, IsError), InvalidCmd, "NetworkNackError" },
/* InvalidDestError -- packet dest field invalid */
{ SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
/* BadAddressError -- memory address invalid */
// @TODO these should be classified as responses rather than
// requests; coding them as requests initially for backwards
// compatibility
- NetworkNackError, // nacked at network layer (not by protocol)
InvalidDestError, // packet dest field invalid
BadAddressError, // memory address invalid
FunctionalReadError, // unable to fulfill functional read
// Network error conditions... encapsulate them as methods since
// their encoding keeps changing (from result field to command
// field, etc.)
- void
- setNacked()
- {
- assert(isResponse());
- cmd = MemCmd::NetworkNackError;
- }
-
void
setBadAddress()
{
cmd = MemCmd::BadAddressError;
}
- bool wasNacked() const { return cmd == MemCmd::NetworkNackError; }
bool hadBadAddress() const { return cmd == MemCmd::BadAddressError; }
void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; }
}
}
- /**
- * Take a request packet that has been returned as NACKED and
- * modify it so that it can be sent out again. Only packets that
- * need a response can be NACKED, so verify that that is true.
- */
- void
- reinitNacked()
- {
- assert(wasNacked());
- cmd = origCmd;
- assert(needsResponse());
- clearDest();
- }
-
void
setSize(unsigned size)
{