/*
+ * 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) 2007 The Hewlett-Packard Development Company
* All rights reserved.
*
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();
+ assert(pkt->isResponse());
+ 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;
}
}
- } else {
- DPRINTF(PageTableWalker, "Received strange packet\n");
+ 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();
+ }
}
return true;
}
-Tick
-Walker::WalkerPort::recvAtomic(PacketPtr pkt)
-{
- return 0;
-}
-
-void
-Walker::WalkerPort::recvFunctional(PacketPtr pkt)
-{
- return;
-}
-
void
Walker::WalkerPort::recvRetry()
{
bool
Walker::WalkerState::recvPacket(PacketPtr pkt)
{
- if (pkt->isResponse() && !pkt->wasNacked()) {
+ assert(pkt->isResponse());
+ if (!pkt->wasNacked()) {
assert(inflight);
assert(state == Waiting);
assert(!read);
}
return true;
}
- } else if (pkt->wasNacked()) {
+ } else {
DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n");
pkt->reinitNacked();
if (!walker->sendTiming(this, pkt)) {
Walker *walker;
bool recvTiming(PacketPtr pkt);
- Tick recvAtomic(PacketPtr pkt);
- void recvFunctional(PacketPtr pkt);
+
+ /**
+ * Snooping a coherence request, do nothing.
+ */
+ bool recvTimingSnoop(PacketPtr pkt) { return true; }
+ Tick recvAtomicSnoop(PacketPtr pkt) { return 0; }
+ void recvFunctionalSnoop(PacketPtr pkt) { }
void recvRetry();
bool isSnooping() const { return true; }
};
bool
BaseCPU::CpuPort::recvTiming(PacketPtr pkt)
{
- panic("BaseCPU doesn't expect recvTiming callback!");
+ panic("BaseCPU doesn't expect recvTiming!\n");
return true;
}
void
BaseCPU::CpuPort::recvRetry()
{
- panic("BaseCPU doesn't expect recvRetry callback!");
-}
-
-Tick
-BaseCPU::CpuPort::recvAtomic(PacketPtr pkt)
-{
- panic("BaseCPU doesn't expect recvAtomic callback!");
- return curTick();
+ panic("BaseCPU doesn't expect recvRetry!\n");
}
void
-BaseCPU::CpuPort::recvFunctional(PacketPtr pkt)
+BaseCPU::CpuPort::recvFunctionalSnoop(PacketPtr pkt)
{
- // No internal storage to update (in the general case). In the
- // long term this should never be called, but that assumed a split
- // into master/slave and request/response.
+ // No internal storage to update (in the general case). A CPU with
+ // internal storage, e.g. an LSQ that should be part of the
+ // coherent memory has to check against stored data.
}
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt);
-
virtual void recvRetry();
- void recvFunctional(PacketPtr pkt);
+ virtual void recvFunctionalSnoop(PacketPtr pkt);
};
bool
InOrderCPU::CachePort::recvTiming(Packet *pkt)
{
+ assert(pkt->isResponse());
+
if (pkt->isError())
DPRINTF(InOrderCachePort, "Got error packet back for address: %x\n",
pkt->getAddr());
- else if (pkt->isResponse())
+ else
cacheUnit->processCacheCompletion(pkt);
- else {
- //@note: depending on consistency model, update here
- DPRINTF(InOrderCachePort, "Received snoop pkt %x,Ignoring\n",
- pkt->getAddr());
- }
return true;
}
/** Handles doing a retry of a failed timing request. */
void recvRetry();
+
+ /** Ignoring snoops for now. */
+ bool recvTimingSnoop(PacketPtr pkt) { return true; }
};
/** Define TickEvent for the CPU */
/*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
bool
FullO3CPU<Impl>::IcachePort::recvTiming(PacketPtr pkt)
{
+ assert(pkt->isResponse());
DPRINTF(O3CPU, "Fetch unit received timing\n");
- if (pkt->isResponse()) {
- // We shouldn't ever get a block in ownership state
- assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
+ // We shouldn't ever get a block in ownership state
+ assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
+ fetch->processCacheCompletion(pkt);
- fetch->processCacheCompletion(pkt);
- }
- //else Snooped a coherence request, just return
return true;
}
bool
FullO3CPU<Impl>::DcachePort::recvTiming(PacketPtr pkt)
{
+ assert(pkt->isResponse());
return lsq->recvTiming(pkt);
}
+template <class Impl>
+bool
+FullO3CPU<Impl>::DcachePort::recvTimingSnoop(PacketPtr pkt)
+{
+ assert(pkt->isRequest());
+ return lsq->recvTimingSnoop(pkt);
+}
+
template <class Impl>
void
FullO3CPU<Impl>::DcachePort::recvRetry()
/** Timing version of receive. Handles setting fetch to the
* proper status to start fetching. */
virtual bool recvTiming(PacketPtr pkt);
+ virtual bool recvTimingSnoop(PacketPtr pkt) { return true; }
/** Handles doing a retry of a failed fetch. */
virtual void recvRetry();
* completing the load or store that has returned from
* memory. */
virtual bool recvTiming(PacketPtr pkt);
+ virtual bool recvTimingSnoop(PacketPtr pkt);
/** Handles doing a retry of the previous send. */
virtual void recvRetry();
*/
bool recvTiming(PacketPtr pkt);
+ bool recvTimingSnoop(PacketPtr pkt);
+
/** The CPU pointer. */
O3CPU *cpu;
/*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
bool
LSQ<Impl>::recvTiming(PacketPtr pkt)
{
+ assert(pkt->isResponse());
if (pkt->isError())
DPRINTF(LSQ, "Got error packet back for address: %#X\n",
pkt->getAddr());
- if (pkt->isResponse()) {
- thread[pkt->req->threadId()].completeDataAccess(pkt);
- } else {
- DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
- pkt->cmdString());
-
- // must be a snoop
- if (pkt->isInvalidate()) {
- DPRINTF(LSQ, "received invalidation for addr:%#x\n",
- pkt->getAddr());
- for (ThreadID tid = 0; tid < numThreads; tid++) {
- thread[tid].checkSnoop(pkt);
- }
+ thread[pkt->req->threadId()].completeDataAccess(pkt);
+ return true;
+}
+
+template <class Impl>
+bool
+LSQ<Impl>::recvTimingSnoop(PacketPtr pkt)
+{
+ assert(pkt->isRequest());
+ DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
+ pkt->cmdString());
+
+ // must be a snoop
+ if (pkt->isInvalidate()) {
+ DPRINTF(LSQ, "received invalidation for addr:%#x\n",
+ pkt->getAddr());
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ thread[tid].checkSnoop(pkt);
}
- // to provide stronger consistency model
}
+
+ // to provide stronger consistency model
return true;
}
protected:
- virtual Tick recvAtomic(PacketPtr pkt)
+ virtual Tick recvAtomicSnoop(PacketPtr pkt)
{
// Snooping a coherence request, just return
return 0;
/*
- * 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
bool
TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
{
- if (pkt->isResponse() && !pkt->wasNacked()) {
+ assert(pkt->isResponse());
+ 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());
tickEvent.schedule(pkt, next_tick);
return true;
- } else if (pkt->wasNacked()) {
+ } else {
assert(cpu->_status == IcacheWaitResponse);
pkt->reinitNacked();
if (!sendTiming(pkt)) {
cpu->ifetch_pkt = pkt;
}
}
- //Snooping a Coherence Request, do nothing
+
return true;
}
bool
TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
{
- if (pkt->isResponse() && !pkt->wasNacked()) {
+ assert(pkt->isResponse());
+ if (!pkt->wasNacked()) {
// delay processing of returned data until next CPU clock edge
Tick next_tick = cpu->nextCycle(curTick());
}
return true;
- }
- else if (pkt->wasNacked()) {
+ } else {
assert(cpu->_status == DcacheWaitResponse);
pkt->reinitNacked();
if (!sendTiming(pkt)) {
cpu->dcache_pkt = pkt;
}
}
- //Snooping a Coherence Request, do nothing
+
return true;
}
protected:
+ /**
+ * Snooping a coherence request, do nothing.
+ */
+ virtual bool recvTimingSnoop(PacketPtr pkt) { return true; }
+
TimingSimpleCPU* cpu;
struct TickEvent : public Event
}
}
-Tick
-RubyDirectedTester::CpuPort::recvAtomic(PacketPtr pkt)
-{
- panic("RubyDirectedTester::CpuPort::recvAtomic() not implemented!\n");
- return 0;
-}
-
bool
RubyDirectedTester::CpuPort::recvTiming(PacketPtr pkt)
{
virtual bool recvTiming(PacketPtr pkt);
virtual void recvRetry()
{ panic("%s does not expect a retry\n", name()); }
- virtual Tick recvAtomic(PacketPtr pkt);
- virtual void recvFunctional(PacketPtr pkt) { }
};
typedef RubyDirectedTesterParams Params;
bool
MemTest::CpuPort::recvTiming(PacketPtr pkt)
{
- if (pkt->isResponse()) {
- memtest->completeRequest(pkt);
- } else {
- // must be snoop upcall
- assert(pkt->isRequest());
- assert(pkt->getDest() == Packet::Broadcast);
- }
+ assert(pkt->isResponse());
+ memtest->completeRequest(pkt);
return true;
}
-Tick
-MemTest::CpuPort::recvAtomic(PacketPtr pkt)
-{
- // must be snoop upcall
- assert(pkt->isRequest());
- assert(pkt->getDest() == Packet::Broadcast);
- return curTick();
-}
-
-void
-MemTest::CpuPort::recvFunctional(PacketPtr pkt)
-{
- //Do nothing if we see one come through
-// if (curTick() != 0)//Supress warning durring initialization
-// warn("Functional Writes not implemented in MemTester\n");
- //Need to find any response values that intersect and update
- return;
-}
-
void
MemTest::CpuPort::recvRetry()
{
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt);
+ virtual bool recvTimingSnoop(PacketPtr pkt) { return true; }
- virtual void recvFunctional(PacketPtr pkt);
+ virtual Tick recvAtomicSnoop(PacketPtr pkt) { return 0; }
+
+ virtual void recvFunctionalSnoop(PacketPtr pkt) { }
virtual void recvRetry();
};
bool
NetworkTest::CpuPort::recvTiming(PacketPtr pkt)
{
- if (pkt->isResponse()) {
- networktest->completeRequest(pkt);
- } else {
- // must be snoop upcall
- assert(pkt->isRequest());
- assert(pkt->getDest() == Packet::Broadcast);
- }
+ assert(pkt->isResponse());
+ networktest->completeRequest(pkt);
return true;
}
-Tick
-NetworkTest::CpuPort::recvAtomic(PacketPtr pkt)
-{
- panic("NetworkTest doesn't expect recvAtomic call!");
- // Will not be used
- assert(pkt->isRequest());
- assert(pkt->getDest() == Packet::Broadcast);
- return curTick();
-}
-
-void
-NetworkTest::CpuPort::recvFunctional(PacketPtr pkt)
-{
- panic("NetworkTest doesn't expect recvFunctional call!");
- // Will not be used
- return;
-}
-
void
NetworkTest::CpuPort::recvRetry()
{
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt);
-
- virtual void recvFunctional(PacketPtr pkt);
-
virtual void recvRetry();
};
}
}
-Tick
-RubyTester::CpuPort::recvAtomic(PacketPtr pkt)
-{
- panic("RubyTester::CpuPort::recvAtomic() not implemented!\n");
- return 0;
-}
-
bool
RubyTester::CpuPort::recvTiming(PacketPtr pkt)
{
virtual bool recvTiming(PacketPtr pkt);
virtual void recvRetry()
{ panic("%s does not expect a retry\n", name()); }
- virtual Tick recvAtomic(PacketPtr pkt);
- virtual void recvFunctional(PacketPtr pkt) { }
};
struct SenderState : public Packet::SenderState
/*
+ * 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.
*
bool
DmaPort::recvTiming(PacketPtr pkt)
{
+ assert(pkt->isResponse());
if (pkt->wasNacked()) {
DPRINTF(DMA, "Received nacked %s addr %#x\n",
pkt->cmdString(), pkt->getAddr());
pkt->reinitNacked();
queueDma(pkt, true);
- } else if (pkt->isRequest() && recvSnoops) {
- return true;
} else if (pkt->senderState) {
DmaReqState *state;
backoffTime >>= 2;
/*
+ * 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) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
bool recvSnoops;
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt)
- {
- if (recvSnoops) return 0;
- panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN
+ virtual bool recvTimingSnoop(PacketPtr pkt)
+ {
+ if (!recvSnoops)
+ panic("%s was not expecting a snoop\n", name());
+ return true;
}
- virtual void recvFunctional(PacketPtr pkt)
+
+ virtual Tick recvAtomicSnoop(PacketPtr pkt)
{
- if (recvSnoops) return;
+ if (!recvSnoops)
+ panic("%s was not expecting a snoop\n", name());
+ return 0;
+ }
- panic("dma port shouldn't be used for pio access.");
+ virtual void recvFunctionalSnoop(PacketPtr pkt)
+ {
+ if (!recvSnoops)
+ panic("%s was not expecting a snoop\n", name());
}
virtual void recvRetry() ;
bridge->schedule(sendEvent, nextReady);
}
-Tick
-Bridge::BridgeMasterPort::recvAtomic(PacketPtr pkt)
-{
- // master port should never receive any atomic access (panic only
- // works once the other side, i.e. the busses, respects this)
- //
- //panic("Master port on %s got a recvAtomic\n", bridge->name());
- return 0;
-}
-
Tick
Bridge::BridgeSlavePort::recvAtomic(PacketPtr pkt)
{
return delay + masterPort.sendAtomic(pkt);
}
-void
-Bridge::BridgeMasterPort::recvFunctional(PacketPtr pkt)
-{
- // master port should never receive any functional access (panic
- // only works once the other side, i.e. the busses, respect this)
-
- // panic("Master port on %s got a recvFunctional\n", bridge->name());
-}
-
void
Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt)
{
/** When receiving a retry request from the peer port,
pass it to the bridge. */
virtual void recvRetry();
-
- /** When receiving a Atomic requestfrom the peer port,
- pass it to the bridge. */
- virtual Tick recvAtomic(PacketPtr pkt);
-
- /** When receiving a Functional request from the peer port,
- pass it to the bridge. */
- virtual void recvFunctional(PacketPtr pkt);
};
/** Slave port of the bridge. */
: MemObject(p), clock(p->clock),
headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
drainEvent(NULL), busIdleEvent(this), inRetry(false),
- nbrMasterPorts(p->port_master_connection_count),
defaultPortId(INVALID_PORT_ID), useDefaultRange(p->use_default_range),
defaultBlockSize(p->block_size),
cachedBlockSize(0), cachedBlockSizeValid(false)
fatal("Number of header cycles must be positive\n");
// create the ports based on the size of the master and slave
- // vector ports, and the presence of the default master
-
- // id used to index into master and slave ports, that currently
- // has holes to be able to use the id to index into either
- int id = 0;
+ // vector ports, and the presence of the default port, the ports
+ // are enumerated starting from zero
for (int i = 0; i < p->port_master_connection_count; ++i) {
- std::string portName = csprintf("%s-p%d", name(), id);
- BusMasterPort* bp = new BusMasterPort(portName, this, id);
+ std::string portName = csprintf("%s-p%d", name(), i);
+ BusMasterPort* bp = new BusMasterPort(portName, this, i);
masterPorts.push_back(bp);
- slavePorts.push_back(NULL);
- ++id;
}
- // see if we have a default master connected and if so add the
- // port
+ // see if we have a default slave device connected and if so add
+ // our corresponding master port
if (p->port_default_connection_count) {
- defaultPortId = id;
+ defaultPortId = masterPorts.size();
std::string portName = csprintf("%s-default", name());
- BusMasterPort* bp = new BusMasterPort(portName, this, id);
+ BusMasterPort* bp = new BusMasterPort(portName, this, defaultPortId);
masterPorts.push_back(bp);
- slavePorts.push_back(NULL);
- ++id;
- // this is an additional master port
- ++nbrMasterPorts;
}
- // note that the first slave port is now stored on index
- // nbrMasterPorts in the vector
+ // create the slave ports, once again starting at zero
for (int i = 0; i < p->port_slave_connection_count; ++i) {
- std::string portName = csprintf("%s-p%d", name(), id);
- BusSlavePort* bp = new BusSlavePort(portName, this, id);
- masterPorts.push_back(NULL);
+ std::string portName = csprintf("%s-p%d", name(), i);
+ BusSlavePort* bp = new BusSlavePort(portName, this, i);
slavePorts.push_back(bp);
- ++id;
}
clearPortCache();
MasterPort &
Bus::getMasterPort(const std::string &if_name, int idx)
{
- if (if_name == "master") {
- // the master index translates directly to the interfaces
- // vector as they are stored first
+ if (if_name == "master" && idx < masterPorts.size()) {
+ // the master port index translates directly to the vector position
return *masterPorts[idx];
} else if (if_name == "default") {
return *masterPorts[defaultPortId];
SlavePort &
Bus::getSlavePort(const std::string &if_name, int idx)
{
- if (if_name == "slave") {
- return *slavePorts[nbrMasterPorts + idx];
+ if (if_name == "slave" && idx < slavePorts.size()) {
+ // the slave port index translates directly to the vector position
+ return *slavePorts[idx];
} else {
return MemObject::getSlavePort(if_name, idx);
}
void
Bus::init()
{
- std::vector<BusSlavePort*>::iterator intIter;
-
- // iterate over our interfaces and determine which of our neighbours
- // are snooping and add them as snoopers
- for (intIter = slavePorts.begin(); intIter != slavePorts.end();
- intIter++) {
- // since there are holes in the vector, check for NULL
- if (*intIter != NULL) {
- if ((*intIter)->getMasterPort().isSnooping()) {
- DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
- (*intIter)->getMasterPort().name());
- snoopPorts.push_back(*intIter);
- }
+ std::vector<BusSlavePort*>::iterator p;
+
+ // iterate over our slave ports and determine which of our
+ // neighbouring master ports are snooping and add them as snoopers
+ for (p = slavePorts.begin(); p != slavePorts.end(); ++p) {
+ if ((*p)->getMasterPort().isSnooping()) {
+ DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
+ (*p)->getMasterPort().name());
+ snoopPorts.push_back(*p);
}
}
}
curTick(), tickNextIdle);
}
-/** Function called by the port when the bus is receiving a Timing
- * transaction.*/
bool
-Bus::recvTiming(PacketPtr pkt)
+Bus::isOccupied(PacketPtr pkt, Port* port)
{
- // called for both requests and responses
+ // first we see if the next idle tick is in the future, next the
+ // bus is considered occupied if there are ports on the retry list
+ // and we are not in a retry with the current port
+ if (tickNextIdle > curTick() ||
+ (!retryList.empty() && !(inRetry && port == retryList.front()))) {
+ addToRetryList(port);
+ return true;
+ }
+ return false;
+}
- // get the source id and port
+bool
+Bus::recvTiming(PacketPtr pkt)
+{
+ // get the source id
Packet::NodeID src_id = pkt->getSrc();
- // determine the source port based on the id
- Port *src_port = slavePorts[src_id] ?
- (Port*) slavePorts[src_id] : (Port*) masterPorts[src_id];
-
- // If the bus is busy, or other devices are in line ahead of the current
- // one, put this device on the retry list.
- if (!pkt->isExpressSnoop() &&
- (tickNextIdle > curTick() ||
- (!retryList.empty() && (!inRetry || src_port != retryList.front()))))
- {
- addToRetryList(src_port);
+ // determine the source port based on the id and direction
+ Port *src_port = NULL;
+ if (pkt->isRequest())
+ src_port = slavePorts[src_id];
+ else
+ src_port = masterPorts[src_id];
+
+ // test if the bus should be considered occupied for the current
+ // packet, and exclude express snoops from the check
+ if (!pkt->isExpressSnoop() && isOccupied(pkt, src_port)) {
DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
return false;
Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
- Packet::NodeID dest = pkt->getDest();
- int dest_id;
- Port *dest_port;
-
+ // decide what to do based on the direction
if (pkt->isRequest()) {
// the packet is a memory-mapped request and should be broadcasted to
// our snoopers
- assert(dest == Packet::Broadcast);
-
- SnoopIter s_end = snoopPorts.end();
- for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
- BusSlavePort *p = *s_iter;
- // we got this request from a snooping master
- // (corresponding to our own slave port that is also in
- // snoopPorts) and should not send it back to where it
- // came from
- if (p->getId() != src_id) {
- // cache is not allowed to refuse snoop
- bool success M5_VAR_USED = p->sendTiming(pkt);
- assert(success);
- }
+ assert(pkt->getDest() == Packet::Broadcast);
+
+ // forward to all snoopers but the source
+ forwardTiming(pkt, src_id);
+
+ // remember if we add an outstanding req so we can undo it if
+ // necessary, if the packet needs a response, we should add it
+ // as outstanding and express snoops never fail so there is
+ // not need to worry about them
+ bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse();
+
+ // keep track that we have an outstanding request packet
+ // matching this request, this is used by the coherency
+ // mechanism in determining what to do with snoop responses
+ // (in recvTimingSnoop)
+ if (add_outstanding) {
+ // we should never have an exsiting request outstanding
+ assert(outstandingReq.find(pkt->req) == outstandingReq.end());
+ outstandingReq.insert(pkt->req);
}
- // since it is a request, similar to functional and atomic,
- // determine the destination based on the address and forward
- // through the corresponding master port
- dest_id = findPort(pkt->getAddr());
- dest_port = masterPorts[dest_id];
- } else {
- // the packet is a response, and it should always go back to
- // the port determined by the destination field
- dest_id = dest;
- assert(dest_id != src_id); // catch infinite loops
- dest_port = slavePorts[dest_id] ?
- (Port*) slavePorts[dest_id] : (Port*) masterPorts[dest_id];
-
- // a normal response from the memory system (i.e. from a
- // connected slave) should always go back to the master
- // that issued it through one of our slave ports, however
- // if this is a snoop response it could go either way, for
- // example, it could be coming from a slave port
- // connecting an L1 with a coherent master and another L1
- // coherent master (one of our slave ports), or coming
- // from the L1 and going to the L2 slave port (through one
- // of our master ports)
- }
-
- assert(dest_port != NULL);
-
- // if this is a snoop from a slave (corresponding to our own
- // master), i.e. the memory side of the bus, then do not send it
- // back to where it came from
- if (dest_id != src_id) {
- // send to actual target
- if (!dest_port->sendTiming(pkt)) {
- // Packet not successfully sent. Leave or put it on the retry list.
- // illegal to block responses... can lead to deadlock
- assert(!pkt->isResponse());
- // It's also illegal to force a transaction to retry after
- // someone else has committed to respond.
+ // since it is a normal request, determine the destination
+ // based on the address and attempt to send the packet
+ bool success = masterPorts[findPort(pkt->getAddr())]->sendTiming(pkt);
+
+ if (!success) {
+ // inhibited packets should never be forced to retry
assert(!pkt->memInhibitAsserted());
- DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
+
+ // if it was added as outstanding and the send failed, then
+ // erase it again
+ if (add_outstanding)
+ outstandingReq.erase(pkt->req);
+
+ DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x RETRY\n",
src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
addToRetryList(src_port);
occupyBus(headerFinishTime);
+
return false;
}
- // send OK, fall through... pkt may have been deleted by
- // target at this point, so it should *not* be referenced
- // again. We'll set it to NULL here just to be safe.
- pkt = NULL;
+ } else {
+ // the packet is a normal response to a request that we should
+ // have seen passing through the bus
+ assert(outstandingReq.find(pkt->req) != outstandingReq.end());
+
+ // remove it as outstanding
+ outstandingReq.erase(pkt->req);
+
+ // send the packet to the destination through one of our slave
+ // ports, as determined by the destination field
+ bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTiming(pkt);
+
+ // currently it is illegal to block responses... can lead to
+ // deadlock
+ assert(success);
}
- occupyBus(packetFinishTime);
+ succeededTiming(packetFinishTime);
+
+ return true;
+}
+
+bool
+Bus::recvTimingSnoop(PacketPtr pkt)
+{
+ // get the source id
+ Packet::NodeID src_id = pkt->getSrc();
+
+ if (pkt->isRequest()) {
+ DPRINTF(Bus, "recvTimingSnoop: src %d dst %d %s 0x%x\n",
+ src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
+ // the packet is an express snoop request and should be
+ // broadcasted to our snoopers
+ assert(pkt->getDest() == Packet::Broadcast);
+ assert(pkt->isExpressSnoop());
+
+ // forward to all snoopers
+ forwardTiming(pkt, INVALID_PORT_ID);
+
+ // a snoop request came from a connected slave device (one of
+ // our master ports), and if it is not coming from the slave
+ // device responsible for the address range something is
+ // wrong, hence there is nothing further to do as the packet
+ // would be going back to where it came from
+ assert(src_id == findPort(pkt->getAddr()));
+
+ // this is an express snoop and is never forced to retry
+ assert(!inRetry);
+
+ return true;
+ } else {
+ // determine the source port based on the id
+ SlavePort* src_port = slavePorts[src_id];
- // Packet was successfully sent.
- // Also take care of retries
+ if (isOccupied(pkt, src_port)) {
+ DPRINTF(Bus, "recvTimingSnoop: src %d dst %d %s 0x%x BUSY\n",
+ src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+ return false;
+ }
+
+ DPRINTF(Bus, "recvTimingSnoop: src %d dst %d %s 0x%x\n",
+ src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
+ // get the destination from the packet
+ Packet::NodeID dest = pkt->getDest();
+
+ // responses are never express snoops
+ assert(!pkt->isExpressSnoop());
+
+ calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->finishTime;
+
+ // determine if the response is from a snoop request we
+ // created as the result of a normal request (in which case it
+ // should be in the outstandingReq), or if we merely forwarded
+ // someone else's snoop request
+ if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
+ // this is a snoop response to a snoop request we
+ // forwarded, e.g. coming from the L1 and going to the L2
+ // this should be forwarded as a snoop response
+ bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoop(pkt);
+ assert(success);
+ } else {
+ // we got a snoop response on one of our slave ports,
+ // i.e. from a coherent master connected to the bus, and
+ // since we created the snoop request as part of
+ // recvTiming, this should now be a normal response again
+ outstandingReq.erase(pkt->req);
+
+ // this is a snoop response from a coherent master, with a
+ // destination field set on its way through the bus as
+ // request, hence it should never go back to where the
+ // snoop response came from, but instead to where the
+ // original request came from
+ assert(src_id != dest);
+
+ // as a normal response, it should go back to a master
+ // through one of our slave ports
+ bool success M5_VAR_USED = slavePorts[dest]->sendTiming(pkt);
+
+ // currently it is illegal to block responses... can lead
+ // to deadlock
+ assert(success);
+ }
+
+ succeededTiming(packetFinishTime);
+
+ return true;
+ }
+}
+
+void
+Bus::succeededTiming(Tick busy_time)
+{
+ // occupy the bus accordingly
+ occupyBus(busy_time);
+
+ // if a retrying port succeeded, also take it off the retry list
if (inRetry) {
- DPRINTF(Bus, "Remove retry from list %d\n", src_id);
+ DPRINTF(Bus, "Remove retry from list %s\n",
+ retryList.front()->name());
retryList.pop_front();
inRetry = false;
}
- return true;
+}
+
+void
+Bus::forwardTiming(PacketPtr pkt, int exclude_slave_port_id)
+{
+ SnoopIter s_end = snoopPorts.end();
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
+ BusSlavePort *p = *s_iter;
+ // we could have gotten this request from a snooping master
+ // (corresponding to our own slave port that is also in
+ // snoopPorts) and should not send it back to where it came
+ // from
+ if (exclude_slave_port_id == INVALID_PORT_ID ||
+ p->getId() != exclude_slave_port_id) {
+ // cache is not allowed to refuse snoop
+ bool success M5_VAR_USED = p->sendTimingSnoop(pkt);
+ assert(success);
+ }
+ }
}
void
name());
}
-
-/** Function called by the port when the bus is receiving a Atomic
- * transaction.*/
Tick
Bus::recvAtomic(PacketPtr pkt)
{
assert(pkt->getDest() == Packet::Broadcast);
assert(pkt->isRequest());
- // the packet may be changed by another bus on snoops, record the
- // source id here
- Packet::NodeID src_id = pkt->getSrc();
+ // forward to all snoopers but the source
+ std::pair<MemCmd, Tick> snoop_result = forwardAtomic(pkt, pkt->getSrc());
+ MemCmd snoop_response_cmd = snoop_result.first;
+ Tick snoop_response_latency = snoop_result.second;
- // record the original command to enable us to restore it between
- // snoops so that additional snoops can take place properly
+ // even if we had a snoop response, we must continue and also
+ // perform the actual request at the destination
+ int dest_id = findPort(pkt->getAddr());
+
+ // forward the request to the appropriate destination
+ Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
+
+ // if we got a response from a snooper, restore it here
+ if (snoop_response_cmd != MemCmd::InvalidCmd) {
+ // no one else should have responded
+ assert(!pkt->isResponse());
+ pkt->cmd = snoop_response_cmd;
+ response_latency = snoop_response_latency;
+ }
+
+ pkt->finishTime = curTick() + response_latency;
+ return response_latency;
+}
+
+Tick
+Bus::recvAtomicSnoop(PacketPtr pkt)
+{
+ DPRINTF(Bus, "recvAtomicSnoop: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+
+ // we should always see a request routed based on the address
+ assert(pkt->getDest() == Packet::Broadcast);
+ assert(pkt->isRequest());
+
+ // forward to all snoopers
+ std::pair<MemCmd, Tick> snoop_result = forwardAtomic(pkt, INVALID_PORT_ID);
+ MemCmd snoop_response_cmd = snoop_result.first;
+ Tick snoop_response_latency = snoop_result.second;
+
+ if (snoop_response_cmd != MemCmd::InvalidCmd)
+ pkt->cmd = snoop_response_cmd;
+
+ pkt->finishTime = curTick() + snoop_response_latency;
+ return snoop_response_latency;
+}
+
+std::pair<MemCmd, Tick>
+Bus::forwardAtomic(PacketPtr pkt, int exclude_slave_port_id)
+{
+ // the packet may be changed on snoops, record the original source
+ // and command to enable us to restore it between snoops so that
+ // additional snoops can take place properly
+ Packet::NodeID orig_src_id = pkt->getSrc();
MemCmd orig_cmd = pkt->cmd;
MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
Tick snoop_response_latency = 0;
// (corresponding to our own slave port that is also in
// snoopPorts) and should not send it back to where it came
// from
- if (p->getId() != src_id) {
- Tick latency = p->sendAtomic(pkt);
+ if (exclude_slave_port_id == INVALID_PORT_ID ||
+ p->getId() != exclude_slave_port_id) {
+ Tick latency = p->sendAtomicSnoop(pkt);
// in contrast to a functional access, we have to keep on
// going as all snoopers must be updated even if we get a
// response
snoop_response_latency = latency;
// restore original packet state for remaining snoopers
pkt->cmd = orig_cmd;
- pkt->setSrc(src_id);
+ pkt->setSrc(orig_src_id);
pkt->setDest(Packet::Broadcast);
}
}
}
- // even if we had a snoop response, we must continue and also
- // perform the actual request at the destination
- int dest_id = findPort(pkt->getAddr());
-
- Tick response_latency = 0;
+ // the packet is restored as part of the loop and any potential
+ // snoop response is part of the returned pair
+ return std::make_pair(snoop_response_cmd, snoop_response_latency);
+}
- // if this is a snoop from a slave (corresponding to our own
- // master), i.e. the memory side of the bus, then do not send it
- // back to where it came from
- if (dest_id != src_id) {
- response_latency = masterPorts[dest_id]->sendAtomic(pkt);
+void
+Bus::recvFunctional(PacketPtr pkt)
+{
+ if (!pkt->isPrint()) {
+ // don't do DPRINTFs on PrintReq as it clutters up the output
+ DPRINTF(Bus,
+ "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(),
+ pkt->cmdString());
}
- // if we got a response from a snooper, restore it here
- if (snoop_response_cmd != MemCmd::InvalidCmd) {
- // no one else should have responded
- assert(!pkt->isResponse());
- assert(pkt->cmd == orig_cmd);
- pkt->cmd = snoop_response_cmd;
- response_latency = snoop_response_latency;
- }
+ // we should always see a request routed based on the address
+ assert(pkt->getDest() == Packet::Broadcast);
+ assert(pkt->isRequest());
- // why do we have this packet field and the return value both???
- pkt->finishTime = curTick() + response_latency;
- return response_latency;
+ // forward to all snoopers but the source
+ forwardFunctional(pkt, pkt->getSrc());
+
+ // there is no need to continue if the snooping has found what we
+ // were looking for and the packet is already a response
+ if (!pkt->isResponse()) {
+ int dest_id = findPort(pkt->getAddr());
+
+ masterPorts[dest_id]->sendFunctional(pkt);
+ }
}
-/** Function called by the port when the bus is receiving a Functional
- * transaction.*/
void
-Bus::recvFunctional(PacketPtr pkt)
+Bus::recvFunctionalSnoop(PacketPtr pkt)
{
if (!pkt->isPrint()) {
// don't do DPRINTFs on PrintReq as it clutters up the output
DPRINTF(Bus,
- "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
+ "recvFunctionalSnoop: packet src %d dest %d addr 0x%x cmd %s\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr(),
pkt->cmdString());
}
assert(pkt->getDest() == Packet::Broadcast);
assert(pkt->isRequest());
- // the packet may be changed by another bus on snoops, record the
- // source id here
- Packet::NodeID src_id = pkt->getSrc();
+ // forward to all snoopers
+ forwardFunctional(pkt, INVALID_PORT_ID);
+}
+void
+Bus::forwardFunctional(PacketPtr pkt, int exclude_slave_port_id)
+{
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
BusSlavePort *p = *s_iter;
// (corresponding to our own slave port that is also in
// snoopPorts) and should not send it back to where it came
// from
- if (p->getId() != src_id) {
- p->sendFunctional(pkt);
-
- // if we get a response we are done
- if (pkt->isResponse()) {
- break;
- }
- }
- }
-
- // there is no need to continue if the snooping has found what we
- // were looking for and the packet is already a response
- if (!pkt->isResponse()) {
- int dest_id = findPort(pkt->getAddr());
+ if (exclude_slave_port_id == INVALID_PORT_ID ||
+ p->getId() != exclude_slave_port_id)
+ p->sendFunctionalSnoop(pkt);
- // if this is a snoop from a slave (corresponding to our own
- // master), i.e. the memory side of the bus, then do not send
- // it back to where it came from,
- if (dest_id != src_id) {
- masterPorts[dest_id]->sendFunctional(pkt);
+ // if we get a response we are done
+ if (pkt->isResponse()) {
+ break;
}
}
}
std::vector<BusSlavePort*>::const_iterator intIter;
for (intIter = slavePorts.begin(); intIter != slavePorts.end(); intIter++)
- if (*intIter != NULL && (*intIter)->getId() != id)
- (*intIter)->sendRangeChange();
+ (*intIter)->sendRangeChange();
inRecvRangeChange.erase(id);
}
protected:
- /** When reciving a timing request from the peer port (at id),
- pass it to the bus. */
+ /**
+ * When receiving a timing request, pass it to the bus.
+ */
virtual bool recvTiming(PacketPtr pkt)
{ pkt->setSrc(id); return bus->recvTiming(pkt); }
- /** When reciving a Atomic requestfrom the peer port (at id),
- pass it to the bus. */
+ /**
+ * When receiving a timing snoop response, pass it to the bus.
+ */
+ virtual bool recvTimingSnoop(PacketPtr pkt)
+ { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
+
+ /**
+ * When receiving an atomic request, pass it to the bus.
+ */
virtual Tick recvAtomic(PacketPtr pkt)
{ pkt->setSrc(id); return bus->recvAtomic(pkt); }
- /** When reciving a Functional requestfrom the peer port (at id),
- pass it to the bus. */
+ /**
+ * When receiving a functional request, pass it to the bus.
+ */
virtual void recvFunctional(PacketPtr pkt)
{ pkt->setSrc(id); bus->recvFunctional(pkt); }
- /** When reciving a retry from the peer port (at id),
- pass it to the bus. */
+ /**
+ * When receiving a retry, pass it to the bus.
+ */
virtual void recvRetry()
- { bus->recvRetry(id); }
+ { panic("Bus slave ports always succeed and should never retry.\n"); }
// This should return all the 'owned' addresses that are
// downstream from this bus, yes? That is, the union of all
protected:
- /** When reciving a timing request from the peer port (at id),
- pass it to the bus. */
+ /**
+ * When receiving a timing response, pass it to the bus.
+ */
virtual bool recvTiming(PacketPtr pkt)
{ pkt->setSrc(id); return bus->recvTiming(pkt); }
- /** When reciving a Atomic requestfrom the peer port (at id),
- pass it to the bus. */
- virtual Tick recvAtomic(PacketPtr pkt)
- { pkt->setSrc(id); return bus->recvAtomic(pkt); }
+ /**
+ * When receiving a timing snoop request, pass it to the bus.
+ */
+ virtual bool recvTimingSnoop(PacketPtr pkt)
+ { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
- /** When reciving a Functional requestfrom the peer port (at id),
- pass it to the bus. */
- virtual void recvFunctional(PacketPtr pkt)
- { pkt->setSrc(id); bus->recvFunctional(pkt); }
+ /**
+ * When receiving an atomic snoop request, pass it to the bus.
+ */
+ virtual Tick recvAtomicSnoop(PacketPtr pkt)
+ { pkt->setSrc(id); return bus->recvAtomicSnoop(pkt); }
+
+ /**
+ * When receiving a functional snoop request, pass it to the bus.
+ */
+ virtual void recvFunctionalSnoop(PacketPtr pkt)
+ { pkt->setSrc(id); bus->recvFunctionalSnoop(pkt); }
/** When reciving a range change from the peer port (at id),
pass it to the bus. */
typedef std::vector<BusSlavePort*>::iterator SnoopIter;
std::vector<BusSlavePort*> snoopPorts;
+ /**
+ * Store the outstanding requests so we can determine which ones
+ * we generated and which ones were merely forwarded. This is used
+ * in the coherent bus when coherency responses come back.
+ */
+ std::set<RequestPtr> outstandingReq;
+
/** Function called by the port when the bus is recieving a Timing
transaction.*/
bool recvTiming(PacketPtr pkt);
+ /** Function called by the port when the bus is recieving a timing
+ snoop transaction.*/
+ bool recvTimingSnoop(PacketPtr pkt);
+
+ /**
+ * Forward a timing packet to our snoopers, potentially excluding
+ * one of the connected coherent masters to avoid sending a packet
+ * back to where it came from.
+ *
+ * @param pkt Packet to forward
+ * @param exclude_slave_port_id Id of slave port to exclude
+ */
+ void forwardTiming(PacketPtr pkt, int exclude_slave_port_id);
+
+ /**
+ * Determine if the bus is to be considered occupied when being
+ * presented with a packet from a specific port. If so, the port
+ * in question is also added to the retry list.
+ *
+ * @param pkt Incoming packet
+ * @param port Source port on the bus presenting the packet
+ *
+ * @return True if the bus is to be considered occupied
+ */
+ bool isOccupied(PacketPtr pkt, Port* port);
+
+ /**
+ * Deal with a destination port accepting a packet by potentially
+ * removing the source port from the retry list (if retrying) and
+ * occupying the bus accordingly.
+ *
+ * @param busy_time Time to spend as a result of a successful send
+ */
+ void succeededTiming(Tick busy_time);
+
/** Function called by the port when the bus is recieving a Atomic
transaction.*/
Tick recvAtomic(PacketPtr pkt);
+ /** Function called by the port when the bus is recieving an
+ atomic snoop transaction.*/
+ Tick recvAtomicSnoop(PacketPtr pkt);
+
+ /**
+ * Forward an atomic packet to our snoopers, potentially excluding
+ * one of the connected coherent masters to avoid sending a packet
+ * back to where it came from.
+ *
+ * @param pkt Packet to forward
+ * @param exclude_slave_port_id Id of slave port to exclude
+ *
+ * @return a pair containing the snoop response and snoop latency
+ */
+ std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
+ int exclude_slave_port_id);
+
/** Function called by the port when the bus is recieving a Functional
transaction.*/
void recvFunctional(PacketPtr pkt);
+ /** Function called by the port when the bus is recieving a functional
+ snoop transaction.*/
+ void recvFunctionalSnoop(PacketPtr pkt);
+
+ /**
+ * Forward a functional packet to our snoopers, potentially
+ * excluding one of the connected coherent masters to avoid
+ * sending a packet back to where it came from.
+ *
+ * @param pkt Packet to forward
+ * @param exclude_slave_port_id Id of slave port to exclude
+ */
+ void forwardFunctional(PacketPtr pkt, int exclude_slave_port_id);
+
/** Timing function called by port when it is once again able to process
* requests. */
void recvRetry(int id);
bool inRetry;
std::set<int> inRecvRangeChange;
- // keep track of the number of master ports (not counting the
- // default master) since we need this as an offset into the
- // interfaces vector
- unsigned int nbrMasterPorts;
-
/** The master and slave ports of the bus */
std::vector<BusSlavePort*> slavePorts;
std::vector<BusMasterPort*> masterPorts;
* @param when time to send the response
*/
void respond(PacketPtr pkt, Tick time) {
- queue.schedSendTiming(pkt, time);
+ queue.schedSendTiming(pkt, time, true);
}
protected:
protected:
+ virtual bool recvTimingSnoop(PacketPtr pkt);
+
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
protected:
+ virtual bool recvTimingSnoop(PacketPtr pkt);
+
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt);
+ virtual Tick recvAtomicSnoop(PacketPtr pkt);
- virtual void recvFunctional(PacketPtr pkt);
+ virtual void recvFunctionalSnoop(PacketPtr pkt);
virtual unsigned deviceBlockSize() const
{ return cache->getBlockSize(); }
} else if (forwardSnoops && cpuSidePort->getMasterPort().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->sendFunctional(pkt);
+ cpuSidePort->sendFunctionalSnoop(pkt);
}
}
}
// 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->sendTimingSnoop(&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);
+ Packet::NodeID origSrc = pkt->getSrc();
+ cpuSidePort->sendAtomicSnoop(pkt);
if (!alreadyResponded && pkt->memInhibitAsserted()) {
// cache-to-cache response from some upper cache:
// forward response to original requester
handleSnoop(pkt, blk, true, false, false);
}
+template<class TagStore>
+bool
+Cache<TagStore>::CpuSidePort::recvTimingSnoop(PacketPtr pkt)
+{
+ // Express snoop responses from master to slave, e.g., from L1 to L2
+ assert(pkt->isResponse());
+
+ cache->timingAccess(pkt);
+ return true;
+}
template<class TagStore>
Tick
PacketPtr snoop_pkt = new Packet(tgt_pkt, true);
snoop_pkt->setExpressSnoop();
snoop_pkt->senderState = mshr;
- cpuSidePort->sendTiming(snoop_pkt);
+ cpuSidePort->sendTimingSnoop(snoop_pkt);
if (snoop_pkt->memInhibitAsserted()) {
markInService(mshr, snoop_pkt);
bool
Cache<TagStore>::CpuSidePort::recvTiming(PacketPtr pkt)
{
- // illegal to block responses... can lead to deadlock
- if (pkt->isRequest() && !pkt->memInhibitAsserted() && blocked) {
+ assert(pkt->isRequest());
+ // always let inhibited requests through even if blocked
+ if (!pkt->memInhibitAsserted() && blocked) {
DPRINTF(Cache,"Scheduling a retry while blocked\n");
mustSendRetry = true;
return false;
if (pkt->wasNacked())
panic("Need to implement cache resending nacked packets!\n");
- if (pkt->isResponse()) {
- cache->handleResponse(pkt);
- } else {
- cache->snoopTiming(pkt);
- }
+ assert(pkt->isResponse());
+ cache->handleResponse(pkt);
+ return true;
+}
+
+// Express snooping requests to memside port
+template<class TagStore>
+bool
+Cache<TagStore>::MemSidePort::recvTimingSnoop(PacketPtr pkt)
+{
+ // handle snooping requests
+ assert(pkt->isRequest());
+ cache->snoopTiming(pkt);
return true;
}
template<class TagStore>
Tick
-Cache<TagStore>::MemSidePort::recvAtomic(PacketPtr pkt)
+Cache<TagStore>::MemSidePort::recvAtomicSnoop(PacketPtr pkt)
{
assert(pkt->isRequest());
// atomic snoop
template<class TagStore>
void
-Cache<TagStore>::MemSidePort::recvFunctional(PacketPtr pkt)
+Cache<TagStore>::MemSidePort::recvFunctionalSnoop(PacketPtr pkt)
{
assert(pkt->isRequest());
// functional snoop (note that in contrast to atomic we don't have
name(), pkt->cmd.toString(), getMasterPort().name());
}
}
-
-Tick
-MessageMasterPort::recvAtomic(PacketPtr pkt)
-{
- if (pkt->cmd == MemCmd::MessageResp) {
- // normally we would never see responses in recvAtomic, but
- // since the timing port uses recvAtomic to implement
- // recvTiming we have to deal with them here
- return recvResponse(pkt);
- } else {
- panic("%s received unexpected atomic command %s from %s.\n",
- name(), pkt->cmd.toString(), getSlavePort().name());
- }
-}
virtual ~MessageMasterPort()
{}
- void recvFunctional(PacketPtr pkt) { assert(false); }
-
- Tick recvAtomic(PacketPtr pkt);
-
- bool recvTiming(PacketPtr pkt) { recvAtomic(pkt); return true; }
+ bool recvTiming(PacketPtr pkt) { recvResponse(pkt); return true; }
protected:
}
void
-PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
+PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
{
assert(when > curTick());
// note that currently we ignore a potentially outstanding retry
// and could in theory put a new packet at the head of the
// transmit list before retrying the existing packet
- transmitList.push_front(DeferredPacket(when, pkt));
+ transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
schedSendEvent(when);
return;
}
// list is non-empty and this belongs at the end
if (when >= transmitList.back().tick) {
- transmitList.push_back(DeferredPacket(when, pkt));
+ transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
return;
}
++i; // already checked for insertion at front
while (i != transmitList.end() && when >= i->tick)
++i;
- transmitList.insert(i, DeferredPacket(when, pkt));
+ transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
}
void PacketQueue::trySendTiming()
transmitList.pop_front();
// attempt to send the packet and remember the outcome
- waitingOnRetry = !port.sendTiming(dp.pkt);
+ if (!dp.sendAsSnoop)
+ waitingOnRetry = !port.sendTiming(dp.pkt);
+ else
+ waitingOnRetry = !port.sendTimingSnoop(dp.pkt);
if (waitingOnRetry) {
// put the packet back at the front of the list (packet should
public:
Tick tick; ///< The tick when the packet is ready to transmit
PacketPtr pkt; ///< Pointer to the packet to transmit
- DeferredPacket(Tick t, PacketPtr p)
- : tick(t), pkt(p)
+ bool sendAsSnoop; ///< Should it be sent as a snoop or not
+ DeferredPacket(Tick t, PacketPtr p, bool send_as_snoop)
+ : tick(t), pkt(p), sendAsSnoop(send_as_snoop)
{}
};
*
* @param pkt Packet to send
* @param when Absolute time (in ticks) to send packet
+ * @param send_as_snoop Send the packet as a snoop or not
*/
- void schedSendTiming(PacketPtr pkt, Tick when);
+ void schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop = false);
/**
* Used by a port to notify the queue that a retry was received
unsigned int drain(Event *de);
};
-#endif // __MEM_TPORT_HH__
+#endif // __MEM_PACKET_QUEUE_HH__
return _slavePort->deviceBlockSize();
}
- void
+Tick
+MasterPort::sendAtomic(PacketPtr pkt)
+{
+ return _slavePort->recvAtomic(pkt);
+}
+
+void
+MasterPort::sendFunctional(PacketPtr pkt)
+{
+ return _slavePort->recvFunctional(pkt);
+}
+
+void
MasterPort::printAddr(Addr a)
{
Request req(a, 1, 0, Request::funcMasterId);
{
return _masterPort != NULL;
}
+
+Tick
+SlavePort::sendAtomicSnoop(PacketPtr pkt)
+{
+ return _masterPort->recvAtomicSnoop(pkt);
+}
+
+void
+SlavePort::sendFunctionalSnoop(PacketPtr pkt)
+{
+ return _masterPort->recvFunctionalSnoop(pkt);
+}
/** These functions are protected because they should only be
* called by a peer port, never directly by any outside object. */
- /** Called to recive a timing call from the peer port. */
+ /**
+ * Receive a timing request or response packet from the peer port.
+ */
virtual bool recvTiming(PacketPtr pkt) = 0;
- /** Called to recive a atomic call from the peer port. */
- virtual Tick recvAtomic(PacketPtr pkt) = 0;
-
- /** Called to recive a functional call from the peer port. */
- virtual void recvFunctional(PacketPtr pkt) = 0;
+ /**
+ * Receive a timing snoop request or snoop response packet from
+ * the peer port.
+ */
+ virtual bool recvTimingSnoop(PacketPtr pkt)
+ {
+ panic("%s was not expecting a timing snoop\n", name());
+ return false;
+ }
/**
- * Called by a peer port if sendTiming was unsuccesful, and had to
- * wait.
+ * Called by a peer port if sendTiming or sendTimingSnoop was
+ * unsuccesful, and had to wait.
*/
virtual void recvRetry() = 0;
public:
/**
- * Attempt to send a timing packet to the peer port by calling its
- * receive function. If the send does not succeed, as indicated by
- * the return value, then the sender must wait for a recvRetry at
- * which point it can re-issue a sendTiming.
+ * Attempt to send a timing request or response packet to the peer
+ * port by calling its receive function. If the send does not
+ * succeed, as indicated by the return value, then the sender must
+ * wait for a recvRetry at which point it can re-issue a
+ * sendTiming.
*
* @param pkt Packet to send.
*
bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); }
/**
- * Send a retry to a peer port that previously attempted a sendTiming
- * which was unsuccessful.
- */
- void sendRetry() { return peer->recvRetry(); }
-
- /**
- * Send an atomic packet, where the data is moved and the state
- * is updated in zero time, without interleaving with other
- * memory accesses.
+ * Attempt to send a timing snoop request or snoop response packet
+ * to the peer port by calling its receive function. If the send
+ * does not succeed, as indicated by the return value, then the
+ * sender must wait for a recvRetry at which point it can re-issue
+ * a sendTimingSnoop.
*
* @param pkt Packet to send.
*
- * @return Estimated latency of access.
- */
- Tick sendAtomic(PacketPtr pkt) { return peer->recvAtomic(pkt); }
+ * @return If the send was succesful or not.
+ */
+ bool sendTimingSnoop(PacketPtr pkt) { return peer->recvTimingSnoop(pkt); }
/**
- * Send a functional packet, where the data is instantly updated
- * everywhere in the memory system, without affecting the current
- * state of any block or moving the block.
- *
- * @param pkt Packet to send.
+ * Send a retry to a peer port that previously attempted a
+ * sendTiming or sendTimingSnoop which was unsuccessful.
*/
- void sendFunctional(PacketPtr pkt) { return peer->recvFunctional(pkt); }
+ void sendRetry() { return peer->recvRetry(); }
};
SlavePort& getSlavePort() const;
bool isConnected() const;
+ /**
+ * Send an atomic request packet, where the data is moved and the
+ * state is updated in zero time, without interleaving with other
+ * memory accesses.
+ *
+ * @param pkt Packet to send.
+ *
+ * @return Estimated latency of access.
+ */
+ Tick sendAtomic(PacketPtr pkt);
+
+ /**
+ * Send a functional request packet, where the data is instantly
+ * updated everywhere in the memory system, without affecting the
+ * current state of any block or moving the block.
+ *
+ * @param pkt Packet to send.
+ */
+ void sendFunctional(PacketPtr pkt);
+
+ /**
+ * Receive an atomic snoop request packet from the slave port.
+ */
+ virtual Tick recvAtomicSnoop(PacketPtr pkt)
+ {
+ panic("%s was not expecting an atomic snoop\n", name());
+ return 0;
+ }
+
+ /**
+ * Receive a functional snoop request packet from the slave port.
+ */
+ virtual void recvFunctionalSnoop(PacketPtr pkt)
+ {
+ panic("%s was not expecting a functional snoop\n", name());
+ }
+
/**
* Called to receive an address range change from the peer slave
* port. the default implementation ignored the change and does
MasterPort& getMasterPort() const;
bool isConnected() const;
+ /**
+ * Send an atomic snoop request packet, where the data is moved
+ * and the state is updated in zero time, without interleaving
+ * with other memory accesses.
+ *
+ * @param pkt Snoop packet to send.
+ *
+ * @return Estimated latency of access.
+ */
+ Tick sendAtomicSnoop(PacketPtr pkt);
+
+ /**
+ * Send a functional snoop request packet, where the data is
+ * instantly updated everywhere in the memory system, without
+ * affecting the current state of any block or moving the block.
+ *
+ * @param pkt Snoop packet to send.
+ */
+ void sendFunctionalSnoop(PacketPtr pkt);
+
+ /**
+ * Receive an atomic request packet from the master port.
+ */
+ virtual Tick recvAtomic(PacketPtr pkt) = 0;
+
+ /**
+ * Receive a functional request packet from the master port.
+ */
+ virtual void recvFunctional(PacketPtr pkt) = 0;
+
/**
* Called by a peer port in order to determine the block size of
* the owner of this port.
DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name);
}
-Tick
-RubyPort::PioPort::recvAtomic(PacketPtr pkt)
-{
- panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
- return 0;
-}
-
Tick
RubyPort::M5Port::recvAtomic(PacketPtr pkt)
{
}
bool
-RubyPort::M5Port::sendNextCycle(PacketPtr pkt)
+RubyPort::M5Port::sendNextCycle(PacketPtr pkt, bool send_as_snoop)
{
//minimum latency, must be > 0
- queue.schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
+ queue.schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()),
+ send_as_snoop);
return true;
}
for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
if ((*p)->getMasterPort().isSnooping()) {
Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1);
- (*p)->sendNextCycle(pkt);
+ // send as a snoop request
+ (*p)->sendNextCycle(pkt, true);
}
}
}
public:
M5Port(const std::string &_name, RubyPort *_port,
RubySystem*_system, bool _access_phys_mem);
- bool sendNextCycle(PacketPtr pkt);
+ bool sendNextCycle(PacketPtr pkt, bool send_as_snoop = false);
void hitCallback(PacketPtr pkt);
void evictionCallback(const Address& address);
unsigned deviceBlockSize() const;
protected:
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt);
- virtual void recvFunctional(PacketPtr pkt) { }
};
friend class PioPort;
{ panic("SystemPort does not receive timing!\n"); return false; }
void recvRetry()
{ panic("SystemPort does not expect retry!\n"); }
- Tick recvAtomic(PacketPtr pkt)
- { panic("SystemPort does not receive atomic!\n"); return 0; }
- void recvFunctional(PacketPtr pkt)
- { panic("SystemPort does not receive functional!\n"); }
};
SystemPort _systemPort;