diff options
author | Andreas Hansson <andreas.hansson@arm.com> | 2012-04-14 05:45:07 -0400 |
---|---|---|
committer | Andreas Hansson <andreas.hansson@arm.com> | 2012-04-14 05:45:07 -0400 |
commit | dccca0d3a9c985972d3d603190e62899d03825e8 (patch) | |
tree | f186c5b7c6656397f04660ec2e43a2cb1a6c11f6 /src/mem | |
parent | b9bc530ad20bceeed6e43ea459d271046f43e70c (diff) | |
download | gem5-dccca0d3a9c985972d3d603190e62899d03825e8.tar.xz |
MEM: Separate snoops and normal memory requests/responses
This patch introduces port access methods that separates snoop
request/responses from normal memory request/responses. The
differentiation is made for functional, atomic and timing accesses and
builds on the introduction of master and slave ports.
Before the introduction of this patch, the packets belonging to the
different phases of the protocol (request -> [forwarded snoop request
-> snoop response]* -> response) all use the same port access
functions, even though the snoop packets flow in the opposite
direction to the normal packet. That is, a coherent master sends
normal request and receives responses, but receives snoop requests and
sends snoop responses (vice versa for the slave). These two distinct
phases now use different access functions, as described below.
Starting with the functional access, a master sends a request to a
slave through sendFunctional, and the request packet is turned into a
response before the call returns. In a system without cache coherence,
this is all that is needed from the functional interface. For the
cache-coherent scenario, a slave also sends snoop requests to coherent
masters through sendFunctionalSnoop, with responses returned within
the same packet pointer. This is currently used by the bus and caches,
and the LSQ of the O3 CPU. The send/recvFunctional and
send/recvFunctionalSnoop are moved from the Port super class to the
appropriate subclass.
Atomic accesses follow the same flow as functional accesses, with
request being sent from master to slave through sendAtomic. In the
case of cache-coherent ports, a slave can send snoop requests to a
master through sendAtomicSnoop. Just as for the functional access
methods, the atomic send and receive member functions are moved to the
appropriate subclasses.
The timing access methods are different from the functional and atomic
in that requests and responses are separated in time and
send/recvTiming are used for both directions. Hence, a master uses
sendTiming to send a request to a slave, and a slave uses sendTiming
to send a response back to a master, at a later point in time. Snoop
requests and responses travel in the opposite direction, similar to
what happens in functional and atomic accesses. With the introduction
of this patch, it is possible to determine the direction of packets in
the bus, and no longer necessary to look for both a master and a slave
port with the requested port id.
In contrast to the normal recvFunctional, recvAtomic and recvTiming
that are pure virtual functions, the recvFunctionalSnoop,
recvAtomicSnoop and recvTimingSnoop have a default implementation that
calls panic. This is to allow non-coherent master and slave ports to
not implement these functions.
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/bridge.cc | 19 | ||||
-rw-r--r-- | src/mem/bridge.hh | 8 | ||||
-rw-r--r-- | src/mem/bus.cc | 502 | ||||
-rw-r--r-- | src/mem/bus.hh | 135 | ||||
-rw-r--r-- | src/mem/cache/base.hh | 2 | ||||
-rw-r--r-- | src/mem/cache/cache.hh | 8 | ||||
-rw-r--r-- | src/mem/cache/cache_impl.hh | 60 | ||||
-rw-r--r-- | src/mem/mport.cc | 14 | ||||
-rw-r--r-- | src/mem/mport.hh | 6 | ||||
-rw-r--r-- | src/mem/packet_queue.cc | 13 | ||||
-rw-r--r-- | src/mem/packet_queue.hh | 10 | ||||
-rw-r--r-- | src/mem/port.cc | 26 | ||||
-rw-r--r-- | src/mem/port.hh | 127 | ||||
-rw-r--r-- | src/mem/ruby/system/RubyPort.cc | 15 | ||||
-rw-r--r-- | src/mem/ruby/system/RubyPort.hh | 4 |
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; |