summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/cache/base.cc76
-rw-r--r--src/mem/cache/base.hh96
-rw-r--r--src/mem/cache/cache.hh70
-rw-r--r--src/mem/cache/cache_impl.hh139
-rw-r--r--src/mem/tport.cc116
-rw-r--r--src/mem/tport.hh49
6 files changed, 304 insertions, 242 deletions
diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc
index 27ff6961b..c7c213cc6 100644
--- a/src/mem/cache/base.cc
+++ b/src/mem/cache/base.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -42,13 +54,20 @@
using namespace std;
-BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
- const std::string &_label)
- : SimpleTimingPort(_name, _cache), cache(_cache),
- label(_label), blocked(false), mustSendRetry(false)
+BaseCache::CacheMasterPort::CacheMasterPort(const std::string &_name,
+ BaseCache *_cache,
+ const std::string &_label)
+ : SimpleTimingPort(_name, _cache, _label)
{
}
+BaseCache::CacheSlavePort::CacheSlavePort(const std::string &_name,
+ BaseCache *_cache,
+ const std::string &_label)
+ : SimpleTimingPort(_name, _cache, _label), blocked(false),
+ mustSendRetry(false), sendRetryEvent(this)
+{
+}
BaseCache::BaseCache(const Params *p)
: MemObject(p),
@@ -69,56 +88,25 @@ BaseCache::BaseCache(const Params *p)
{
}
-
-bool
-BaseCache::CachePort::checkFunctional(PacketPtr pkt)
-{
- pkt->pushLabel(label);
- bool done = SimpleTimingPort::checkFunctional(pkt);
- pkt->popLabel();
- return done;
-}
-
-
-unsigned
-BaseCache::CachePort::deviceBlockSize() const
-{
- return cache->getBlockSize();
-}
-
-
-bool
-BaseCache::CachePort::recvRetryCommon()
-{
- assert(waitingOnRetry);
- waitingOnRetry = false;
- return false;
-}
-
-
void
-BaseCache::CachePort::setBlocked()
+BaseCache::CacheSlavePort::setBlocked()
{
assert(!blocked);
- DPRINTF(Cache, "Cache Blocking\n");
+ DPRINTF(CachePort, "Cache port %s blocking new requests\n", name());
blocked = true;
- //Clear the retry flag
- mustSendRetry = false;
}
void
-BaseCache::CachePort::clearBlocked()
+BaseCache::CacheSlavePort::clearBlocked()
{
assert(blocked);
- DPRINTF(Cache, "Cache Unblocking\n");
+ DPRINTF(CachePort, "Cache port %s accepting new requests\n", name());
blocked = false;
- if (mustSendRetry)
- {
- DPRINTF(Cache, "Cache Sending Retry\n");
+ if (mustSendRetry) {
+ DPRINTF(CachePort, "Cache port %s sending retry\n", name());
mustSendRetry = false;
- SendRetryEvent *ev = new SendRetryEvent(this, true);
// @TODO: need to find a better time (next bus cycle?)
- cache->schedule(ev, curTick() + 1);
+ owner->schedule(sendRetryEvent, curTick() + 1);
}
}
@@ -126,8 +114,8 @@ BaseCache::CachePort::clearBlocked()
void
BaseCache::init()
{
- if (!cpuSidePort || !memSidePort)
- panic("Cache not hooked up on both sides\n");
+ if (!cpuSidePort->isConnected() || !memSidePort->isConnected())
+ panic("Cache %s not hooked up on both sides\n", name());
cpuSidePort->sendRangeChange();
}
diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh
index cff8813cd..e522bc0c9 100644
--- a/src/mem/cache/base.hh
+++ b/src/mem/cache/base.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -97,50 +109,88 @@ class BaseCache : public MemObject
protected:
- class CachePort : public SimpleTimingPort
+ /**
+ * A cache master port is used for the memory-side port of the
+ * cache, and in addition to the basic timing port that only sends
+ * response packets through a transmit list, it also offers the
+ * ability to schedule and send request packets (requests &
+ * writebacks). The send event is scheduled through requestBus,
+ * and the sendDeferredPacket of the timing port is modified to
+ * consider both the transmit list and the requests from the MSHR.
+ */
+ class CacheMasterPort : public SimpleTimingPort
{
+
public:
- BaseCache *cache;
- protected:
- CachePort(const std::string &_name, BaseCache *_cache,
- const std::string &_label);
+ /**
+ * Schedule a send of a request packet (from the MSHR). Note
+ * that we could already have a retry or a transmit list of
+ * responses outstanding.
+ */
+ void requestBus(RequestCause cause, Tick time)
+ {
+ DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
+ schedSendEvent(time);
+ }
- virtual unsigned deviceBlockSize() const;
+ void respond(PacketPtr pkt, Tick time) {
+ schedSendTiming(pkt, time);
+ }
- bool recvRetryCommon();
+ protected:
- typedef EventWrapper<Port, &Port::sendRetry>
- SendRetryEvent;
+ CacheMasterPort(const std::string &_name, BaseCache *_cache,
+ const std::string &_label);
- const std::string label;
+ /**
+ * Memory-side port always snoops.
+ *
+ * return always true
+ */
+ virtual bool isSnooping() { return true; }
+ };
+
+ /**
+ * A cache slave port is used for the CPU-side port of the cache,
+ * and it is basically a simple timing port that uses a transmit
+ * list for responses to the CPU (or connected master). In
+ * addition, it has the functionality to block the port for
+ * incoming requests. If blocked, the port will issue a retry once
+ * unblocked.
+ */
+ class CacheSlavePort : public SimpleTimingPort
+ {
public:
+
+ /** Do not accept any new requests. */
void setBlocked();
+ /** Return to normal operation and accept new requests. */
void clearBlocked();
- bool checkFunctional(PacketPtr pkt);
+ void respond(PacketPtr pkt, Tick time) {
+ schedSendTiming(pkt, time);
+ }
+
+ protected:
+
+ CacheSlavePort(const std::string &_name, BaseCache *_cache,
+ const std::string &_label);
bool blocked;
bool mustSendRetry;
- void requestBus(RequestCause cause, Tick time)
- {
- DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
- if (!waitingOnRetry) {
- schedSendEvent(time);
- }
- }
+ private:
+
+ EventWrapper<Port, &Port::sendRetry> sendRetryEvent;
- void respond(PacketPtr pkt, Tick time) {
- schedSendTiming(pkt, time);
- }
};
- CachePort *cpuSidePort;
- CachePort *memSidePort;
+ CacheSlavePort *cpuSidePort;
+ CacheMasterPort *memSidePort;
protected:
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index b2569648e..288395584 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -41,6 +41,7 @@
* Dave Greene
* Steve Reinhardt
* Ron Dreslinski
+ * Andreas Hansson
*/
/**
@@ -76,59 +77,68 @@ class Cache : public BaseCache
protected:
- class CpuSidePort : public CachePort
+ /**
+ * The CPU-side port extends the base cache slave port with access
+ * functions for functional, atomic and timing requests.
+ */
+ class CpuSidePort : public CacheSlavePort
{
- public:
- CpuSidePort(const std::string &_name,
- Cache<TagStore> *_cache,
- const std::string &_label);
+ private:
- // BaseCache::CachePort just has a BaseCache *; this function
- // lets us get back the type info we lost when we stored the
- // cache pointer there.
- Cache<TagStore> *myCache() {
- return static_cast<Cache<TagStore> *>(cache);
- }
+ // a pointer to our specific cache implementation
+ Cache<TagStore> *cache;
- virtual AddrRangeList getAddrRanges();
+ protected:
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
- };
- class MemSidePort : public CachePort
- {
+ virtual unsigned deviceBlockSize() const
+ { return cache->getBlockSize(); }
+
+ virtual AddrRangeList getAddrRanges();
+
public:
- MemSidePort(const std::string &_name,
- Cache<TagStore> *_cache,
+
+ CpuSidePort(const std::string &_name, Cache<TagStore> *_cache,
const std::string &_label);
- // BaseCache::CachePort just has a BaseCache *; this function
- // lets us get back the type info we lost when we stored the
- // cache pointer there.
- Cache<TagStore> *myCache() {
- return static_cast<Cache<TagStore> *>(cache);
- }
+ };
- void sendPacket();
+ /**
+ * The memory-side port extends the base cache master port with
+ * access functions for functional, atomic and timing snoops.
+ */
+ class MemSidePort : public CacheMasterPort
+ {
+ private:
- void processSendEvent();
+ // a pointer to our specific cache implementation
+ Cache<TagStore> *cache;
- virtual bool isSnooping();
+ protected:
virtual bool recvTiming(PacketPtr pkt);
- virtual void recvRetry();
-
virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
- typedef EventWrapper<MemSidePort, &MemSidePort::processSendEvent>
- SendEvent;
+ virtual unsigned deviceBlockSize() const
+ { return cache->getBlockSize(); }
+
+ public:
+
+ MemSidePort(const std::string &_name, Cache<TagStore> *_cache,
+ const std::string &_label);
+
+ /**
+ * Overload sendDeferredPacket of SimpleTimingPort.
+ */
+ virtual void sendDeferredPacket();
};
/** Tag and data Storage */
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 87b688617..40359d31e 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -95,7 +95,7 @@ template<class TagStore>
Port *
Cache<TagStore>::getPort(const std::string &if_name, int idx)
{
- if (if_name == "" || if_name == "cpu_side") {
+ if (if_name == "cpu_side") {
return cpuSidePort;
} else if (if_name == "mem_side") {
return memSidePort;
@@ -1553,17 +1553,13 @@ Cache<TagStore>::nextMSHRReadyTime()
template<class TagStore>
AddrRangeList
-Cache<TagStore>::CpuSidePort::
-getAddrRanges()
+Cache<TagStore>::CpuSidePort::getAddrRanges()
{
- // CPU side port doesn't snoop; it's a target only. It can
- // potentially respond to any address.
AddrRangeList ranges;
- ranges.push_back(myCache()->getAddrRange());
+ ranges.push_back(cache->getAddrRange());
return ranges;
}
-
template<class TagStore>
bool
Cache<TagStore>::CpuSidePort::recvTiming(PacketPtr pkt)
@@ -1575,32 +1571,33 @@ Cache<TagStore>::CpuSidePort::recvTiming(PacketPtr pkt)
return false;
}
- myCache()->timingAccess(pkt);
+ cache->timingAccess(pkt);
return true;
}
-
template<class TagStore>
Tick
Cache<TagStore>::CpuSidePort::recvAtomic(PacketPtr pkt)
{
- return myCache()->atomicAccess(pkt);
+ assert(pkt->isRequest());
+ // atomic request
+ return cache->atomicAccess(pkt);
}
-
template<class TagStore>
void
Cache<TagStore>::CpuSidePort::recvFunctional(PacketPtr pkt)
{
- myCache()->functionalAccess(pkt, true);
+ assert(pkt->isRequest());
+ // functional request
+ cache->functionalAccess(pkt, true);
}
-
template<class TagStore>
Cache<TagStore>::
CpuSidePort::CpuSidePort(const std::string &_name, Cache<TagStore> *_cache,
const std::string &_label)
- : BaseCache::CachePort(_name, _cache, _label)
+ : BaseCache::CacheSlavePort(_name, _cache, _label), cache(_cache)
{
}
@@ -1612,17 +1609,6 @@ CpuSidePort::CpuSidePort(const std::string &_name, Cache<TagStore> *_cache,
template<class TagStore>
bool
-Cache<TagStore>::MemSidePort::isSnooping()
-{
- // Memory-side port always snoops, but never passes requests
- // through to targets on the cpu side (so we don't add anything to
- // the address range list).
- return true;
-}
-
-
-template<class TagStore>
-bool
Cache<TagStore>::MemSidePort::recvTiming(PacketPtr pkt)
{
// this needs to be fixed so that the cache updates the mshr and sends the
@@ -1631,60 +1617,45 @@ Cache<TagStore>::MemSidePort::recvTiming(PacketPtr pkt)
if (pkt->wasNacked())
panic("Need to implement cache resending nacked packets!\n");
- if (pkt->isRequest() && blocked) {
- DPRINTF(Cache,"Scheduling a retry while blocked\n");
- mustSendRetry = true;
- return false;
- }
-
if (pkt->isResponse()) {
- myCache()->handleResponse(pkt);
+ cache->handleResponse(pkt);
} else {
- myCache()->snoopTiming(pkt);
+ cache->snoopTiming(pkt);
}
return true;
}
-
template<class TagStore>
Tick
Cache<TagStore>::MemSidePort::recvAtomic(PacketPtr pkt)
{
- // in atomic mode, responses go back to the sender via the
- // function return from sendAtomic(), not via a separate
- // sendAtomic() from the responder. Thus we should never see a
- // response packet in recvAtomic() (anywhere, not just here).
- assert(!pkt->isResponse());
- return myCache()->snoopAtomic(pkt);
+ assert(pkt->isRequest());
+ // atomic snoop
+ return cache->snoopAtomic(pkt);
}
-
template<class TagStore>
void
Cache<TagStore>::MemSidePort::recvFunctional(PacketPtr pkt)
{
- myCache()->functionalAccess(pkt, false);
+ assert(pkt->isRequest());
+ // functional snoop (note that in contrast to atomic we don't have
+ // a specific functionalSnoop method, as they have the same
+ // behaviour regardless)
+ cache->functionalAccess(pkt, false);
}
-
-
template<class TagStore>
void
-Cache<TagStore>::MemSidePort::sendPacket()
+Cache<TagStore>::MemSidePort::sendDeferredPacket()
{
- // if we have responses that are ready, they take precedence
+ // if we have a response packet waiting we have to start with that
if (deferredPacketReady()) {
- bool success = sendTiming(transmitList.front().pkt);
-
- if (success) {
- //send successful, remove packet
- transmitList.pop_front();
- }
-
- waitingOnRetry = !success;
+ // use the normal approach from the timing port
+ trySendTiming();
} else {
- // check for non-response packets (requests & writebacks)
- PacketPtr pkt = myCache()->getTimingPacket();
+ // check for request packets (requests & writebacks)
+ PacketPtr pkt = cache->getTimingPacket();
if (pkt == NULL) {
// can happen if e.g. we attempt a writeback and fail, but
// before the retry, the writeback is eliminated because
@@ -1693,65 +1664,39 @@ Cache<TagStore>::MemSidePort::sendPacket()
} else {
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
- bool success = sendTiming(pkt);
+ waitingOnRetry = !sendTiming(pkt);
- waitingOnRetry = !success;
if (waitingOnRetry) {
DPRINTF(CachePort, "now waiting on a retry\n");
if (!mshr->isForwardNoResponse()) {
+ // we are awaiting a retry, but we
+ // delete the packet and will be creating a new packet
+ // when we get the opportunity
delete pkt;
}
+ // note that we have now masked any requestBus and
+ // schedSendEvent (we will wait for a retry before
+ // doing anything), and this is so even if we do not
+ // care about this packet and might override it before
+ // it gets retried
} else {
- myCache()->markInService(mshr, pkt);
+ cache->markInService(mshr, pkt);
}
}
}
-
- // tried to send packet... if it was successful (no retry), see if
- // we need to rerequest bus or not
+ // if we succeeded and are not waiting for a retry, schedule the
+ // next send, not only looking at the response transmit list, but
+ // also considering when the next MSHR is ready
if (!waitingOnRetry) {
- Tick nextReady = std::min(deferredPacketReadyTime(),
- myCache()->nextMSHRReadyTime());
- // @TODO: need to facotr in prefetch requests here somehow
- if (nextReady != MaxTick) {
- DPRINTF(CachePort, "more packets to send @ %d\n", nextReady);
- cache->schedule(sendEvent, std::max(nextReady, curTick() + 1));
- } else {
- // no more to send right now: if we're draining, we may be done
- if (drainEvent && !sendEvent->scheduled()) {
- drainEvent->process();
- drainEvent = NULL;
- }
- }
+ scheduleSend(cache->nextMSHRReadyTime());
}
}
template<class TagStore>
-void
-Cache<TagStore>::MemSidePort::recvRetry()
-{
- assert(waitingOnRetry);
- sendPacket();
-}
-
-
-template<class TagStore>
-void
-Cache<TagStore>::MemSidePort::processSendEvent()
-{
- assert(!waitingOnRetry);
- sendPacket();
-}
-
-
-template<class TagStore>
Cache<TagStore>::
MemSidePort::MemSidePort(const std::string &_name, Cache<TagStore> *_cache,
const std::string &_label)
- : BaseCache::CachePort(_name, _cache, _label)
+ : BaseCache::CacheMasterPort(_name, _cache, _label), cache(_cache)
{
- // override default send event from SimpleTimingPort
- delete sendEvent;
- sendEvent = new SendEvent(this);
}
diff --git a/src/mem/tport.cc b/src/mem/tport.cc
index 7b1fdb850..cbb7ed2ac 100644
--- a/src/mem/tport.cc
+++ b/src/mem/tport.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -26,6 +38,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
+ * Andreas Hansson
*/
#include "debug/Bus.hh"
@@ -34,35 +47,36 @@
using namespace std;
-SimpleTimingPort::SimpleTimingPort(string pname, MemObject *_owner)
- : Port(pname, _owner), sendEvent(NULL), drainEvent(NULL),
+SimpleTimingPort::SimpleTimingPort(const string &_name, MemObject *_owner,
+ const string _label)
+ : Port(_name, _owner), label(_label), sendEvent(this), drainEvent(NULL),
waitingOnRetry(false)
{
- sendEvent = new EventWrapper<SimpleTimingPort,
- &SimpleTimingPort::processSendEvent>(this);
}
SimpleTimingPort::~SimpleTimingPort()
{
- delete sendEvent;
}
bool
SimpleTimingPort::checkFunctional(PacketPtr pkt)
{
+ pkt->pushLabel(label);
+
DeferredPacketIterator i = transmitList.begin();
DeferredPacketIterator end = transmitList.end();
+ bool found = false;
- for (; i != end; ++i) {
- PacketPtr target = i->pkt;
- // If the target contains data, and it overlaps the
- // probed request, need to update data
- if (pkt->checkFunctional(target)) {
- return true;
- }
+ while (!found && i != end) {
+ // If the buffered packet contains data, and it overlaps the
+ // current packet, then update data
+ found = pkt->checkFunctional(i->pkt);
+ ++i;
}
- return false;
+ pkt->popLabel();
+
+ return found;
}
void
@@ -108,15 +122,17 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
void
SimpleTimingPort::schedSendEvent(Tick when)
{
+ // if we are waiting on a retry, do not schedule a send event, and
+ // instead rely on retry being called
if (waitingOnRetry) {
- assert(!sendEvent->scheduled());
+ assert(!sendEvent.scheduled());
return;
}
- if (!sendEvent->scheduled()) {
- owner->schedule(sendEvent, when);
- } else if (sendEvent->when() > when) {
- owner->reschedule(sendEvent, when);
+ if (!sendEvent.scheduled()) {
+ owner->schedule(&sendEvent, when);
+ } else if (sendEvent.when() > when) {
+ owner->reschedule(&sendEvent, when);
}
}
@@ -153,40 +169,55 @@ SimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when)
assert(false); // should never get here
}
-
-void
-SimpleTimingPort::sendDeferredPacket()
+void SimpleTimingPort::trySendTiming()
{
assert(deferredPacketReady());
- // take packet off list here; if recvTiming() on the other side
- // calls sendTiming() back on us (like SimpleTimingCpu does), then
- // we get confused by having a non-active packet on transmitList
+ // take the next packet off the list here, as we might return to
+ // ourselves through the sendTiming call below
DeferredPacket dp = transmitList.front();
transmitList.pop_front();
- bool success = sendTiming(dp.pkt);
- if (success) {
- if (!transmitList.empty() && !sendEvent->scheduled()) {
- Tick time = transmitList.front().tick;
- owner->schedule(sendEvent, time <= curTick() ? curTick()+1 : time);
- }
+ // attempt to send the packet and remember the outcome
+ waitingOnRetry = !sendTiming(dp.pkt);
+
+ if (waitingOnRetry) {
+ // put the packet back at the front of the list (packet should
+ // not have changed since it wasn't accepted)
+ assert(!sendEvent.scheduled());
+ transmitList.push_front(dp);
+ }
+}
- if (transmitList.empty() && drainEvent && !sendEvent->scheduled()) {
+void
+SimpleTimingPort::scheduleSend(Tick time)
+{
+ // the next ready time is either determined by the next deferred packet,
+ // or in the cache through the MSHR ready time
+ Tick nextReady = std::min(deferredPacketReadyTime(), time);
+ if (nextReady != MaxTick) {
+ // if the sendTiming caused someone else to call our
+ // recvTiming we could already have an event scheduled, check
+ if (!sendEvent.scheduled())
+ owner->schedule(&sendEvent, std::max(nextReady, curTick() + 1));
+ } else {
+ // no more to send, so if we're draining, we may be done
+ if (drainEvent && !sendEvent.scheduled()) {
drainEvent->process();
drainEvent = NULL;
}
- } else {
- // Unsuccessful, need to put back on transmitList. Callee
- // should not have messed with it (since it didn't accept that
- // packet), so we can just push it back on the front.
- assert(!sendEvent->scheduled());
- transmitList.push_front(dp);
}
+}
- waitingOnRetry = !success;
+void
+SimpleTimingPort::sendDeferredPacket()
+{
+ // try to send what is on the list
+ trySendTiming();
- if (waitingOnRetry) {
- DPRINTF(Bus, "Send failed, waiting on retry\n");
+ // if we succeeded and are not waiting for a retry, schedule the
+ // next send
+ if (!waitingOnRetry) {
+ scheduleSend();
}
}
@@ -195,6 +226,9 @@ void
SimpleTimingPort::recvRetry()
{
DPRINTF(Bus, "Received retry\n");
+ // note that in the cache we get a retry even though we may not
+ // have a packet to retry (we could potentially decide on a new
+ // packet every time we retry)
assert(waitingOnRetry);
sendDeferredPacket();
}
@@ -211,7 +245,7 @@ SimpleTimingPort::processSendEvent()
unsigned int
SimpleTimingPort::drain(Event *de)
{
- if (transmitList.size() == 0 && !sendEvent->scheduled())
+ if (transmitList.empty() && !sendEvent.scheduled())
return 0;
drainEvent = de;
return 1;
diff --git a/src/mem/tport.hh b/src/mem/tport.hh
index eaf5acd5d..d720f227c 100644
--- a/src/mem/tport.hh
+++ b/src/mem/tport.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -26,6 +38,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
+ * Andreas Hansson
*/
#ifndef __MEM_TPORT_HH__
@@ -76,6 +89,9 @@ class SimpleTimingPort : public Port
* serviced yet. */
DeferredPacketList transmitList;
+ /** Label to use for print request packets label stack. */
+ const std::string label;
+
/** This function attempts to send deferred packets. Scheduled to
* be called in the future via SendEvent. */
void processSendEvent();
@@ -86,7 +102,8 @@ class SimpleTimingPort : public Port
* When the event time expires it attempts to send the packet.
* If it cannot, the packet sent when recvRetry() is called.
**/
- Event *sendEvent;
+ EventWrapper<SimpleTimingPort,
+ &SimpleTimingPort::processSendEvent> sendEvent;
/** If we need to drain, keep the drain event around until we're done
* here.*/
@@ -95,10 +112,6 @@ class SimpleTimingPort : public Port
/** Remember whether we're awaiting a retry from the bus. */
bool waitingOnRetry;
- /** Check the list of buffered packets against the supplied
- * functional request. */
- bool checkFunctional(PacketPtr funcPkt);
-
/** Check whether we have a packet ready to go on the transmit list. */
bool deferredPacketReady()
{ return !transmitList.empty() && transmitList.front().tick <= curTick(); }
@@ -126,7 +139,24 @@ class SimpleTimingPort : public Port
* non-empty and that the head packet is scheduled for curTick() (or
* earlier).
*/
- void sendDeferredPacket();
+ virtual void sendDeferredPacket();
+
+ /**
+ * Attempt to send the packet at the front of the transmit list,
+ * and set waitingOnRetry accordingly. The packet is temporarily
+ * taken off the list, but put back at the front if not
+ * successfully sent.
+ */
+ void trySendTiming();
+
+ /**
+ * Based on the transmit list, or the provided time, schedule a
+ * send event if there are packets to send. If we are idle and
+ * asked to drain then do so.
+ *
+ * @param time an alternative time for the next send event
+ */
+ void scheduleSend(Tick time = MaxTick);
/** This function is notification that the device should attempt to send a
* packet again. */
@@ -149,9 +179,14 @@ class SimpleTimingPort : public Port
public:
- SimpleTimingPort(std::string pname, MemObject *_owner);
+ SimpleTimingPort(const std::string &_name, MemObject *_owner,
+ const std::string _label = "SimpleTimingPort");
~SimpleTimingPort();
+ /** Check the list of buffered packets against the supplied
+ * functional request. */
+ bool checkFunctional(PacketPtr pkt);
+
/** Hook for draining timing accesses from the system. The
* associated SimObject's drain() functions should be implemented
* something like this when this class is used: