coherent_xbar.hh revision 8711
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 */ 43 44/** 45 * @file 46 * Declaration of a bus object. 47 */ 48 49#ifndef __MEM_BUS_HH__ 50#define __MEM_BUS_HH__ 51 52#include <list> 53#include <set> 54#include <string> 55 56#include "base/hashmap.hh" 57#include "base/range.hh" 58#include "base/range_map.hh" 59#include "base/types.hh" 60#include "mem/mem_object.hh" 61#include "mem/packet.hh" 62#include "mem/port.hh" 63#include "mem/request.hh" 64#include "params/Bus.hh" 65#include "sim/eventq.hh" 66 67class Bus : public MemObject 68{ 69 /** Declaration of the buses port type, one will be instantiated for each 70 of the interfaces connecting to the bus. */ 71 class BusPort : public Port 72 { 73 bool _onRetryList; 74 75 /** A pointer to the bus to which this port belongs. */ 76 Bus *bus; 77 78 /** A id to keep track of the intercafe ID this port is connected to. */ 79 int id; 80 81 public: 82 83 /** Constructor for the BusPort.*/ 84 BusPort(const std::string &_name, Bus *_bus, int _id) 85 : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id) 86 { } 87 88 bool onRetryList() 89 { return _onRetryList; } 90 91 void onRetryList(bool newVal) 92 { _onRetryList = newVal; } 93 94 int getId() { return id; } 95 96 /** 97 * Determine if this port should be considered a snooper. This 98 * is determined by the bus. 99 * 100 * @return a boolean that is true if this port is snooping 101 */ 102 virtual bool isSnooping() 103 { return bus->isSnooping(id); } 104 105 protected: 106 107 /** When reciving a timing request from the peer port (at id), 108 pass it to the bus. */ 109 virtual bool recvTiming(PacketPtr pkt) 110 { pkt->setSrc(id); return bus->recvTiming(pkt); } 111 112 /** When reciving a Atomic requestfrom the peer port (at id), 113 pass it to the bus. */ 114 virtual Tick recvAtomic(PacketPtr pkt) 115 { pkt->setSrc(id); return bus->recvAtomic(pkt); } 116 117 /** When reciving a Functional requestfrom the peer port (at id), 118 pass it to the bus. */ 119 virtual void recvFunctional(PacketPtr pkt) 120 { pkt->setSrc(id); bus->recvFunctional(pkt); } 121 122 /** When reciving a range change from the peer port (at id), 123 pass it to the bus. */ 124 virtual void recvRangeChange() 125 { bus->recvRangeChange(id); } 126 127 /** When reciving a retry from the peer port (at id), 128 pass it to the bus. */ 129 virtual void recvRetry() 130 { bus->recvRetry(id); } 131 132 // This should return all the 'owned' addresses that are 133 // downstream from this bus, yes? That is, the union of all 134 // the 'owned' address ranges of all the other interfaces on 135 // this bus... 136 virtual AddrRangeList getAddrRanges() 137 { return bus->getAddrRanges(id); } 138 139 // Ask the bus to ask everyone on the bus what their block size is and 140 // take the max of it. This might need to be changed a bit if we ever 141 // support multiple block sizes. 142 virtual unsigned deviceBlockSize() const 143 { return bus->findBlockSize(id); } 144 145 }; 146 147 class BusFreeEvent : public Event 148 { 149 Bus * bus; 150 151 public: 152 BusFreeEvent(Bus * _bus); 153 void process(); 154 const char *description() const; 155 }; 156 157 /** a globally unique id for this bus. */ 158 int busId; 159 /** the clock speed for the bus */ 160 int clock; 161 /** cycles of overhead per transaction */ 162 int headerCycles; 163 /** the width of the bus in bytes */ 164 int width; 165 /** the next tick at which the bus will be idle */ 166 Tick tickNextIdle; 167 168 Event * drainEvent; 169 170 171 static const int defaultId = -3; //Make it unique from Broadcast 172 173 typedef range_map<Addr,int>::iterator PortIter; 174 range_map<Addr, int> portMap; 175 176 AddrRangeList defaultRange; 177 178 typedef std::vector<BusPort*>::iterator SnoopIter; 179 std::vector<BusPort*> snoopPorts; 180 181 /** Function called by the port when the bus is recieving a Timing 182 transaction.*/ 183 bool recvTiming(PacketPtr pkt); 184 185 /** Function called by the port when the bus is recieving a Atomic 186 transaction.*/ 187 Tick recvAtomic(PacketPtr pkt); 188 189 /** Function called by the port when the bus is recieving a Functional 190 transaction.*/ 191 void recvFunctional(PacketPtr pkt); 192 193 /** Timing function called by port when it is once again able to process 194 * requests. */ 195 void recvRetry(int id); 196 197 /** Function called by the port when the bus is recieving a range change.*/ 198 void recvRangeChange(int id); 199 200 /** Find which port connected to this bus (if any) should be given a packet 201 * with this address. 202 * @param addr Address to find port for. 203 * @return id of port that the packet should be sent out of. 204 */ 205 int findPort(Addr addr); 206 207 // Cache for the findPort function storing recently used ports from portMap 208 struct PortCache { 209 bool valid; 210 int id; 211 Addr start; 212 Addr end; 213 }; 214 215 PortCache portCache[3]; 216 217 // Checks the cache and returns the id of the port that has the requested 218 // address within its range 219 inline int checkPortCache(Addr addr) { 220 if (portCache[0].valid && addr >= portCache[0].start && 221 addr < portCache[0].end) { 222 return portCache[0].id; 223 } 224 if (portCache[1].valid && addr >= portCache[1].start && 225 addr < portCache[1].end) { 226 return portCache[1].id; 227 } 228 if (portCache[2].valid && addr >= portCache[2].start && 229 addr < portCache[2].end) { 230 return portCache[2].id; 231 } 232 233 return -1; 234 } 235 236 // Clears the earliest entry of the cache and inserts a new port entry 237 inline void updatePortCache(short id, Addr start, Addr end) { 238 portCache[2].valid = portCache[1].valid; 239 portCache[2].id = portCache[1].id; 240 portCache[2].start = portCache[1].start; 241 portCache[2].end = portCache[1].end; 242 243 portCache[1].valid = portCache[0].valid; 244 portCache[1].id = portCache[0].id; 245 portCache[1].start = portCache[0].start; 246 portCache[1].end = portCache[0].end; 247 248 portCache[0].valid = true; 249 portCache[0].id = id; 250 portCache[0].start = start; 251 portCache[0].end = end; 252 } 253 254 // Clears the cache. Needs to be called in constructor. 255 inline void clearPortCache() { 256 portCache[2].valid = false; 257 portCache[1].valid = false; 258 portCache[0].valid = false; 259 } 260 261 /** 262 * Return the address ranges this port is responsible for. 263 * 264 * @param id id of the bus port that made the request 265 * 266 * @return a list of non-overlapping address ranges 267 */ 268 AddrRangeList getAddrRanges(int id); 269 270 /** 271 * Determine if the bus port is snooping or not. 272 * 273 * @param id id of the bus port that made the request 274 * 275 * @return a boolean indicating if this port is snooping or not 276 */ 277 bool isSnooping(int id); 278 279 /** Calculate the timing parameters for the packet. Updates the 280 * firstWordTime and finishTime fields of the packet object. 281 * Returns the tick at which the packet header is completed (which 282 * will be all that is sent if the target rejects the packet). 283 */ 284 Tick calcPacketTiming(PacketPtr pkt); 285 286 /** Occupy the bus until until */ 287 void occupyBus(Tick until); 288 289 /** Ask everyone on the bus what their size is 290 * @param id id of the busport that made the request 291 * @return the max of all the sizes 292 */ 293 unsigned findBlockSize(int id); 294 295 BusFreeEvent busIdle; 296 297 bool inRetry; 298 std::set<int> inRecvRangeChange; 299 300 /** max number of bus ids we've handed out so far */ 301 short maxId; 302 303 /** An array of pointers to the peer port interfaces 304 connected to this bus.*/ 305 m5::hash_map<short,BusPort*> interfaces; 306 307 /** An array of pointers to ports that retry should be called on because the 308 * original send failed for whatever reason.*/ 309 std::list<BusPort*> retryList; 310 311 void addToRetryList(BusPort * port) 312 { 313 if (!inRetry) { 314 // The device wasn't retrying a packet, or wasn't at an appropriate 315 // time. 316 assert(!port->onRetryList()); 317 port->onRetryList(true); 318 retryList.push_back(port); 319 } else { 320 if (port->onRetryList()) { 321 // The device was retrying a packet. It didn't work, so we'll leave 322 // it at the head of the retry list. 323 assert(port == retryList.front()); 324 inRetry = false; 325 } 326 else { 327 port->onRetryList(true); 328 retryList.push_back(port); 329 } 330 } 331 } 332 333 /** Port that handles requests that don't match any of the interfaces.*/ 334 BusPort *defaultPort; 335 336 BusPort *funcPort; 337 int funcPortId; 338 339 /** If true, use address range provided by default device. Any 340 address not handled by another port and not in default device's 341 range will cause a fatal error. If false, just send all 342 addresses not handled by another port to default device. */ 343 bool useDefaultRange; 344 345 unsigned defaultBlockSize; 346 unsigned cachedBlockSize; 347 bool cachedBlockSizeValid; 348 349 // Cache for the peer port interfaces 350 struct BusCache { 351 bool valid; 352 short id; 353 BusPort *port; 354 }; 355 356 BusCache busCache[3]; 357 358 // Checks the peer port interfaces cache for the port id and returns 359 // a pointer to the matching port 360 inline BusPort* checkBusCache(short id) { 361 if (busCache[0].valid && id == busCache[0].id) { 362 return busCache[0].port; 363 } 364 if (busCache[1].valid && id == busCache[1].id) { 365 return busCache[1].port; 366 } 367 if (busCache[2].valid && id == busCache[2].id) { 368 return busCache[2].port; 369 } 370 371 return NULL; 372 } 373 374 // Replaces the earliest entry in the cache with a new entry 375 inline void updateBusCache(short id, BusPort *port) { 376 busCache[2].valid = busCache[1].valid; 377 busCache[2].id = busCache[1].id; 378 busCache[2].port = busCache[1].port; 379 380 busCache[1].valid = busCache[0].valid; 381 busCache[1].id = busCache[0].id; 382 busCache[1].port = busCache[0].port; 383 384 busCache[0].valid = true; 385 busCache[0].id = id; 386 busCache[0].port = port; 387 } 388 389 // Invalidates the cache. Needs to be called in constructor. 390 inline void clearBusCache() { 391 busCache[2].valid = false; 392 busCache[1].valid = false; 393 busCache[0].valid = false; 394 } 395 396 397 public: 398 399 /** A function used to return the port associated with this bus object. */ 400 virtual Port *getPort(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