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