xbar.cc revision 2665
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 Definition of a bus object. 33 */ 34 35 36#include "base/trace.hh" 37#include "mem/bus.hh" 38#include "sim/builder.hh" 39 40Port * 41Bus::getPort(const std::string &if_name) 42{ 43 // if_name ignored? forced to be empty? 44 int id = interfaces.size(); 45 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 46 interfaces.push_back(bp); 47 return bp; 48} 49 50/** Get the ranges of anyone that we are connected to. */ 51void 52Bus::init() 53{ 54 std::vector<Port*>::iterator intIter; 55 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 56 (*intIter)->sendStatusChange(Port::RangeChange); 57} 58 59 60/** Function called by the port when the bus is receiving a Timing 61 * transaction.*/ 62bool 63Bus::recvTiming(Packet *pkt) 64{ 65 Port *port; 66 DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 67 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 68 69 short dest = pkt->getDest(); 70 if (dest == Packet::Broadcast) { 71 port = findPort(pkt->getAddr(), pkt->getSrc()); 72 } else { 73 assert(dest >= 0 && dest < interfaces.size()); 74 assert(dest != pkt->getSrc()); // catch infinite loops 75 port = interfaces[dest]; 76 } 77 if (port->sendTiming(pkt)) { 78 // packet was successfully sent, just return true. 79 return true; 80 } 81 82 // packet not successfully sent 83 retryList.push_back(interfaces[pkt->getSrc()]); 84 return false; 85} 86 87void 88Bus::recvRetry(int id) 89{ 90 // Go through all the elements on the list calling sendRetry on each 91 // This is not very efficient at all but it works. Ultimately we should end 92 // up with something that is more intelligent. 93 int initialSize = retryList.size(); 94 int i; 95 Port *p; 96 97 for (i = 0; i < initialSize; i++) { 98 assert(retryList.size() > 0); 99 p = retryList.front(); 100 retryList.pop_front(); 101 p->sendRetry(); 102 } 103} 104 105 106Port * 107Bus::findPort(Addr addr, int id) 108{ 109 /* An interval tree would be a better way to do this. --ali. */ 110 int dest_id = -1; 111 int i = 0; 112 bool found = false; 113 114 while (i < portList.size() && !found) 115 { 116 if (portList[i].range == addr) { 117 dest_id = portList[i].portId; 118 found = true; 119 DPRINTF(Bus, " found addr 0x%llx on device %d\n", addr, dest_id); 120 } 121 i++; 122 } 123 if (dest_id == -1) 124 panic("Unable to find destination for addr: %llx", addr); 125 126 // we shouldn't be sending this back to where it came from 127 assert(dest_id != id); 128 129 return interfaces[dest_id]; 130} 131 132/** Function called by the port when the bus is receiving a Atomic 133 * transaction.*/ 134Tick 135Bus::recvAtomic(Packet *pkt) 136{ 137 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 138 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 139 assert(pkt->getDest() == Packet::Broadcast); 140 return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); 141} 142 143/** Function called by the port when the bus is receiving a Functional 144 * transaction.*/ 145void 146Bus::recvFunctional(Packet *pkt) 147{ 148 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 149 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 150 assert(pkt->getDest() == Packet::Broadcast); 151 findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); 152} 153 154/** Function called by the port when the bus is receiving a status change.*/ 155void 156Bus::recvStatusChange(Port::Status status, int id) 157{ 158 assert(status == Port::RangeChange && 159 "The other statuses need to be implemented."); 160 161 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 162 163 assert(id < interfaces.size() && id >= 0); 164 int x; 165 Port *port = interfaces[id]; 166 AddrRangeList ranges; 167 AddrRangeList snoops; 168 AddrRangeIter iter; 169 std::vector<DevMap>::iterator portIter; 170 171 // Clean out any previously existent ids 172 for (portIter = portList.begin(); portIter != portList.end(); ) { 173 if (portIter->portId == id) 174 portIter = portList.erase(portIter); 175 else 176 portIter++; 177 } 178 179 port->getPeerAddressRanges(ranges, snoops); 180 181 // not dealing with snooping yet either 182 assert(snoops.size() == 0); 183 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 184 DevMap dm; 185 dm.portId = id; 186 dm.range = *iter; 187 188 DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n", 189 dm.range.start, dm.range.end, id); 190 portList.push_back(dm); 191 } 192 DPRINTF(MMU, "port list has %d entries\n", portList.size()); 193 194 // tell all our peers that our address range has changed. 195 // Don't tell the device that caused this change, it already knows 196 for (x = 0; x < interfaces.size(); x++) 197 if (x != id) 198 interfaces[x]->sendStatusChange(Port::RangeChange); 199} 200 201void 202Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) 203{ 204 std::vector<DevMap>::iterator portIter; 205 206 resp.clear(); 207 snoop.clear(); 208 209 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 210 for (portIter = portList.begin(); portIter != portList.end(); portIter++) { 211 if (portIter->portId != id) { 212 resp.push_back(portIter->range); 213 DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n", 214 portIter->range.start, portIter->range.end); 215 } 216 } 217} 218 219BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 220 221 Param<int> bus_id; 222 223END_DECLARE_SIM_OBJECT_PARAMS(Bus) 224 225BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 226 INIT_PARAM(bus_id, "a globally unique bus id") 227END_INIT_SIM_OBJECT_PARAMS(Bus) 228 229CREATE_SIM_OBJECT(Bus) 230{ 231 return new Bus(getInstanceName(), bus_id); 232} 233 234REGISTER_SIM_OBJECT("Bus", Bus) 235