xbar.cc revision 2846
15132Sgblack@eecs.umich.edu/* 25132Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 35132Sgblack@eecs.umich.edu * All rights reserved. 45132Sgblack@eecs.umich.edu * 57087Snate@binkert.org * Redistribution and use in source and binary forms, with or without 67087Snate@binkert.org * modification, are permitted provided that the following conditions are 77087Snate@binkert.org * met: redistributions of source code must retain the above copyright 87087Snate@binkert.org * notice, this list of conditions and the following disclaimer; 97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright 107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 117087Snate@binkert.org * documentation and/or other materials provided with the distribution; 127087Snate@binkert.org * neither the name of the copyright holders nor the names of its 135132Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147087Snate@binkert.org * this software without specific prior written permission. 157087Snate@binkert.org * 167087Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177087Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187087Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197087Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207087Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217087Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225132Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237087Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245132Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255132Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265132Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275132Sgblack@eecs.umich.edu * 285132Sgblack@eecs.umich.edu * Authors: Ali Saidi 295132Sgblack@eecs.umich.edu */ 305132Sgblack@eecs.umich.edu 315132Sgblack@eecs.umich.edu/** 325132Sgblack@eecs.umich.edu * @file Definition of a bus object. 335132Sgblack@eecs.umich.edu */ 345132Sgblack@eecs.umich.edu 355132Sgblack@eecs.umich.edu 365132Sgblack@eecs.umich.edu#include "base/misc.hh" 375132Sgblack@eecs.umich.edu#include "base/trace.hh" 385132Sgblack@eecs.umich.edu#include "mem/bus.hh" 395132Sgblack@eecs.umich.edu#include "sim/builder.hh" 405132Sgblack@eecs.umich.edu 415132Sgblack@eecs.umich.eduPort * 425132Sgblack@eecs.umich.eduBus::getPort(const std::string &if_name, int idx) 435132Sgblack@eecs.umich.edu{ 445132Sgblack@eecs.umich.edu if (if_name == "default") 455132Sgblack@eecs.umich.edu if (defaultPort == NULL) { 465132Sgblack@eecs.umich.edu defaultPort = new BusPort(csprintf("%s-default",name()), this, 475132Sgblack@eecs.umich.edu defaultId); 485132Sgblack@eecs.umich.edu return defaultPort; 495132Sgblack@eecs.umich.edu } else 505132Sgblack@eecs.umich.edu fatal("Default port already set\n"); 515132Sgblack@eecs.umich.edu 525132Sgblack@eecs.umich.edu // if_name ignored? forced to be empty? 535334Sgblack@eecs.umich.edu int id = interfaces.size(); 545334Sgblack@eecs.umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 555334Sgblack@eecs.umich.edu interfaces.push_back(bp); 565334Sgblack@eecs.umich.edu return bp; 575334Sgblack@eecs.umich.edu} 585334Sgblack@eecs.umich.edu 595625Sgblack@eecs.umich.edu/** Get the ranges of anyone other buses that we are connected to. */ 605625Sgblack@eecs.umich.eduvoid 615625Sgblack@eecs.umich.eduBus::init() 625625Sgblack@eecs.umich.edu{ 635625Sgblack@eecs.umich.edu std::vector<Port*>::iterator intIter; 645334Sgblack@eecs.umich.edu 655334Sgblack@eecs.umich.edu for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 665132Sgblack@eecs.umich.edu (*intIter)->sendStatusChange(Port::RangeChange); 675132Sgblack@eecs.umich.edu} 685132Sgblack@eecs.umich.edu 695132Sgblack@eecs.umich.edu 705132Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a Timing 715132Sgblack@eecs.umich.edu * transaction.*/ 725132Sgblack@eecs.umich.edubool 735132Sgblack@eecs.umich.eduBus::recvTiming(Packet *pkt) 745132Sgblack@eecs.umich.edu{ 755132Sgblack@eecs.umich.edu Port *port; 765132Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 775299Sgblack@eecs.umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 785299Sgblack@eecs.umich.edu 795299Sgblack@eecs.umich.edu short dest = pkt->getDest(); 807532Ssteve.reinhardt@amd.com if (dest == Packet::Broadcast) { 815132Sgblack@eecs.umich.edu port = findPort(pkt->getAddr(), pkt->getSrc()); 825132Sgblack@eecs.umich.edu } else { 835334Sgblack@eecs.umich.edu assert(dest >= 0 && dest < interfaces.size()); 845334Sgblack@eecs.umich.edu assert(dest != pkt->getSrc()); // catch infinite loops 855625Sgblack@eecs.umich.edu port = interfaces[dest]; 865625Sgblack@eecs.umich.edu } 875627Sgblack@eecs.umich.edu if (port->sendTiming(pkt)) { 885334Sgblack@eecs.umich.edu // packet was successfully sent, just return true. 895615Sgblack@eecs.umich.edu return true; 905615Sgblack@eecs.umich.edu } 915334Sgblack@eecs.umich.edu 925625Sgblack@eecs.umich.edu // packet not successfully sent 935625Sgblack@eecs.umich.edu retryList.push_back(interfaces[pkt->getSrc()]); 945625Sgblack@eecs.umich.edu return false; 955132Sgblack@eecs.umich.edu} 965132Sgblack@eecs.umich.edu 975132Sgblack@eecs.umich.eduvoid 985132Sgblack@eecs.umich.eduBus::recvRetry(int id) 995132Sgblack@eecs.umich.edu{ 1005132Sgblack@eecs.umich.edu // Go through all the elements on the list calling sendRetry on each 1015132Sgblack@eecs.umich.edu // This is not very efficient at all but it works. Ultimately we should end 1025132Sgblack@eecs.umich.edu // up with something that is more intelligent. 1035132Sgblack@eecs.umich.edu int initialSize = retryList.size(); 1045132Sgblack@eecs.umich.edu int i; 1055132Sgblack@eecs.umich.edu Port *p; 106 107 for (i = 0; i < initialSize; i++) { 108 assert(retryList.size() > 0); 109 p = retryList.front(); 110 retryList.pop_front(); 111 p->sendRetry(); 112 } 113} 114 115 116Port * 117Bus::findPort(Addr addr, int id) 118{ 119 /* An interval tree would be a better way to do this. --ali. */ 120 int dest_id = -1; 121 int i = 0; 122 bool found = false; 123 AddrRangeIter iter; 124 125 while (i < portList.size() && !found) 126 { 127 if (portList[i].range == addr) { 128 dest_id = portList[i].portId; 129 found = true; 130 DPRINTF(Bus, " found addr 0x%llx on device %d\n", addr, dest_id); 131 } 132 i++; 133 } 134 135 // Check if this matches the default range 136 if (dest_id == -1) { 137 for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) { 138 if (*iter == addr) { 139 DPRINTF(Bus, " found addr 0x%llx on default\n", addr); 140 return defaultPort; 141 } 142 } 143 panic("Unable to find destination for addr: %llx", addr); 144 } 145 146 147 // we shouldn't be sending this back to where it came from 148 assert(dest_id != id); 149 150 return interfaces[dest_id]; 151} 152 153/** Function called by the port when the bus is receiving a Atomic 154 * transaction.*/ 155Tick 156Bus::recvAtomic(Packet *pkt) 157{ 158 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 159 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 160 assert(pkt->getDest() == Packet::Broadcast); 161 return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); 162} 163 164/** Function called by the port when the bus is receiving a Functional 165 * transaction.*/ 166void 167Bus::recvFunctional(Packet *pkt) 168{ 169 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 170 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 171 assert(pkt->getDest() == Packet::Broadcast); 172 findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); 173} 174 175/** Function called by the port when the bus is receiving a status change.*/ 176void 177Bus::recvStatusChange(Port::Status status, int id) 178{ 179 AddrRangeList ranges; 180 AddrRangeList snoops; 181 int x; 182 AddrRangeIter iter; 183 184 assert(status == Port::RangeChange && 185 "The other statuses need to be implemented."); 186 187 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 188 189 if (id == defaultId) { 190 defaultRange.clear(); 191 defaultPort->getPeerAddressRanges(ranges, snoops); 192 assert(snoops.size() == 0); 193 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 194 defaultRange.push_back(*iter); 195 DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default\n", 196 iter->start, iter->end); 197 } 198 } else { 199 200 assert((id < interfaces.size() && id >= 0) || id == -1); 201 Port *port = interfaces[id]; 202 std::vector<DevMap>::iterator portIter; 203 204 // Clean out any previously existent ids 205 for (portIter = portList.begin(); portIter != portList.end(); ) { 206 if (portIter->portId == id) 207 portIter = portList.erase(portIter); 208 else 209 portIter++; 210 } 211 212 port->getPeerAddressRanges(ranges, snoops); 213 214 // not dealing with snooping yet either 215 assert(snoops.size() == 0); 216 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 217 DevMap dm; 218 dm.portId = id; 219 dm.range = *iter; 220 221 DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n", 222 dm.range.start, dm.range.end, id); 223 portList.push_back(dm); 224 } 225 } 226 DPRINTF(MMU, "port list has %d entries\n", portList.size()); 227 228 // tell all our peers that our address range has changed. 229 // Don't tell the device that caused this change, it already knows 230 for (x = 0; x < interfaces.size(); x++) 231 if (x != id) 232 interfaces[x]->sendStatusChange(Port::RangeChange); 233 234 if (id != defaultId && defaultPort) 235 defaultPort->sendStatusChange(Port::RangeChange); 236} 237 238void 239Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) 240{ 241 std::vector<DevMap>::iterator portIter; 242 AddrRangeIter dflt_iter; 243 bool subset; 244 245 resp.clear(); 246 snoop.clear(); 247 248 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 249 250 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 251 dflt_iter++) { 252 resp.push_back(*dflt_iter); 253 DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",dflt_iter->start, 254 dflt_iter->end); 255 } 256 for (portIter = portList.begin(); portIter != portList.end(); portIter++) { 257 subset = false; 258 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 259 dflt_iter++) { 260 if ((portIter->range.start < dflt_iter->start && 261 portIter->range.end >= dflt_iter->start) || 262 (portIter->range.start < dflt_iter->end && 263 portIter->range.end >= dflt_iter->end)) 264 fatal("Devices can not set ranges that itersect the default set\ 265 but are not a subset of the default set.\n"); 266 if (portIter->range.start >= dflt_iter->start && 267 portIter->range.end <= dflt_iter->end) { 268 subset = true; 269 DPRINTF(BusAddrRanges, " -- %#llX : %#llX is a SUBSET\n", 270 portIter->range.start, portIter->range.end); 271 } 272 } 273 if (portIter->portId != id && !subset) { 274 resp.push_back(portIter->range); 275 DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n", 276 portIter->range.start, portIter->range.end); 277 } 278 } 279} 280 281BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 282 283 Param<int> bus_id; 284 285END_DECLARE_SIM_OBJECT_PARAMS(Bus) 286 287BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 288 INIT_PARAM(bus_id, "a globally unique bus id") 289END_INIT_SIM_OBJECT_PARAMS(Bus) 290 291CREATE_SIM_OBJECT(Bus) 292{ 293 return new Bus(getInstanceName(), bus_id); 294} 295 296REGISTER_SIM_OBJECT("Bus", Bus) 297