xbar.cc revision 3074
12686Sksewell@umich.edu/* 22686Sksewell@umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 35268Sksewell@umich.edu * All rights reserved. 45268Sksewell@umich.edu * 55268Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 65268Sksewell@umich.edu * modification, are permitted provided that the following conditions are 75268Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 85268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 95268Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 105268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 115268Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 125268Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 135268Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 145268Sksewell@umich.edu * this software without specific prior written permission. 155268Sksewell@umich.edu * 165268Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175268Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185268Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195268Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205268Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215268Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225268Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235268Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245268Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255268Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265268Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275268Sksewell@umich.edu * 285268Sksewell@umich.edu * Authors: Ali Saidi 295268Sksewell@umich.edu */ 305268Sksewell@umich.edu 312706Sksewell@umich.edu/** 322022SN/A * @file 332022SN/A * Definition of a bus object. 342022SN/A */ 352022SN/A 362022SN/A 372022SN/A#include "base/misc.hh" 382022SN/A#include "base/trace.hh" 392022SN/A#include "mem/bus.hh" 402022SN/A#include "sim/builder.hh" 412028SN/A 422022SN/APort * 432022SN/ABus::getPort(const std::string &if_name, int idx) 442022SN/A{ 452022SN/A if (if_name == "default") 462028SN/A if (defaultPort == NULL) { 472022SN/A defaultPort = new BusPort(csprintf("%s-default",name()), this, 482022SN/A defaultId); 492022SN/A return defaultPort; 502022SN/A } else 512022SN/A fatal("Default port already set\n"); 525222Sksewell@umich.edu 535222Sksewell@umich.edu // if_name ignored? forced to be empty? 545222Sksewell@umich.edu int id = interfaces.size(); 555222Sksewell@umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 565222Sksewell@umich.edu interfaces.push_back(bp); 575222Sksewell@umich.edu return bp; 585222Sksewell@umich.edu} 595222Sksewell@umich.edu 605222Sksewell@umich.edu/** Get the ranges of anyone other buses that we are connected to. */ 615222Sksewell@umich.eduvoid 625222Sksewell@umich.eduBus::init() 635222Sksewell@umich.edu{ 645222Sksewell@umich.edu std::vector<Port*>::iterator intIter; 655222Sksewell@umich.edu 665222Sksewell@umich.edu for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 675222Sksewell@umich.edu (*intIter)->sendStatusChange(Port::RangeChange); 685222Sksewell@umich.edu} 692022SN/A 702022SN/A 712022SN/A/** Function called by the port when the bus is receiving a Timing 722022SN/A * transaction.*/ 732022SN/Abool 742686Sksewell@umich.eduBus::recvTiming(Packet *pkt) 752022SN/A{ 765222Sksewell@umich.edu Port *port; 775222Sksewell@umich.edu DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 785222Sksewell@umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 795222Sksewell@umich.edu 802022SN/A short dest = pkt->getDest(); 812022SN/A if (dest == Packet::Broadcast) { 822022SN/A if ( timingSnoopPhase1(pkt) ) 832686Sksewell@umich.edu { 8410196SCurtis.Dunham@arm.com timingSnoopPhase2(pkt); 852022SN/A port = findPort(pkt->getAddr(), pkt->getSrc()); 862022SN/A } 872022SN/A else 882022SN/A { 892686Sksewell@umich.edu //Snoop didn't succeed 902022SN/A retryList.push_back(interfaces[pkt->getSrc()]); 912022SN/A return false; 922022SN/A } 935222Sksewell@umich.edu } else { 942022SN/A assert(dest >= 0 && dest < interfaces.size()); 955222Sksewell@umich.edu assert(dest != pkt->getSrc()); // catch infinite loops 965222Sksewell@umich.edu port = interfaces[dest]; 9710474Sandreas.hansson@arm.com } 985222Sksewell@umich.edu if (port->sendTiming(pkt)) { 993951Sgblack@eecs.umich.edu // packet was successfully sent, just return true. 1002022SN/A return true; 1012022SN/A } 1022239SN/A 1032239SN/A // packet not successfully sent 1042022SN/A retryList.push_back(interfaces[pkt->getSrc()]); 1055222Sksewell@umich.edu return false; 1065222Sksewell@umich.edu} 1075222Sksewell@umich.edu 1085222Sksewell@umich.eduvoid 10910474Sandreas.hansson@arm.comBus::recvRetry(int id) 1105222Sksewell@umich.edu{ 1115222Sksewell@umich.edu // Go through all the elements on the list calling sendRetry on each 1125222Sksewell@umich.edu // This is not very efficient at all but it works. Ultimately we should end 1135222Sksewell@umich.edu // up with something that is more intelligent. 1145222Sksewell@umich.edu int initialSize = retryList.size(); 1155222Sksewell@umich.edu 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