coherent_xbar.cc revision 9716
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 } else { 201 // for normal requests, check if successful 202 if (!success) { 203 // inhibited packets should never be forced to retry 204 assert(!pkt->memInhibitAsserted()); 205 206 // if it was added as outstanding and the send failed, then 207 // erase it again 208 if (add_outstanding) 209 outstandingReq.erase(pkt->req); 210 211 // undo the calculation so we can check for 0 again 212 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 213 214 DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", 215 src_port->name(), pkt->cmdString(), pkt->getAddr()); 216 217 // update the bus state and schedule an idle event 218 reqLayers[master_port_id]->failedTiming(src_port, 219 clockEdge(headerCycles)); 220 } else { 221 // update the bus state and schedule an idle event 222 reqLayers[master_port_id]->succeededTiming(packetFinishTime); 223 dataThroughBus += pkt_size; 224 } 225 } 226 227 // stats updates only consider packets that were successfully sent 228 if (success) { 229 pktCount[slave_port_id][master_port_id]++; 230 totPktSize[slave_port_id][master_port_id] += pkt_size; 231 transDist[pkt_cmd]++; 232 } 233 234 return success; 235} 236 237bool 238CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) 239{ 240 // determine the source port based on the id 241 MasterPort *src_port = masterPorts[master_port_id]; 242 243 // determine the destination based on what is stored in the packet 244 PortID slave_port_id = pkt->getDest(); 245 246 // test if the bus should be considered occupied for the current 247 // port 248 if (!respLayers[slave_port_id]->tryTiming(src_port)) { 249 DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", 250 src_port->name(), pkt->cmdString(), pkt->getAddr()); 251 return false; 252 } 253 254 DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", 255 src_port->name(), pkt->cmdString(), pkt->getAddr()); 256 257 // store size and command as they might be modified when 258 // forwarding the packet 259 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 260 unsigned int pkt_cmd = pkt->cmdToIndex(); 261 262 calcPacketTiming(pkt); 263 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 264 265 // the packet is a normal response to a request that we should 266 // have seen passing through the bus 267 assert(outstandingReq.find(pkt->req) != outstandingReq.end()); 268 269 // remove it as outstanding 270 outstandingReq.erase(pkt->req); 271 272 // send the packet through the destination slave port 273 bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt); 274 275 // currently it is illegal to block responses... can lead to 276 // deadlock 277 assert(success); 278 279 respLayers[slave_port_id]->succeededTiming(packetFinishTime); 280 281 // stats updates 282 dataThroughBus += pkt_size; 283 pktCount[slave_port_id][master_port_id]++; 284 totPktSize[slave_port_id][master_port_id] += pkt_size; 285 transDist[pkt_cmd]++; 286 287 return true; 288} 289 290void 291CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) 292{ 293 DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", 294 masterPorts[master_port_id]->name(), pkt->cmdString(), 295 pkt->getAddr()); 296 297 // update stats here as we know the forwarding will succeed 298 transDist[pkt->cmdToIndex()]++; 299 snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 300 301 // we should only see express snoops from caches 302 assert(pkt->isExpressSnoop()); 303 304 // set the source port for routing of the response 305 pkt->setSrc(master_port_id); 306 307 // forward to all snoopers 308 forwardTiming(pkt, InvalidPortID); 309 310 // a snoop request came from a connected slave device (one of 311 // our master ports), and if it is not coming from the slave 312 // device responsible for the address range something is 313 // wrong, hence there is nothing further to do as the packet 314 // would be going back to where it came from 315 assert(master_port_id == findPort(pkt->getAddr())); 316} 317 318bool 319CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) 320{ 321 // determine the source port based on the id 322 SlavePort* src_port = slavePorts[slave_port_id]; 323 324 // get the destination from the packet 325 PortID dest_port_id = pkt->getDest(); 326 327 // determine if the response is from a snoop request we 328 // created as the result of a normal request (in which case it 329 // should be in the outstandingReq), or if we merely forwarded 330 // someone else's snoop request 331 bool forwardAsSnoop = outstandingReq.find(pkt->req) == 332 outstandingReq.end(); 333 334 // test if the bus should be considered occupied for the current 335 // port, note that the check is bypassed if the response is being 336 // passed on as a normal response since this is occupying the 337 // response layer rather than the snoop response layer 338 if (forwardAsSnoop) { 339 if (!snoopLayers[dest_port_id]->tryTiming(src_port)) { 340 DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 341 src_port->name(), pkt->cmdString(), pkt->getAddr()); 342 return false; 343 } 344 } else { 345 // get the master port that mirrors this slave port internally 346 MasterPort* snoop_port = snoopRespPorts[slave_port_id]; 347 if (!respLayers[dest_port_id]->tryTiming(snoop_port)) { 348 DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 349 snoop_port->name(), pkt->cmdString(), pkt->getAddr()); 350 return false; 351 } 352 } 353 354 DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n", 355 src_port->name(), pkt->cmdString(), pkt->getAddr()); 356 357 // store size and command as they might be modified when 358 // forwarding the packet 359 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 360 unsigned int pkt_cmd = pkt->cmdToIndex(); 361 362 // responses are never express snoops 363 assert(!pkt->isExpressSnoop()); 364 365 calcPacketTiming(pkt); 366 Tick packetFinishTime = pkt->busLastWordDelay + curTick(); 367 368 // forward it either as a snoop response or a normal response 369 if (forwardAsSnoop) { 370 // this is a snoop response to a snoop request we forwarded, 371 // e.g. coming from the L1 and going to the L2, and it should 372 // be forwarded as a snoop response 373 bool success M5_VAR_USED = 374 masterPorts[dest_port_id]->sendTimingSnoopResp(pkt); 375 pktCount[slave_port_id][dest_port_id]++; 376 totPktSize[slave_port_id][dest_port_id] += pkt_size; 377 assert(success); 378 379 snoopLayers[dest_port_id]->succeededTiming(packetFinishTime); 380 } else { 381 // we got a snoop response on one of our slave ports, 382 // i.e. from a coherent master connected to the bus, and 383 // since we created the snoop request as part of 384 // recvTiming, this should now be a normal response again 385 outstandingReq.erase(pkt->req); 386 387 // this is a snoop response from a coherent master, with a 388 // destination field set on its way through the bus as 389 // request, hence it should never go back to where the 390 // snoop response came from, but instead to where the 391 // original request came from 392 assert(slave_port_id != dest_port_id); 393 394 // as a normal response, it should go back to a master through 395 // one of our slave ports, at this point we are ignoring the 396 // fact that the response layer could be busy and do not touch 397 // its state 398 bool success M5_VAR_USED = 399 slavePorts[dest_port_id]->sendTimingResp(pkt); 400 401 // @todo Put the response in an internal FIFO and pass it on 402 // to the response layer from there 403 404 // currently it is illegal to block responses... can lead 405 // to deadlock 406 assert(success); 407 408 respLayers[dest_port_id]->succeededTiming(packetFinishTime); 409 } 410 411 // stats updates 412 transDist[pkt_cmd]++; 413 snoopDataThroughBus += pkt_size; 414 415 return true; 416} 417 418 419void 420CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) 421{ 422 DPRINTF(CoherentBus, "%s for %s address %x size %d\n", __func__, 423 pkt->cmdString(), pkt->getAddr(), pkt->getSize()); 424 425 // snoops should only happen if the system isn't bypassing caches 426 assert(!system->bypassCaches()); 427 428 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 429 SlavePort *p = *s; 430 // we could have gotten this request from a snooping master 431 // (corresponding to our own slave port that is also in 432 // snoopPorts) and should not send it back to where it came 433 // from 434 if (exclude_slave_port_id == InvalidPortID || 435 p->getId() != exclude_slave_port_id) { 436 // cache is not allowed to refuse snoop 437 p->sendTimingSnoopReq(pkt); 438 } 439 } 440} 441 442void 443CoherentBus::recvRetry(PortID master_port_id) 444{ 445 // responses and snoop responses never block on forwarding them, 446 // so the retry will always be coming from a port to which we 447 // tried to forward a request 448 reqLayers[master_port_id]->recvRetry(); 449} 450 451Tick 452CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) 453{ 454 DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 455 slavePorts[slave_port_id]->name(), pkt->getAddr(), 456 pkt->cmdString()); 457 458 // add the request data 459 dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 460 461 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 462 Tick snoop_response_latency = 0; 463 464 // uncacheable requests need never be snooped 465 if (!pkt->req->isUncacheable() && !system->bypassCaches()) { 466 // forward to all snoopers but the source 467 std::pair<MemCmd, Tick> snoop_result = 468 forwardAtomic(pkt, slave_port_id); 469 snoop_response_cmd = snoop_result.first; 470 snoop_response_latency = snoop_result.second; 471 } 472 473 // even if we had a snoop response, we must continue and also 474 // perform the actual request at the destination 475 PortID dest_id = findPort(pkt->getAddr()); 476 477 // forward the request to the appropriate destination 478 Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 479 480 // if we got a response from a snooper, restore it here 481 if (snoop_response_cmd != MemCmd::InvalidCmd) { 482 // no one else should have responded 483 assert(!pkt->isResponse()); 484 pkt->cmd = snoop_response_cmd; 485 response_latency = snoop_response_latency; 486 } 487 488 // add the response data 489 if (pkt->isResponse()) 490 dataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 491 492 // @todo: Not setting first-word time 493 pkt->busLastWordDelay = response_latency; 494 return response_latency; 495} 496 497Tick 498CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) 499{ 500 DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", 501 masterPorts[master_port_id]->name(), pkt->getAddr(), 502 pkt->cmdString()); 503 504 // add the request snoop data 505 snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 506 507 // forward to all snoopers 508 std::pair<MemCmd, Tick> snoop_result = 509 forwardAtomic(pkt, InvalidPortID); 510 MemCmd snoop_response_cmd = snoop_result.first; 511 Tick snoop_response_latency = snoop_result.second; 512 513 if (snoop_response_cmd != MemCmd::InvalidCmd) 514 pkt->cmd = snoop_response_cmd; 515 516 // add the response snoop data 517 if (pkt->isResponse()) 518 snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0; 519 520 // @todo: Not setting first-word time 521 pkt->busLastWordDelay = snoop_response_latency; 522 return snoop_response_latency; 523} 524 525std::pair<MemCmd, Tick> 526CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) 527{ 528 // the packet may be changed on snoops, record the original 529 // command to enable us to restore it between snoops so that 530 // additional snoops can take place properly 531 MemCmd orig_cmd = pkt->cmd; 532 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 533 Tick snoop_response_latency = 0; 534 535 // snoops should only happen if the system isn't bypassing caches 536 assert(!system->bypassCaches()); 537 538 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 539 SlavePort *p = *s; 540 // we could have gotten this request from a snooping master 541 // (corresponding to our own slave port that is also in 542 // snoopPorts) and should not send it back to where it came 543 // from 544 if (exclude_slave_port_id == InvalidPortID || 545 p->getId() != exclude_slave_port_id) { 546 Tick latency = p->sendAtomicSnoop(pkt); 547 // in contrast to a functional access, we have to keep on 548 // going as all snoopers must be updated even if we get a 549 // response 550 if (pkt->isResponse()) { 551 // response from snoop agent 552 assert(pkt->cmd != orig_cmd); 553 assert(pkt->memInhibitAsserted()); 554 // should only happen once 555 assert(snoop_response_cmd == MemCmd::InvalidCmd); 556 // save response state 557 snoop_response_cmd = pkt->cmd; 558 snoop_response_latency = latency; 559 // restore original packet state for remaining snoopers 560 pkt->cmd = orig_cmd; 561 } 562 } 563 } 564 565 // the packet is restored as part of the loop and any potential 566 // snoop response is part of the returned pair 567 return std::make_pair(snoop_response_cmd, snoop_response_latency); 568} 569 570void 571CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) 572{ 573 if (!pkt->isPrint()) { 574 // don't do DPRINTFs on PrintReq as it clutters up the output 575 DPRINTF(CoherentBus, 576 "recvFunctional: packet src %s addr 0x%x cmd %s\n", 577 slavePorts[slave_port_id]->name(), pkt->getAddr(), 578 pkt->cmdString()); 579 } 580 581 // uncacheable requests need never be snooped 582 if (!pkt->req->isUncacheable() && !system->bypassCaches()) { 583 // forward to all snoopers but the source 584 forwardFunctional(pkt, slave_port_id); 585 } 586 587 // there is no need to continue if the snooping has found what we 588 // were looking for and the packet is already a response 589 if (!pkt->isResponse()) { 590 PortID dest_id = findPort(pkt->getAddr()); 591 592 masterPorts[dest_id]->sendFunctional(pkt); 593 } 594} 595 596void 597CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) 598{ 599 if (!pkt->isPrint()) { 600 // don't do DPRINTFs on PrintReq as it clutters up the output 601 DPRINTF(CoherentBus, 602 "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", 603 masterPorts[master_port_id]->name(), pkt->getAddr(), 604 pkt->cmdString()); 605 } 606 607 // forward to all snoopers 608 forwardFunctional(pkt, InvalidPortID); 609} 610 611void 612CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) 613{ 614 // snoops should only happen if the system isn't bypassing caches 615 assert(!system->bypassCaches()); 616 617 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 618 SlavePort *p = *s; 619 // we could have gotten this request from a snooping master 620 // (corresponding to our own slave port that is also in 621 // snoopPorts) and should not send it back to where it came 622 // from 623 if (exclude_slave_port_id == InvalidPortID || 624 p->getId() != exclude_slave_port_id) 625 p->sendFunctionalSnoop(pkt); 626 627 // if we get a response we are done 628 if (pkt->isResponse()) { 629 break; 630 } 631 } 632} 633 634unsigned int 635CoherentBus::drain(DrainManager *dm) 636{ 637 // sum up the individual layers 638 unsigned int total = 0; 639 for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) 640 total += (*l)->drain(dm); 641 for (auto l = respLayers.begin(); l != respLayers.end(); ++l) 642 total += (*l)->drain(dm); 643 for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) 644 total += (*l)->drain(dm); 645 return total; 646} 647 648void 649CoherentBus::regStats() 650{ 651 // register the stats of the base class and our three bus layers 652 BaseBus::regStats(); 653 for (auto l = reqLayers.begin(); l != reqLayers.end(); ++l) 654 (*l)->regStats(); 655 for (auto l = respLayers.begin(); l != respLayers.end(); ++l) 656 (*l)->regStats(); 657 for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) 658 (*l)->regStats(); 659 660 dataThroughBus 661 .name(name() + ".data_through_bus") 662 .desc("Total data (bytes)") 663 ; 664 665 snoopDataThroughBus 666 .name(name() + ".snoop_data_through_bus") 667 .desc("Total snoop data (bytes)") 668 ; 669 670 throughput 671 .name(name() + ".throughput") 672 .desc("Throughput (bytes/s)") 673 .precision(0) 674 ; 675 676 throughput = (dataThroughBus + snoopDataThroughBus) / simSeconds; 677} 678 679CoherentBus * 680CoherentBusParams::create() 681{ 682 return new CoherentBus(this); 683} 684