coherent_xbar.hh revision 8922
12600SN/A/* 22600SN/A * Copyright (c) 2011 ARM Limited 32600SN/A * All rights reserved 42600SN/A * 52600SN/A * The license below extends only to copyright in the software and shall 62600SN/A * not be construed as granting a license to any other intellectual 72600SN/A * property including but not limited to intellectual property relating 82600SN/A * to a hardware implementation of the functionality of the software 92600SN/A * licensed hereunder. You may use the software subject to the license 102600SN/A * terms below provided that you ensure that this notice is replicated 112600SN/A * unmodified and in its entirety in all distributions of the software, 122600SN/A * modified or unmodified, in source code or in binary form. 132600SN/A * 142600SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 152600SN/A * All rights reserved. 162600SN/A * 172600SN/A * Redistribution and use in source and binary forms, with or without 182600SN/A * modification, are permitted provided that the following conditions are 192600SN/A * met: redistributions of source code must retain the above copyright 202600SN/A * notice, this list of conditions and the following disclaimer; 212600SN/A * redistributions in binary form must reproduce the above copyright 222600SN/A * notice, this list of conditions and the following disclaimer in the 232600SN/A * documentation and/or other materials provided with the distribution; 242600SN/A * neither the name of the copyright holders nor the names of its 252600SN/A * contributors may be used to endorse or promote products derived from 262600SN/A * this software without specific prior written permission. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292600SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302600SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 318229Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 328229Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332600SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342600SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352600SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362600SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372600SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 385543Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 395543Ssaidi@eecs.umich.edu * 405543Ssaidi@eecs.umich.edu * Authors: Ron Dreslinski 415543Ssaidi@eecs.umich.edu * Ali Saidi 425543Ssaidi@eecs.umich.edu * Andreas Hansson 435543Ssaidi@eecs.umich.edu * William Wang 445543Ssaidi@eecs.umich.edu */ 452600SN/A 465543Ssaidi@eecs.umich.edu/** 475543Ssaidi@eecs.umich.edu * @file 482600SN/A * Declaration of a bus object. 492600SN/A */ 505543Ssaidi@eecs.umich.edu 512600SN/A#ifndef __MEM_BUS_HH__ 522600SN/A#define __MEM_BUS_HH__ 535543Ssaidi@eecs.umich.edu 545543Ssaidi@eecs.umich.edu#include <list> 555543Ssaidi@eecs.umich.edu#include <set> 562600SN/A#include <string> 572600SN/A 585543Ssaidi@eecs.umich.edu#include "base/range.hh" 595543Ssaidi@eecs.umich.edu#include "base/range_map.hh" 605543Ssaidi@eecs.umich.edu#include "base/types.hh" 615543Ssaidi@eecs.umich.edu#include "mem/mem_object.hh" 625543Ssaidi@eecs.umich.edu#include "mem/packet.hh" 635543Ssaidi@eecs.umich.edu#include "mem/port.hh" 645543Ssaidi@eecs.umich.edu#include "params/Bus.hh" 655543Ssaidi@eecs.umich.edu#include "sim/eventq.hh" 665543Ssaidi@eecs.umich.edu 675543Ssaidi@eecs.umich.educlass Bus : public MemObject 682600SN/A{ 695543Ssaidi@eecs.umich.edu /** 705543Ssaidi@eecs.umich.edu * Declaration of the bus slave port type, one will be 715543Ssaidi@eecs.umich.edu * instantiated for each of the master interfaces connecting to 722600SN/A * the bus. 732600SN/A */ 742600SN/A class BusSlavePort : public SlavePort 752600SN/A { 762600SN/A private: 772600SN/A /** A pointer to the bus to which this port belongs. */ 782600SN/A Bus *bus; 79 80 /** A id to keep track of the interface ID of this port. */ 81 int id; 82 83 public: 84 85 /** Constructor for the BusSlavePort.*/ 86 BusSlavePort(const std::string &_name, Bus *_bus, int _id) 87 : SlavePort(_name, _bus), bus(_bus), id(_id) 88 { } 89 90 int getId() const { return id; } 91 92 protected: 93 94 /** When reciving a timing request from the peer port (at id), 95 pass it to the bus. */ 96 virtual bool recvTiming(PacketPtr pkt) 97 { pkt->setSrc(id); return bus->recvTiming(pkt); } 98 99 /** When reciving a Atomic requestfrom the peer port (at id), 100 pass it to the bus. */ 101 virtual Tick recvAtomic(PacketPtr pkt) 102 { pkt->setSrc(id); return bus->recvAtomic(pkt); } 103 104 /** When reciving a Functional requestfrom the peer port (at id), 105 pass it to the bus. */ 106 virtual void recvFunctional(PacketPtr pkt) 107 { pkt->setSrc(id); bus->recvFunctional(pkt); } 108 109 /** When reciving a retry from the peer port (at id), 110 pass it to the bus. */ 111 virtual void recvRetry() 112 { bus->recvRetry(id); } 113 114 // This should return all the 'owned' addresses that are 115 // downstream from this bus, yes? That is, the union of all 116 // the 'owned' address ranges of all the other interfaces on 117 // this bus... 118 virtual AddrRangeList getAddrRanges() 119 { return bus->getAddrRanges(id); } 120 121 // Ask the bus to ask everyone on the bus what their block size is and 122 // take the max of it. This might need to be changed a bit if we ever 123 // support multiple block sizes. 124 virtual unsigned deviceBlockSize() const 125 { return bus->findBlockSize(id); } 126 127 }; 128 129 /** 130 * Declaration of the bus master port type, one will be 131 * instantiated for each of the slave interfaces connecting to the 132 * bus. 133 */ 134 class BusMasterPort : public MasterPort 135 { 136 private: 137 /** A pointer to the bus to which this port belongs. */ 138 Bus *bus; 139 140 /** A id to keep track of the interface ID of this port. */ 141 int id; 142 143 public: 144 145 /** Constructor for the BusMasterPort.*/ 146 BusMasterPort(const std::string &_name, Bus *_bus, int _id) 147 : MasterPort(_name, _bus), bus(_bus), id(_id) 148 { } 149 150 int getId() const { return id; } 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 /** When reciving a timing request from the peer port (at id), 164 pass it to the bus. */ 165 virtual bool recvTiming(PacketPtr pkt) 166 { pkt->setSrc(id); return bus->recvTiming(pkt); } 167 168 /** When reciving a Atomic requestfrom the peer port (at id), 169 pass it to the bus. */ 170 virtual Tick recvAtomic(PacketPtr pkt) 171 { pkt->setSrc(id); return bus->recvAtomic(pkt); } 172 173 /** When reciving a Functional requestfrom the peer port (at id), 174 pass it to the bus. */ 175 virtual void recvFunctional(PacketPtr pkt) 176 { pkt->setSrc(id); bus->recvFunctional(pkt); } 177 178 /** When reciving a range change from the peer port (at id), 179 pass it to the bus. */ 180 virtual void recvRangeChange() 181 { bus->recvRangeChange(id); } 182 183 /** When reciving a retry from the peer port (at id), 184 pass it to the bus. */ 185 virtual void recvRetry() 186 { bus->recvRetry(id); } 187 188 // Ask the bus to ask everyone on the bus what their block size is and 189 // take the max of it. This might need to be changed a bit if we ever 190 // support multiple block sizes. 191 virtual unsigned deviceBlockSize() const 192 { return bus->findBlockSize(id); } 193 194 }; 195 196 /** the clock speed for the bus */ 197 int clock; 198 /** cycles of overhead per transaction */ 199 int headerCycles; 200 /** the width of the bus in bytes */ 201 int width; 202 /** the next tick at which the bus will be idle */ 203 Tick tickNextIdle; 204 205 Event * drainEvent; 206 207 typedef range_map<Addr,int>::iterator PortIter; 208 range_map<Addr, int> portMap; 209 210 AddrRangeList defaultRange; 211 212 typedef std::vector<BusSlavePort*>::iterator SnoopIter; 213 std::vector<BusSlavePort*> snoopPorts; 214 215 /** Function called by the port when the bus is recieving a Timing 216 transaction.*/ 217 bool recvTiming(PacketPtr pkt); 218 219 /** Function called by the port when the bus is recieving a Atomic 220 transaction.*/ 221 Tick recvAtomic(PacketPtr pkt); 222 223 /** Function called by the port when the bus is recieving a Functional 224 transaction.*/ 225 void recvFunctional(PacketPtr pkt); 226 227 /** Timing function called by port when it is once again able to process 228 * requests. */ 229 void recvRetry(int id); 230 231 /** Function called by the port when the bus is recieving a range change.*/ 232 void recvRangeChange(int id); 233 234 /** Find which port connected to this bus (if any) should be given a packet 235 * with this address. 236 * @param addr Address to find port for. 237 * @return id of port that the packet should be sent out of. 238 */ 239 int findPort(Addr addr); 240 241 // Cache for the findPort function storing recently used ports from portMap 242 struct PortCache { 243 bool valid; 244 int id; 245 Addr start; 246 Addr end; 247 }; 248 249 PortCache portCache[3]; 250 251 // Checks the cache and returns the id of the port that has the requested 252 // address within its range 253 inline int checkPortCache(Addr addr) { 254 if (portCache[0].valid && addr >= portCache[0].start && 255 addr < portCache[0].end) { 256 return portCache[0].id; 257 } 258 if (portCache[1].valid && addr >= portCache[1].start && 259 addr < portCache[1].end) { 260 return portCache[1].id; 261 } 262 if (portCache[2].valid && addr >= portCache[2].start && 263 addr < portCache[2].end) { 264 return portCache[2].id; 265 } 266 267 return INVALID_PORT_ID; 268 } 269 270 // Clears the earliest entry of the cache and inserts a new port entry 271 inline void updatePortCache(short id, Addr start, Addr end) { 272 portCache[2].valid = portCache[1].valid; 273 portCache[2].id = portCache[1].id; 274 portCache[2].start = portCache[1].start; 275 portCache[2].end = portCache[1].end; 276 277 portCache[1].valid = portCache[0].valid; 278 portCache[1].id = portCache[0].id; 279 portCache[1].start = portCache[0].start; 280 portCache[1].end = portCache[0].end; 281 282 portCache[0].valid = true; 283 portCache[0].id = id; 284 portCache[0].start = start; 285 portCache[0].end = end; 286 } 287 288 // Clears the cache. Needs to be called in constructor. 289 inline void clearPortCache() { 290 portCache[2].valid = false; 291 portCache[1].valid = false; 292 portCache[0].valid = false; 293 } 294 295 /** 296 * Return the address ranges this port is responsible for. 297 * 298 * @param id id of the bus port that made the request 299 * 300 * @return a list of non-overlapping address ranges 301 */ 302 AddrRangeList getAddrRanges(int id); 303 304 /** 305 * Determine if the bus port is snooping or not. 306 * 307 * @param id id of the bus port that made the request 308 * 309 * @return a boolean indicating if this port is snooping or not 310 */ 311 bool isSnooping(int id) const; 312 313 /** Calculate the timing parameters for the packet. Updates the 314 * firstWordTime and finishTime fields of the packet object. 315 * Returns the tick at which the packet header is completed (which 316 * will be all that is sent if the target rejects the packet). 317 */ 318 Tick calcPacketTiming(PacketPtr pkt); 319 320 /** Occupy the bus until until */ 321 void occupyBus(Tick until); 322 323 /** 324 * Release the bus after being occupied and return to an idle 325 * state where we proceed to send a retry to any potential waiting 326 * port, or drain if asked to do so. 327 */ 328 void releaseBus(); 329 330 /** 331 * Send a retry to the port at the head of the retryList. The 332 * caller must ensure that the list is not empty. 333 */ 334 void retryWaiting(); 335 336 /** Ask everyone on the bus what their size is 337 * @param id id of the busport that made the request 338 * @return the max of all the sizes 339 */ 340 unsigned findBlockSize(int id); 341 342 // event used to schedule a release of the bus 343 EventWrapper<Bus, &Bus::releaseBus> busIdleEvent; 344 345 bool inRetry; 346 std::set<int> inRecvRangeChange; 347 348 // keep track of the number of master ports (not counting the 349 // default master) since we need this as an offset into the 350 // interfaces vector 351 unsigned int nbrMasterPorts; 352 353 /** The master and slave ports of the bus */ 354 std::vector<BusSlavePort*> slavePorts; 355 std::vector<BusMasterPort*> masterPorts; 356 357 /** An array of pointers to ports that retry should be called on because the 358 * original send failed for whatever reason.*/ 359 std::list<Port*> retryList; 360 361 void addToRetryList(Port* port) 362 { 363 if (!inRetry) { 364 // The device wasn't retrying a packet, or wasn't at an 365 // appropriate time. 366 retryList.push_back(port); 367 } else { 368 if (!retryList.empty() && port == retryList.front()) { 369 // The device was retrying a packet. It didn't work, 370 // so we'll leave it at the head of the retry list. 371 inRetry = false; 372 } else { 373 // We are in retry, but not for this port, put it at 374 // the end. 375 retryList.push_back(port); 376 } 377 } 378 } 379 380 /** Port that handles requests that don't match any of the interfaces.*/ 381 short defaultPortId; 382 383 /** A symbolic name for a port id that denotes no port. */ 384 static const short INVALID_PORT_ID = -1; 385 386 /** If true, use address range provided by default device. Any 387 address not handled by another port and not in default device's 388 range will cause a fatal error. If false, just send all 389 addresses not handled by another port to default device. */ 390 bool useDefaultRange; 391 392 unsigned defaultBlockSize; 393 unsigned cachedBlockSize; 394 bool cachedBlockSizeValid; 395 396 public: 397 398 /** A function used to return the port associated with this bus object. */ 399 virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1); 400 virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); 401 402 virtual void init(); 403 virtual void startup(); 404 405 unsigned int drain(Event *de); 406 407 Bus(const BusParams *p); 408}; 409 410#endif //__MEM_BUS_HH__ 411