xbar.hh revision 5354
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#include <inttypes.h> 44 45#include "base/range.hh" 46#include "base/hashmap.hh" 47#include "base/range_map.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 /** Prepare a packet to be sent on the bus. The header finishes at tick 249 * headerTime 250 */ 251 void preparePacket(PacketPtr pkt, Tick & headerTime); 252 253 /** Occupy the bus until until */ 254 void occupyBus(Tick until); 255 256 /** Ask everyone on the bus what their size is 257 * @param id id of the busport that made the request 258 * @return the max of all the sizes 259 */ 260 int findBlockSize(int id); 261 262 BusFreeEvent busIdle; 263 264 bool inRetry; 265 std::set<int> inRecvStatusChange; 266 267 /** max number of bus ids we've handed out so far */ 268 short maxId; 269 270 /** An array of pointers to the peer port interfaces 271 connected to this bus.*/ 272 m5::hash_map<short,BusPort*> interfaces; 273 274 /** An array of pointers to ports that retry should be called on because the 275 * original send failed for whatever reason.*/ 276 std::list<BusPort*> retryList; 277 278 void addToRetryList(BusPort * port) 279 { 280 if (!inRetry) { 281 // The device wasn't retrying a packet, or wasn't at an appropriate 282 // time. 283 assert(!port->onRetryList()); 284 port->onRetryList(true); 285 retryList.push_back(port); 286 } else { 287 if (port->onRetryList()) { 288 // The device was retrying a packet. It didn't work, so we'll leave 289 // it at the head of the retry list. 290 assert(port == retryList.front()); 291 inRetry = false; 292 } 293 else { 294 port->onRetryList(true); 295 retryList.push_back(port); 296 } 297 } 298 } 299 300 /** Port that handles requests that don't match any of the interfaces.*/ 301 BusPort *defaultPort; 302 303 BusPort *funcPort; 304 int funcPortId; 305 306 /** Has the user specified their own default responder? */ 307 bool responderSet; 308 309 int defaultBlockSize; 310 int cachedBlockSize; 311 bool cachedBlockSizeValid; 312 313 // Cache for the peer port interfaces 314 struct BusCache { 315 bool valid; 316 short id; 317 BusPort *port; 318 }; 319 320 BusCache busCache[3]; 321 322 // Checks the peer port interfaces cache for the port id and returns 323 // a pointer to the matching port 324 inline BusPort* checkBusCache(short id) { 325 if (busCache[0].valid && id == busCache[0].id) { 326 return busCache[0].port; 327 } 328 if (busCache[1].valid && id == busCache[1].id) { 329 return busCache[1].port; 330 } 331 if (busCache[2].valid && id == busCache[2].id) { 332 return busCache[2].port; 333 } 334 335 return NULL; 336 } 337 338 // Replaces the earliest entry in the cache with a new entry 339 inline void updateBusCache(short id, BusPort *port) { 340 busCache[2].valid = busCache[1].valid; 341 busCache[2].id = busCache[1].id; 342 busCache[2].port = busCache[1].port; 343 344 busCache[1].valid = busCache[0].valid; 345 busCache[1].id = busCache[0].id; 346 busCache[1].port = busCache[0].port; 347 348 busCache[0].valid = true; 349 busCache[0].id = id; 350 busCache[0].port = port; 351 } 352 353 // Invalidates the cache. Needs to be called in constructor. 354 inline void clearBusCache() { 355 busCache[2].valid = false; 356 busCache[1].valid = false; 357 busCache[0].valid = false; 358 } 359 360 361 public: 362 363 /** A function used to return the port associated with this bus object. */ 364 virtual Port *getPort(const std::string &if_name, int idx = -1); 365 virtual void deletePortRefs(Port *p); 366 367 virtual void init(); 368 virtual void startup(); 369 370 unsigned int drain(Event *de); 371 372 Bus(const BusParams *p) 373 : MemObject(p), busId(p->bus_id), clock(p->clock), 374 headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 375 drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), 376 defaultPort(NULL), funcPort(NULL), funcPortId(-4), 377 responderSet(p->responder_set), defaultBlockSize(p->block_size), 378 cachedBlockSize(0), cachedBlockSizeValid(false) 379 { 380 //width, clock period, and header cycles must be positive 381 if (width <= 0) 382 fatal("Bus width must be positive\n"); 383 if (clock <= 0) 384 fatal("Bus clock period must be positive\n"); 385 if (headerCycles <= 0) 386 fatal("Number of header cycles must be positive\n"); 387 clearBusCache(); 388 clearPortCache(); 389 } 390 391}; 392 393#endif //__MEM_BUS_HH__ 394