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