diff options
Diffstat (limited to 'src/mem/coherent_bus.cc')
-rw-r--r-- | src/mem/coherent_bus.cc | 830 |
1 files changed, 0 insertions, 830 deletions
diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_bus.cc deleted file mode 100644 index 9529e9e7d..000000000 --- a/src/mem/coherent_bus.cc +++ /dev/null @@ -1,830 +0,0 @@ -/* - * Copyright (c) 2011-2013 ARM Limited - * All rights reserved - * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Ali Saidi - * Andreas Hansson - * William Wang - */ - -/** - * @file - * Definition of a bus object. - */ - -#include "base/misc.hh" -#include "base/trace.hh" -#include "debug/BusAddrRanges.hh" -#include "debug/CoherentBus.hh" -#include "mem/coherent_bus.hh" -#include "sim/system.hh" - -CoherentBus::CoherentBus(const CoherentBusParams *p) - : BaseBus(p), system(p->system), snoopFilter(p->snoop_filter) -{ - // create the ports based on the size of the master and slave - // 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.master[%d]", name(), i); - MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); - masterPorts.push_back(bp); - reqLayers.push_back(new ReqLayer(*bp, *this, - csprintf(".reqLayer%d", i))); - snoopLayers.push_back(new SnoopLayer(*bp, *this, - csprintf(".snoopLayer%d", i))); - } - - // see if we have a default slave device connected and if so add - // our corresponding master port - if (p->port_default_connection_count) { - defaultPortID = masterPorts.size(); - std::string portName = name() + ".default"; - MasterPort* bp = new CoherentBusMasterPort(portName, *this, - defaultPortID); - masterPorts.push_back(bp); - reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d", - defaultPortID))); - snoopLayers.push_back(new SnoopLayer(*bp, *this, - csprintf(".snoopLayer%d", - defaultPortID))); - } - - // 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.slave[%d]", name(), i); - SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); - slavePorts.push_back(bp); - respLayers.push_back(new RespLayer(*bp, *this, - csprintf(".respLayer%d", i))); - snoopRespPorts.push_back(new SnoopRespPort(*bp, *this)); - } - - if (snoopFilter) - snoopFilter->setSlavePorts(slavePorts); - - clearPortCache(); -} - -CoherentBus::~CoherentBus() -{ - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - delete *l; - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - delete *l; - for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) - delete *l; - for (auto p = snoopRespPorts.begin(); p != snoopRespPorts.end(); ++p) - delete *p; -} - -void -CoherentBus::init() -{ - // the base class is responsible for determining the block size - BaseBus::init(); - - // iterate over our slave ports and determine which of our - // neighbouring master ports are snooping and add them as snoopers - for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); - ++p) { - // check if the connected master port is snooping - if ((*p)->isSnooping()) { - DPRINTF(BusAddrRanges, "Adding snooping master %s\n", - (*p)->getMasterPort().name()); - snoopPorts.push_back(*p); - } - } - - if (snoopPorts.empty()) - warn("CoherentBus %s has no snooping ports attached!\n", name()); -} - -bool -CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) -{ - // determine the source port based on the id - SlavePort *src_port = slavePorts[slave_port_id]; - - // remember if the packet is an express snoop - bool is_express_snoop = pkt->isExpressSnoop(); - - // determine the destination based on the address - PortID master_port_id = findPort(pkt->getAddr()); - - // test if the bus should be considered occupied for the current - // port, and exclude express snoops from the check - if (!is_express_snoop && !reqLayers[master_port_id]->tryTiming(src_port)) { - DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUS BUSY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - - DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n", - src_port->name(), pkt->cmdString(), is_express_snoop, - pkt->getAddr()); - - // store size and command as they might be modified when - // forwarding the packet - unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; - unsigned int pkt_cmd = pkt->cmdToIndex(); - - // set the source port for routing of the response - pkt->setSrc(slave_port_id); - - calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); - - // uncacheable requests need never be snooped - if (!pkt->req->isUncacheable() && !system->bypassCaches()) { - // the packet is a memory-mapped request and should be - // broadcasted to our snoopers but the source - if (snoopFilter) { - // check with the snoop filter where to forward this packet - auto sf_res = snoopFilter->lookupRequest(pkt, *src_port); - packetFinishTime += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x"\ - " SF size: %i lat: %i\n", src_port->name(), - pkt->cmdString(), pkt->getAddr(), sf_res.first.size(), - sf_res.second); - forwardTiming(pkt, slave_port_id, sf_res.first); - } else { - forwardTiming(pkt, slave_port_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 = !is_express_snoop && 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); - } - - // Note: Cannot create a copy of the full packet, here. - MemCmd orig_cmd(pkt->cmd); - - // since it is a normal request, attempt to send the packet - bool success = masterPorts[master_port_id]->sendTimingReq(pkt); - - if (snoopFilter && !pkt->req->isUncacheable() - && !system->bypassCaches()) { - // The packet may already be overwritten by the sendTimingReq function. - // The snoop filter needs to see the original request *and* the return - // status of the send operation, so we need to recreate the original - // request. Atomic mode does not have the issue, as there the send - // operation and the response happen instantaneously and don't need two - // phase tracking. - MemCmd tmp_cmd(pkt->cmd); - pkt->cmd = orig_cmd; - // Let the snoop filter know about the success of the send operation - snoopFilter->updateRequest(pkt, *src_port, !success); - pkt->cmd = tmp_cmd; - } - - // if this is an express snoop, we are done at this point - if (is_express_snoop) { - assert(success); - snoopDataThroughBus += pkt_size; - snoopsThroughBus++; - } else { - // for normal requests, check if successful - if (!success) { - // inhibited packets should never be forced to retry - assert(!pkt->memInhibitAsserted()); - - // if it was added as outstanding and the send failed, then - // erase it again - if (add_outstanding) - outstandingReq.erase(pkt->req); - - // undo the calculation so we can check for 0 again - pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; - - DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - // update the bus state and schedule an idle event - reqLayers[master_port_id]->failedTiming(src_port, - clockEdge(headerCycles)); - } else { - // update the bus state and schedule an idle event - reqLayers[master_port_id]->succeededTiming(packetFinishTime); - dataThroughBus += pkt_size; - } - } - - // stats updates only consider packets that were successfully sent - if (success) { - pktCount[slave_port_id][master_port_id]++; - totPktSize[slave_port_id][master_port_id] += pkt_size; - transDist[pkt_cmd]++; - } - - return success; -} - -bool -CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) -{ - // determine the source port based on the id - MasterPort *src_port = masterPorts[master_port_id]; - - // determine the destination based on what is stored in the packet - PortID slave_port_id = pkt->getDest(); - - // test if the bus should be considered occupied for the current - // port - if (!respLayers[slave_port_id]->tryTiming(src_port)) { - DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - - DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - // store size and command as they might be modified when - // forwarding the packet - unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; - unsigned int pkt_cmd = pkt->cmdToIndex(); - - calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); - - // 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()); - - if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches()) { - // let the snoop filter inspect the response and update its state - snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]); - } - - // remove it as outstanding - outstandingReq.erase(pkt->req); - - // send the packet through the destination slave port - bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt); - - // currently it is illegal to block responses... can lead to - // deadlock - assert(success); - - respLayers[slave_port_id]->succeededTiming(packetFinishTime); - - // stats updates - dataThroughBus += pkt_size; - pktCount[slave_port_id][master_port_id]++; - totPktSize[slave_port_id][master_port_id] += pkt_size; - transDist[pkt_cmd]++; - - return true; -} - -void -CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) -{ - DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", - masterPorts[master_port_id]->name(), pkt->cmdString(), - pkt->getAddr()); - - // update stats here as we know the forwarding will succeed - transDist[pkt->cmdToIndex()]++; - snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - snoopsThroughBus++; - - // we should only see express snoops from caches - assert(pkt->isExpressSnoop()); - - // set the source port for routing of the response - pkt->setSrc(master_port_id); - - if (snoopFilter) { - // let the Snoop Filter work its magic and guide probing - auto sf_res = snoopFilter->lookupSnoop(pkt); - // No timing here: packetFinishTime += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x"\ - " SF size: %i lat: %i\n", masterPorts[master_port_id]->name(), - pkt->cmdString(), pkt->getAddr(), sf_res.first.size(), - sf_res.second); - - // forward to all snoopers - forwardTiming(pkt, InvalidPortID, sf_res.first); - } else { - forwardTiming(pkt, InvalidPortID); - } - - // 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(master_port_id == findPort(pkt->getAddr())); -} - -bool -CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) -{ - // determine the source port based on the id - SlavePort* src_port = slavePorts[slave_port_id]; - - // get the destination from the packet - PortID dest_port_id = pkt->getDest(); - - // 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 - bool forwardAsSnoop = outstandingReq.find(pkt->req) == - outstandingReq.end(); - - // test if the bus should be considered occupied for the current - // port, note that the check is bypassed if the response is being - // passed on as a normal response since this is occupying the - // response layer rather than the snoop response layer - if (forwardAsSnoop) { - if (!snoopLayers[dest_port_id]->tryTiming(src_port)) { - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - } else { - // get the master port that mirrors this slave port internally - MasterPort* snoop_port = snoopRespPorts[slave_port_id]; - if (!respLayers[dest_port_id]->tryTiming(snoop_port)) { - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", - snoop_port->name(), pkt->cmdString(), pkt->getAddr()); - return false; - } - } - - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n", - src_port->name(), pkt->cmdString(), pkt->getAddr()); - - // store size and command as they might be modified when - // forwarding the packet - unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; - unsigned int pkt_cmd = pkt->cmdToIndex(); - - // responses are never express snoops - assert(!pkt->isExpressSnoop()); - - calcPacketTiming(pkt); - Tick packetFinishTime = pkt->busLastWordDelay + curTick(); - - // forward it either as a snoop response or a normal response - if (forwardAsSnoop) { - // this is a snoop response to a snoop request we forwarded, - // e.g. coming from the L1 and going to the L2, and it should - // be forwarded as a snoop response - - if (snoopFilter) { - // update the probe filter so that it can properly track the line - snoopFilter->updateSnoopForward(pkt, *slavePorts[slave_port_id], - *masterPorts[dest_port_id]); - } - - bool success M5_VAR_USED = - masterPorts[dest_port_id]->sendTimingSnoopResp(pkt); - pktCount[slave_port_id][dest_port_id]++; - totPktSize[slave_port_id][dest_port_id] += pkt_size; - assert(success); - - snoopLayers[dest_port_id]->succeededTiming(packetFinishTime); - } 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(slave_port_id != dest_port_id); - - if (snoopFilter) { - // update the probe filter so that it can properly track the line - snoopFilter->updateSnoopResponse(pkt, *slavePorts[slave_port_id], - *slavePorts[dest_port_id]); - } - - DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x"\ - " FWD RESP\n", src_port->name(), pkt->cmdString(), - pkt->getAddr()); - - // as a normal response, it should go back to a master through - // one of our slave ports, at this point we are ignoring the - // fact that the response layer could be busy and do not touch - // its state - bool success M5_VAR_USED = - slavePorts[dest_port_id]->sendTimingResp(pkt); - - // @todo Put the response in an internal FIFO and pass it on - // to the response layer from there - - // currently it is illegal to block responses... can lead - // to deadlock - assert(success); - - respLayers[dest_port_id]->succeededTiming(packetFinishTime); - } - - // stats updates - transDist[pkt_cmd]++; - snoopDataThroughBus += pkt_size; - snoopsThroughBus++; - - return true; -} - - -void -CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id, - const std::vector<SlavePort*>& dests) -{ - DPRINTF(CoherentBus, "%s for %s address %x size %d\n", __func__, - pkt->cmdString(), pkt->getAddr(), pkt->getSize()); - - // snoops should only happen if the system isn't bypassing caches - assert(!system->bypassCaches()); - - unsigned fanout = 0; - - for (SlavePortConstIter s = dests.begin(); s != dests.end(); ++s) { - SlavePort *p = *s; - // 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 == InvalidPortID || - p->getId() != exclude_slave_port_id) { - // cache is not allowed to refuse snoop - p->sendTimingSnoopReq(pkt); - fanout++; - } - } - - // Stats for fanout of this forward operation - snoopFanout.sample(fanout); -} - -void -CoherentBus::recvRetry(PortID master_port_id) -{ - // responses and snoop responses never block on forwarding them, - // so the retry will always be coming from a port to which we - // tried to forward a request - reqLayers[master_port_id]->recvRetry(); -} - -Tick -CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) -{ - DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", - slavePorts[slave_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - - // add the request data - dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - - MemCmd snoop_response_cmd = MemCmd::InvalidCmd; - Tick snoop_response_latency = 0; - - // uncacheable requests need never be snooped - if (!pkt->req->isUncacheable() && !system->bypassCaches()) { - // forward to all snoopers but the source - std::pair<MemCmd, Tick> snoop_result; - if (snoopFilter) { - // check with the snoop filter where to forward this packet - auto sf_res = - snoopFilter->lookupRequest(pkt, *slavePorts[slave_port_id]); - snoop_response_latency += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "%s: src %s %s 0x%x"\ - " SF size: %i lat: %i\n", __func__, - slavePorts[slave_port_id]->name(), pkt->cmdString(), - pkt->getAddr(), sf_res.first.size(), sf_res.second); - snoop_result = forwardAtomic(pkt, slave_port_id, InvalidPortID, - sf_res.first); - } else { - snoop_result = forwardAtomic(pkt, slave_port_id); - } - snoop_response_cmd = snoop_result.first; - snoop_response_latency += snoop_result.second; - } - - // even if we had a snoop response, we must continue and also - // perform the actual request at the destination - PortID dest_id = findPort(pkt->getAddr()); - - // forward the request to the appropriate destination - Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); - - // Lower levels have replied, tell the snoop filter - if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches() && - pkt->isResponse()) { - snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]); - } - - // 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; - } - - // add the response data - if (pkt->isResponse()) - dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - - // @todo: Not setting first-word time - pkt->busLastWordDelay = response_latency; - return response_latency; -} - -Tick -CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) -{ - DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", - masterPorts[master_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - - // add the request snoop data - snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - snoopsThroughBus++; - - // forward to all snoopers - std::pair<MemCmd, Tick> snoop_result; - Tick snoop_response_latency = 0; - if (snoopFilter) { - auto sf_res = snoopFilter->lookupSnoop(pkt); - snoop_response_latency += sf_res.second * clockPeriod(); - DPRINTF(CoherentBus, "%s: src %s %s 0x%x SF size: %i lat: %i\n", - __func__, masterPorts[master_port_id]->name(), pkt->cmdString(), - pkt->getAddr(), sf_res.first.size(), sf_res.second); - snoop_result = forwardAtomic(pkt, InvalidPortID, master_port_id, - sf_res.first); - } else { - snoop_result = forwardAtomic(pkt, InvalidPortID); - } - MemCmd snoop_response_cmd = snoop_result.first; - snoop_response_latency += snoop_result.second; - - if (snoop_response_cmd != MemCmd::InvalidCmd) - pkt->cmd = snoop_response_cmd; - - // add the response snoop data - if (pkt->isResponse()) { - snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; - snoopsThroughBus++; - } - - // @todo: Not setting first-word time - pkt->busLastWordDelay = snoop_response_latency; - return snoop_response_latency; -} - -std::pair<MemCmd, Tick> -CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id, - PortID source_master_port_id, - const std::vector<SlavePort*>& dests) -{ - // the packet may be changed on snoops, record the original - // command to enable us to restore it between snoops so that - // additional snoops can take place properly - MemCmd orig_cmd = pkt->cmd; - MemCmd snoop_response_cmd = MemCmd::InvalidCmd; - Tick snoop_response_latency = 0; - - // snoops should only happen if the system isn't bypassing caches - assert(!system->bypassCaches()); - - unsigned fanout = 0; - - for (SlavePortConstIter s = dests.begin(); s != dests.end(); ++s) { - SlavePort *p = *s; - // 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 != InvalidPortID && - p->getId() == exclude_slave_port_id) - continue; - - Tick latency = p->sendAtomicSnoop(pkt); - fanout++; - - // in contrast to a functional access, we have to keep on - // going as all snoopers must be updated even if we get a - // response - if (!pkt->isResponse()) - continue; - - // response from snoop agent - assert(pkt->cmd != orig_cmd); - assert(pkt->memInhibitAsserted()); - // should only happen once - assert(snoop_response_cmd == MemCmd::InvalidCmd); - // save response state - snoop_response_cmd = pkt->cmd; - snoop_response_latency = latency; - - if (snoopFilter) { - // Handle responses by the snoopers and differentiate between - // responses to requests from above and snoops from below - if (source_master_port_id != InvalidPortID) { - // Getting a response for a snoop from below - assert(exclude_slave_port_id == InvalidPortID); - snoopFilter->updateSnoopForward(pkt, *p, - *masterPorts[source_master_port_id]); - } else { - // Getting a response for a request from above - assert(source_master_port_id == InvalidPortID); - snoopFilter->updateSnoopResponse(pkt, *p, - *slavePorts[exclude_slave_port_id]); - } - } - // restore original packet state for remaining snoopers - pkt->cmd = orig_cmd; - } - - // Stats for fanout - snoopFanout.sample(fanout); - - // 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); -} - -void -CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) -{ - if (!pkt->isPrint()) { - // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(CoherentBus, - "recvFunctional: packet src %s addr 0x%x cmd %s\n", - slavePorts[slave_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - } - - // uncacheable requests need never be snooped - if (!pkt->req->isUncacheable() && !system->bypassCaches()) { - // forward to all snoopers but the source - forwardFunctional(pkt, slave_port_id); - } - - // 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()) { - PortID dest_id = findPort(pkt->getAddr()); - - masterPorts[dest_id]->sendFunctional(pkt); - } -} - -void -CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) -{ - if (!pkt->isPrint()) { - // don't do DPRINTFs on PrintReq as it clutters up the output - DPRINTF(CoherentBus, - "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", - masterPorts[master_port_id]->name(), pkt->getAddr(), - pkt->cmdString()); - } - - // forward to all snoopers - forwardFunctional(pkt, InvalidPortID); -} - -void -CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) -{ - // snoops should only happen if the system isn't bypassing caches - assert(!system->bypassCaches()); - - for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { - SlavePort *p = *s; - // 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 == InvalidPortID || - p->getId() != exclude_slave_port_id) - p->sendFunctionalSnoop(pkt); - - // if we get a response we are done - if (pkt->isResponse()) { - break; - } - } -} - -unsigned int -CoherentBus::drain(DrainManager *dm) -{ - // sum up the individual layers - unsigned int total = 0; - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - total += (*l)->drain(dm); - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - total += (*l)->drain(dm); - for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) - total += (*l)->drain(dm); - return total; -} - -void -CoherentBus::regStats() -{ - // register the stats of the base class and our three bus layers - BaseBus::regStats(); - for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) - (*l)->regStats(); - for (auto l = respLayers.begin(); l != respLayers.end(); ++l) - (*l)->regStats(); - for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) - (*l)->regStats(); - - dataThroughBus - .name(name() + ".data_through_bus") - .desc("Total data (bytes)") - ; - - snoopDataThroughBus - .name(name() + ".snoop_data_through_bus") - .desc("Total snoop data (bytes)") - ; - - snoopsThroughBus - .name(name() + ".snoops_through_bus") - .desc("Total snoops (count)") - ; - - snoopFanout - .init(0, snoopPorts.size(), 1) - .name(name() + ".snoop_fanout") - .desc("Request fanout histogram") - ; - - throughput - .name(name() + ".throughput") - .desc("Throughput (bytes/s)") - .precision(0) - ; - - throughput = (dataThroughBus + snoopDataThroughBus) / simSeconds; -} - -CoherentBus * -CoherentBusParams::create() -{ - return new CoherentBus(this); -} |