coherent_xbar.cc revision 10401
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/BusAddrRanges.hh" 53#include "debug/CoherentBus.hh" 54#include "mem/coherent_bus.hh" 55#include "sim/system.hh" 56 57CoherentBus::CoherentBus(const CoherentBusParams *p) 58 : BaseBus(p), system(p->system) 59{ 60 // create the ports based on the size of the master and slave 61 // vector ports, and the presence of the default port, the ports 62 // are enumerated starting from zero 63 for (int i = 0; i < p->port_master_connection_count; ++i) { 64 std::string portName = csprintf("%s.master[%d]", name(), i); 65 MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); 66 masterPorts.push_back(bp); 67 reqLayers.push_back(new ReqLayer(*bp, *this, 68 csprintf(".reqLayer%d", i))); 69 snoopLayers.push_back(new SnoopLayer(*bp, *this, 70 csprintf(".snoopLayer%d", i))); 71 } 72 73 // see if we have a default slave device connected and if so add 74 // our corresponding master port 75 if (p->port_default_connection_count) { 76 defaultPortID = masterPorts.size(); 77 std::string portName = name() + ".default"; 78 MasterPort* bp = new CoherentBusMasterPort(portName, *this, 79 defaultPortID); 80 masterPorts.push_back(bp); 81 reqLayers.push_back(new ReqLayer(*bp, *this, csprintf(".reqLayer%d", 82 defaultPortID))); 83 snoopLayers.push_back(new SnoopLayer(*bp, *this, 84 csprintf(".snoopLayer%d", 85 defaultPortID))); 86 } 87 88 // create the slave ports, once again starting at zero 89 for (int i = 0; i < p->port_slave_connection_count; ++i) { 90 std::string portName = csprintf("%s.slave[%d]", name(), i); 91 SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); 92 slavePorts.push_back(bp); 93 respLayers.push_back(new RespLayer(*bp, *this, 94 csprintf(".respLayer%d", i))); 95 snoopRespPorts.push_back(new SnoopRespPort(*bp, *this)); 96 } 97 98 clearPortCache(); 99} 100 101CoherentBus::~CoherentBus() 102{ 103 for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) 104 delete *l; 105 for (auto l = respLayers.begin(); l != respLayers.end(); ++l) 106 delete *l; 107 for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) 108 delete *l; 109 for (auto p = snoopRespPorts.begin(); p != snoopRespPorts.end(); ++p) 110 delete *p; 111} 112 113void 114CoherentBus::init() 115{ 116 // the base class is responsible for determining the block size 117 BaseBus::init(); 118 119 // iterate over our slave ports and determine which of our 120 // neighbouring master ports are snooping and add them as snoopers 121 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 122 ++p) { 123 // check if the connected master port is snooping 124 if ((*p)->isSnooping()) { 125 DPRINTF(BusAddrRanges, "Adding snooping master %s\n", 126 (*p)->getMasterPort().name()); 127 snoopPorts.push_back(*p); 128 } 129 } 130 131 if (snoopPorts.empty()) 132 warn("CoherentBus %s has no snooping ports attached!\n", name()); 133} 134 135bool 136CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) 137{ 138 // determine the source port based on the id 139 SlavePort *src_port = slavePorts[slave_port_id]; 140 141 // remember if the packet is an express snoop 142 bool is_express_snoop = pkt->isExpressSnoop(); 143 144 // determine the destination based on the address 145 PortID master_port_id = findPort(pkt->getAddr()); 146 147 // test if the bus should be considered occupied for the current 148 // port, and exclude express snoops from the check 149 if (!is_express_snoop && !reqLayers[master_port_id]->tryTiming(src_port)) { 150 DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUS BUSY\n", 151 src_port->name(), pkt->cmdString(), pkt->getAddr()); 152 return false; 153 } 154 155 DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n", 156 src_port->name(), pkt->cmdString(), is_express_snoop, 157 pkt->getAddr()); 158 159 // store size and command as they might be modified when 160 // forwarding the packet 161 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 162 unsigned int pkt_cmd = pkt->cmdToIndex(); 163 164 // set the source port for routing of the response 165 pkt->setSrc(slave_port_id); 166 167 calcPacketTiming(pkt); 168 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 169 170 // uncacheable requests need never be snooped 171 if (!pkt->req->isUncacheable() && !system->bypassCaches()) { 172 // the packet is a memory-mapped request and should be 173 // broadcasted to our snoopers but the source 174 forwardTiming(pkt, slave_port_id); 175 } 176 177 // remember if we add an outstanding req so we can undo it if 178 // necessary, if the packet needs a response, we should add it 179 // as outstanding and express snoops never fail so there is 180 // not need to worry about them 181 bool add_outstanding = !is_express_snoop && pkt->needsResponse(); 182 183 // keep track that we have an outstanding request packet 184 // matching this request, this is used by the coherency 185 // mechanism in determining what to do with snoop responses 186 // (in recvTimingSnoop) 187 if (add_outstanding) { 188 // we should never have an exsiting request outstanding 189 assert(outstandingReq.find(pkt->req) == outstandingReq.end()); 190 outstandingReq.insert(pkt->req); 191 } 192 193 // since it is a normal request, attempt to send the packet 194 bool success = masterPorts[master_port_id]->sendTimingReq(pkt); 195 196 // if this is an express snoop, we are done at this point 197 if (is_express_snoop) { 198 assert(success); 199 snoopDataThroughBus += pkt_size; 200 snoopsThroughBus++; 201 } else { 202 // for normal requests, check if successful 203 if (!success) { 204 // inhibited packets should never be forced to retry 205 assert(!pkt->memInhibitAsserted()); 206 207 // if it was added as outstanding and the send failed, then 208 // erase it again 209 if (add_outstanding) 210 outstandingReq.erase(pkt->req); 211 212 // undo the calculation so we can check for 0 again 213 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 214 215 DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", 216 src_port->name(), pkt->cmdString(), pkt->getAddr()); 217 218 // update the bus state and schedule an idle event 219 reqLayers[master_port_id]->failedTiming(src_port, 220 clockEdge(headerCycles)); 221 } else { 222 // update the bus state and schedule an idle event 223 reqLayers[master_port_id]->succeededTiming(packetFinishTime); 224 dataThroughBus += pkt_size; 225 } 226 } 227 228 // stats updates only consider packets that were successfully sent 229 if (success) { 230 pktCount[slave_port_id][master_port_id]++; 231 totPktSize[slave_port_id][master_port_id] += pkt_size; 232 transDist[pkt_cmd]++; 233 } 234 235 return success; 236} 237 238bool 239CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) 240{ 241 // determine the source port based on the id 242 MasterPort *src_port = masterPorts[master_port_id]; 243 244 // determine the destination based on what is stored in the packet 245 PortID slave_port_id = pkt->getDest(); 246 247 // test if the bus should be considered occupied for the current 248 // port 249 if (!respLayers[slave_port_id]->tryTiming(src_port)) { 250 DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", 251 src_port->name(), pkt->cmdString(), pkt->getAddr()); 252 return false; 253 } 254 255 DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", 256 src_port->name(), pkt->cmdString(), pkt->getAddr()); 257 258 // store size and command as they might be modified when 259 // forwarding the packet 260 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 261 unsigned int pkt_cmd = pkt->cmdToIndex(); 262 263 calcPacketTiming(pkt); 264 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 265 266 // the packet is a normal response to a request that we should 267 // have seen passing through the bus 268 assert(outstandingReq.find(pkt->req) != outstandingReq.end()); 269 270 // remove it as outstanding 271 outstandingReq.erase(pkt->req); 272 273 // send the packet through the destination slave port 274 bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt); 275 276 // currently it is illegal to block responses... can lead to 277 // deadlock 278 assert(success); 279 280 respLayers[slave_port_id]->succeededTiming(packetFinishTime); 281 282 // stats updates 283 dataThroughBus += pkt_size; 284 pktCount[slave_port_id][master_port_id]++; 285 totPktSize[slave_port_id][master_port_id] += pkt_size; 286 transDist[pkt_cmd]++; 287 288 return true; 289} 290 291void 292CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) 293{ 294 DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", 295 masterPorts[master_port_id]->name(), pkt->cmdString(), 296 pkt->getAddr()); 297 298 // update stats here as we know the forwarding will succeed 299 transDist[pkt->cmdToIndex()]++; 300 snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 301 snoopsThroughBus++; 302 303 // we should only see express snoops from caches 304 assert(pkt->isExpressSnoop()); 305 306 // set the source port for routing of the response 307 pkt->setSrc(master_port_id); 308 309 // forward to all snoopers 310 forwardTiming(pkt, InvalidPortID); 311 312 // a snoop request came from a connected slave device (one of 313 // our master ports), and if it is not coming from the slave 314 // device responsible for the address range something is 315 // wrong, hence there is nothing further to do as the packet 316 // would be going back to where it came from 317 assert(master_port_id == findPort(pkt->getAddr())); 318} 319 320bool 321CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) 322{ 323 // determine the source port based on the id 324 SlavePort* src_port = slavePorts[slave_port_id]; 325 326 // get the destination from the packet 327 PortID dest_port_id = pkt->getDest(); 328 329 // determine if the response is from a snoop request we 330 // created as the result of a normal request (in which case it 331 // should be in the outstandingReq), or if we merely forwarded 332 // someone else's snoop request 333 bool forwardAsSnoop = outstandingReq.find(pkt->req) == 334 outstandingReq.end(); 335 336 // test if the bus should be considered occupied for the current 337 // port, note that the check is bypassed if the response is being 338 // passed on as a normal response since this is occupying the 339 // response layer rather than the snoop response layer 340 if (forwardAsSnoop) { 341 if (!snoopLayers[dest_port_id]->tryTiming(src_port)) { 342 DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 343 src_port->name(), pkt->cmdString(), pkt->getAddr()); 344 return false; 345 } 346 } else { 347 // get the master port that mirrors this slave port internally 348 MasterPort* snoop_port = snoopRespPorts[slave_port_id]; 349 if (!respLayers[dest_port_id]->tryTiming(snoop_port)) { 350 DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 351 snoop_port->name(), pkt->cmdString(), pkt->getAddr()); 352 return false; 353 } 354 } 355 356 DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n", 357 src_port->name(), pkt->cmdString(), pkt->getAddr()); 358 359 // store size and command as they might be modified when 360 // forwarding the packet 361 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 362 unsigned int pkt_cmd = pkt->cmdToIndex(); 363 364 // responses are never express snoops 365 assert(!pkt->isExpressSnoop()); 366 367 calcPacketTiming(pkt); 368 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 369 370 // forward it either as a snoop response or a normal response 371 if (forwardAsSnoop) { 372 // this is a snoop response to a snoop request we forwarded, 373 // e.g. coming from the L1 and going to the L2, and it should 374 // be forwarded as a snoop response 375 bool success M5_VAR_USED = 376 masterPorts[dest_port_id]->sendTimingSnoopResp(pkt); 377 pktCount[slave_port_id][dest_port_id]++; 378 totPktSize[slave_port_id][dest_port_id] += pkt_size; 379 assert(success); 380 381 snoopLayers[dest_port_id]->succeededTiming(packetFinishTime); 382 } else { 383 // we got a snoop response on one of our slave ports, 384 // i.e. from a coherent master connected to the bus, and 385 // since we created the snoop request as part of 386 // recvTiming, this should now be a normal response again 387 outstandingReq.erase(pkt->req); 388 389 // this is a snoop response from a coherent master, with a 390 // destination field set on its way through the bus as 391 // request, hence it should never go back to where the 392 // snoop response came from, but instead to where the 393 // original request came from 394 assert(slave_port_id != dest_port_id); 395 396 // as a normal response, it should go back to a master through 397 // one of our slave ports, at this point we are ignoring the 398 // fact that the response layer could be busy and do not touch 399 // its state 400 bool success M5_VAR_USED = 401 slavePorts[dest_port_id]->sendTimingResp(pkt); 402 403 // @todo Put the response in an internal FIFO and pass it on 404 // to the response layer from there 405 406 // currently it is illegal to block responses... can lead 407 // to deadlock 408 assert(success); 409 410 respLayers[dest_port_id]->succeededTiming(packetFinishTime); 411 } 412 413 // stats updates 414 transDist[pkt_cmd]++; 415 snoopDataThroughBus += pkt_size; 416 snoopsThroughBus++; 417 418 return true; 419} 420 421 422void 423CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) 424{ 425 DPRINTF(CoherentBus, "%s for %s address %x size %d\n", __func__, 426 pkt->cmdString(), pkt->getAddr(), pkt->getSize()); 427 428 // snoops should only happen if the system isn't bypassing caches 429 assert(!system->bypassCaches()); 430 431 unsigned fanout = 0; 432 433 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 434 SlavePort *p = *s; 435 // we could have gotten this request from a snooping master 436 // (corresponding to our own slave port that is also in 437 // snoopPorts) and should not send it back to where it came 438 // from 439 if (exclude_slave_port_id == InvalidPortID || 440 p->getId() != exclude_slave_port_id) { 441 // cache is not allowed to refuse snoop 442 p->sendTimingSnoopReq(pkt); 443 fanout++; 444 } 445 } 446 447 // Stats for fanout of this forward operation 448 snoopFanout.sample(fanout); 449} 450 451void 452CoherentBus::recvRetry(PortID master_port_id) 453{ 454 // responses and snoop responses never block on forwarding them, 455 // so the retry will always be coming from a port to which we 456 // tried to forward a request 457 reqLayers[master_port_id]->recvRetry(); 458} 459 460Tick 461CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) 462{ 463 DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 464 slavePorts[slave_port_id]->name(), pkt->getAddr(), 465 pkt->cmdString()); 466 467 // add the request data 468 dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 469 470 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 471 Tick snoop_response_latency = 0; 472 473 // uncacheable requests need never be snooped 474 if (!pkt->req->isUncacheable() && !system->bypassCaches()) { 475 // forward to all snoopers but the source 476 std::pair<MemCmd, Tick> snoop_result = 477 forwardAtomic(pkt, slave_port_id); 478 snoop_response_cmd = snoop_result.first; 479 snoop_response_latency = snoop_result.second; 480 } 481 482 // even if we had a snoop response, we must continue and also 483 // perform the actual request at the destination 484 PortID dest_id = findPort(pkt->getAddr()); 485 486 // forward the request to the appropriate destination 487 Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 488 489 // if we got a response from a snooper, restore it here 490 if (snoop_response_cmd != MemCmd::InvalidCmd) { 491 // no one else should have responded 492 assert(!pkt->isResponse()); 493 pkt->cmd = snoop_response_cmd; 494 response_latency = snoop_response_latency; 495 } 496 497 // add the response data 498 if (pkt->isResponse()) 499 dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 500 501 // @todo: Not setting first-word time 502 pkt->busLastWordDelay = response_latency; 503 return response_latency; 504} 505 506Tick 507CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) 508{ 509 DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", 510 masterPorts[master_port_id]->name(), pkt->getAddr(), 511 pkt->cmdString()); 512 513 // add the request snoop data 514 snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 515 snoopsThroughBus++; 516 517 // forward to all snoopers 518 std::pair<MemCmd, Tick> snoop_result = 519 forwardAtomic(pkt, InvalidPortID); 520 MemCmd snoop_response_cmd = snoop_result.first; 521 Tick snoop_response_latency = snoop_result.second; 522 523 if (snoop_response_cmd != MemCmd::InvalidCmd) 524 pkt->cmd = snoop_response_cmd; 525 526 // add the response snoop data 527 if (pkt->isResponse()) { 528 snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 529 snoopsThroughBus++; 530 } 531 532 // @todo: Not setting first-word time 533 pkt->busLastWordDelay = snoop_response_latency; 534 return snoop_response_latency; 535} 536 537std::pair<MemCmd, Tick> 538CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) 539{ 540 // the packet may be changed on snoops, record the original 541 // command to enable us to restore it between snoops so that 542 // additional snoops can take place properly 543 MemCmd orig_cmd = pkt->cmd; 544 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 545 Tick snoop_response_latency = 0; 546 547 // snoops should only happen if the system isn't bypassing caches 548 assert(!system->bypassCaches()); 549 550 unsigned fanout = 0; 551 552 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 553 SlavePort *p = *s; 554 // we could have gotten this request from a snooping master 555 // (corresponding to our own slave port that is also in 556 // snoopPorts) and should not send it back to where it came 557 // from 558 if (exclude_slave_port_id == InvalidPortID || 559 p->getId() != exclude_slave_port_id) { 560 Tick latency = p->sendAtomicSnoop(pkt); 561 fanout++; 562 563 // in contrast to a functional access, we have to keep on 564 // going as all snoopers must be updated even if we get a 565 // response 566 if (pkt->isResponse()) { 567 // response from snoop agent 568 assert(pkt->cmd != orig_cmd); 569 assert(pkt->memInhibitAsserted()); 570 // should only happen once 571 assert(snoop_response_cmd == MemCmd::InvalidCmd); 572 // save response state 573 snoop_response_cmd = pkt->cmd; 574 snoop_response_latency = latency; 575 // restore original packet state for remaining snoopers 576 pkt->cmd = orig_cmd; 577 } 578 } 579 } 580 581 // Stats for fanout 582 snoopFanout.sample(fanout); 583 584 // the packet is restored as part of the loop and any potential 585 // snoop response is part of the returned pair 586 return std::make_pair(snoop_response_cmd, snoop_response_latency); 587} 588 589void 590CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) 591{ 592 if (!pkt->isPrint()) { 593 // don't do DPRINTFs on PrintReq as it clutters up the output 594 DPRINTF(CoherentBus, 595 "recvFunctional: packet src %s addr 0x%x cmd %s\n", 596 slavePorts[slave_port_id]->name(), pkt->getAddr(), 597 pkt->cmdString()); 598 } 599 600 // uncacheable requests need never be snooped 601 if (!pkt->req->isUncacheable() && !system->bypassCaches()) { 602 // forward to all snoopers but the source 603 forwardFunctional(pkt, slave_port_id); 604 } 605 606 // there is no need to continue if the snooping has found what we 607 // were looking for and the packet is already a response 608 if (!pkt->isResponse()) { 609 PortID dest_id = findPort(pkt->getAddr()); 610 611 masterPorts[dest_id]->sendFunctional(pkt); 612 } 613} 614 615void 616CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) 617{ 618 if (!pkt->isPrint()) { 619 // don't do DPRINTFs on PrintReq as it clutters up the output 620 DPRINTF(CoherentBus, 621 "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", 622 masterPorts[master_port_id]->name(), pkt->getAddr(), 623 pkt->cmdString()); 624 } 625 626 // forward to all snoopers 627 forwardFunctional(pkt, InvalidPortID); 628} 629 630void 631CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) 632{ 633 // snoops should only happen if the system isn't bypassing caches 634 assert(!system->bypassCaches()); 635 636 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 637 SlavePort *p = *s; 638 // we could have gotten this request from a snooping master 639 // (corresponding to our own slave port that is also in 640 // snoopPorts) and should not send it back to where it came 641 // from 642 if (exclude_slave_port_id == InvalidPortID || 643 p->getId() != exclude_slave_port_id) 644 p->sendFunctionalSnoop(pkt); 645 646 // if we get a response we are done 647 if (pkt->isResponse()) { 648 break; 649 } 650 } 651} 652 653unsigned int 654CoherentBus::drain(DrainManager *dm) 655{ 656 // sum up the individual layers 657 unsigned int total = 0; 658 for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) 659 total += (*l)->drain(dm); 660 for (auto l = respLayers.begin(); l != respLayers.end(); ++l) 661 total += (*l)->drain(dm); 662 for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) 663 total += (*l)->drain(dm); 664 return total; 665} 666 667void 668CoherentBus::regStats() 669{ 670 // register the stats of the base class and our three bus layers 671 BaseBus::regStats(); 672 for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) 673 (*l)->regStats(); 674 for (auto l = respLayers.begin(); l != respLayers.end(); ++l) 675 (*l)->regStats(); 676 for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) 677 (*l)->regStats(); 678 679 dataThroughBus 680 .name(name() + ".data_through_bus") 681 .desc("Total data (bytes)") 682 ; 683 684 snoopDataThroughBus 685 .name(name() + ".snoop_data_through_bus") 686 .desc("Total snoop data (bytes)") 687 ; 688 689 snoopsThroughBus 690 .name(name() + ".snoops_through_bus") 691 .desc("Total snoops (count)") 692 ; 693 694 snoopFanout 695 .init(0, snoopPorts.size(), 1) 696 .name(name() + ".snoop_fanout") 697 .desc("Request fanout histogram") 698 ; 699 700 throughput 701 .name(name() + ".throughput") 702 .desc("Throughput (bytes/s)") 703 .precision(0) 704 ; 705 706 throughput = (dataThroughBus + snoopDataThroughBus) / simSeconds; 707} 708 709CoherentBus * 710CoherentBusParams::create() 711{ 712 return new CoherentBus(this); 713} 714