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); - - virtual unsigned deviceBlockSize() const; - - bool recvRetryCommon(); - - typedef EventWrapper - SendRetryEvent; - - const std::string label; public: - void setBlocked(); - - void clearBlocked(); - - bool checkFunctional(PacketPtr pkt); - - bool blocked; - - bool mustSendRetry; + /** + * 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); - if (!waitingOnRetry) { - schedSendEvent(time); - } + schedSendEvent(time); } void respond(PacketPtr pkt, Tick time) { schedSendTiming(pkt, time); } + + protected: + + CacheMasterPort(const std::string &_name, BaseCache *_cache, + const std::string &_label); + + /** + * Memory-side port always snoops. + * + * return always true + */ + virtual bool isSnooping() { return true; } }; - CachePort *cpuSidePort; - CachePort *memSidePort; + /** + * 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(); + + 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; + + private: + + EventWrapper sendRetryEvent; + + }; + + 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 *_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 *myCache() { - return static_cast *>(cache); - } + // a pointer to our specific cache implementation + Cache *cache; + + protected: + + virtual bool recvTiming(PacketPtr pkt); + + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvFunctional(PacketPtr pkt); + + virtual unsigned deviceBlockSize() const + { return cache->getBlockSize(); } virtual AddrRangeList getAddrRanges(); - virtual bool recvTiming(PacketPtr pkt); - - virtual Tick recvAtomic(PacketPtr pkt); - - virtual void recvFunctional(PacketPtr pkt); - }; - - class MemSidePort : public CachePort - { public: - MemSidePort(const std::string &_name, - Cache *_cache, + + CpuSidePort(const std::string &_name, Cache *_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 *myCache() { - return static_cast *>(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 *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 - SendEvent; + virtual unsigned deviceBlockSize() const + { return cache->getBlockSize(); } + + public: + + MemSidePort(const std::string &_name, Cache *_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 Port * Cache::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::nextMSHRReadyTime() template AddrRangeList -Cache::CpuSidePort:: -getAddrRanges() +Cache::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 bool Cache::CpuSidePort::recvTiming(PacketPtr pkt) @@ -1575,32 +1571,33 @@ Cache::CpuSidePort::recvTiming(PacketPtr pkt) return false; } - myCache()->timingAccess(pkt); + cache->timingAccess(pkt); return true; } - template Tick Cache::CpuSidePort::recvAtomic(PacketPtr pkt) { - return myCache()->atomicAccess(pkt); + assert(pkt->isRequest()); + // atomic request + return cache->atomicAccess(pkt); } - template void Cache::CpuSidePort::recvFunctional(PacketPtr pkt) { - myCache()->functionalAccess(pkt, true); + assert(pkt->isRequest()); + // functional request + cache->functionalAccess(pkt, true); } - template Cache:: CpuSidePort::CpuSidePort(const std::string &_name, Cache *_cache, const std::string &_label) - : BaseCache::CachePort(_name, _cache, _label) + : BaseCache::CacheSlavePort(_name, _cache, _label), cache(_cache) { } @@ -1610,17 +1607,6 @@ CpuSidePort::CpuSidePort(const std::string &_name, Cache *_cache, // /////////////// -template -bool -Cache::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 bool Cache::MemSidePort::recvTiming(PacketPtr pkt) @@ -1631,60 +1617,45 @@ Cache::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 Tick Cache::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 void Cache::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 void -Cache::MemSidePort::sendPacket() +Cache::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::MemSidePort::sendPacket() } else { MSHR *mshr = dynamic_cast(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 -void -Cache::MemSidePort::recvRetry() -{ - assert(waitingOnRetry); - sendPacket(); -} - - -template -void -Cache::MemSidePort::processSendEvent() -{ - assert(!waitingOnRetry); - sendPacket(); -} - - template Cache:: MemSidePort::MemSidePort(const std::string &_name, Cache *_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(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::trySendTiming() +{ + assert(deferredPacketReady()); + // 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(); + + // 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); + } +} + +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; + } + } +} void SimpleTimingPort::sendDeferredPacket() { - 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 - DeferredPacket dp = transmitList.front(); - transmitList.pop_front(); - bool success = sendTiming(dp.pkt); + // try to send what is on the list + trySendTiming(); - if (success) { - if (!transmitList.empty() && !sendEvent->scheduled()) { - Tick time = transmitList.front().tick; - owner->schedule(sendEvent, time <= curTick() ? curTick()+1 : time); - } - - if (transmitList.empty() && 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; - - 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 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: