diff options
Diffstat (limited to 'src/mem/noncoherent_xbar.cc')
-rw-r--r-- | src/mem/noncoherent_xbar.cc | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/mem/noncoherent_xbar.cc b/src/mem/noncoherent_xbar.cc new file mode 100644 index 000000000..bc51be5a2 --- /dev/null +++ b/src/mem/noncoherent_xbar.cc @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2011-2014 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 non-coherent crossbar object. + */ + +#include "base/misc.hh" +#include "base/trace.hh" +#include "debug/NoncoherentXBar.hh" +#include "debug/XBar.hh" +#include "mem/noncoherent_xbar.hh" + +NoncoherentXBar::NoncoherentXBar(const NoncoherentXBarParams *p) + : BaseXBar(p) +{ + // 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 NoncoherentXBarMasterPort(portName, *this, i); + masterPorts.push_back(bp); + reqLayers.push_back(new ReqLayer(*bp, *this, + csprintf(".reqLayer%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 NoncoherentXBarMasterPort(portName, *this, + defaultPortID); + masterPorts.push_back(bp); + reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%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 NoncoherentXBarSlavePort(portName, *this, i); + slavePorts.push_back(bp); + respLayers.push_back(new RespLayer(*bp, *this, + csprintf(".respLayer%d", i))); + } + + clearPortCache(); +} + +NoncoherentXBar::~NoncoherentXBar() +{ + for (auto l: reqLayers) + delete l; + for (auto l: respLayers) + delete l; +} + +bool +NoncoherentXBar::recvTimingReq(PacketPtr pkt, PortID slave_port_id) +{ + // determine the source port based on the id + SlavePort *src_port = slavePorts[slave_port_id]; + + // we should never see express snoops on a non-coherent crossbar + assert(!pkt->isExpressSnoop()); + + // determine the destination based on the address + PortID master_port_id = findPort(pkt->getAddr()); + + // test if the layer should be considered occupied for the current + // port + if (!reqLayers[master_port_id]->tryTiming(src_port)) { + DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(NoncoherentXBar, "recvTimingReq: 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(); + + // set the source port for routing of the response + pkt->setSrc(slave_port_id); + + calcPacketTiming(pkt); + Tick packetFinishTime = pkt->lastWordDelay + curTick(); + + // since it is a normal request, attempt to send the packet + bool success = masterPorts[master_port_id]->sendTimingReq(pkt); + + if (!success) { + // inhibited packets should never be forced to retry + assert(!pkt->memInhibitAsserted()); + + DPRINTF(NoncoherentXBar, "recvTimingReq: src %s %s 0x%x RETRY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + // undo the calculation so we can check for 0 again + pkt->firstWordDelay = pkt->lastWordDelay = 0; + + // occupy until the header is sent + reqLayers[master_port_id]->failedTiming(src_port, + clockEdge(headerCycles)); + + return false; + } + + reqLayers[master_port_id]->succeededTiming(packetFinishTime); + + // stats updates + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + + return true; +} + +bool +NoncoherentXBar::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 layer should be considered occupied for the current + // port + if (!respLayers[slave_port_id]->tryTiming(src_port)) { + DPRINTF(NoncoherentXBar, "recvTimingResp: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(NoncoherentXBar, "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->lastWordDelay + curTick(); + + // 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 + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + + return true; +} + +void +NoncoherentXBar::recvRetry(PortID master_port_id) +{ + // 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 +NoncoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id) +{ + DPRINTF(NoncoherentXBar, "recvAtomic: packet src %s addr 0x%x cmd %s\n", + slavePorts[slave_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + + unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; + unsigned int pkt_cmd = pkt->cmdToIndex(); + + // determine the destination port + PortID master_port_id = findPort(pkt->getAddr()); + + // stats updates for the request + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + + // forward the request to the appropriate destination + Tick response_latency = masterPorts[master_port_id]->sendAtomic(pkt); + + // add the response data + if (pkt->isResponse()) { + pkt_size = pkt->hasData() ? pkt->getSize() : 0; + pkt_cmd = pkt->cmdToIndex(); + + // stats updates + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + } + + // @todo: Not setting first-word time + pkt->lastWordDelay = response_latency; + return response_latency; +} + +void +NoncoherentXBar::recvFunctional(PacketPtr pkt, PortID slave_port_id) +{ + if (!pkt->isPrint()) { + // don't do DPRINTFs on PrintReq as it clutters up the output + DPRINTF(NoncoherentXBar, + "recvFunctional: packet src %s addr 0x%x cmd %s\n", + slavePorts[slave_port_id]->name(), pkt->getAddr(), + pkt->cmdString()); + } + + // determine the destination port + PortID dest_id = findPort(pkt->getAddr()); + + // forward the request to the appropriate destination + masterPorts[dest_id]->sendFunctional(pkt); +} + +unsigned int +NoncoherentXBar::drain(DrainManager *dm) +{ + // sum up the individual layers + unsigned int total = 0; + for (auto l: reqLayers) + total += l->drain(dm); + for (auto l: respLayers) + total += l->drain(dm); + return total; +} + +NoncoherentXBar* +NoncoherentXBarParams::create() +{ + return new NoncoherentXBar(this); +} + +void +NoncoherentXBar::regStats() +{ + // register the stats of the base class and our layers + BaseXBar::regStats(); + for (auto l: reqLayers) + l->regStats(); + for (auto l: respLayers) + l->regStats(); +} |