coherent_xbar.cc revision 4912
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 */ 30 31/** 32 * @file 33 * Definition of a bus object. 34 */ 35 36#include <algorithm> 37#include <limits> 38 39#include "base/misc.hh" 40#include "base/trace.hh" 41#include "mem/bus.hh" 42#include "sim/builder.hh" 43 44Port * 45Bus::getPort(const std::string &if_name, int idx) 46{ 47 if (if_name == "default") { 48 if (defaultPort == NULL) { 49 defaultPort = new BusPort(csprintf("%s-default",name()), this, 50 defaultId); 51 cachedBlockSizeValid = false; 52 return defaultPort; 53 } else 54 fatal("Default port already set\n"); 55 } 56 int id; 57 if (if_name == "functional") { 58 if (!funcPort) { 59 id = maxId++; 60 funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 61 funcPortId = id; 62 interfaces[id] = funcPort; 63 } 64 return funcPort; 65 } 66 67 // if_name ignored? forced to be empty? 68 id = maxId++; 69 assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 70 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 71 interfaces[id] = bp; 72 cachedBlockSizeValid = false; 73 return bp; 74} 75 76void 77Bus::deletePortRefs(Port *p) 78{ 79 80 BusPort *bp = dynamic_cast<BusPort*>(p); 81 if (bp == NULL) 82 panic("Couldn't convert Port* to BusPort*\n"); 83 // If this is our one functional port 84 if (funcPort == bp) 85 return; 86 interfaces.erase(bp->getId()); 87 delete bp; 88} 89 90/** Get the ranges of anyone other buses that we are connected to. */ 91void 92Bus::init() 93{ 94 m5::hash_map<short,BusPort*>::iterator intIter; 95 96 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 97 intIter->second->sendStatusChange(Port::RangeChange); 98} 99 100Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 101{} 102 103void Bus::BusFreeEvent::process() 104{ 105 bus->recvRetry(-1); 106} 107 108const char * Bus::BusFreeEvent::description() 109{ 110 return "bus became available"; 111} 112 113void Bus::occupyBus(PacketPtr pkt) 114{ 115 //Bring tickNextIdle up to the present tick 116 //There is some potential ambiguity where a cycle starts, which might make 117 //a difference when devices are acting right around a cycle boundary. Using 118 //a < allows things which happen exactly on a cycle boundary to take up 119 //only the following cycle. Anything that happens later will have to "wait" 120 //for the end of that cycle, and then start using the bus after that. 121 if (tickNextIdle < curTick) { 122 tickNextIdle = curTick; 123 if (tickNextIdle % clock != 0) 124 tickNextIdle = curTick - (curTick % clock) + clock; 125 } 126 127 // The packet will be sent. Figure out how long it occupies the bus, and 128 // how much of that time is for the first "word", aka bus width. 129 int numCycles = 0; 130 // Requests need one cycle to send an address 131 if (pkt->isRequest()) 132 numCycles++; 133 else if (pkt->isResponse() || pkt->hasData()) { 134 // If a packet has data, it needs ceil(size/width) cycles to send it 135 // We're using the "adding instead of dividing" trick again here 136 if (pkt->hasData()) { 137 int dataSize = pkt->getSize(); 138 numCycles += dataSize/width; 139 if (dataSize % width) 140 numCycles++; 141 } else { 142 // If the packet didn't have data, it must have been a response. 143 // Those use the bus for one cycle to send their data. 144 numCycles++; 145 } 146 } 147 148 // The first word will be delivered after the current tick, the delivery 149 // of the address if any, and one bus cycle to deliver the data 150 pkt->firstWordTime = 151 tickNextIdle + 152 pkt->isRequest() ? clock : 0 + 153 clock; 154 155 //Advance it numCycles bus cycles. 156 //XXX Should this use the repeated addition trick as well? 157 tickNextIdle += (numCycles * clock); 158 if (!busIdle.scheduled()) { 159 busIdle.schedule(tickNextIdle); 160 } else { 161 busIdle.reschedule(tickNextIdle); 162 } 163 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 164 curTick, tickNextIdle); 165 166 // The bus will become idle once the current packet is delivered. 167 pkt->finishTime = tickNextIdle; 168} 169 170/** Function called by the port when the bus is receiving a Timing 171 * transaction.*/ 172bool 173Bus::recvTiming(PacketPtr pkt) 174{ 175 short src = pkt->getSrc(); 176 DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 177 src, pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 178 179 BusPort *src_port = (src == defaultId) ? defaultPort : interfaces[src]; 180 181 // If the bus is busy, or other devices are in line ahead of the current 182 // one, put this device on the retry list. 183 if (!(pkt->isResponse() || pkt->isExpressSnoop()) && 184 (tickNextIdle > curTick || 185 (retryList.size() && (!inRetry || src_port != retryList.front())))) 186 { 187 addToRetryList(src_port); 188 DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n"); 189 return false; 190 } 191 192 occupyBus(pkt); 193 194 short dest = pkt->getDest(); 195 int dest_port_id; 196 Port *dest_port; 197 198 if (dest == Packet::Broadcast) { 199 dest_port_id = findPort(pkt->getAddr()); 200 dest_port = interfaces[dest_port_id]; 201 for (SnoopIter s_iter = snoopPorts.begin(); 202 s_iter != snoopPorts.end(); 203 s_iter++) { 204 BusPort *p = *s_iter; 205 if (p != dest_port && p != src_port) { 206#ifndef NDEBUG 207 // cache is not allowed to refuse snoop 208 bool success = p->sendTiming(pkt); 209 assert(success); 210#else 211 // avoid unused variable warning 212 p->sendTiming(pkt); 213#endif 214 } 215 } 216 } else { 217 assert(dest >= 0 && dest < maxId); 218 assert(dest != src); // catch infinite loops 219 dest_port_id = dest; 220 dest_port = interfaces[dest_port_id]; 221 } 222 223 if (dest_port_id == src) { 224 // Must be forwarded snoop up from below... 225 assert(dest == Packet::Broadcast); 226 } else { 227 // send to actual target 228 if (!dest_port->sendTiming(pkt)) { 229 // Packet not successfully sent. Leave or put it on the retry list. 230 // illegal to block responses... can lead to deadlock 231 assert(!pkt->isResponse()); 232 DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", src); 233 addToRetryList(src_port); 234 return false; 235 } 236 // send OK, fall through 237 } 238 239 // Packet was successfully sent. 240 // Also take care of retries 241 if (inRetry) { 242 DPRINTF(Bus, "Remove retry from list %d\n", src); 243 retryList.front()->onRetryList(false); 244 retryList.pop_front(); 245 inRetry = false; 246 } 247 return true; 248} 249 250void 251Bus::recvRetry(int id) 252{ 253 // If there's anything waiting, and the bus isn't busy... 254 if (retryList.size() && curTick >= tickNextIdle) { 255 //retryingPort = retryList.front(); 256 inRetry = true; 257 DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 258 retryList.front()->sendRetry(); 259 // If inRetry is still true, sendTiming wasn't called 260 if (inRetry) 261 { 262 retryList.front()->onRetryList(false); 263 retryList.pop_front(); 264 inRetry = false; 265 266 //Bring tickNextIdle up to the present 267 while (tickNextIdle < curTick) 268 tickNextIdle += clock; 269 270 //Burn a cycle for the missed grant. 271 tickNextIdle += clock; 272 273 busIdle.reschedule(tickNextIdle, true); 274 } 275 } 276 //If we weren't able to drain before, we might be able to now. 277 if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 278 drainEvent->process(); 279 // Clear the drain event once we're done with it. 280 drainEvent = NULL; 281 } 282} 283 284int 285Bus::findPort(Addr addr) 286{ 287 /* An interval tree would be a better way to do this. --ali. */ 288 int dest_id = -1; 289 290 PortIter i = portMap.find(RangeSize(addr,1)); 291 if (i != portMap.end()) 292 dest_id = i->second; 293 294 // Check if this matches the default range 295 if (dest_id == -1) { 296 for (AddrRangeIter iter = defaultRange.begin(); 297 iter != defaultRange.end(); iter++) { 298 if (*iter == addr) { 299 DPRINTF(Bus, " found addr %#llx on default\n", addr); 300 return defaultId; 301 } 302 } 303 304 if (responderSet) { 305 panic("Unable to find destination for addr (user set default " 306 "responder): %#llx", addr); 307 } else { 308 DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " 309 "default port", addr); 310 311 return defaultId; 312 } 313 } 314 315 return dest_id; 316} 317 318 319/** Function called by the port when the bus is receiving a Atomic 320 * transaction.*/ 321Tick 322Bus::recvAtomic(PacketPtr pkt) 323{ 324 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 325 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 326 assert(pkt->getDest() == Packet::Broadcast); 327 assert(pkt->isRequest()); 328 329 // Variables for recording original command and snoop response (if 330 // any)... if a snooper respondes, we will need to restore 331 // original command so that additional snoops can take place 332 // properly 333 MemCmd orig_cmd = pkt->cmd; 334 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 335 Tick snoop_response_latency = 0; 336 int orig_src = pkt->getSrc(); 337 338 int target_port_id = findPort(pkt->getAddr()); 339 Port *target_port = interfaces[target_port_id]; 340 341 SnoopIter s_end = snoopPorts.end(); 342 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 343 BusPort *p = *s_iter; 344 // same port should not have both target addresses and snooping 345 assert(p != target_port); 346 if (p->getId() != pkt->getSrc()) { 347 Tick latency = p->sendAtomic(pkt); 348 if (pkt->isResponse()) { 349 // response from snoop agent 350 assert(pkt->cmd != orig_cmd); 351 assert(pkt->memInhibitAsserted()); 352 // should only happen once 353 assert(snoop_response_cmd == MemCmd::InvalidCmd); 354 // save response state 355 snoop_response_cmd = pkt->cmd; 356 snoop_response_latency = latency; 357 // restore original packet state for remaining snoopers 358 pkt->cmd = orig_cmd; 359 pkt->setSrc(orig_src); 360 pkt->setDest(Packet::Broadcast); 361 } 362 } 363 } 364 365 Tick response_latency = 0; 366 367 // we can get requests sent up from the memory side of the bus for 368 // snooping... don't send them back down! 369 if (target_port_id != pkt->getSrc()) { 370 response_latency = target_port->sendAtomic(pkt); 371 } 372 373 // if we got a response from a snooper, restore it here 374 if (snoop_response_cmd != MemCmd::InvalidCmd) { 375 // no one else should have responded 376 assert(!pkt->isResponse()); 377 assert(pkt->cmd == orig_cmd); 378 pkt->cmd = snoop_response_cmd; 379 response_latency = snoop_response_latency; 380 } 381 382 // why do we have this packet field and the return value both??? 383 pkt->finishTime = curTick + response_latency; 384 return response_latency; 385} 386 387/** Function called by the port when the bus is receiving a Functional 388 * transaction.*/ 389void 390Bus::recvFunctional(PacketPtr pkt) 391{ 392 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 393 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 394 assert(pkt->getDest() == Packet::Broadcast); 395 396 int port_id = findPort(pkt->getAddr()); 397 Port *port = interfaces[port_id]; 398 // The packet may be changed by another bus on snoops, restore the 399 // id after each 400 int src_id = pkt->getSrc(); 401 402 assert(pkt->isRequest()); // hasn't already been satisfied 403 404 for (SnoopIter s_iter = snoopPorts.begin(); 405 s_iter != snoopPorts.end(); 406 s_iter++) { 407 BusPort *p = *s_iter; 408 if (p != port && p->getId() != src_id) { 409 p->sendFunctional(pkt); 410 } 411 if (pkt->isResponse()) { 412 break; 413 } 414 pkt->setSrc(src_id); 415 } 416 417 // If the snooping hasn't found what we were looking for, keep going. 418 if (!pkt->isResponse() && port_id != pkt->getSrc()) { 419 port->sendFunctional(pkt); 420 } 421} 422 423/** Function called by the port when the bus is receiving a status change.*/ 424void 425Bus::recvStatusChange(Port::Status status, int id) 426{ 427 AddrRangeList ranges; 428 bool snoops; 429 AddrRangeIter iter; 430 431 assert(status == Port::RangeChange && 432 "The other statuses need to be implemented."); 433 434 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 435 436 if (id == defaultId) { 437 defaultRange.clear(); 438 // Only try to update these ranges if the user set a default responder. 439 if (responderSet) { 440 defaultPort->getPeerAddressRanges(ranges, snoops); 441 assert(snoops == false); 442 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 443 defaultRange.push_back(*iter); 444 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 445 iter->start, iter->end); 446 } 447 } 448 } else { 449 450 assert((id < maxId && id >= 0) || id == defaultId); 451 BusPort *port = interfaces[id]; 452 453 // Clean out any previously existent ids 454 for (PortIter portIter = portMap.begin(); 455 portIter != portMap.end(); ) { 456 if (portIter->second == id) 457 portMap.erase(portIter++); 458 else 459 portIter++; 460 } 461 462 for (SnoopIter s_iter = snoopPorts.begin(); 463 s_iter != snoopPorts.end(); ) { 464 if ((*s_iter)->getId() == id) 465 s_iter = snoopPorts.erase(s_iter); 466 else 467 s_iter++; 468 } 469 470 port->getPeerAddressRanges(ranges, snoops); 471 472 if (snoops) { 473 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 474 snoopPorts.push_back(port); 475 } 476 477 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 478 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 479 iter->start, iter->end, id); 480 if (portMap.insert(*iter, id) == portMap.end()) 481 panic("Two devices with same range\n"); 482 483 } 484 } 485 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 486 487 // tell all our peers that our address range has changed. 488 // Don't tell the device that caused this change, it already knows 489 m5::hash_map<short,BusPort*>::iterator intIter; 490 491 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 492 if (intIter->first != id && intIter->first != funcPortId) 493 intIter->second->sendStatusChange(Port::RangeChange); 494 495 if (id != defaultId && defaultPort) 496 defaultPort->sendStatusChange(Port::RangeChange); 497} 498 499void 500Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 501{ 502 resp.clear(); 503 snoop = false; 504 505 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 506 507 for (AddrRangeIter dflt_iter = defaultRange.begin(); 508 dflt_iter != defaultRange.end(); dflt_iter++) { 509 resp.push_back(*dflt_iter); 510 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 511 dflt_iter->end); 512 } 513 for (PortIter portIter = portMap.begin(); 514 portIter != portMap.end(); portIter++) { 515 bool subset = false; 516 for (AddrRangeIter dflt_iter = defaultRange.begin(); 517 dflt_iter != defaultRange.end(); dflt_iter++) { 518 if ((portIter->first.start < dflt_iter->start && 519 portIter->first.end >= dflt_iter->start) || 520 (portIter->first.start < dflt_iter->end && 521 portIter->first.end >= dflt_iter->end)) 522 fatal("Devices can not set ranges that itersect the default set\ 523 but are not a subset of the default set.\n"); 524 if (portIter->first.start >= dflt_iter->start && 525 portIter->first.end <= dflt_iter->end) { 526 subset = true; 527 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 528 portIter->first.start, portIter->first.end); 529 } 530 } 531 if (portIter->second != id && !subset) { 532 resp.push_back(portIter->first); 533 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 534 portIter->first.start, portIter->first.end); 535 } 536 } 537 538 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 539 s_iter++) { 540 if ((*s_iter)->getId() != id) { 541 snoop = true; 542 break; 543 } 544 } 545} 546 547int 548Bus::findBlockSize(int id) 549{ 550 if (cachedBlockSizeValid) 551 return cachedBlockSize; 552 553 int max_bs = -1; 554 555 for (PortIter portIter = portMap.begin(); 556 portIter != portMap.end(); portIter++) { 557 int tmp_bs = interfaces[portIter->second]->peerBlockSize(); 558 if (tmp_bs > max_bs) 559 max_bs = tmp_bs; 560 } 561 for (SnoopIter s_iter = snoopPorts.begin(); 562 s_iter != snoopPorts.end(); s_iter++) { 563 int tmp_bs = (*s_iter)->peerBlockSize(); 564 if (tmp_bs > max_bs) 565 max_bs = tmp_bs; 566 } 567 if (max_bs <= 0) 568 max_bs = defaultBlockSize; 569 570 if (max_bs != 64) 571 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 572 cachedBlockSize = max_bs; 573 cachedBlockSizeValid = true; 574 return max_bs; 575} 576 577 578unsigned int 579Bus::drain(Event * de) 580{ 581 //We should check that we're not "doing" anything, and that noone is 582 //waiting. We might be idle but have someone waiting if the device we 583 //contacted for a retry didn't actually retry. 584 if (curTick >= tickNextIdle && retryList.size() == 0) { 585 return 0; 586 } else { 587 drainEvent = de; 588 return 1; 589 } 590} 591 592void 593Bus::startup() 594{ 595 if (tickNextIdle < curTick) 596 tickNextIdle = (curTick / clock) * clock + clock; 597} 598 599BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 600 601 Param<int> bus_id; 602 Param<int> clock; 603 Param<int> width; 604 Param<bool> responder_set; 605 Param<int> block_size; 606 607END_DECLARE_SIM_OBJECT_PARAMS(Bus) 608 609BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 610 INIT_PARAM(bus_id, "a globally unique bus id"), 611 INIT_PARAM(clock, "bus clock speed"), 612 INIT_PARAM(width, "width of the bus (bits)"), 613 INIT_PARAM(responder_set, "Is a default responder set by the user"), 614 INIT_PARAM(block_size, "Default blocksize if no device has one") 615END_INIT_SIM_OBJECT_PARAMS(Bus) 616 617CREATE_SIM_OBJECT(Bus) 618{ 619 return new Bus(getInstanceName(), bus_id, clock, width, responder_set, 620 block_size); 621} 622 623REGISTER_SIM_OBJECT("Bus", Bus) 624