xbar.cc revision 3074
1/* 2 * Copyright (c) 2006 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: Ali Saidi 29 */ 30 31/** 32 * @file 33 * Definition of a bus object. 34 */ 35 36 37#include "base/misc.hh" 38#include "base/trace.hh" 39#include "mem/bus.hh" 40#include "sim/builder.hh" 41 42Port * 43Bus::getPort(const std::string &if_name, int idx) 44{ 45 if (if_name == "default") 46 if (defaultPort == NULL) { 47 defaultPort = new BusPort(csprintf("%s-default",name()), this, 48 defaultId); 49 return defaultPort; 50 } else 51 fatal("Default port already set\n"); 52 53 // if_name ignored? forced to be empty? 54 int id = interfaces.size(); 55 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 56 interfaces.push_back(bp); 57 return bp; 58} 59 60/** Get the ranges of anyone other buses that we are connected to. */ 61void 62Bus::init() 63{ 64 std::vector<Port*>::iterator intIter; 65 66 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 67 (*intIter)->sendStatusChange(Port::RangeChange); 68} 69 70 71/** Function called by the port when the bus is receiving a Timing 72 * transaction.*/ 73bool 74Bus::recvTiming(Packet *pkt) 75{ 76 Port *port; 77 DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 78 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 79 80 short dest = pkt->getDest(); 81 if (dest == Packet::Broadcast) { 82 if ( timingSnoopPhase1(pkt) ) 83 { 84 timingSnoopPhase2(pkt); 85 port = findPort(pkt->getAddr(), pkt->getSrc()); 86 } 87 else 88 { 89 //Snoop didn't succeed 90 retryList.push_back(interfaces[pkt->getSrc()]); 91 return false; 92 } 93 } else { 94 assert(dest >= 0 && dest < interfaces.size()); 95 assert(dest != pkt->getSrc()); // catch infinite loops 96 port = interfaces[dest]; 97 } 98 if (port->sendTiming(pkt)) { 99 // packet was successfully sent, just return true. 100 return true; 101 } 102 103 // packet not successfully sent 104 retryList.push_back(interfaces[pkt->getSrc()]); 105 return false; 106} 107 108void 109Bus::recvRetry(int id) 110{ 111 // Go through all the elements on the list calling sendRetry on each 112 // This is not very efficient at all but it works. Ultimately we should end 113 // up with something that is more intelligent. 114 int initialSize = retryList.size(); 115 int i; 116 Port *p; 117 118 for (i = 0; i < initialSize; i++) { 119 assert(retryList.size() > 0); 120 p = retryList.front(); 121 retryList.pop_front(); 122 p->sendRetry(); 123 } 124} 125 126 127Port * 128Bus::findPort(Addr addr, int id) 129{ 130 /* An interval tree would be a better way to do this. --ali. */ 131 int dest_id = -1; 132 int i = 0; 133 bool found = false; 134 AddrRangeIter iter; 135 136 while (i < portList.size() && !found) 137 { 138 if (portList[i].range == addr) { 139 dest_id = portList[i].portId; 140 found = true; 141 DPRINTF(Bus, " found addr 0x%llx on device %d\n", addr, dest_id); 142 } 143 i++; 144 } 145 146 // Check if this matches the default range 147 if (dest_id == -1) { 148 for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) { 149 if (*iter == addr) { 150 DPRINTF(Bus, " found addr 0x%llx on default\n", addr); 151 return defaultPort; 152 } 153 } 154 panic("Unable to find destination for addr: %llx", addr); 155 } 156 157 158 // we shouldn't be sending this back to where it came from 159 assert(dest_id != id); 160 161 return interfaces[dest_id]; 162} 163 164std::vector<int> 165Bus::findSnoopPorts(Addr addr, int id) 166{ 167 int i = 0; 168 AddrRangeIter iter; 169 std::vector<int> ports; 170 171 while (i < portSnoopList.size()) 172 { 173 if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) { 174 //Careful to not overlap ranges 175 //or snoop will be called more than once on the port 176 ports.push_back(portSnoopList[i].portId); 177 DPRINTF(Bus, " found snoop addr 0x%llx on device%d\n", addr, 178 portSnoopList[i].portId); 179 } 180 i++; 181 } 182 return ports; 183} 184 185void 186Bus::atomicSnoop(Packet *pkt) 187{ 188 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 189 190 while (!ports.empty()) 191 { 192 interfaces[ports.back()]->sendAtomic(pkt); 193 ports.pop_back(); 194 } 195} 196 197bool 198Bus::timingSnoopPhase1(Packet *pkt) 199{ 200 std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 201 bool success = true; 202 203 while (!ports.empty() && success) 204 { 205 snoopCallbacks.push_back(ports.back()); 206 success = interfaces[ports.back()]->sendTiming(pkt); 207 ports.pop_back(); 208 } 209 if (!success) 210 { 211 while (!snoopCallbacks.empty()) 212 { 213 interfaces[snoopCallbacks.back()]->sendStatusChange(Port::SnoopSquash); 214 snoopCallbacks.pop_back(); 215 } 216 return false; 217 } 218 return true; 219} 220 221void 222Bus::timingSnoopPhase2(Packet *pkt) 223{ 224 bool success; 225 pkt->flags |= SNOOP_COMMIT; 226 while (!snoopCallbacks.empty()) 227 { 228 success = interfaces[snoopCallbacks.back()]->sendTiming(pkt); 229 //We should not fail on snoop callbacks 230 assert(success); 231 snoopCallbacks.pop_back(); 232 } 233} 234 235/** Function called by the port when the bus is receiving a Atomic 236 * transaction.*/ 237Tick 238Bus::recvAtomic(Packet *pkt) 239{ 240 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 241 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 242 assert(pkt->getDest() == Packet::Broadcast); 243 atomicSnoop(pkt); 244 return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); 245} 246 247/** Function called by the port when the bus is receiving a Functional 248 * transaction.*/ 249void 250Bus::recvFunctional(Packet *pkt) 251{ 252 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 253 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 254 assert(pkt->getDest() == Packet::Broadcast); 255 findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); 256} 257 258/** Function called by the port when the bus is receiving a status change.*/ 259void 260Bus::recvStatusChange(Port::Status status, int id) 261{ 262 AddrRangeList ranges; 263 AddrRangeList snoops; 264 int x; 265 AddrRangeIter iter; 266 267 assert(status == Port::RangeChange && 268 "The other statuses need to be implemented."); 269 270 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 271 272 if (id == defaultId) { 273 defaultRange.clear(); 274 defaultPort->getPeerAddressRanges(ranges, snoops); 275 assert(snoops.size() == 0); 276 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 277 defaultRange.push_back(*iter); 278 DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default range\n", 279 iter->start, iter->end); 280 } 281 } else { 282 283 assert((id < interfaces.size() && id >= 0) || id == -1); 284 Port *port = interfaces[id]; 285 std::vector<DevMap>::iterator portIter; 286 std::vector<DevMap>::iterator snoopIter; 287 288 // Clean out any previously existent ids 289 for (portIter = portList.begin(); portIter != portList.end(); ) { 290 if (portIter->portId == id) 291 portIter = portList.erase(portIter); 292 else 293 portIter++; 294 } 295 296 for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) { 297 if (snoopIter->portId == id) 298 snoopIter = portSnoopList.erase(snoopIter); 299 else 300 snoopIter++; 301 } 302 303 port->getPeerAddressRanges(ranges, snoops); 304 305 for(iter = snoops.begin(); iter != snoops.end(); iter++) { 306 DevMap dm; 307 dm.portId = id; 308 dm.range = *iter; 309 310 DPRINTF(BusAddrRanges, "Adding snoop range %llx - %llx for id %d\n", 311 dm.range.start, dm.range.end, id); 312 portSnoopList.push_back(dm); 313 } 314 315 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 316 DevMap dm; 317 dm.portId = id; 318 dm.range = *iter; 319 320 DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n", 321 dm.range.start, dm.range.end, id); 322 portList.push_back(dm); 323 } 324 } 325 DPRINTF(MMU, "port list has %d entries\n", portList.size()); 326 327 // tell all our peers that our address range has changed. 328 // Don't tell the device that caused this change, it already knows 329 for (x = 0; x < interfaces.size(); x++) 330 if (x != id) 331 interfaces[x]->sendStatusChange(Port::RangeChange); 332 333 if (id != defaultId && defaultPort) 334 defaultPort->sendStatusChange(Port::RangeChange); 335} 336 337void 338Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) 339{ 340 std::vector<DevMap>::iterator portIter; 341 AddrRangeIter dflt_iter; 342 bool subset; 343 344 resp.clear(); 345 snoop.clear(); 346 347 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 348 349 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 350 dflt_iter++) { 351 resp.push_back(*dflt_iter); 352 DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",dflt_iter->start, 353 dflt_iter->end); 354 } 355 for (portIter = portList.begin(); portIter != portList.end(); portIter++) { 356 subset = false; 357 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 358 dflt_iter++) { 359 if ((portIter->range.start < dflt_iter->start && 360 portIter->range.end >= dflt_iter->start) || 361 (portIter->range.start < dflt_iter->end && 362 portIter->range.end >= dflt_iter->end)) 363 fatal("Devices can not set ranges that itersect the default set\ 364 but are not a subset of the default set.\n"); 365 if (portIter->range.start >= dflt_iter->start && 366 portIter->range.end <= dflt_iter->end) { 367 subset = true; 368 DPRINTF(BusAddrRanges, " -- %#llX : %#llX is a SUBSET\n", 369 portIter->range.start, portIter->range.end); 370 } 371 } 372 if (portIter->portId != id && !subset) { 373 resp.push_back(portIter->range); 374 DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n", 375 portIter->range.start, portIter->range.end); 376 } 377 } 378} 379 380BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 381 382 Param<int> bus_id; 383 384END_DECLARE_SIM_OBJECT_PARAMS(Bus) 385 386BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 387 INIT_PARAM(bus_id, "a globally unique bus id") 388END_INIT_SIM_OBJECT_PARAMS(Bus) 389 390CREATE_SIM_OBJECT(Bus) 391{ 392 return new Bus(getInstanceName(), bus_id); 393} 394 395REGISTER_SIM_OBJECT("Bus", Bus) 396