xbar.cc revision 9092
1/* 2 * Copyright (c) 2011-2012 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/intmath.hh" 51#include "base/misc.hh" 52#include "base/trace.hh" 53#include "debug/Bus.hh" 54#include "debug/BusAddrRanges.hh" 55#include "mem/bus.hh" 56 57BaseBus::BaseBus(const BaseBusParams *p) 58 : MemObject(p), clock(p->clock), 59 headerCycles(p->header_cycles), width(p->width), 60 defaultPortID(InvalidPortID), 61 useDefaultRange(p->use_default_range), 62 defaultBlockSize(p->block_size), 63 cachedBlockSize(0), cachedBlockSizeValid(false) 64{ 65 //width, clock period, and header cycles must be positive 66 if (width <= 0) 67 fatal("Bus width must be positive\n"); 68 if (clock <= 0) 69 fatal("Bus clock period must be positive\n"); 70 if (headerCycles <= 0) 71 fatal("Number of header cycles must be positive\n"); 72} 73 74BaseBus::~BaseBus() 75{ 76 for (MasterPortIter m = masterPorts.begin(); m != masterPorts.end(); 77 ++m) { 78 delete *m; 79 } 80 81 for (SlavePortIter s = slavePorts.begin(); s != slavePorts.end(); 82 ++s) { 83 delete *s; 84 } 85} 86 87MasterPort & 88BaseBus::getMasterPort(const std::string &if_name, int idx) 89{ 90 if (if_name == "master" && idx < masterPorts.size()) { 91 // the master port index translates directly to the vector position 92 return *masterPorts[idx]; 93 } else if (if_name == "default") { 94 return *masterPorts[defaultPortID]; 95 } else { 96 return MemObject::getMasterPort(if_name, idx); 97 } 98} 99 100SlavePort & 101BaseBus::getSlavePort(const std::string &if_name, int idx) 102{ 103 if (if_name == "slave" && idx < slavePorts.size()) { 104 // the slave port index translates directly to the vector position 105 return *slavePorts[idx]; 106 } else { 107 return MemObject::getSlavePort(if_name, idx); 108 } 109} 110 111Tick 112BaseBus::calcPacketTiming(PacketPtr pkt) 113{ 114 // determine the current time rounded to the closest following 115 // clock edge 116 Tick now = divCeil(curTick(), clock) * clock; 117 118 Tick headerTime = now + headerCycles * clock; 119 120 // The packet will be sent. Figure out how long it occupies the bus, and 121 // how much of that time is for the first "word", aka bus width. 122 int numCycles = 0; 123 if (pkt->hasData()) { 124 // If a packet has data, it needs ceil(size/width) cycles to send it 125 int dataSize = pkt->getSize(); 126 numCycles += dataSize/width; 127 if (dataSize % width) 128 numCycles++; 129 } 130 131 // The first word will be delivered after the current tick, the delivery 132 // of the address if any, and one bus cycle to deliver the data 133 pkt->firstWordTime = headerTime + clock; 134 135 pkt->finishTime = headerTime + numCycles * clock; 136 137 return headerTime; 138} 139 140BaseBus::Layer::Layer(BaseBus& _bus, const std::string& _name, Tick _clock) : 141 bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL), 142 releaseEvent(this) 143{ 144} 145 146void BaseBus::Layer::occupyLayer(Tick until) 147{ 148 // ensure the state is busy or in retry and never idle at this 149 // point, as the bus should transition from idle as soon as it has 150 // decided to forward the packet to prevent any follow-on calls to 151 // sendTiming seeing an unoccupied bus 152 assert(state != IDLE); 153 154 // note that we do not change the bus state here, if we are going 155 // from idle to busy it is handled by tryTiming, and if we 156 // are in retry we should remain in retry such that 157 // succeededTiming still sees the accurate state 158 159 // until should never be 0 as express snoops never occupy the bus 160 assert(until != 0); 161 bus.schedule(releaseEvent, until); 162 163 DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n", 164 curTick(), until); 165} 166 167bool 168BaseBus::Layer::tryTiming(Port* port) 169{ 170 // first we see if the bus is busy, next we check if we are in a 171 // retry with a port other than the current one 172 if (state == BUSY || (state == RETRY && port != retryList.front())) { 173 // put the port at the end of the retry list 174 retryList.push_back(port); 175 return false; 176 } 177 178 // update the state which is shared for request, response and 179 // snoop responses, if we were idle we are now busy, if we are in 180 // a retry, then do not change 181 if (state == IDLE) 182 state = BUSY; 183 184 return true; 185} 186 187void 188BaseBus::Layer::succeededTiming(Tick busy_time) 189{ 190 // if a retrying port succeeded, also take it off the retry list 191 if (state == RETRY) { 192 DPRINTF(BaseBus, "Remove retry from list %s\n", 193 retryList.front()->name()); 194 retryList.pop_front(); 195 state = BUSY; 196 } 197 198 // we should either have gone from idle to busy in the 199 // tryTiming test, or just gone from a retry to busy 200 assert(state == BUSY); 201 202 // occupy the bus accordingly 203 occupyLayer(busy_time); 204} 205 206void 207BaseBus::Layer::failedTiming(SlavePort* port, Tick busy_time) 208{ 209 // if we are not in a retry, i.e. busy (but never idle), or we are 210 // in a retry but not for the current port, then add the port at 211 // the end of the retry list 212 if (state != RETRY || port != retryList.front()) { 213 retryList.push_back(port); 214 } 215 216 // even if we retried the current one and did not succeed, 217 // we are no longer retrying but instead busy 218 state = BUSY; 219 220 // occupy the bus accordingly 221 occupyLayer(busy_time); 222} 223 224void 225BaseBus::Layer::releaseLayer() 226{ 227 // releasing the bus means we should now be idle 228 assert(state == BUSY); 229 assert(!releaseEvent.scheduled()); 230 231 // update the state 232 state = IDLE; 233 234 // bus is now idle, so if someone is waiting we can retry 235 if (!retryList.empty()) { 236 // note that we block (return false on recvTiming) both 237 // because the bus is busy and because the destination is 238 // busy, and in the latter case the bus may be released before 239 // we see a retry from the destination 240 retryWaiting(); 241 } else if (drainEvent) { 242 //If we weren't able to drain before, do it now. 243 drainEvent->process(); 244 // Clear the drain event once we're done with it. 245 drainEvent = NULL; 246 } 247} 248 249void 250BaseBus::Layer::retryWaiting() 251{ 252 // this should never be called with an empty retry list 253 assert(!retryList.empty()); 254 255 // we always go to retrying from idle 256 assert(state == IDLE); 257 258 // update the state which is shared for request, response and 259 // snoop responses 260 state = RETRY; 261 262 // note that we might have blocked on the receiving port being 263 // busy (rather than the bus itself) and now call retry before the 264 // destination called retry on the bus 265 if (dynamic_cast<SlavePort*>(retryList.front()) != NULL) 266 (dynamic_cast<SlavePort*>(retryList.front()))->sendRetry(); 267 else 268 (dynamic_cast<MasterPort*>(retryList.front()))->sendRetry(); 269 270 // If the bus is still in the retry state, sendTiming wasn't 271 // called in zero time (e.g. the cache does this) 272 if (state == RETRY) { 273 retryList.pop_front(); 274 275 //Burn a cycle for the missed grant. 276 277 // update the state which is shared for request, response and 278 // snoop responses 279 state = BUSY; 280 281 // determine the current time rounded to the closest following 282 // clock edge 283 Tick now = divCeil(curTick(), clock) * clock; 284 285 occupyLayer(now + clock); 286 } 287} 288 289void 290BaseBus::Layer::recvRetry() 291{ 292 // we got a retry from a peer that we tried to send something to 293 // and failed, but we sent it on the account of someone else, and 294 // that source port should be on our retry list, however if the 295 // bus layer is released before this happens and the retry (from 296 // the bus point of view) is successful then this no longer holds 297 // and we could in fact have an empty retry list 298 if (retryList.empty()) 299 return; 300 301 // if the bus layer is idle 302 if (state == IDLE) { 303 // note that we do not care who told us to retry at the moment, we 304 // merely let the first one on the retry list go 305 retryWaiting(); 306 } 307} 308 309PortID 310BaseBus::findPort(Addr addr) 311{ 312 /* An interval tree would be a better way to do this. --ali. */ 313 PortID dest_id = checkPortCache(addr); 314 if (dest_id != InvalidPortID) 315 return dest_id; 316 317 // Check normal port ranges 318 PortMapConstIter i = portMap.find(RangeSize(addr,1)); 319 if (i != portMap.end()) { 320 dest_id = i->second; 321 updatePortCache(dest_id, i->first.start, i->first.end); 322 return dest_id; 323 } 324 325 // Check if this matches the default range 326 if (useDefaultRange) { 327 AddrRangeConstIter a_end = defaultRange.end(); 328 for (AddrRangeConstIter i = defaultRange.begin(); i != a_end; i++) { 329 if (*i == addr) { 330 DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 331 addr); 332 return defaultPortID; 333 } 334 } 335 } else if (defaultPortID != InvalidPortID) { 336 DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 337 "will use default port\n", addr); 338 return defaultPortID; 339 } 340 341 // we should use the range for the default port and it did not 342 // match, or the default port is not set 343 fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 344 name()); 345} 346 347/** Function called by the port when the bus is receiving a range change.*/ 348void 349BaseBus::recvRangeChange(PortID master_port_id) 350{ 351 AddrRangeList ranges; 352 AddrRangeIter iter; 353 354 if (inRecvRangeChange.count(master_port_id)) 355 return; 356 inRecvRangeChange.insert(master_port_id); 357 358 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", 359 master_port_id); 360 361 clearPortCache(); 362 if (master_port_id == defaultPortID) { 363 defaultRange.clear(); 364 // Only try to update these ranges if the user set a default responder. 365 if (useDefaultRange) { 366 // get the address ranges of the connected slave port 367 AddrRangeList ranges = 368 masterPorts[master_port_id]->getAddrRanges(); 369 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 370 defaultRange.push_back(*iter); 371 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 372 iter->start, iter->end); 373 } 374 } 375 } else { 376 377 assert(master_port_id < masterPorts.size() && master_port_id >= 0); 378 MasterPort *port = masterPorts[master_port_id]; 379 380 // Clean out any previously existent ids 381 for (PortMapIter portIter = portMap.begin(); 382 portIter != portMap.end(); ) { 383 if (portIter->second == master_port_id) 384 portMap.erase(portIter++); 385 else 386 portIter++; 387 } 388 389 // get the address ranges of the connected slave port 390 ranges = port->getAddrRanges(); 391 392 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 393 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 394 iter->start, iter->end, master_port_id); 395 if (portMap.insert(*iter, master_port_id) == portMap.end()) { 396 PortID conflict_id = portMap.find(*iter)->second; 397 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 398 name(), 399 masterPorts[master_port_id]->getSlavePort().name(), 400 masterPorts[conflict_id]->getSlavePort().name()); 401 } 402 } 403 } 404 DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size()); 405 406 // tell all our neighbouring master ports that our address range 407 // has changed 408 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 409 ++p) 410 (*p)->sendRangeChange(); 411 412 inRecvRangeChange.erase(master_port_id); 413} 414 415AddrRangeList 416BaseBus::getAddrRanges() const 417{ 418 AddrRangeList ranges; 419 420 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 421 422 for (AddrRangeConstIter dflt_iter = defaultRange.begin(); 423 dflt_iter != defaultRange.end(); dflt_iter++) { 424 ranges.push_back(*dflt_iter); 425 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 426 dflt_iter->end); 427 } 428 for (PortMapConstIter portIter = portMap.begin(); 429 portIter != portMap.end(); portIter++) { 430 bool subset = false; 431 for (AddrRangeConstIter dflt_iter = defaultRange.begin(); 432 dflt_iter != defaultRange.end(); dflt_iter++) { 433 if ((portIter->first.start < dflt_iter->start && 434 portIter->first.end >= dflt_iter->start) || 435 (portIter->first.start < dflt_iter->end && 436 portIter->first.end >= dflt_iter->end)) 437 fatal("Devices can not set ranges that itersect the default set\ 438 but are not a subset of the default set.\n"); 439 if (portIter->first.start >= dflt_iter->start && 440 portIter->first.end <= dflt_iter->end) { 441 subset = true; 442 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 443 portIter->first.start, portIter->first.end); 444 } 445 } 446 if (!subset) { 447 ranges.push_back(portIter->first); 448 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 449 portIter->first.start, portIter->first.end); 450 } 451 } 452 453 return ranges; 454} 455 456unsigned 457BaseBus::findBlockSize() 458{ 459 if (cachedBlockSizeValid) 460 return cachedBlockSize; 461 462 unsigned max_bs = 0; 463 464 for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 465 ++m) { 466 unsigned tmp_bs = (*m)->peerBlockSize(); 467 if (tmp_bs > max_bs) 468 max_bs = tmp_bs; 469 } 470 471 for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 472 ++s) { 473 unsigned tmp_bs = (*s)->peerBlockSize(); 474 if (tmp_bs > max_bs) 475 max_bs = tmp_bs; 476 } 477 if (max_bs == 0) 478 max_bs = defaultBlockSize; 479 480 if (max_bs != 64) 481 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 482 cachedBlockSize = max_bs; 483 cachedBlockSizeValid = true; 484 return max_bs; 485} 486 487 488unsigned int 489BaseBus::Layer::drain(Event * de) 490{ 491 //We should check that we're not "doing" anything, and that noone is 492 //waiting. We might be idle but have someone waiting if the device we 493 //contacted for a retry didn't actually retry. 494 if (!retryList.empty() || state != IDLE) { 495 drainEvent = de; 496 return 1; 497 } 498 return 0; 499} 500