xbar.hh revision 7523
1865SN/A/* 21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 3865SN/A * All rights reserved. 4865SN/A * 5865SN/A * Redistribution and use in source and binary forms, with or without 6865SN/A * modification, are permitted provided that the following conditions are 7865SN/A * met: redistributions of source code must retain the above copyright 8865SN/A * notice, this list of conditions and the following disclaimer; 9865SN/A * redistributions in binary form must reproduce the above copyright 10865SN/A * notice, this list of conditions and the following disclaimer in the 11865SN/A * documentation and/or other materials provided with the distribution; 12865SN/A * neither the name of the copyright holders nor the names of its 13865SN/A * contributors may be used to endorse or promote products derived from 14865SN/A * this software without specific prior written permission. 15865SN/A * 16865SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17865SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18865SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19865SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20865SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21865SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22865SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23865SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24865SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25865SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26865SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Ron Dreslinski 292665Ssaidi@eecs.umich.edu * Ali Saidi 30865SN/A */ 31865SN/A 32865SN/A/** 33865SN/A * @file 34865SN/A * Declaration of a bus object. 35865SN/A */ 36865SN/A 372107SN/A#ifndef __MEM_BUS_HH__ 38865SN/A#define __MEM_BUS_HH__ 392542SN/A 402542SN/A#include <string> 411634SN/A#include <set> 421634SN/A#include <list> 431634SN/A 441634SN/A#include "base/hashmap.hh" 451634SN/A#include "base/range.hh" 461634SN/A#include "base/range_map.hh" 471634SN/A#include "base/types.hh" 481149SN/A#include "mem/mem_object.hh" 491149SN/A#include "mem/packet.hh" 501149SN/A#include "mem/port.hh" 511149SN/A#include "mem/request.hh" 521149SN/A#include "params/Bus.hh" 531149SN/A#include "sim/eventq.hh" 541149SN/A 551149SN/Aclass Bus : public MemObject 561149SN/A{ 571149SN/A /** Declaration of the buses port type, one will be instantiated for each 581149SN/A of the interfaces connecting to the bus. */ 591149SN/A class BusPort : public Port 601149SN/A { 611149SN/A bool _onRetryList; 621149SN/A 631149SN/A /** A pointer to the bus to which this port belongs. */ 641149SN/A Bus *bus; 651149SN/A 66865SN/A /** A id to keep track of the intercafe ID this port is connected to. */ 67865SN/A 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 unsigned deviceBlockSize() const 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 unsigned 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 /** If true, use address range provided by default device. Any 309 address not handled by another port and not in default device's 310 range will cause a fatal error. If false, just send all 311 addresses not handled by another port to default device. */ 312 bool useDefaultRange; 313 314 unsigned defaultBlockSize; 315 unsigned cachedBlockSize; 316 bool cachedBlockSizeValid; 317 318 // Cache for the peer port interfaces 319 struct BusCache { 320 bool valid; 321 short id; 322 BusPort *port; 323 }; 324 325 BusCache busCache[3]; 326 327 // Checks the peer port interfaces cache for the port id and returns 328 // a pointer to the matching port 329 inline BusPort* checkBusCache(short id) { 330 if (busCache[0].valid && id == busCache[0].id) { 331 return busCache[0].port; 332 } 333 if (busCache[1].valid && id == busCache[1].id) { 334 return busCache[1].port; 335 } 336 if (busCache[2].valid && id == busCache[2].id) { 337 return busCache[2].port; 338 } 339 340 return NULL; 341 } 342 343 // Replaces the earliest entry in the cache with a new entry 344 inline void updateBusCache(short id, BusPort *port) { 345 busCache[2].valid = busCache[1].valid; 346 busCache[2].id = busCache[1].id; 347 busCache[2].port = busCache[1].port; 348 349 busCache[1].valid = busCache[0].valid; 350 busCache[1].id = busCache[0].id; 351 busCache[1].port = busCache[0].port; 352 353 busCache[0].valid = true; 354 busCache[0].id = id; 355 busCache[0].port = port; 356 } 357 358 // Invalidates the cache. Needs to be called in constructor. 359 inline void clearBusCache() { 360 busCache[2].valid = false; 361 busCache[1].valid = false; 362 busCache[0].valid = false; 363 } 364 365 366 public: 367 368 /** A function used to return the port associated with this bus object. */ 369 virtual Port *getPort(const std::string &if_name, int idx = -1); 370 virtual void deletePortRefs(Port *p); 371 372 virtual void init(); 373 virtual void startup(); 374 375 unsigned int drain(Event *de); 376 377 Bus(const BusParams *p); 378}; 379 380#endif //__MEM_BUS_HH__ 381