noncoherent_xbar.cc revision 9712
1/* 2 * Copyright (c) 2011-2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2006 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ali Saidi 41 * Andreas Hansson 42 * William Wang 43 */ 44 45/** 46 * @file 47 * Definition of a bus object. 48 */ 49 50#include "base/misc.hh" 51#include "base/trace.hh" 52#include "debug/Bus.hh" 53#include "debug/BusAddrRanges.hh" 54#include "debug/NoncoherentBus.hh" 55#include "mem/noncoherent_bus.hh" 56 57NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p) 58 : BaseBus(p), 59 reqLayer(*this, ".reqLayer", p->port_master_connection_count + 60 p->port_default_connection_count), 61 respLayer(*this, ".respLayer", p->port_slave_connection_count) 62{ 63 // create the ports based on the size of the master and slave 64 // vector ports, and the presence of the default port, the ports 65 // are enumerated starting from zero 66 for (int i = 0; i < p->port_master_connection_count; ++i) { 67 std::string portName = csprintf("%s.master[%d]", name(), i); 68 MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, i); 69 masterPorts.push_back(bp); 70 } 71 72 // see if we have a default slave device connected and if so add 73 // our corresponding master port 74 if (p->port_default_connection_count) { 75 defaultPortID = masterPorts.size(); 76 std::string portName = name() + ".default"; 77 MasterPort* bp = new NoncoherentBusMasterPort(portName, *this, 78 defaultPortID); 79 masterPorts.push_back(bp); 80 } 81 82 // create the slave ports, once again starting at zero 83 for (int i = 0; i < p->port_slave_connection_count; ++i) { 84 std::string portName = csprintf("%s.slave[%d]", name(), i); 85 SlavePort* bp = new NoncoherentBusSlavePort(portName, *this, i); 86 slavePorts.push_back(bp); 87 } 88 89 clearPortCache(); 90} 91 92bool 93NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) 94{ 95 // determine the source port based on the id 96 SlavePort *src_port = slavePorts[slave_port_id]; 97 98 // we should never see express snoops on a non-coherent bus 99 assert(!pkt->isExpressSnoop()); 100 101 // determine the destination based on the address 102 PortID master_port_id = findPort(pkt->getAddr()); 103 104 // test if the bus should be considered occupied for the current 105 // port 106 if (!reqLayer.tryTiming(src_port, master_port_id)) { 107 DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", 108 src_port->name(), pkt->cmdString(), pkt->getAddr()); 109 return false; 110 } 111 112 DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x\n", 113 src_port->name(), pkt->cmdString(), pkt->getAddr()); 114 115 // store size and command as they might be modified when 116 // forwarding the packet 117 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 118 unsigned int pkt_cmd = pkt->cmdToIndex(); 119 120 // set the source port for routing of the response 121 pkt->setSrc(slave_port_id); 122 123 calcPacketTiming(pkt); 124 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 125 126 // since it is a normal request, attempt to send the packet 127 bool success = masterPorts[master_port_id]->sendTimingReq(pkt); 128 129 if (!success) { 130 // inhibited packets should never be forced to retry 131 assert(!pkt->memInhibitAsserted()); 132 133 DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", 134 src_port->name(), pkt->cmdString(), pkt->getAddr()); 135 136 // undo the calculation so we can check for 0 again 137 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 138 139 // occupy until the header is sent 140 reqLayer.failedTiming(src_port, master_port_id, 141 clockEdge(Cycles(headerCycles))); 142 143 return false; 144 } 145 146 reqLayer.succeededTiming(packetFinishTime); 147 148 // stats updates 149 dataThroughBus += pkt_size; 150 pktCount[slave_port_id][master_port_id]++; 151 totPktSize[slave_port_id][master_port_id] += pkt_size; 152 transDist[pkt_cmd]++; 153 154 return true; 155} 156 157bool 158NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) 159{ 160 // determine the source port based on the id 161 MasterPort *src_port = masterPorts[master_port_id]; 162 163 // test if the bus should be considered occupied for the current 164 // port 165 if (!respLayer.tryTiming(src_port, pkt->getDest())) { 166 DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", 167 src_port->name(), pkt->cmdString(), pkt->getAddr()); 168 return false; 169 } 170 171 DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x\n", 172 src_port->name(), pkt->cmdString(), pkt->getAddr()); 173 174 // store size and command as they might be modified when 175 // forwarding the packet 176 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 177 unsigned int pkt_cmd = pkt->cmdToIndex(); 178 179 calcPacketTiming(pkt); 180 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 181 182 // determine the destination based on what is stored in the packet 183 PortID slave_port_id = pkt->getDest(); 184 185 // send the packet through the destination slave port 186 bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); 187 188 // currently it is illegal to block responses... can lead to 189 // deadlock 190 assert(success); 191 192 respLayer.succeededTiming(packetFinishTime); 193 194 // stats updates 195 dataThroughBus += pkt_size; 196 pktCount[slave_port_id][master_port_id]++; 197 totPktSize[slave_port_id][master_port_id] += pkt_size; 198 transDist[pkt_cmd]++; 199 200 return true; 201} 202 203void 204NoncoherentBus::recvRetry(PortID master_port_id) 205{ 206 // responses never block on forwarding them, so the retry will 207 // always be coming from a port to which we tried to forward a 208 // request 209 reqLayer.recvRetry(master_port_id); 210} 211 212Tick 213NoncoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) 214{ 215 DPRINTF(NoncoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 216 slavePorts[slave_port_id]->name(), pkt->getAddr(), 217 pkt->cmdString()); 218 219 // add the request data 220 dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 221 222 // determine the destination port 223 PortID dest_id = findPort(pkt->getAddr()); 224 225 // forward the request to the appropriate destination 226 Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 227 228 // add the response data 229 if (pkt->isResponse()) 230 dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 231 232 // @todo: Not setting first-word time 233 pkt->busLastWordDelay = response_latency; 234 return response_latency; 235} 236 237void 238NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) 239{ 240 if (!pkt->isPrint()) { 241 // don't do DPRINTFs on PrintReq as it clutters up the output 242 DPRINTF(NoncoherentBus, 243 "recvFunctional: packet src %s addr 0x%x cmd %s\n", 244 slavePorts[slave_port_id]->name(), pkt->getAddr(), 245 pkt->cmdString()); 246 } 247 248 // determine the destination port 249 PortID dest_id = findPort(pkt->getAddr()); 250 251 // forward the request to the appropriate destination 252 masterPorts[dest_id]->sendFunctional(pkt); 253} 254 255unsigned int 256NoncoherentBus::drain(DrainManager *dm) 257{ 258 // sum up the individual layers 259 return reqLayer.drain(dm) + respLayer.drain(dm); 260} 261 262NoncoherentBus* 263NoncoherentBusParams::create() 264{ 265 return new NoncoherentBus(this); 266} 267 268void 269NoncoherentBus::regStats() 270{ 271 // register the stats of the base class and our two bus layers 272 BaseBus::regStats(); 273 reqLayer.regStats(); 274 respLayer.regStats(); 275 276 dataThroughBus 277 .name(name() + ".data_through_bus") 278 .desc("Total data (bytes)") 279 ; 280 281 throughput 282 .name(name() + ".throughput") 283 .desc("Throughput (bytes/s)") 284 .precision(0) 285 ; 286 287 throughput = dataThroughBus / simSeconds; 288} 289