xbar.cc revision 9036
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/misc.hh" 51#include "base/trace.hh" 52#include "debug/Bus.hh" 53#include "debug/BusAddrRanges.hh" 54#include "mem/bus.hh" 55 56BaseBus::BaseBus(const BaseBusParams *p) 57 : MemObject(p), clock(p->clock), 58 headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 59 drainEvent(NULL), busIdleEvent(this), inRetry(false), 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 = curTick(); 117 if (now % clock != 0) { 118 now = ((now / clock) + 1) * clock; 119 } 120 121 Tick headerTime = now + headerCycles * clock; 122 123 // The packet will be sent. Figure out how long it occupies the bus, and 124 // how much of that time is for the first "word", aka bus width. 125 int numCycles = 0; 126 if (pkt->hasData()) { 127 // If a packet has data, it needs ceil(size/width) cycles to send it 128 int dataSize = pkt->getSize(); 129 numCycles += dataSize/width; 130 if (dataSize % width) 131 numCycles++; 132 } 133 134 // The first word will be delivered after the current tick, the delivery 135 // of the address if any, and one bus cycle to deliver the data 136 pkt->firstWordTime = headerTime + clock; 137 138 pkt->finishTime = headerTime + numCycles * clock; 139 140 return headerTime; 141} 142 143void BaseBus::occupyBus(Tick until) 144{ 145 if (until == 0) { 146 // shortcut for express snoop packets 147 return; 148 } 149 150 tickNextIdle = until; 151 reschedule(busIdleEvent, tickNextIdle, true); 152 153 DPRINTF(BaseBus, "The bus is now occupied from tick %d to %d\n", 154 curTick(), tickNextIdle); 155} 156 157bool 158BaseBus::isOccupied(Port* port) 159{ 160 // first we see if the next idle tick is in the future, next the 161 // bus is considered occupied if there are ports on the retry list 162 // and we are not in a retry with the current port 163 if (tickNextIdle > curTick() || 164 (!retryList.empty() && !(inRetry && port == retryList.front()))) { 165 addToRetryList(port); 166 return true; 167 } 168 return false; 169} 170 171void 172BaseBus::succeededTiming(Tick busy_time) 173{ 174 // occupy the bus accordingly 175 occupyBus(busy_time); 176 177 // if a retrying port succeeded, also take it off the retry list 178 if (inRetry) { 179 DPRINTF(BaseBus, "Remove retry from list %s\n", 180 retryList.front()->name()); 181 retryList.pop_front(); 182 inRetry = false; 183 } 184} 185 186void 187BaseBus::releaseBus() 188{ 189 // releasing the bus means we should now be idle 190 assert(curTick() >= tickNextIdle); 191 192 // bus is now idle, so if someone is waiting we can retry 193 if (!retryList.empty()) { 194 // note that we block (return false on recvTiming) both 195 // because the bus is busy and because the destination is 196 // busy, and in the latter case the bus may be released before 197 // we see a retry from the destination 198 retryWaiting(); 199 } 200 201 //If we weren't able to drain before, we might be able to now. 202 if (drainEvent && retryList.empty() && curTick() >= tickNextIdle) { 203 drainEvent->process(); 204 // Clear the drain event once we're done with it. 205 drainEvent = NULL; 206 } 207} 208 209void 210BaseBus::retryWaiting() 211{ 212 // this should never be called with an empty retry list 213 assert(!retryList.empty()); 214 215 // send a retry to the port at the head of the retry list 216 inRetry = true; 217 218 // note that we might have blocked on the receiving port being 219 // busy (rather than the bus itself) and now call retry before the 220 // destination called retry on the bus 221 retryList.front()->sendRetry(); 222 223 // If inRetry is still true, sendTiming wasn't called in zero time 224 // (e.g. the cache does this) 225 if (inRetry) { 226 retryList.pop_front(); 227 inRetry = false; 228 229 //Bring tickNextIdle up to the present 230 while (tickNextIdle < curTick()) 231 tickNextIdle += clock; 232 233 //Burn a cycle for the missed grant. 234 tickNextIdle += clock; 235 236 reschedule(busIdleEvent, tickNextIdle, true); 237 } 238} 239 240void 241BaseBus::recvRetry() 242{ 243 // we got a retry from a peer that we tried to send something to 244 // and failed, but we sent it on the account of someone else, and 245 // that source port should be on our retry list, however if the 246 // bus is released before this happens and the retry (from the bus 247 // point of view) is successful then this no longer holds and we 248 // could in fact have an empty retry list 249 if (retryList.empty()) 250 return; 251 252 // if the bus isn't busy 253 if (curTick() >= tickNextIdle) { 254 // note that we do not care who told us to retry at the moment, we 255 // merely let the first one on the retry list go 256 retryWaiting(); 257 } 258} 259 260PortID 261BaseBus::findPort(Addr addr) 262{ 263 /* An interval tree would be a better way to do this. --ali. */ 264 PortID dest_id = checkPortCache(addr); 265 if (dest_id != InvalidPortID) 266 return dest_id; 267 268 // Check normal port ranges 269 PortIter i = portMap.find(RangeSize(addr,1)); 270 if (i != portMap.end()) { 271 dest_id = i->second; 272 updatePortCache(dest_id, i->first.start, i->first.end); 273 return dest_id; 274 } 275 276 // Check if this matches the default range 277 if (useDefaultRange) { 278 AddrRangeIter a_end = defaultRange.end(); 279 for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 280 if (*i == addr) { 281 DPRINTF(BusAddrRanges, " found addr %#llx on default\n", 282 addr); 283 return defaultPortID; 284 } 285 } 286 } else if (defaultPortID != InvalidPortID) { 287 DPRINTF(BusAddrRanges, "Unable to find destination for addr %#llx, " 288 "will use default port\n", addr); 289 return defaultPortID; 290 } 291 292 // we should use the range for the default port and it did not 293 // match, or the default port is not set 294 fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 295 name()); 296} 297 298/** Function called by the port when the bus is receiving a range change.*/ 299void 300BaseBus::recvRangeChange(PortID master_port_id) 301{ 302 AddrRangeList ranges; 303 AddrRangeIter iter; 304 305 if (inRecvRangeChange.count(master_port_id)) 306 return; 307 inRecvRangeChange.insert(master_port_id); 308 309 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", 310 master_port_id); 311 312 clearPortCache(); 313 if (master_port_id == defaultPortID) { 314 defaultRange.clear(); 315 // Only try to update these ranges if the user set a default responder. 316 if (useDefaultRange) { 317 AddrRangeList ranges = 318 masterPorts[master_port_id]->getSlavePort().getAddrRanges(); 319 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 320 defaultRange.push_back(*iter); 321 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 322 iter->start, iter->end); 323 } 324 } 325 } else { 326 327 assert(master_port_id < masterPorts.size() && master_port_id >= 0); 328 MasterPort *port = masterPorts[master_port_id]; 329 330 // Clean out any previously existent ids 331 for (PortIter portIter = portMap.begin(); 332 portIter != portMap.end(); ) { 333 if (portIter->second == master_port_id) 334 portMap.erase(portIter++); 335 else 336 portIter++; 337 } 338 339 ranges = port->getSlavePort().getAddrRanges(); 340 341 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 342 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 343 iter->start, iter->end, master_port_id); 344 if (portMap.insert(*iter, master_port_id) == portMap.end()) { 345 PortID conflict_id = portMap.find(*iter)->second; 346 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 347 name(), 348 masterPorts[master_port_id]->getSlavePort().name(), 349 masterPorts[conflict_id]->getSlavePort().name()); 350 } 351 } 352 } 353 DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size()); 354 355 // tell all our neighbouring master ports that our address range 356 // has changed 357 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 358 ++p) 359 (*p)->sendRangeChange(); 360 361 inRecvRangeChange.erase(master_port_id); 362} 363 364AddrRangeList 365BaseBus::getAddrRanges() 366{ 367 AddrRangeList ranges; 368 369 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 370 371 for (AddrRangeIter dflt_iter = defaultRange.begin(); 372 dflt_iter != defaultRange.end(); dflt_iter++) { 373 ranges.push_back(*dflt_iter); 374 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 375 dflt_iter->end); 376 } 377 for (PortIter portIter = portMap.begin(); 378 portIter != portMap.end(); portIter++) { 379 bool subset = false; 380 for (AddrRangeIter dflt_iter = defaultRange.begin(); 381 dflt_iter != defaultRange.end(); dflt_iter++) { 382 if ((portIter->first.start < dflt_iter->start && 383 portIter->first.end >= dflt_iter->start) || 384 (portIter->first.start < dflt_iter->end && 385 portIter->first.end >= dflt_iter->end)) 386 fatal("Devices can not set ranges that itersect the default set\ 387 but are not a subset of the default set.\n"); 388 if (portIter->first.start >= dflt_iter->start && 389 portIter->first.end <= dflt_iter->end) { 390 subset = true; 391 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 392 portIter->first.start, portIter->first.end); 393 } 394 } 395 if (!subset) { 396 ranges.push_back(portIter->first); 397 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 398 portIter->first.start, portIter->first.end); 399 } 400 } 401 402 return ranges; 403} 404 405unsigned 406BaseBus::findBlockSize() 407{ 408 if (cachedBlockSizeValid) 409 return cachedBlockSize; 410 411 unsigned max_bs = 0; 412 413 for (MasterPortConstIter m = masterPorts.begin(); m != masterPorts.end(); 414 ++m) { 415 unsigned tmp_bs = (*m)->peerBlockSize(); 416 if (tmp_bs > max_bs) 417 max_bs = tmp_bs; 418 } 419 420 for (SlavePortConstIter s = slavePorts.begin(); s != slavePorts.end(); 421 ++s) { 422 unsigned tmp_bs = (*s)->peerBlockSize(); 423 if (tmp_bs > max_bs) 424 max_bs = tmp_bs; 425 } 426 if (max_bs == 0) 427 max_bs = defaultBlockSize; 428 429 if (max_bs != 64) 430 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 431 cachedBlockSize = max_bs; 432 cachedBlockSizeValid = true; 433 return max_bs; 434} 435 436 437unsigned int 438BaseBus::drain(Event * de) 439{ 440 //We should check that we're not "doing" anything, and that noone is 441 //waiting. We might be idle but have someone waiting if the device we 442 //contacted for a retry didn't actually retry. 443 if (!retryList.empty() || (curTick() < tickNextIdle && 444 busIdleEvent.scheduled())) { 445 drainEvent = de; 446 return 1; 447 } 448 return 0; 449} 450 451void 452BaseBus::startup() 453{ 454 if (tickNextIdle < curTick()) 455 tickNextIdle = (curTick() / clock) * clock + clock; 456} 457