xbar.hh revision 8966
1/* 2 * Copyright (c) 2011 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) 2002-2005 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: Ron Dreslinski 41 * Ali Saidi 42 * Andreas Hansson 43 * William Wang 44 */ 45 46/** 47 * @file 48 * Declaration of a bus object. 49 */ 50 51#ifndef __MEM_BUS_HH__ 52#define __MEM_BUS_HH__ 53 54#include <list> 55#include <set> 56#include <string> 57 58#include "base/range.hh" 59#include "base/range_map.hh" 60#include "base/types.hh" 61#include "mem/mem_object.hh" 62#include "mem/packet.hh" 63#include "mem/port.hh" 64#include "params/Bus.hh" 65#include "sim/eventq.hh" 66 67class Bus : public MemObject 68{ 69 /** 70 * Declaration of the bus slave port type, one will be 71 * instantiated for each of the master interfaces connecting to 72 * the bus. 73 */ 74 class BusSlavePort : public SlavePort 75 { 76 private: 77 /** A pointer to the bus to which this port belongs. */ 78 Bus *bus; 79 80 public: 81 82 /** Constructor for the BusSlavePort.*/ 83 BusSlavePort(const std::string &_name, Bus *_bus, Port::PortId _id) 84 : SlavePort(_name, _bus, _id), bus(_bus) 85 { } 86 87 protected: 88 89 /** 90 * When receiving a timing request, pass it to the bus. 91 */ 92 virtual bool recvTiming(PacketPtr pkt) 93 { pkt->setSrc(id); return bus->recvTiming(pkt); } 94 95 /** 96 * When receiving a timing snoop response, pass it to the bus. 97 */ 98 virtual bool recvTimingSnoop(PacketPtr pkt) 99 { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); } 100 101 /** 102 * When receiving an atomic request, pass it to the bus. 103 */ 104 virtual Tick recvAtomic(PacketPtr pkt) 105 { pkt->setSrc(id); return bus->recvAtomic(pkt); } 106 107 /** 108 * When receiving a functional request, pass it to the bus. 109 */ 110 virtual void recvFunctional(PacketPtr pkt) 111 { pkt->setSrc(id); bus->recvFunctional(pkt); } 112 113 /** 114 * When receiving a retry, pass it to the bus. 115 */ 116 virtual void recvRetry() 117 { panic("Bus slave ports always succeed and should never retry.\n"); } 118 119 // This should return all the 'owned' addresses that are 120 // downstream from this bus, yes? That is, the union of all 121 // the 'owned' address ranges of all the other interfaces on 122 // this bus... 123 virtual AddrRangeList getAddrRanges() 124 { return bus->getAddrRanges(id); } 125 126 // Ask the bus to ask everyone on the bus what their block size is and 127 // take the max of it. This might need to be changed a bit if we ever 128 // support multiple block sizes. 129 virtual unsigned deviceBlockSize() const 130 { return bus->findBlockSize(id); } 131 132 }; 133 134 /** 135 * Declaration of the bus master port type, one will be 136 * instantiated for each of the slave interfaces connecting to the 137 * bus. 138 */ 139 class BusMasterPort : public MasterPort 140 { 141 private: 142 /** A pointer to the bus to which this port belongs. */ 143 Bus *bus; 144 145 public: 146 147 /** Constructor for the BusMasterPort.*/ 148 BusMasterPort(const std::string &_name, Bus *_bus, Port::PortId _id) 149 : MasterPort(_name, _bus, _id), bus(_bus) 150 { } 151 152 /** 153 * Determine if this port should be considered a snooper. This 154 * is determined by the bus. 155 * 156 * @return a boolean that is true if this port is snooping 157 */ 158 virtual bool isSnooping() const 159 { return bus->isSnooping(id); } 160 161 protected: 162 163 /** 164 * When receiving a timing response, pass it to the bus. 165 */ 166 virtual bool recvTiming(PacketPtr pkt) 167 { pkt->setSrc(id); return bus->recvTiming(pkt); } 168 169 /** 170 * When receiving a timing snoop request, pass it to the bus. 171 */ 172 virtual bool recvTimingSnoop(PacketPtr pkt) 173 { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); } 174 175 /** 176 * When receiving an atomic snoop request, pass it to the bus. 177 */ 178 virtual Tick recvAtomicSnoop(PacketPtr pkt) 179 { pkt->setSrc(id); return bus->recvAtomicSnoop(pkt); } 180 181 /** 182 * When receiving a functional snoop request, pass it to the bus. 183 */ 184 virtual void recvFunctionalSnoop(PacketPtr pkt) 185 { pkt->setSrc(id); bus->recvFunctionalSnoop(pkt); } 186 187 /** When reciving a range change from the peer port (at id), 188 pass it to the bus. */ 189 virtual void recvRangeChange() 190 { bus->recvRangeChange(id); } 191 192 /** When reciving a retry from the peer port (at id), 193 pass it to the bus. */ 194 virtual void recvRetry() 195 { bus->recvRetry(id); } 196 197 // Ask the bus to ask everyone on the bus what their block size is and 198 // take the max of it. This might need to be changed a bit if we ever 199 // support multiple block sizes. 200 virtual unsigned deviceBlockSize() const 201 { return bus->findBlockSize(id); } 202 203 }; 204 205 /** the clock speed for the bus */ 206 int clock; 207 /** cycles of overhead per transaction */ 208 int headerCycles; 209 /** the width of the bus in bytes */ 210 int width; 211 /** the next tick at which the bus will be idle */ 212 Tick tickNextIdle; 213 214 Event * drainEvent; 215 216 typedef range_map<Addr,int>::iterator PortIter; 217 range_map<Addr, int> portMap; 218 219 AddrRangeList defaultRange; 220 221 std::vector<SlavePort*> snoopPorts; 222 223 /** 224 * Store the outstanding requests so we can determine which ones 225 * we generated and which ones were merely forwarded. This is used 226 * in the coherent bus when coherency responses come back. 227 */ 228 std::set<RequestPtr> outstandingReq; 229 230 /** Function called by the port when the bus is recieving a Timing 231 transaction.*/ 232 bool recvTiming(PacketPtr pkt); 233 234 /** Function called by the port when the bus is recieving a timing 235 snoop transaction.*/ 236 bool recvTimingSnoop(PacketPtr pkt); 237 238 /** 239 * Forward a timing packet to our snoopers, potentially excluding 240 * one of the connected coherent masters to avoid sending a packet 241 * back to where it came from. 242 * 243 * @param pkt Packet to forward 244 * @param exclude_slave_port_id Id of slave port to exclude 245 */ 246 void forwardTiming(PacketPtr pkt, Port::PortId exclude_slave_port_id); 247 248 /** 249 * Determine if the bus is to be considered occupied when being 250 * presented with a packet from a specific port. If so, the port 251 * in question is also added to the retry list. 252 * 253 * @param pkt Incoming packet 254 * @param port Source port on the bus presenting the packet 255 * 256 * @return True if the bus is to be considered occupied 257 */ 258 bool isOccupied(PacketPtr pkt, Port* port); 259 260 /** 261 * Deal with a destination port accepting a packet by potentially 262 * removing the source port from the retry list (if retrying) and 263 * occupying the bus accordingly. 264 * 265 * @param busy_time Time to spend as a result of a successful send 266 */ 267 void succeededTiming(Tick busy_time); 268 269 /** Function called by the port when the bus is recieving a Atomic 270 transaction.*/ 271 Tick recvAtomic(PacketPtr pkt); 272 273 /** Function called by the port when the bus is recieving an 274 atomic snoop transaction.*/ 275 Tick recvAtomicSnoop(PacketPtr pkt); 276 277 /** 278 * Forward an atomic packet to our snoopers, potentially excluding 279 * one of the connected coherent masters to avoid sending a packet 280 * back to where it came from. 281 * 282 * @param pkt Packet to forward 283 * @param exclude_slave_port_id Id of slave port to exclude 284 * 285 * @return a pair containing the snoop response and snoop latency 286 */ 287 std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt, 288 Port::PortId exclude_slave_port_id); 289 290 /** Function called by the port when the bus is recieving a Functional 291 transaction.*/ 292 void recvFunctional(PacketPtr pkt); 293 294 /** Function called by the port when the bus is recieving a functional 295 snoop transaction.*/ 296 void recvFunctionalSnoop(PacketPtr pkt); 297 298 /** 299 * Forward a functional packet to our snoopers, potentially 300 * excluding one of the connected coherent masters to avoid 301 * sending a packet back to where it came from. 302 * 303 * @param pkt Packet to forward 304 * @param exclude_slave_port_id Id of slave port to exclude 305 */ 306 void forwardFunctional(PacketPtr pkt, Port::PortId exclude_slave_port_id); 307 308 /** Timing function called by port when it is once again able to process 309 * requests. */ 310 void recvRetry(Port::PortId id); 311 312 /** Function called by the port when the bus is recieving a range change.*/ 313 void recvRangeChange(Port::PortId id); 314 315 /** Find which port connected to this bus (if any) should be given a packet 316 * with this address. 317 * @param addr Address to find port for. 318 * @return id of port that the packet should be sent out of. 319 */ 320 int findPort(Addr addr); 321 322 // Cache for the findPort function storing recently used ports from portMap 323 struct PortCache { 324 bool valid; 325 Port::PortId id; 326 Addr start; 327 Addr end; 328 }; 329 330 PortCache portCache[3]; 331 332 // Checks the cache and returns the id of the port that has the requested 333 // address within its range 334 inline int checkPortCache(Addr addr) { 335 if (portCache[0].valid && addr >= portCache[0].start && 336 addr < portCache[0].end) { 337 return portCache[0].id; 338 } 339 if (portCache[1].valid && addr >= portCache[1].start && 340 addr < portCache[1].end) { 341 return portCache[1].id; 342 } 343 if (portCache[2].valid && addr >= portCache[2].start && 344 addr < portCache[2].end) { 345 return portCache[2].id; 346 } 347 348 return Port::INVALID_PORT_ID; 349 } 350 351 // Clears the earliest entry of the cache and inserts a new port entry 352 inline void updatePortCache(short id, Addr start, Addr end) { 353 portCache[2].valid = portCache[1].valid; 354 portCache[2].id = portCache[1].id; 355 portCache[2].start = portCache[1].start; 356 portCache[2].end = portCache[1].end; 357 358 portCache[1].valid = portCache[0].valid; 359 portCache[1].id = portCache[0].id; 360 portCache[1].start = portCache[0].start; 361 portCache[1].end = portCache[0].end; 362 363 portCache[0].valid = true; 364 portCache[0].id = id; 365 portCache[0].start = start; 366 portCache[0].end = end; 367 } 368 369 // Clears the cache. Needs to be called in constructor. 370 inline void clearPortCache() { 371 portCache[2].valid = false; 372 portCache[1].valid = false; 373 portCache[0].valid = false; 374 } 375 376 /** 377 * Return the address ranges this port is responsible for. 378 * 379 * @param id id of the bus port that made the request 380 * 381 * @return a list of non-overlapping address ranges 382 */ 383 AddrRangeList getAddrRanges(Port::PortId id); 384 385 /** 386 * Determine if the bus port is snooping or not. 387 * 388 * @param id id of the bus port that made the request 389 * 390 * @return a boolean indicating if this port is snooping or not 391 */ 392 bool isSnooping(Port::PortId id) const; 393 394 /** Calculate the timing parameters for the packet. Updates the 395 * firstWordTime and finishTime fields of the packet object. 396 * Returns the tick at which the packet header is completed (which 397 * will be all that is sent if the target rejects the packet). 398 */ 399 Tick calcPacketTiming(PacketPtr pkt); 400 401 /** Occupy the bus until until */ 402 void occupyBus(Tick until); 403 404 /** 405 * Release the bus after being occupied and return to an idle 406 * state where we proceed to send a retry to any potential waiting 407 * port, or drain if asked to do so. 408 */ 409 void releaseBus(); 410 411 /** 412 * Send a retry to the port at the head of the retryList. The 413 * caller must ensure that the list is not empty. 414 */ 415 void retryWaiting(); 416 417 /** Ask everyone on the bus what their size is 418 * @param id id of the busport that made the request 419 * @return the max of all the sizes 420 */ 421 unsigned findBlockSize(Port::PortId id); 422 423 // event used to schedule a release of the bus 424 EventWrapper<Bus, &Bus::releaseBus> busIdleEvent; 425 426 bool inRetry; 427 std::set<Port::PortId> inRecvRangeChange; 428 429 /** The master and slave ports of the bus */ 430 std::vector<SlavePort*> slavePorts; 431 std::vector<MasterPort*> masterPorts; 432 433 typedef std::vector<SlavePort*>::iterator SlavePortIter; 434 typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter; 435 436 /** An array of pointers to ports that retry should be called on because the 437 * original send failed for whatever reason.*/ 438 std::list<Port*> retryList; 439 440 void addToRetryList(Port* port) 441 { 442 if (!inRetry) { 443 // The device wasn't retrying a packet, or wasn't at an 444 // appropriate time. 445 retryList.push_back(port); 446 } else { 447 if (!retryList.empty() && port == retryList.front()) { 448 // The device was retrying a packet. It didn't work, 449 // so we'll leave it at the head of the retry list. 450 inRetry = false; 451 } else { 452 // We are in retry, but not for this port, put it at 453 // the end. 454 retryList.push_back(port); 455 } 456 } 457 } 458 459 /** Port that handles requests that don't match any of the interfaces.*/ 460 short defaultPortId; 461 462 /** If true, use address range provided by default device. Any 463 address not handled by another port and not in default device's 464 range will cause a fatal error. If false, just send all 465 addresses not handled by another port to default device. */ 466 bool useDefaultRange; 467 468 unsigned defaultBlockSize; 469 unsigned cachedBlockSize; 470 bool cachedBlockSizeValid; 471 472 public: 473 474 /** A function used to return the port associated with this bus object. */ 475 virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1); 476 virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); 477 478 virtual void init(); 479 virtual void startup(); 480 481 unsigned int drain(Event *de); 482 483 Bus(const BusParams *p); 484}; 485 486#endif //__MEM_BUS_HH__ 487