summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/bridge.cc19
-rw-r--r--src/mem/bridge.hh8
-rw-r--r--src/mem/bus.cc502
-rw-r--r--src/mem/bus.hh135
-rw-r--r--src/mem/cache/base.hh2
-rw-r--r--src/mem/cache/cache.hh8
-rw-r--r--src/mem/cache/cache_impl.hh60
-rw-r--r--src/mem/mport.cc14
-rw-r--r--src/mem/mport.hh6
-rw-r--r--src/mem/packet_queue.cc13
-rw-r--r--src/mem/packet_queue.hh10
-rw-r--r--src/mem/port.cc26
-rw-r--r--src/mem/port.hh127
-rw-r--r--src/mem/ruby/system/RubyPort.cc15
-rw-r--r--src/mem/ruby/system/RubyPort.hh4
15 files changed, 619 insertions, 330 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index ebb37e792..4dcb2a537 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -412,31 +412,12 @@ Bridge::BridgeSlavePort::recvRetry()
}
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)
{
std::list<PacketBuffer*>::iterator i;
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
index e7dbc0a28..87b327ca3 100644
--- a/src/mem/bridge.hh
+++ b/src/mem/bridge.hh
@@ -358,14 +358,6 @@ class Bridge : public MemObject
/** 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. */
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index c89455f02..eb26e268b 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -57,7 +57,6 @@ Bus::Bus(const BusParams *p)
: 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)
@@ -71,40 +70,28 @@ Bus::Bus(const BusParams *p)
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();
@@ -113,9 +100,8 @@ Bus::Bus(const BusParams *p)
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];
@@ -127,8 +113,9 @@ Bus::getMasterPort(const std::string &if_name, int idx)
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);
}
@@ -137,19 +124,15 @@ Bus::getSlavePort(const std::string &if_name, int 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);
}
}
}
@@ -200,27 +183,36 @@ void Bus::occupyBus(Tick until)
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;
@@ -232,89 +224,196 @@ Bus::recvTiming(PacketPtr pkt)
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
@@ -430,9 +529,6 @@ Bus::findPort(Addr addr)
name());
}
-
-/** Function called by the port when the bus is receiving a Atomic
- * transaction.*/
Tick
Bus::recvAtomic(PacketPtr pkt)
{
@@ -443,12 +539,59 @@ 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;
@@ -460,8 +603,9 @@ Bus::recvAtomic(PacketPtr pkt)
// (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
@@ -476,48 +620,51 @@ Bus::recvAtomic(PacketPtr pkt)
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());
}
@@ -526,10 +673,13 @@ Bus::recvFunctional(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
+ 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;
@@ -537,26 +687,13 @@ Bus::recvFunctional(PacketPtr pkt)
// (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;
}
}
}
@@ -621,8 +758,7 @@ Bus::recvRangeChange(int id)
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);
}
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index e79e9df9e..8a0676353 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -91,25 +91,35 @@ class Bus : public MemObject
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
@@ -160,20 +170,29 @@ class Bus : public MemObject
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. */
@@ -212,18 +231,91 @@ class Bus : public MemObject
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);
@@ -345,11 +437,6 @@ class Bus : public MemObject
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;
diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh
index 47cbaf7a0..b24e595b7 100644
--- a/src/mem/cache/base.hh
+++ b/src/mem/cache/base.hh
@@ -142,7 +142,7 @@ class BaseCache : public MemObject
* @param when time to send the response
*/
void respond(PacketPtr pkt, Tick time) {
- queue.schedSendTiming(pkt, time);
+ queue.schedSendTiming(pkt, time, true);
}
protected:
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index e745529a7..a774a356c 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -90,6 +90,8 @@ class Cache : public BaseCache
protected:
+ virtual bool recvTimingSnoop(PacketPtr pkt);
+
virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt);
@@ -152,11 +154,13 @@ class Cache : public BaseCache
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(); }
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 3525e0777..fa6f6c860 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -785,7 +785,7 @@ Cache<TagStore>::functionalAccess(PacketPtr pkt, bool fromCpuSide)
} 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);
}
}
}
@@ -1178,24 +1178,23 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
// 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
@@ -1335,6 +1334,16 @@ Cache<TagStore>::snoopTiming(PacketPtr pkt)
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
@@ -1483,7 +1492,7 @@ Cache<TagStore>::getTimingPacket()
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);
@@ -1550,8 +1559,9 @@ template<class TagStore>
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;
@@ -1603,17 +1613,25 @@ Cache<TagStore>::MemSidePort::recvTiming(PacketPtr pkt)
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
@@ -1622,7 +1640,7 @@ Cache<TagStore>::MemSidePort::recvAtomic(PacketPtr pkt)
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
diff --git a/src/mem/mport.cc b/src/mem/mport.cc
index 9af394d27..5678f87d7 100644
--- a/src/mem/mport.cc
+++ b/src/mem/mport.cc
@@ -52,17 +52,3 @@ MessageSlavePort::recvAtomic(PacketPtr pkt)
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());
- }
-}
diff --git a/src/mem/mport.hh b/src/mem/mport.hh
index 664acc559..7f9e8f4e0 100644
--- a/src/mem/mport.hh
+++ b/src/mem/mport.hh
@@ -82,11 +82,7 @@ class MessageMasterPort : public QueuedMasterPort
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:
diff --git a/src/mem/packet_queue.cc b/src/mem/packet_queue.cc
index 29914bea2..bffae5674 100644
--- a/src/mem/packet_queue.cc
+++ b/src/mem/packet_queue.cc
@@ -104,7 +104,7 @@ PacketQueue::schedSendEvent(Tick when)
}
void
-PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
+PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
{
assert(when > curTick());
@@ -114,14 +114,14 @@ PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
// 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;
}
@@ -130,7 +130,7 @@ PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
++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()
@@ -143,7 +143,10 @@ 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
diff --git a/src/mem/packet_queue.hh b/src/mem/packet_queue.hh
index ac868802b..fbcd7d449 100644
--- a/src/mem/packet_queue.hh
+++ b/src/mem/packet_queue.hh
@@ -70,8 +70,9 @@ class PacketQueue
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)
{}
};
@@ -196,8 +197,9 @@ class PacketQueue
*
* @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
@@ -215,4 +217,4 @@ class PacketQueue
unsigned int drain(Event *de);
};
-#endif // __MEM_TPORT_HH__
+#endif // __MEM_PACKET_QUEUE_HH__
diff --git a/src/mem/port.cc b/src/mem/port.cc
index 3305541c7..92c6aaab8 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -104,7 +104,19 @@ MasterPort::peerBlockSize() const
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);
@@ -155,3 +167,15 @@ SlavePort::isConnected() const
{
return _masterPort != NULL;
}
+
+Tick
+SlavePort::sendAtomicSnoop(PacketPtr pkt)
+{
+ return _masterPort->recvAtomicSnoop(pkt);
+}
+
+void
+SlavePort::sendFunctionalSnoop(PacketPtr pkt)
+{
+ return _masterPort->recvFunctionalSnoop(pkt);
+}
diff --git a/src/mem/port.hh b/src/mem/port.hh
index 80bb3b085..61c92d8e4 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -115,28 +115,35 @@ class Port
/** 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.
*
@@ -145,30 +152,23 @@ class Port
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(); }
};
@@ -198,6 +198,43 @@ class MasterPort : public Port
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
* nothing. Override this function in a derived class if the owner
@@ -257,6 +294,36 @@ class SlavePort : public Port
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.
*/
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 0cdb919b1..74a60f863 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -133,13 +133,6 @@ RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
}
Tick
-RubyPort::PioPort::recvAtomic(PacketPtr pkt)
-{
- panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
- return 0;
-}
-
-Tick
RubyPort::M5Port::recvAtomic(PacketPtr pkt)
{
panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
@@ -662,10 +655,11 @@ RubyPort::M5Port::hitCallback(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;
}
@@ -706,7 +700,8 @@ RubyPort::ruby_eviction_callback(const Address& address)
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);
}
}
}
diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh
index 553614021..f41c98f55 100644
--- a/src/mem/ruby/system/RubyPort.hh
+++ b/src/mem/ruby/system/RubyPort.hh
@@ -71,7 +71,7 @@ class RubyPort : public MemObject
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;
@@ -110,8 +110,6 @@ class RubyPort : public MemObject
protected:
virtual bool recvTiming(PacketPtr pkt);
- virtual Tick recvAtomic(PacketPtr pkt);
- virtual void recvFunctional(PacketPtr pkt) { }
};
friend class PioPort;