coherent_xbar.hh revision 8975
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 recvTimingReq(PacketPtr pkt) 93 { pkt->setSrc(id); return bus->recvTimingReq(pkt); } 94 95 /** 96 * When receiving a timing snoop response, pass it to the bus. 97 */ 98 virtual bool recvTimingSnoopResp(PacketPtr pkt) 99 { pkt->setSrc(id); return bus->recvTimingSnoopResp(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 recvTimingResp(PacketPtr pkt) 167 { pkt->setSrc(id); return bus->recvTimingResp(pkt); } 168 169 /** 170 * When receiving a timing snoop request, pass it to the bus. 171 */ 172 virtual void recvTimingSnoopReq(PacketPtr pkt) 173 { pkt->setSrc(id); return bus->recvTimingSnoopReq(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 request packet.*/ 232 bool recvTimingReq(PacketPtr pkt); 233 234 /** Function called by the port when the bus is recieving a Timing 235 response packet.*/ 236 bool recvTimingResp(PacketPtr pkt); 237 238 /** Function called by the port when the bus is recieving a timing 239 snoop request.*/ 240 void recvTimingSnoopReq(PacketPtr pkt); 241 242 /** Function called by the port when the bus is recieving a timing 243 snoop response.*/ 244 bool recvTimingSnoopResp(PacketPtr pkt); 245 246 /** 247 * Forward a timing packet to our snoopers, potentially excluding 248 * one of the connected coherent masters to avoid sending a packet 249 * back to where it came from. 250 * 251 * @param pkt Packet to forward 252 * @param exclude_slave_port_id Id of slave port to exclude 253 */ 254 void forwardTiming(PacketPtr pkt, Port::PortId exclude_slave_port_id); 255 256 /** 257 * Determine if the bus is to be considered occupied when being 258 * presented with a packet from a specific port. If so, the port 259 * in question is also added to the retry list. 260 * 261 * @param pkt Incoming packet 262 * @param port Source port on the bus presenting the packet 263 * 264 * @return True if the bus is to be considered occupied 265 */ 266 bool isOccupied(PacketPtr pkt, Port* port); 267 268 /** 269 * Deal with a destination port accepting a packet by potentially 270 * removing the source port from the retry list (if retrying) and 271 * occupying the bus accordingly. 272 * 273 * @param busy_time Time to spend as a result of a successful send 274 */ 275 void succeededTiming(Tick busy_time); 276 277 /** Function called by the port when the bus is recieving a Atomic 278 transaction.*/ 279 Tick recvAtomic(PacketPtr pkt); 280 281 /** Function called by the port when the bus is recieving an 282 atomic snoop transaction.*/ 283 Tick recvAtomicSnoop(PacketPtr pkt); 284 285 /** 286 * Forward an atomic packet to our snoopers, potentially excluding 287 * one of the connected coherent masters to avoid sending a packet 288 * back to where it came from. 289 * 290 * @param pkt Packet to forward 291 * @param exclude_slave_port_id Id of slave port to exclude 292 * 293 * @return a pair containing the snoop response and snoop latency 294 */ 295 std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt, 296 Port::PortId exclude_slave_port_id); 297 298 /** Function called by the port when the bus is recieving a Functional 299 transaction.*/ 300 void recvFunctional(PacketPtr pkt); 301 302 /** Function called by the port when the bus is recieving a functional 303 snoop transaction.*/ 304 void recvFunctionalSnoop(PacketPtr pkt); 305 306 /** 307 * Forward a functional packet to our snoopers, potentially 308 * excluding one of the connected coherent masters to avoid 309 * sending a packet back to where it came from. 310 * 311 * @param pkt Packet to forward 312 * @param exclude_slave_port_id Id of slave port to exclude 313 */ 314 void forwardFunctional(PacketPtr pkt, Port::PortId exclude_slave_port_id); 315 316 /** Timing function called by port when it is once again able to process 317 * requests. */ 318 void recvRetry(Port::PortId id); 319 320 /** Function called by the port when the bus is recieving a range change.*/ 321 void recvRangeChange(Port::PortId id); 322 323 /** Find which port connected to this bus (if any) should be given a packet 324 * with this address. 325 * @param addr Address to find port for. 326 * @return id of port that the packet should be sent out of. 327 */ 328 int findPort(Addr addr); 329 330 // Cache for the findPort function storing recently used ports from portMap 331 struct PortCache { 332 bool valid; 333 Port::PortId id; 334 Addr start; 335 Addr end; 336 }; 337 338 PortCache portCache[3]; 339 340 // Checks the cache and returns the id of the port that has the requested 341 // address within its range 342 inline int checkPortCache(Addr addr) { 343 if (portCache[0].valid && addr >= portCache[0].start && 344 addr < portCache[0].end) { 345 return portCache[0].id; 346 } 347 if (portCache[1].valid && addr >= portCache[1].start && 348 addr < portCache[1].end) { 349 return portCache[1].id; 350 } 351 if (portCache[2].valid && addr >= portCache[2].start && 352 addr < portCache[2].end) { 353 return portCache[2].id; 354 } 355 356 return Port::INVALID_PORT_ID; 357 } 358 359 // Clears the earliest entry of the cache and inserts a new port entry 360 inline void updatePortCache(short id, Addr start, Addr end) { 361 portCache[2].valid = portCache[1].valid; 362 portCache[2].id = portCache[1].id; 363 portCache[2].start = portCache[1].start; 364 portCache[2].end = portCache[1].end; 365 366 portCache[1].valid = portCache[0].valid; 367 portCache[1].id = portCache[0].id; 368 portCache[1].start = portCache[0].start; 369 portCache[1].end = portCache[0].end; 370 371 portCache[0].valid = true; 372 portCache[0].id = id; 373 portCache[0].start = start; 374 portCache[0].end = end; 375 } 376 377 // Clears the cache. Needs to be called in constructor. 378 inline void clearPortCache() { 379 portCache[2].valid = false; 380 portCache[1].valid = false; 381 portCache[0].valid = false; 382 } 383 384 /** 385 * Return the address ranges this port is responsible for. 386 * 387 * @param id id of the bus port that made the request 388 * 389 * @return a list of non-overlapping address ranges 390 */ 391 AddrRangeList getAddrRanges(Port::PortId id); 392 393 /** 394 * Determine if the bus port is snooping or not. 395 * 396 * @param id id of the bus port that made the request 397 * 398 * @return a boolean indicating if this port is snooping or not 399 */ 400 bool isSnooping(Port::PortId id) const; 401 402 /** Calculate the timing parameters for the packet. Updates the 403 * firstWordTime and finishTime fields of the packet object. 404 * Returns the tick at which the packet header is completed (which 405 * will be all that is sent if the target rejects the packet). 406 */ 407 Tick calcPacketTiming(PacketPtr pkt); 408 409 /** Occupy the bus until until */ 410 void occupyBus(Tick until); 411 412 /** 413 * Release the bus after being occupied and return to an idle 414 * state where we proceed to send a retry to any potential waiting 415 * port, or drain if asked to do so. 416 */ 417 void releaseBus(); 418 419 /** 420 * Send a retry to the port at the head of the retryList. The 421 * caller must ensure that the list is not empty. 422 */ 423 void retryWaiting(); 424 425 /** Ask everyone on the bus what their size is 426 * @param id id of the busport that made the request 427 * @return the max of all the sizes 428 */ 429 unsigned findBlockSize(Port::PortId id); 430 431 // event used to schedule a release of the bus 432 EventWrapper<Bus, &Bus::releaseBus> busIdleEvent; 433 434 bool inRetry; 435 std::set<Port::PortId> inRecvRangeChange; 436 437 /** The master and slave ports of the bus */ 438 std::vector<SlavePort*> slavePorts; 439 std::vector<MasterPort*> masterPorts; 440 441 typedef std::vector<SlavePort*>::iterator SlavePortIter; 442 typedef std::vector<SlavePort*>::const_iterator SlavePortConstIter; 443 444 /** An array of pointers to ports that retry should be called on because the 445 * original send failed for whatever reason.*/ 446 std::list<Port*> retryList; 447 448 void addToRetryList(Port* port) 449 { 450 if (!inRetry) { 451 // The device wasn't retrying a packet, or wasn't at an 452 // appropriate time. 453 retryList.push_back(port); 454 } else { 455 if (!retryList.empty() && port == retryList.front()) { 456 // The device was retrying a packet. It didn't work, 457 // so we'll leave it at the head of the retry list. 458 inRetry = false; 459 } else { 460 // We are in retry, but not for this port, put it at 461 // the end. 462 retryList.push_back(port); 463 } 464 } 465 } 466 467 /** Port that handles requests that don't match any of the interfaces.*/ 468 short defaultPortId; 469 470 /** If true, use address range provided by default device. Any 471 address not handled by another port and not in default device's 472 range will cause a fatal error. If false, just send all 473 addresses not handled by another port to default device. */ 474 bool useDefaultRange; 475 476 unsigned defaultBlockSize; 477 unsigned cachedBlockSize; 478 bool cachedBlockSizeValid; 479 480 public: 481 482 /** A function used to return the port associated with this bus object. */ 483 virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1); 484 virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); 485 486 virtual void init(); 487 virtual void startup(); 488 489 unsigned int drain(Event *de); 490 491 Bus(const BusParams *p); 492}; 493 494#endif //__MEM_BUS_HH__ 495