xbar.hh revision 6215
1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ron Dreslinski 29 * Ali Saidi 30 */ 31 32/** 33 * @file 34 * Declaration of a bus object. 35 */ 36 37#ifndef __MEM_BUS_HH__ 38#define __MEM_BUS_HH__ 39 40#include <string> 41#include <set> 42#include <list> 43 44#include "base/range.hh" 45#include "base/hashmap.hh" 46#include "base/range_map.hh" 47#include "base/types.hh" 48#include "mem/mem_object.hh" 49#include "mem/packet.hh" 50#include "mem/port.hh" 51#include "mem/request.hh" 52#include "sim/eventq.hh" 53#include "params/Bus.hh" 54 55class Bus : public MemObject 56{ 57 /** Declaration of the buses port type, one will be instantiated for each 58 of the interfaces connecting to the bus. */ 59 class BusPort : public Port 60 { 61 bool _onRetryList; 62 63 /** A pointer to the bus to which this port belongs. */ 64 Bus *bus; 65 66 /** A id to keep track of the intercafe ID this port is connected to. */ 67 int id; 68 69 public: 70 71 /** Constructor for the BusPort.*/ 72 BusPort(const std::string &_name, Bus *_bus, int _id) 73 : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id) 74 { } 75 76 bool onRetryList() 77 { return _onRetryList; } 78 79 void onRetryList(bool newVal) 80 { _onRetryList = newVal; } 81 82 int getId() { return id; } 83 84 protected: 85 86 /** When reciving a timing request from the peer port (at id), 87 pass it to the bus. */ 88 virtual bool recvTiming(PacketPtr pkt) 89 { pkt->setSrc(id); return bus->recvTiming(pkt); } 90 91 /** When reciving a Atomic requestfrom the peer port (at id), 92 pass it to the bus. */ 93 virtual Tick recvAtomic(PacketPtr pkt) 94 { pkt->setSrc(id); return bus->recvAtomic(pkt); } 95 96 /** When reciving a Functional requestfrom the peer port (at id), 97 pass it to the bus. */ 98 virtual void recvFunctional(PacketPtr pkt) 99 { pkt->setSrc(id); bus->recvFunctional(pkt); } 100 101 /** When reciving a status changefrom the peer port (at id), 102 pass it to the bus. */ 103 virtual void recvStatusChange(Status status) 104 { bus->recvStatusChange(status, id); } 105 106 /** When reciving a retry from the peer port (at id), 107 pass it to the bus. */ 108 virtual void recvRetry() 109 { bus->recvRetry(id); } 110 111 // This should return all the 'owned' addresses that are 112 // downstream from this bus, yes? That is, the union of all 113 // the 'owned' address ranges of all the other interfaces on 114 // this bus... 115 virtual void getDeviceAddressRanges(AddrRangeList &resp, 116 bool &snoop) 117 { bus->addressRanges(resp, snoop, id); } 118 119 // Ask the bus to ask everyone on the bus what their block size is and 120 // take the max of it. This might need to be changed a bit if we ever 121 // support multiple block sizes. 122 virtual int deviceBlockSize() 123 { return bus->findBlockSize(id); } 124 125 }; 126 127 class BusFreeEvent : public Event 128 { 129 Bus * bus; 130 131 public: 132 BusFreeEvent(Bus * _bus); 133 void process(); 134 const char *description() const; 135 }; 136 137 /** a globally unique id for this bus. */ 138 int busId; 139 /** the clock speed for the bus */ 140 int clock; 141 /** cycles of overhead per transaction */ 142 int headerCycles; 143 /** the width of the bus in bytes */ 144 int width; 145 /** the next tick at which the bus will be idle */ 146 Tick tickNextIdle; 147 148 Event * drainEvent; 149 150 151 static const int defaultId = -3; //Make it unique from Broadcast 152 153 typedef range_map<Addr,int>::iterator PortIter; 154 range_map<Addr, int> portMap; 155 156 AddrRangeList defaultRange; 157 158 typedef std::vector<BusPort*>::iterator SnoopIter; 159 std::vector<BusPort*> snoopPorts; 160 161 /** Function called by the port when the bus is recieving a Timing 162 transaction.*/ 163 bool recvTiming(PacketPtr pkt); 164 165 /** Function called by the port when the bus is recieving a Atomic 166 transaction.*/ 167 Tick recvAtomic(PacketPtr pkt); 168 169 /** Function called by the port when the bus is recieving a Functional 170 transaction.*/ 171 void recvFunctional(PacketPtr pkt); 172 173 /** Timing function called by port when it is once again able to process 174 * requests. */ 175 void recvRetry(int id); 176 177 /** Function called by the port when the bus is recieving a status change.*/ 178 void recvStatusChange(Port::Status status, int id); 179 180 /** Find which port connected to this bus (if any) should be given a packet 181 * with this address. 182 * @param addr Address to find port for. 183 * @return id of port that the packet should be sent out of. 184 */ 185 int findPort(Addr addr); 186 187 // Cache for the findPort function storing recently used ports from portMap 188 struct PortCache { 189 bool valid; 190 int id; 191 Addr start; 192 Addr end; 193 }; 194 195 PortCache portCache[3]; 196 197 // Checks the cache and returns the id of the port that has the requested 198 // address within its range 199 inline int checkPortCache(Addr addr) { 200 if (portCache[0].valid && addr >= portCache[0].start && 201 addr < portCache[0].end) { 202 return portCache[0].id; 203 } 204 if (portCache[1].valid && addr >= portCache[1].start && 205 addr < portCache[1].end) { 206 return portCache[1].id; 207 } 208 if (portCache[2].valid && addr >= portCache[2].start && 209 addr < portCache[2].end) { 210 return portCache[2].id; 211 } 212 213 return -1; 214 } 215 216 // Clears the earliest entry of the cache and inserts a new port entry 217 inline void updatePortCache(short id, Addr start, Addr end) { 218 portCache[2].valid = portCache[1].valid; 219 portCache[2].id = portCache[1].id; 220 portCache[2].start = portCache[1].start; 221 portCache[2].end = portCache[1].end; 222 223 portCache[1].valid = portCache[0].valid; 224 portCache[1].id = portCache[0].id; 225 portCache[1].start = portCache[0].start; 226 portCache[1].end = portCache[0].end; 227 228 portCache[0].valid = true; 229 portCache[0].id = id; 230 portCache[0].start = start; 231 portCache[0].end = end; 232 } 233 234 // Clears the cache. Needs to be called in constructor. 235 inline void clearPortCache() { 236 portCache[2].valid = false; 237 portCache[1].valid = false; 238 portCache[0].valid = false; 239 } 240 241 /** Process address range request. 242 * @param resp addresses that we can respond to 243 * @param snoop addresses that we would like to snoop 244 * @param id ide of the busport that made the request. 245 */ 246 void addressRanges(AddrRangeList &resp, bool &snoop, int id); 247 248 /** Calculate the timing parameters for the packet. Updates the 249 * firstWordTime and finishTime fields of the packet object. 250 * Returns the tick at which the packet header is completed (which 251 * will be all that is sent if the target rejects the packet). 252 */ 253 Tick calcPacketTiming(PacketPtr pkt); 254 255 /** Occupy the bus until until */ 256 void occupyBus(Tick until); 257 258 /** Ask everyone on the bus what their size is 259 * @param id id of the busport that made the request 260 * @return the max of all the sizes 261 */ 262 int findBlockSize(int id); 263 264 BusFreeEvent busIdle; 265 266 bool inRetry; 267 std::set<int> inRecvStatusChange; 268 269 /** max number of bus ids we've handed out so far */ 270 short maxId; 271 272 /** An array of pointers to the peer port interfaces 273 connected to this bus.*/ 274 m5::hash_map<short,BusPort*> interfaces; 275 276 /** An array of pointers to ports that retry should be called on because the 277 * original send failed for whatever reason.*/ 278 std::list<BusPort*> retryList; 279 280 void addToRetryList(BusPort * port) 281 { 282 if (!inRetry) { 283 // The device wasn't retrying a packet, or wasn't at an appropriate 284 // time. 285 assert(!port->onRetryList()); 286 port->onRetryList(true); 287 retryList.push_back(port); 288 } else { 289 if (port->onRetryList()) { 290 // The device was retrying a packet. It didn't work, so we'll leave 291 // it at the head of the retry list. 292 assert(port == retryList.front()); 293 inRetry = false; 294 } 295 else { 296 port->onRetryList(true); 297 retryList.push_back(port); 298 } 299 } 300 } 301 302 /** Port that handles requests that don't match any of the interfaces.*/ 303 BusPort *defaultPort; 304 305 BusPort *funcPort; 306 int funcPortId; 307 308 /** Has the user specified their own default responder? */ 309 bool responderSet; 310 311 int defaultBlockSize; 312 int cachedBlockSize; 313 bool cachedBlockSizeValid; 314 315 // Cache for the peer port interfaces 316 struct BusCache { 317 bool valid; 318 short id; 319 BusPort *port; 320 }; 321 322 BusCache busCache[3]; 323 324 // Checks the peer port interfaces cache for the port id and returns 325 // a pointer to the matching port 326 inline BusPort* checkBusCache(short id) { 327 if (busCache[0].valid && id == busCache[0].id) { 328 return busCache[0].port; 329 } 330 if (busCache[1].valid && id == busCache[1].id) { 331 return busCache[1].port; 332 } 333 if (busCache[2].valid && id == busCache[2].id) { 334 return busCache[2].port; 335 } 336 337 return NULL; 338 } 339 340 // Replaces the earliest entry in the cache with a new entry 341 inline void updateBusCache(short id, BusPort *port) { 342 busCache[2].valid = busCache[1].valid; 343 busCache[2].id = busCache[1].id; 344 busCache[2].port = busCache[1].port; 345 346 busCache[1].valid = busCache[0].valid; 347 busCache[1].id = busCache[0].id; 348 busCache[1].port = busCache[0].port; 349 350 busCache[0].valid = true; 351 busCache[0].id = id; 352 busCache[0].port = port; 353 } 354 355 // Invalidates the cache. Needs to be called in constructor. 356 inline void clearBusCache() { 357 busCache[2].valid = false; 358 busCache[1].valid = false; 359 busCache[0].valid = false; 360 } 361 362 363 public: 364 365 /** A function used to return the port associated with this bus object. */ 366 virtual Port *getPort(const std::string &if_name, int idx = -1); 367 virtual void deletePortRefs(Port *p); 368 369 virtual void init(); 370 virtual void startup(); 371 372 unsigned int drain(Event *de); 373 374 Bus(const BusParams *p) 375 : MemObject(p), busId(p->bus_id), clock(p->clock), 376 headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 377 drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), 378 defaultPort(NULL), funcPort(NULL), funcPortId(-4), 379 responderSet(p->responder_set), defaultBlockSize(p->block_size), 380 cachedBlockSize(0), cachedBlockSizeValid(false) 381 { 382 //width, clock period, and header cycles must be positive 383 if (width <= 0) 384 fatal("Bus width must be positive\n"); 385 if (clock <= 0) 386 fatal("Bus clock period must be positive\n"); 387 if (headerCycles <= 0) 388 fatal("Number of header cycles must be positive\n"); 389 clearBusCache(); 390 clearPortCache(); 391 } 392 393}; 394 395#endif //__MEM_BUS_HH__ 396