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