/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* Cache definitions.
*/
-#include "base/fast_alloc.hh"
#include "base/misc.hh"
#include "base/range.hh"
#include "base/types.hh"
+#include "debug/Cache.hh"
+#include "debug/CachePort.hh"
+#include "mem/cache/prefetch/base.hh"
#include "mem/cache/blk.hh"
#include "mem/cache/cache.hh"
#include "mem/cache/mshr.hh"
-#include "mem/cache/prefetch/base.hh"
#include "sim/sim_exit.hh"
template<class TagStore>
-Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf)
+Cache<TagStore>::Cache(const Params *p, TagStore *tags)
: BaseCache(p),
tags(tags),
- prefetcher(pf),
+ prefetcher(p->prefetcher),
doFastWrites(true),
prefetchOnAccess(p->prefetch_on_access)
{
"CpuSidePort");
memSidePort = new MemSidePort(p->name + "-mem_side_port", this,
"MemSidePort");
- cpuSidePort->setOtherPort(memSidePort);
- memSidePort->setOtherPort(cpuSidePort);
tags->setCache(this);
if (prefetcher)
{
BaseCache::regStats();
tags->regStats(name());
- if (prefetcher)
- prefetcher->regStats(name());
-}
-
-template<class TagStore>
-Port *
-Cache<TagStore>::getPort(const std::string &if_name, int idx)
-{
- if (if_name == "" || if_name == "cpu_side") {
- return cpuSidePort;
- } else if (if_name == "mem_side") {
- return memSidePort;
- } else if (if_name == "functional") {
- CpuSidePort *funcPort =
- new CpuSidePort(name() + "-cpu_side_funcport", this,
- "CpuSideFuncPort");
- funcPort->setOtherPort(memSidePort);
- return funcPort;
- } else {
- panic("Port name %s unrecognized\n", if_name);
- }
-}
-
-template<class TagStore>
-void
-Cache<TagStore>::deletePortRefs(Port *p)
-{
- if (cpuSidePort == p || memSidePort == p)
- panic("Can only delete functional ports\n");
-
- delete p;
}
-
template<class TagStore>
void
Cache<TagStore>::cmpAndSwap(BlkType *blk, PacketPtr pkt)
if (blk->isDirty()) {
// special considerations if we're owner:
- if (!deferred_response) {
+ if (!deferred_response && !isTopLevel) {
// if we are responding immediately and can
// signal that we're transferring ownership
// along with exclusivity, do so
int &lat, PacketList &writebacks)
{
if (pkt->req->isUncacheable()) {
- if (pkt->req->isClrex()) {
+ if (pkt->req->isClearLL()) {
tags->clearLocks();
- } else {
+ } else if (pkt->isWrite()) {
blk = tags->findBlock(pkt->getAddr());
if (blk != NULL) {
tags->invalidateBlk(blk);
if (pkt->needsExclusive() ? blk->isWritable() : blk->isReadable()) {
// OK to satisfy access
- incHitCount(pkt, id);
+ incHitCount(pkt);
satisfyCpuSideRequest(pkt, blk);
return true;
}
if (blk == NULL) {
// no replaceable block available, give up.
// writeback will be forwarded to next level.
- incMissCount(pkt, id);
+ incMissCount(pkt);
return false;
}
- int id = pkt->req->hasContextId() ? pkt->req->contextId() : -1;
+ int id = pkt->req->masterId();
tags->insertBlock(pkt->getAddr(), blk, id);
blk->status = BlkValid | BlkReadable;
}
}
// nothing else to do; writeback doesn't expect response
assert(!pkt->needsResponse());
- incHitCount(pkt, id);
+ incHitCount(pkt);
return true;
}
- incMissCount(pkt, id);
+ incMissCount(pkt);
if (blk == NULL && pkt->isLLSC() && pkt->isWrite()) {
// complete miss on store conditional... just give up now
}
-class ForwardResponseRecord : public Packet::SenderState, public FastAlloc
+class ForwardResponseRecord : public Packet::SenderState
{
Packet::SenderState *prevSenderState;
- int prevSrc;
+ PortID prevSrc;
#ifndef NDEBUG
BaseCache *cache;
#endif
//@todo Add back in MemDebug Calls
// MemDebug::cacheAccess(pkt);
+
+ /// @todo temporary hack to deal with memory corruption issue until
+ /// 4-phase transactions are complete
+ for (int x = 0; x < pendingDelete.size(); x++)
+ delete pendingDelete[x];
+ pendingDelete.clear();
+
// we charge hitLatency for doing just about anything here
- Tick time = curTick + hitLatency;
+ Tick time = curTick() + hitLatency;
if (pkt->isResponse()) {
// must be cache-to-cache response from upper to lower level
ForwardResponseRecord *rec =
dynamic_cast<ForwardResponseRecord *>(pkt->senderState);
- assert(rec != NULL);
+
+ if (rec == NULL) {
+ assert(pkt->cmd == MemCmd::HardPFResp);
+ // Check if it's a prefetch response and handle it. We shouldn't
+ // get any other kinds of responses without FRRs.
+ DPRINTF(Cache, "Got prefetch response from above for addr %#x\n",
+ pkt->getAddr());
+ handleResponse(pkt);
+ return true;
+ }
+
rec->restore(pkt, this);
delete rec;
memSidePort->respond(pkt, time);
Packet *snoopPkt = new Packet(pkt, true); // clear flags
snoopPkt->setExpressSnoop();
snoopPkt->assertMemInhibit();
- memSidePort->sendTiming(snoopPkt);
+ memSidePort->sendTimingReq(snoopPkt);
// main memory will delete snoopPkt
}
// since we're the official target but we aren't responding,
// delete the packet now.
- delete pkt;
+
+ /// @todo nominally we should just delete the packet here,
+ /// however, until 4-phase stuff we can't because sending
+ /// cache is still relying on it
+ pendingDelete.push_back(pkt);
return true;
}
if (pkt->req->isUncacheable()) {
- if (pkt->req->isClrex()) {
+ if (pkt->req->isClearLL()) {
tags->clearLocks();
- } else {
+ } else if (pkt->isWrite()) {
BlkType *blk = tags->findBlock(pkt->getAddr());
if (blk != NULL) {
tags->invalidateBlk(blk);
bool needsResponse = pkt->needsResponse();
if (satisfied) {
- if (needsResponse) {
- pkt->makeTimingResponse();
- cpuSidePort->respond(pkt, curTick+lat);
- } else {
- delete pkt;
- }
-
if (prefetcher && (prefetchOnAccess || (blk && blk->wasPrefetched()))) {
if (blk)
blk->status &= ~BlkHWPrefetched;
next_pf_time = prefetcher->notify(pkt, time);
}
+
+ if (needsResponse) {
+ pkt->makeTimingResponse();
+ cpuSidePort->respond(pkt, curTick()+lat);
+ } else {
+ /// @todo nominally we should just delete the packet here,
+ /// however, until 4-phase stuff we can't because sending
+ /// cache is still relying on it
+ pendingDelete.push_back(pkt);
+ }
} else {
// miss
if (mshr) {
// MSHR hit
//@todo remove hw_pf here
- mshr_hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
+ assert(pkt->req->masterId() < system->maxMasters());
+ mshr_hits[pkt->cmdToIndex()][pkt->req->masterId()]++;
if (mshr->threadNum != 0/*pkt->req->threadId()*/) {
mshr->threadNum = -1;
}
noTargetMSHR = mshr;
setBlocked(Blocked_NoTargets);
// need to be careful with this... if this mshr isn't
- // ready yet (i.e. time > curTick_, we don't want to
+ // ready yet (i.e. time > curTick()_, we don't want to
// move it ahead of mshrs that are ready
// mshrQueue.moveToFront(mshr);
}
} else {
// no MSHR
- mshr_misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
+ assert(pkt->req->masterId() < system->maxMasters());
+ mshr_misses[pkt->cmdToIndex()][pkt->req->masterId()]++;
// always mark as cache fill for now... if we implement
// no-write-allocate or bypass accesses this will have to
// be changed.
// block is invalid
cmd = needsExclusive ? MemCmd::ReadExReq : MemCmd::ReadReq;
}
- PacketPtr pkt = new Packet(cpu_pkt->req, cmd, Packet::Broadcast, blkSize);
+ PacketPtr pkt = new Packet(cpu_pkt->req, cmd, blkSize);
pkt->allocate();
return pkt;
template<class TagStore>
void
-Cache<TagStore>::functionalAccess(PacketPtr pkt,
- CachePort *incomingPort,
- CachePort *otherSidePort)
+Cache<TagStore>::functionalAccess(PacketPtr pkt, bool fromCpuSide)
{
Addr blk_addr = blockAlign(pkt->getAddr());
BlkType *blk = tags->findBlock(pkt->getAddr());
(mshr && mshr->inService && mshr->isPendingDirty()));
bool done = have_dirty
- || incomingPort->checkFunctional(pkt)
+ || cpuSidePort->checkFunctional(pkt)
|| mshrQueue.checkFunctional(pkt, blk_addr)
|| writeBuffer.checkFunctional(pkt, blk_addr)
- || otherSidePort->checkFunctional(pkt);
+ || memSidePort->checkFunctional(pkt);
DPRINTF(Cache, "functional %s %x %s%s%s\n",
pkt->cmdString(), pkt->getAddr(),
if (done) {
pkt->makeResponse();
} else {
- otherSidePort->sendFunctional(pkt);
+ // if it came as a request from the CPU side then make sure it
+ // continues towards the memory side
+ if (fromCpuSide) {
+ memSidePort->sendFunctional(pkt);
+ } else if (forwardSnoops && cpuSidePort->isSnooping()) {
+ // if it came from the memory side, it must be a snoop request
+ // and we should only forward it if we are forwarding snoops
+ cpuSidePort->sendFunctionalSnoop(pkt);
+ }
}
}
void
Cache<TagStore>::handleResponse(PacketPtr pkt)
{
- Tick time = curTick + hitLatency;
+ Tick time = curTick() + hitLatency;
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
bool is_error = pkt->isError();
MSHR::Target *initial_tgt = mshr->getTarget();
BlkType *blk = tags->findBlock(pkt->getAddr());
int stats_cmd_idx = initial_tgt->pkt->cmdToIndex();
- Tick miss_latency = curTick - initial_tgt->recvTime;
+ Tick miss_latency = curTick() - initial_tgt->recvTime;
PacketList writebacks;
if (pkt->req->isUncacheable()) {
- mshr_uncacheable_lat[stats_cmd_idx][0/*pkt->req->threadId()*/] +=
+ assert(pkt->req->masterId() < system->maxMasters());
+ mshr_uncacheable_lat[stats_cmd_idx][pkt->req->masterId()] +=
miss_latency;
} else {
- mshr_miss_latency[stats_cmd_idx][0/*pkt->req->threadId()*/] +=
+ assert(pkt->req->masterId() < system->maxMasters());
+ mshr_miss_latency[stats_cmd_idx][pkt->req->masterId()] +=
miss_latency;
}
(transfer_offset ? pkt->finishTime : pkt->firstWordTime);
assert(!target->pkt->req->isUncacheable());
- missLatency[target->pkt->cmdToIndex()][0/*pkt->req->threadId()*/] +=
+
+ assert(target->pkt->req->masterId() < system->maxMasters());
+ missLatency[target->pkt->cmdToIndex()][target->pkt->req->masterId()] +=
completion_time - target->recvTime;
} else if (pkt->cmd == MemCmd::UpgradeFailResp) {
// failed StoreCond upgrade
assert(target->pkt->cmd == MemCmd::StoreCondReq ||
- target->pkt->cmd == MemCmd::StoreCondFailReq);
+ target->pkt->cmd == MemCmd::StoreCondFailReq ||
+ target->pkt->cmd == MemCmd::SCUpgradeFailReq);
completion_time = tags->getHitLatency() + pkt->finishTime;
target->pkt->req->setExtraData(0);
} else {
if (blk->isDirty()) {
allocateWriteBuffer(writebackBlk(blk), time, true);
}
+ blk->status &= ~BlkValid;
tags->invalidateBlk(blk);
}
{
assert(blk && blk->isValid() && blk->isDirty());
- writebacks[0/*pkt->req->threadId()*/]++;
+ writebacks[Request::wbMasterId]++;
Request *writebackReq =
- new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0);
- PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback, -1);
+ new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0,
+ Request::wbMasterId);
+ PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback);
if (blk->isWritable()) {
writeback->setSupplyExclusive();
}
tempBlock->tag = tags->extractTag(addr);
DPRINTF(Cache, "using temp block for %x\n", addr);
} else {
- int id = pkt->req->hasContextId() ? pkt->req->contextId() : -1;
+ int id = pkt->req->masterId();
tags->insertBlock(pkt->getAddr(), blk, id);
}
// invalidate it.
pkt->cmd = MemCmd::ReadRespWithInvalidate;
}
- memSidePort->respond(pkt, curTick + hitLatency);
+ memSidePort->respond(pkt, curTick() + hitLatency);
}
template<class TagStore>
// rewritten to be relative to cpu-side bus (if any)
bool alreadyResponded = pkt->memInhibitAsserted();
if (is_timing) {
- Packet *snoopPkt = new Packet(pkt, true); // clear flags
- snoopPkt->setExpressSnoop();
- snoopPkt->senderState = new ForwardResponseRecord(pkt, this);
- cpuSidePort->sendTiming(snoopPkt);
- if (snoopPkt->memInhibitAsserted()) {
+ Packet snoopPkt(pkt, true); // clear flags
+ snoopPkt.setExpressSnoop();
+ snoopPkt.senderState = new ForwardResponseRecord(pkt, this);
+ cpuSidePort->sendTimingSnoopReq(&snoopPkt);
+ if (snoopPkt.memInhibitAsserted()) {
// cache-to-cache response from some upper cache
assert(!alreadyResponded);
pkt->assertMemInhibit();
} else {
- delete snoopPkt->senderState;
+ delete snoopPkt.senderState;
}
- if (snoopPkt->sharedAsserted()) {
+ if (snoopPkt.sharedAsserted()) {
pkt->assertShared();
}
- delete snoopPkt;
} else {
- int origSrc = pkt->getSrc();
- cpuSidePort->sendAtomic(pkt);
+ cpuSidePort->sendAtomicSnoop(pkt);
if (!alreadyResponded && pkt->memInhibitAsserted()) {
// cache-to-cache response from some upper cache:
// forward response to original requester
assert(pkt->isResponse());
}
- pkt->setSrc(origSrc);
}
}
pkt->getAddr());
//Look through writebacks for any non-uncachable writes, use that
- for (int i = 0; i < writebacks.size(); i++) {
- mshr = writebacks[i];
+ if (writebacks.size()) {
+ // We should only ever find a single match
+ assert(writebacks.size() == 1);
+ mshr = writebacks[0];
assert(!mshr->isUncacheable());
assert(mshr->getNumTargets() == 1);
PacketPtr wb_pkt = mshr->getTarget()->pkt;
markInService(mshr);
delete wb_pkt;
}
-
- // If this was a shared writeback, there may still be
- // other shared copies above that require invalidation.
- // We could be more selective and return here if the
- // request is non-exclusive or if the writeback is
- // exclusive.
- break;
- }
+ } // writebacks.size()
}
+ // If this was a shared writeback, there may still be
+ // other shared copies above that require invalidation.
+ // We could be more selective and return here if the
+ // request is non-exclusive or if the writeback is
+ // exclusive.
handleSnoop(pkt, blk, true, false, false);
}
+template<class TagStore>
+bool
+Cache<TagStore>::CpuSidePort::recvTimingSnoopResp(PacketPtr pkt)
+{
+ // Express snoop responses from master to slave, e.g., from L1 to L2
+ cache->timingAccess(pkt);
+ return true;
+}
template<class TagStore>
Tick
PacketPtr pkt = prefetcher->getPacket();
if (pkt) {
Addr pf_addr = blockAlign(pkt->getAddr());
- if (!tags->findBlock(pf_addr) && !mshrQueue.findMatch(pf_addr)) {
+ if (!tags->findBlock(pf_addr) && !mshrQueue.findMatch(pf_addr) &&
+ !writeBuffer.findMatch(pf_addr)) {
// Update statistic on number of prefetches issued
// (hwpf_mshr_misses)
- mshr_misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
+ assert(pkt->req->masterId() < system->maxMasters());
+ mshr_misses[pkt->cmdToIndex()][pkt->req->masterId()]++;
// Don't request bus, since we already have it
- return allocateMissBuffer(pkt, curTick, false);
+ return allocateMissBuffer(pkt, curTick(), false);
+ } else {
+ // free the request and packet
+ delete pkt->req;
+ delete pkt;
}
}
}
pkt = new Packet(tgt_pkt);
pkt->cmd = MemCmd::UpgradeFailResp;
pkt->senderState = mshr;
- pkt->firstWordTime = pkt->finishTime = curTick;
+ pkt->firstWordTime = pkt->finishTime = curTick();
handleResponse(pkt);
return NULL;
} else if (mshr->isForwardNoResponse()) {
pkt = tgt_pkt;
} else {
BlkType *blk = tags->findBlock(mshr->addr);
+
+ if (tgt_pkt->cmd == MemCmd::HardPFReq) {
+ // It might be possible for a writeback to arrive between
+ // the time the prefetch is placed in the MSHRs and when
+ // it's selected to send... if so, this assert will catch
+ // that, and then we'll have to figure out what to do.
+ assert(blk == NULL);
+
+ // We need to check the caches above us to verify that they don't have
+ // a copy of this block in the dirty state at the moment. Without this
+ // check we could get a stale copy from memory that might get used
+ // in place of the dirty one.
+ PacketPtr snoop_pkt = new Packet(tgt_pkt, true);
+ snoop_pkt->setExpressSnoop();
+ snoop_pkt->senderState = mshr;
+ cpuSidePort->sendTimingSnoopReq(snoop_pkt);
+
+ if (snoop_pkt->memInhibitAsserted()) {
+ markInService(mshr, snoop_pkt);
+ DPRINTF(Cache, "Upward snoop of prefetch for addr %#x hit\n",
+ tgt_pkt->getAddr());
+ delete snoop_pkt;
+ return NULL;
+ }
+ delete snoop_pkt;
+ }
+
pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive());
mshr->isForward = (pkt == NULL);
return nextReady;
}
+template<class TagStore>
+void
+Cache<TagStore>::serialize(std::ostream &os)
+{
+ warn("*** Creating checkpoints with caches is not supported. ***\n");
+ warn(" Remove any caches before taking checkpoints\n");
+ warn(" This checkpoint will not restore correctly and dirty data in "
+ "the cache will be lost!\n");
+
+ // Since we don't write back the data dirty in the caches to the physical
+ // memory if caches exist in the system we won't be able to restore
+ // from the checkpoint as any data dirty in the caches will be lost.
+
+ bool bad_checkpoint = true;
+ SERIALIZE_SCALAR(bad_checkpoint);
+}
+
+template<class TagStore>
+void
+Cache<TagStore>::unserialize(Checkpoint *cp, const std::string §ion)
+{
+ bool bad_checkpoint;
+ UNSERIALIZE_SCALAR(bad_checkpoint);
+ if (bad_checkpoint) {
+ fatal("Restoring from checkpoints with caches is not supported in the "
+ "classic memory system. Please remove any caches before taking "
+ "checkpoints.\n");
+ }
+}
///////////////
//
///////////////
template<class TagStore>
-void
-Cache<TagStore>::CpuSidePort::
-getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+AddrRangeList
+Cache<TagStore>::CpuSidePort::getAddrRanges() const
{
- // CPU side port doesn't snoop; it's a target only. It can
- // potentially respond to any address.
- snoop = false;
- resp.push_back(myCache()->getAddrRange());
+ return cache->getAddrRanges();
}
-
template<class TagStore>
bool
-Cache<TagStore>::CpuSidePort::recvTiming(PacketPtr pkt)
+Cache<TagStore>::CpuSidePort::recvTimingReq(PacketPtr pkt)
{
- // illegal to block responses... can lead to deadlock
- if (pkt->isRequest() && !pkt->memInhibitAsserted() && blocked) {
+ // always let inhibited requests through even if blocked
+ if (!pkt->memInhibitAsserted() && blocked) {
DPRINTF(Cache,"Scheduling a retry while blocked\n");
mustSendRetry = true;
return false;
}
- myCache()->timingAccess(pkt);
+ cache->timingAccess(pkt);
return true;
}
-
template<class TagStore>
Tick
Cache<TagStore>::CpuSidePort::recvAtomic(PacketPtr pkt)
{
- return myCache()->atomicAccess(pkt);
+ // atomic request
+ return cache->atomicAccess(pkt);
}
-
template<class TagStore>
void
Cache<TagStore>::CpuSidePort::recvFunctional(PacketPtr pkt)
{
- myCache()->functionalAccess(pkt, this, otherPort);
+ // 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)
{
}
//
///////////////
-template<class TagStore>
-void
-Cache<TagStore>::MemSidePort::
-getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
-{
- // 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).
- snoop = true;
-}
-
-
template<class TagStore>
bool
-Cache<TagStore>::MemSidePort::recvTiming(PacketPtr pkt)
+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
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);
- } else {
- myCache()->snoopTiming(pkt);
- }
+ cache->handleResponse(pkt);
return true;
}
+// Express snooping requests to memside port
+template<class TagStore>
+void
+Cache<TagStore>::MemSidePort::recvTimingSnoopReq(PacketPtr pkt)
+{
+ // handle snooping requests
+ cache->snoopTiming(pkt);
+}
template<class TagStore>
Tick
-Cache<TagStore>::MemSidePort::recvAtomic(PacketPtr pkt)
+Cache<TagStore>::MemSidePort::recvAtomicSnoop(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);
+ // atomic snoop
+ return cache->snoopAtomic(pkt);
}
-
template<class TagStore>
void
-Cache<TagStore>::MemSidePort::recvFunctional(PacketPtr pkt)
+Cache<TagStore>::MemSidePort::recvFunctionalSnoop(PacketPtr pkt)
{
- myCache()->functionalAccess(pkt, this, otherPort);
+ // 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>::MemSidePacketQueue::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
} else {
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
- bool success = sendTiming(pkt);
+ waitingOnRetry = !masterPort.sendTimingReq(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);
- 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, _queue),
+ _queue(*_cache, *this, _label), cache(_cache)
{
- // override default send event from SimpleTimingPort
- delete sendEvent;
- sendEvent = new SendEvent(this);
}