coherent_xbar.cc revision 8975
15647Sgblack@eecs.umich.edu/* 25647Sgblack@eecs.umich.edu * Copyright (c) 2011-2012 ARM Limited 35647Sgblack@eecs.umich.edu * All rights reserved 45647Sgblack@eecs.umich.edu * 55647Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 65647Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 75647Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 85647Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 95647Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 105647Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 115647Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 125647Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 135647Sgblack@eecs.umich.edu * 145647Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 155647Sgblack@eecs.umich.edu * All rights reserved. 165647Sgblack@eecs.umich.edu * 175647Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 185647Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 195647Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 205647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 215647Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 225647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 235647Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 245647Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 255647Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 265647Sgblack@eecs.umich.edu * this software without specific prior written permission. 275647Sgblack@eecs.umich.edu * 285647Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 295647Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305647Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 315647Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 325647Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 335647Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 345647Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 355647Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 365647Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 375647Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 385647Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 395647Sgblack@eecs.umich.edu * 405647Sgblack@eecs.umich.edu * Authors: Ali Saidi 415647Sgblack@eecs.umich.edu * Andreas Hansson 425647Sgblack@eecs.umich.edu * William Wang 435647Sgblack@eecs.umich.edu */ 445647Sgblack@eecs.umich.edu 455647Sgblack@eecs.umich.edu/** 465647Sgblack@eecs.umich.edu * @file 475647Sgblack@eecs.umich.edu * Definition of a bus object. 485647Sgblack@eecs.umich.edu */ 495647Sgblack@eecs.umich.edu 505647Sgblack@eecs.umich.edu#include "base/misc.hh" 515647Sgblack@eecs.umich.edu#include "base/trace.hh" 525647Sgblack@eecs.umich.edu#include "debug/Bus.hh" 535647Sgblack@eecs.umich.edu#include "debug/BusAddrRanges.hh" 545647Sgblack@eecs.umich.edu#include "mem/bus.hh" 555647Sgblack@eecs.umich.edu 565647Sgblack@eecs.umich.eduBus::Bus(const BusParams *p) 575647Sgblack@eecs.umich.edu : MemObject(p), clock(p->clock), 585648Sgblack@eecs.umich.edu headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 595647Sgblack@eecs.umich.edu drainEvent(NULL), busIdleEvent(this), inRetry(false), 605654Sgblack@eecs.umich.edu defaultPortId(Port::INVALID_PORT_ID), 615647Sgblack@eecs.umich.edu useDefaultRange(p->use_default_range), 625654Sgblack@eecs.umich.edu defaultBlockSize(p->block_size), 636046Sgblack@eecs.umich.edu cachedBlockSize(0), cachedBlockSizeValid(false) 645647Sgblack@eecs.umich.edu{ 655648Sgblack@eecs.umich.edu //width, clock period, and header cycles must be positive 665648Sgblack@eecs.umich.edu if (width <= 0) 675647Sgblack@eecs.umich.edu fatal("Bus width must be positive\n"); 685647Sgblack@eecs.umich.edu if (clock <= 0) 695647Sgblack@eecs.umich.edu fatal("Bus clock period must be positive\n"); 705647Sgblack@eecs.umich.edu if (headerCycles <= 0) 715647Sgblack@eecs.umich.edu fatal("Number of header cycles must be positive\n"); 725647Sgblack@eecs.umich.edu 735647Sgblack@eecs.umich.edu // create the ports based on the size of the master and slave 745647Sgblack@eecs.umich.edu // vector ports, and the presence of the default port, the ports 755647Sgblack@eecs.umich.edu // are enumerated starting from zero 765648Sgblack@eecs.umich.edu for (int i = 0; i < p->port_master_connection_count; ++i) { 775647Sgblack@eecs.umich.edu std::string portName = csprintf("%s-p%d", name(), i); 785648Sgblack@eecs.umich.edu MasterPort* bp = new BusMasterPort(portName, this, i); 795648Sgblack@eecs.umich.edu masterPorts.push_back(bp); 805648Sgblack@eecs.umich.edu } 815648Sgblack@eecs.umich.edu 825648Sgblack@eecs.umich.edu // see if we have a default slave device connected and if so add 835648Sgblack@eecs.umich.edu // our corresponding master port 845648Sgblack@eecs.umich.edu if (p->port_default_connection_count) { 855648Sgblack@eecs.umich.edu defaultPortId = masterPorts.size(); 865648Sgblack@eecs.umich.edu std::string portName = csprintf("%s-default", name()); 875648Sgblack@eecs.umich.edu MasterPort* bp = new BusMasterPort(portName, this, defaultPortId); 885648Sgblack@eecs.umich.edu masterPorts.push_back(bp); 895648Sgblack@eecs.umich.edu } 905648Sgblack@eecs.umich.edu 915648Sgblack@eecs.umich.edu // create the slave ports, once again starting at zero 925648Sgblack@eecs.umich.edu for (int i = 0; i < p->port_slave_connection_count; ++i) { 935648Sgblack@eecs.umich.edu std::string portName = csprintf("%s-p%d", name(), i); 945648Sgblack@eecs.umich.edu SlavePort* bp = new BusSlavePort(portName, this, i); 955648Sgblack@eecs.umich.edu slavePorts.push_back(bp); 965648Sgblack@eecs.umich.edu } 975648Sgblack@eecs.umich.edu 985648Sgblack@eecs.umich.edu clearPortCache(); 995648Sgblack@eecs.umich.edu} 1005648Sgblack@eecs.umich.edu 1015648Sgblack@eecs.umich.eduMasterPort & 1025648Sgblack@eecs.umich.eduBus::getMasterPort(const std::string &if_name, int idx) 1035648Sgblack@eecs.umich.edu{ 1045648Sgblack@eecs.umich.edu if (if_name == "master" && idx < masterPorts.size()) { 1055648Sgblack@eecs.umich.edu // the master port index translates directly to the vector position 1065648Sgblack@eecs.umich.edu return *masterPorts[idx]; 1075648Sgblack@eecs.umich.edu } else if (if_name == "default") { 1085648Sgblack@eecs.umich.edu return *masterPorts[defaultPortId]; 1095648Sgblack@eecs.umich.edu } else { 1105648Sgblack@eecs.umich.edu return MemObject::getMasterPort(if_name, idx); 1115648Sgblack@eecs.umich.edu } 1125648Sgblack@eecs.umich.edu} 1135648Sgblack@eecs.umich.edu 1145648Sgblack@eecs.umich.eduSlavePort & 1155648Sgblack@eecs.umich.eduBus::getSlavePort(const std::string &if_name, int idx) 1165648Sgblack@eecs.umich.edu{ 1175648Sgblack@eecs.umich.edu if (if_name == "slave" && idx < slavePorts.size()) { 1185648Sgblack@eecs.umich.edu // the slave port index translates directly to the vector position 1195648Sgblack@eecs.umich.edu return *slavePorts[idx]; 1205648Sgblack@eecs.umich.edu } else { 1215648Sgblack@eecs.umich.edu return MemObject::getSlavePort(if_name, idx); 1225648Sgblack@eecs.umich.edu } 1235648Sgblack@eecs.umich.edu} 1245648Sgblack@eecs.umich.edu 1255648Sgblack@eecs.umich.eduvoid 1265648Sgblack@eecs.umich.eduBus::init() 1275648Sgblack@eecs.umich.edu{ 1285648Sgblack@eecs.umich.edu // iterate over our slave ports and determine which of our 1295648Sgblack@eecs.umich.edu // neighbouring master ports are snooping and add them as snoopers 1305648Sgblack@eecs.umich.edu for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 1315648Sgblack@eecs.umich.edu ++p) { 1325648Sgblack@eecs.umich.edu if ((*p)->getMasterPort().isSnooping()) { 1335648Sgblack@eecs.umich.edu DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", 1345648Sgblack@eecs.umich.edu (*p)->getMasterPort().name()); 1355648Sgblack@eecs.umich.edu snoopPorts.push_back(*p); 1365648Sgblack@eecs.umich.edu } 1375648Sgblack@eecs.umich.edu } 1385648Sgblack@eecs.umich.edu} 1395648Sgblack@eecs.umich.edu 1405648Sgblack@eecs.umich.eduTick 1415648Sgblack@eecs.umich.eduBus::calcPacketTiming(PacketPtr pkt) 1425648Sgblack@eecs.umich.edu{ 1435648Sgblack@eecs.umich.edu // determine the current time rounded to the closest following 1445648Sgblack@eecs.umich.edu // clock edge 1455648Sgblack@eecs.umich.edu Tick now = curTick(); 1465648Sgblack@eecs.umich.edu if (now % clock != 0) { 1475648Sgblack@eecs.umich.edu now = ((now / clock) + 1) * clock; 1485648Sgblack@eecs.umich.edu } 1495648Sgblack@eecs.umich.edu 1505648Sgblack@eecs.umich.edu Tick headerTime = now + headerCycles * clock; 1515648Sgblack@eecs.umich.edu 1525648Sgblack@eecs.umich.edu // The packet will be sent. Figure out how long it occupies the bus, and 1535648Sgblack@eecs.umich.edu // how much of that time is for the first "word", aka bus width. 1545648Sgblack@eecs.umich.edu int numCycles = 0; 1555648Sgblack@eecs.umich.edu if (pkt->hasData()) { 1565648Sgblack@eecs.umich.edu // If a packet has data, it needs ceil(size/width) cycles to send it 1575648Sgblack@eecs.umich.edu int dataSize = pkt->getSize(); 1585648Sgblack@eecs.umich.edu numCycles += dataSize/width; 1595648Sgblack@eecs.umich.edu if (dataSize % width) 1605648Sgblack@eecs.umich.edu numCycles++; 1615648Sgblack@eecs.umich.edu } 1625648Sgblack@eecs.umich.edu 1635648Sgblack@eecs.umich.edu // The first word will be delivered after the current tick, the delivery 1645648Sgblack@eecs.umich.edu // of the address if any, and one bus cycle to deliver the data 1655648Sgblack@eecs.umich.edu pkt->firstWordTime = headerTime + clock; 1665648Sgblack@eecs.umich.edu 1675648Sgblack@eecs.umich.edu pkt->finishTime = headerTime + numCycles * clock; 1685648Sgblack@eecs.umich.edu 1695648Sgblack@eecs.umich.edu return headerTime; 1705648Sgblack@eecs.umich.edu} 1715648Sgblack@eecs.umich.edu 1725648Sgblack@eecs.umich.eduvoid Bus::occupyBus(Tick until) 1735648Sgblack@eecs.umich.edu{ 1745648Sgblack@eecs.umich.edu if (until == 0) { 1755648Sgblack@eecs.umich.edu // shortcut for express snoop packets 1765648Sgblack@eecs.umich.edu return; 1775648Sgblack@eecs.umich.edu } 1785648Sgblack@eecs.umich.edu 1795648Sgblack@eecs.umich.edu tickNextIdle = until; 1805648Sgblack@eecs.umich.edu reschedule(busIdleEvent, tickNextIdle, true); 1815648Sgblack@eecs.umich.edu 1825648Sgblack@eecs.umich.edu DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1835648Sgblack@eecs.umich.edu curTick(), tickNextIdle); 1845648Sgblack@eecs.umich.edu} 1855648Sgblack@eecs.umich.edu 1865648Sgblack@eecs.umich.edubool 1875648Sgblack@eecs.umich.eduBus::isOccupied(PacketPtr pkt, Port* port) 1885648Sgblack@eecs.umich.edu{ 1895648Sgblack@eecs.umich.edu // first we see if the next idle tick is in the future, next the 1905648Sgblack@eecs.umich.edu // bus is considered occupied if there are ports on the retry list 1915648Sgblack@eecs.umich.edu // and we are not in a retry with the current port 1925648Sgblack@eecs.umich.edu if (tickNextIdle > curTick() || 1935648Sgblack@eecs.umich.edu (!retryList.empty() && !(inRetry && port == retryList.front()))) { 1945648Sgblack@eecs.umich.edu addToRetryList(port); 1955648Sgblack@eecs.umich.edu return true; 1965648Sgblack@eecs.umich.edu } 1975648Sgblack@eecs.umich.edu return false; 1985648Sgblack@eecs.umich.edu} 1995648Sgblack@eecs.umich.edu 2005648Sgblack@eecs.umich.edubool 2015648Sgblack@eecs.umich.eduBus::recvTimingReq(PacketPtr pkt) 2025648Sgblack@eecs.umich.edu{ 2035648Sgblack@eecs.umich.edu // determine the source port based on the id 2045648Sgblack@eecs.umich.edu SlavePort *src_port = slavePorts[pkt->getSrc()]; 2055648Sgblack@eecs.umich.edu 2065648Sgblack@eecs.umich.edu // test if the bus should be considered occupied for the current 2075648Sgblack@eecs.umich.edu // packet, and exclude express snoops from the check 2085648Sgblack@eecs.umich.edu if (!pkt->isExpressSnoop() && isOccupied(pkt, src_port)) { 2095648Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x BUSY\n", 2105648Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 2115648Sgblack@eecs.umich.edu return false; 2125648Sgblack@eecs.umich.edu } 2135648Sgblack@eecs.umich.edu 2145648Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x\n", 2155648Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 2165648Sgblack@eecs.umich.edu 2175648Sgblack@eecs.umich.edu Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); 2185648Sgblack@eecs.umich.edu Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; 2195648Sgblack@eecs.umich.edu 2205648Sgblack@eecs.umich.edu // the packet is a memory-mapped request and should be 2215649Sgblack@eecs.umich.edu // broadcasted to our snoopers but the source 2225649Sgblack@eecs.umich.edu forwardTiming(pkt, pkt->getSrc()); 2235649Sgblack@eecs.umich.edu 2245648Sgblack@eecs.umich.edu // remember if we add an outstanding req so we can undo it if 2255898Sgblack@eecs.umich.edu // necessary, if the packet needs a response, we should add it 2265648Sgblack@eecs.umich.edu // as outstanding and express snoops never fail so there is 2275648Sgblack@eecs.umich.edu // not need to worry about them 2285648Sgblack@eecs.umich.edu bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse(); 2295648Sgblack@eecs.umich.edu 2305648Sgblack@eecs.umich.edu // keep track that we have an outstanding request packet 2315648Sgblack@eecs.umich.edu // matching this request, this is used by the coherency 2325648Sgblack@eecs.umich.edu // mechanism in determining what to do with snoop responses 2335648Sgblack@eecs.umich.edu // (in recvTimingSnoop) 2345648Sgblack@eecs.umich.edu if (add_outstanding) { 2355648Sgblack@eecs.umich.edu // we should never have an exsiting request outstanding 2365648Sgblack@eecs.umich.edu assert(outstandingReq.find(pkt->req) == outstandingReq.end()); 2375648Sgblack@eecs.umich.edu outstandingReq.insert(pkt->req); 2385648Sgblack@eecs.umich.edu } 2395649Sgblack@eecs.umich.edu 2405649Sgblack@eecs.umich.edu // since it is a normal request, determine the destination 2415649Sgblack@eecs.umich.edu // based on the address and attempt to send the packet 2425648Sgblack@eecs.umich.edu bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); 2435898Sgblack@eecs.umich.edu 2445648Sgblack@eecs.umich.edu if (!success) { 2455647Sgblack@eecs.umich.edu // inhibited packets should never be forced to retry 2465691Sgblack@eecs.umich.edu assert(!pkt->memInhibitAsserted()); 2475691Sgblack@eecs.umich.edu 2485691Sgblack@eecs.umich.edu // if it was added as outstanding and the send failed, then 2495691Sgblack@eecs.umich.edu // erase it again 2505691Sgblack@eecs.umich.edu if (add_outstanding) 2515691Sgblack@eecs.umich.edu outstandingReq.erase(pkt->req); 2525691Sgblack@eecs.umich.edu 2535691Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingReq: src %s %s 0x%x RETRY\n", 2545691Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 2555691Sgblack@eecs.umich.edu 2565691Sgblack@eecs.umich.edu addToRetryList(src_port); 2575691Sgblack@eecs.umich.edu occupyBus(headerFinishTime); 2585691Sgblack@eecs.umich.edu 2595691Sgblack@eecs.umich.edu return false; 2605691Sgblack@eecs.umich.edu } 2615691Sgblack@eecs.umich.edu 2625691Sgblack@eecs.umich.edu succeededTiming(packetFinishTime); 2635691Sgblack@eecs.umich.edu 2645691Sgblack@eecs.umich.edu return true; 2655691Sgblack@eecs.umich.edu} 2665691Sgblack@eecs.umich.edu 2675691Sgblack@eecs.umich.edubool 2685691Sgblack@eecs.umich.eduBus::recvTimingResp(PacketPtr pkt) 2695691Sgblack@eecs.umich.edu{ 2705691Sgblack@eecs.umich.edu // determine the source port based on the id 2715691Sgblack@eecs.umich.edu MasterPort *src_port = masterPorts[pkt->getSrc()]; 2725691Sgblack@eecs.umich.edu 2735691Sgblack@eecs.umich.edu // test if the bus should be considered occupied for the current 2745691Sgblack@eecs.umich.edu // packet 2755691Sgblack@eecs.umich.edu if (isOccupied(pkt, src_port)) { 2765691Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x BUSY\n", 2775691Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 2785691Sgblack@eecs.umich.edu return false; 2795691Sgblack@eecs.umich.edu } 2805691Sgblack@eecs.umich.edu 2815691Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingResp: src %s %s 0x%x\n", 2825691Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 2835691Sgblack@eecs.umich.edu 2845691Sgblack@eecs.umich.edu calcPacketTiming(pkt); 2855691Sgblack@eecs.umich.edu Tick packetFinishTime = pkt->finishTime; 2865691Sgblack@eecs.umich.edu 2875811Sgblack@eecs.umich.edu // the packet is a normal response to a request that we should 2885691Sgblack@eecs.umich.edu // have seen passing through the bus 2895647Sgblack@eecs.umich.edu assert(outstandingReq.find(pkt->req) != outstandingReq.end()); 2906041Sgblack@eecs.umich.edu 2916041Sgblack@eecs.umich.edu // remove it as outstanding 2926041Sgblack@eecs.umich.edu outstandingReq.erase(pkt->req); 2936041Sgblack@eecs.umich.edu 2946041Sgblack@eecs.umich.edu // send the packet to the destination through one of our slave 2956041Sgblack@eecs.umich.edu // ports, as determined by the destination field 2966041Sgblack@eecs.umich.edu bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); 2976041Sgblack@eecs.umich.edu 2986041Sgblack@eecs.umich.edu // currently it is illegal to block responses... can lead to 2996041Sgblack@eecs.umich.edu // deadlock 3005651Sgblack@eecs.umich.edu assert(success); 3015651Sgblack@eecs.umich.edu 3025651Sgblack@eecs.umich.edu succeededTiming(packetFinishTime); 3036041Sgblack@eecs.umich.edu 3045654Sgblack@eecs.umich.edu return true; 3055651Sgblack@eecs.umich.edu} 3065651Sgblack@eecs.umich.edu 3075651Sgblack@eecs.umich.eduvoid 3085651Sgblack@eecs.umich.eduBus::recvTimingSnoopReq(PacketPtr pkt) 3095654Sgblack@eecs.umich.edu{ 3105654Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingSnoopReq: src %s %s 0x%x\n", 3115654Sgblack@eecs.umich.edu masterPorts[pkt->getSrc()]->name(), pkt->cmdString(), 3125654Sgblack@eecs.umich.edu pkt->getAddr()); 3135697Snate@binkert.org 3145654Sgblack@eecs.umich.edu // we should only see express snoops from caches 3155654Sgblack@eecs.umich.edu assert(pkt->isExpressSnoop()); 3165654Sgblack@eecs.umich.edu 3175655Sgblack@eecs.umich.edu // forward to all snoopers 3185691Sgblack@eecs.umich.edu forwardTiming(pkt, Port::INVALID_PORT_ID); 3195691Sgblack@eecs.umich.edu 3205654Sgblack@eecs.umich.edu // a snoop request came from a connected slave device (one of 3215651Sgblack@eecs.umich.edu // our master ports), and if it is not coming from the slave 3225651Sgblack@eecs.umich.edu // device responsible for the address range something is 3235651Sgblack@eecs.umich.edu // wrong, hence there is nothing further to do as the packet 3245651Sgblack@eecs.umich.edu // would be going back to where it came from 3255651Sgblack@eecs.umich.edu assert(pkt->getSrc() == findPort(pkt->getAddr())); 3265651Sgblack@eecs.umich.edu 3275651Sgblack@eecs.umich.edu // this is an express snoop and is never forced to retry 3285651Sgblack@eecs.umich.edu assert(!inRetry); 3295651Sgblack@eecs.umich.edu} 3305651Sgblack@eecs.umich.edu 3315651Sgblack@eecs.umich.edubool 3325651Sgblack@eecs.umich.eduBus::recvTimingSnoopResp(PacketPtr pkt) 3336041Sgblack@eecs.umich.edu{ 3346041Sgblack@eecs.umich.edu // determine the source port based on the id 3356041Sgblack@eecs.umich.edu SlavePort* src_port = slavePorts[pkt->getSrc()]; 3366041Sgblack@eecs.umich.edu 3376041Sgblack@eecs.umich.edu if (isOccupied(pkt, src_port)) { 3386041Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 3396041Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 3406041Sgblack@eecs.umich.edu return false; 3416041Sgblack@eecs.umich.edu } 3426041Sgblack@eecs.umich.edu 3436041Sgblack@eecs.umich.edu DPRINTF(Bus, "recvTimingSnoop: src %s %s 0x%x\n", 3446041Sgblack@eecs.umich.edu src_port->name(), pkt->cmdString(), pkt->getAddr()); 3456041Sgblack@eecs.umich.edu 3466041Sgblack@eecs.umich.edu // get the destination from the packet 3476041Sgblack@eecs.umich.edu Packet::NodeID dest = pkt->getDest(); 3486041Sgblack@eecs.umich.edu 3496041Sgblack@eecs.umich.edu // responses are never express snoops 3506041Sgblack@eecs.umich.edu assert(!pkt->isExpressSnoop()); 3516041Sgblack@eecs.umich.edu 3526041Sgblack@eecs.umich.edu calcPacketTiming(pkt); 3535647Sgblack@eecs.umich.edu Tick packetFinishTime = pkt->finishTime; 3545648Sgblack@eecs.umich.edu 3555647Sgblack@eecs.umich.edu // determine if the response is from a snoop request we 3565647Sgblack@eecs.umich.edu // created as the result of a normal request (in which case it 3575647Sgblack@eecs.umich.edu // should be in the outstandingReq), or if we merely forwarded 3585647Sgblack@eecs.umich.edu // someone else's snoop request 3595647Sgblack@eecs.umich.edu if (outstandingReq.find(pkt->req) == outstandingReq.end()) { 3605647Sgblack@eecs.umich.edu // this is a snoop response to a snoop request we 3615647Sgblack@eecs.umich.edu // forwarded, e.g. coming from the L1 and going to the L2 3625647Sgblack@eecs.umich.edu // this should be forwarded as a snoop response 3635647Sgblack@eecs.umich.edu bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt); 3645647Sgblack@eecs.umich.edu assert(success); 3655647Sgblack@eecs.umich.edu } else { 3665647Sgblack@eecs.umich.edu // we got a snoop response on one of our slave ports, 3675647Sgblack@eecs.umich.edu // i.e. from a coherent master connected to the bus, and 3685647Sgblack@eecs.umich.edu // since we created the snoop request as part of 3695647Sgblack@eecs.umich.edu // recvTiming, this should now be a normal response again 3705647Sgblack@eecs.umich.edu outstandingReq.erase(pkt->req); 3715647Sgblack@eecs.umich.edu 3725848Sgblack@eecs.umich.edu // this is a snoop response from a coherent master, with a 3735848Sgblack@eecs.umich.edu // destination field set on its way through the bus as 3745848Sgblack@eecs.umich.edu // request, hence it should never go back to where the 3755848Sgblack@eecs.umich.edu // snoop response came from, but instead to where the 3765848Sgblack@eecs.umich.edu // original request came from 3775848Sgblack@eecs.umich.edu assert(pkt->getSrc() != dest); 3785848Sgblack@eecs.umich.edu 3795848Sgblack@eecs.umich.edu // as a normal response, it should go back to a master 3805848Sgblack@eecs.umich.edu // through one of our slave ports 3815848Sgblack@eecs.umich.edu bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt); 3825848Sgblack@eecs.umich.edu 3835848Sgblack@eecs.umich.edu // currently it is illegal to block responses... can lead 3845848Sgblack@eecs.umich.edu // to deadlock 3855647Sgblack@eecs.umich.edu assert(success); 3865647Sgblack@eecs.umich.edu } 3875647Sgblack@eecs.umich.edu 3885647Sgblack@eecs.umich.edu succeededTiming(packetFinishTime); 3895648Sgblack@eecs.umich.edu 3905647Sgblack@eecs.umich.edu return true; 3915647Sgblack@eecs.umich.edu} 3925647Sgblack@eecs.umich.edu 3935648Sgblack@eecs.umich.edu 3945647Sgblack@eecs.umich.eduvoid 3955647Sgblack@eecs.umich.eduBus::succeededTiming(Tick busy_time) 3965647Sgblack@eecs.umich.edu{ 3975647Sgblack@eecs.umich.edu // occupy the bus accordingly 3985647Sgblack@eecs.umich.edu occupyBus(busy_time); 3995647Sgblack@eecs.umich.edu 4005647Sgblack@eecs.umich.edu // if a retrying port succeeded, also take it off the retry list 4015647Sgblack@eecs.umich.edu if (inRetry) { 4025647Sgblack@eecs.umich.edu DPRINTF(Bus, "Remove retry from list %s\n", 4035647Sgblack@eecs.umich.edu retryList.front()->name()); 4045647Sgblack@eecs.umich.edu retryList.pop_front(); 4055647Sgblack@eecs.umich.edu inRetry = false; 4065647Sgblack@eecs.umich.edu } 4075647Sgblack@eecs.umich.edu} 4085647Sgblack@eecs.umich.edu 4095647Sgblack@eecs.umich.eduvoid 4105647Sgblack@eecs.umich.eduBus::forwardTiming(PacketPtr pkt, int exclude_slave_port_id) 4115647Sgblack@eecs.umich.edu{ 4125647Sgblack@eecs.umich.edu for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 4135647Sgblack@eecs.umich.edu SlavePort *p = *s; 4145647Sgblack@eecs.umich.edu // we could have gotten this request from a snooping master 4155647Sgblack@eecs.umich.edu // (corresponding to our own slave port that is also in 4165647Sgblack@eecs.umich.edu // snoopPorts) and should not send it back to where it came 4175647Sgblack@eecs.umich.edu // from 4185647Sgblack@eecs.umich.edu if (exclude_slave_port_id == Port::INVALID_PORT_ID || 4195647Sgblack@eecs.umich.edu p->getId() != exclude_slave_port_id) { 4205647Sgblack@eecs.umich.edu // cache is not allowed to refuse snoop 4215647Sgblack@eecs.umich.edu p->sendTimingSnoopReq(pkt); 4225647Sgblack@eecs.umich.edu } 4235647Sgblack@eecs.umich.edu } 4245647Sgblack@eecs.umich.edu} 4255647Sgblack@eecs.umich.edu 4265690Sgblack@eecs.umich.eduvoid 4275690Sgblack@eecs.umich.eduBus::releaseBus() 4285690Sgblack@eecs.umich.edu{ 4295690Sgblack@eecs.umich.edu // releasing the bus means we should now be idle 4305647Sgblack@eecs.umich.edu assert(curTick() >= tickNextIdle); 4315647Sgblack@eecs.umich.edu 4325647Sgblack@eecs.umich.edu // bus is now idle, so if someone is waiting we can retry 4335647Sgblack@eecs.umich.edu if (!retryList.empty()) { 4345647Sgblack@eecs.umich.edu // note that we block (return false on recvTiming) both 4355647Sgblack@eecs.umich.edu // because the bus is busy and because the destination is 4365647Sgblack@eecs.umich.edu // busy, and in the latter case the bus may be released before 4375647Sgblack@eecs.umich.edu // we see a retry from the destination 4385647Sgblack@eecs.umich.edu retryWaiting(); 4395647Sgblack@eecs.umich.edu } 4405647Sgblack@eecs.umich.edu 4415647Sgblack@eecs.umich.edu //If we weren't able to drain before, we might be able to now. 4425647Sgblack@eecs.umich.edu if (drainEvent && retryList.empty() && curTick() >= tickNextIdle) { 4435647Sgblack@eecs.umich.edu drainEvent->process(); 4445647Sgblack@eecs.umich.edu // Clear the drain event once we're done with it. 4455647Sgblack@eecs.umich.edu drainEvent = NULL; 4465647Sgblack@eecs.umich.edu } 4475647Sgblack@eecs.umich.edu} 4485647Sgblack@eecs.umich.edu 4495647Sgblack@eecs.umich.eduvoid 4505647Sgblack@eecs.umich.eduBus::retryWaiting() 4515647Sgblack@eecs.umich.edu{ 4525647Sgblack@eecs.umich.edu // this should never be called with an empty retry list 4535647Sgblack@eecs.umich.edu assert(!retryList.empty()); 4545647Sgblack@eecs.umich.edu 4556046Sgblack@eecs.umich.edu // send a retry to the port at the head of the retry list 4566046Sgblack@eecs.umich.edu inRetry = true; 4576046Sgblack@eecs.umich.edu 4586046Sgblack@eecs.umich.edu // note that we might have blocked on the receiving port being 4596046Sgblack@eecs.umich.edu // busy (rather than the bus itself) and now call retry before the 4606046Sgblack@eecs.umich.edu // destination called retry on the bus 4616046Sgblack@eecs.umich.edu retryList.front()->sendRetry(); 4626046Sgblack@eecs.umich.edu 4636046Sgblack@eecs.umich.edu // If inRetry is still true, sendTiming wasn't called in zero time 4646046Sgblack@eecs.umich.edu // (e.g. the cache does this) 4656046Sgblack@eecs.umich.edu if (inRetry) { 4666046Sgblack@eecs.umich.edu retryList.pop_front(); 4676046Sgblack@eecs.umich.edu inRetry = false; 4686046Sgblack@eecs.umich.edu 4696046Sgblack@eecs.umich.edu //Bring tickNextIdle up to the present 4706046Sgblack@eecs.umich.edu while (tickNextIdle < curTick()) 4716046Sgblack@eecs.umich.edu tickNextIdle += clock; 4726046Sgblack@eecs.umich.edu 4736046Sgblack@eecs.umich.edu //Burn a cycle for the missed grant. 4746046Sgblack@eecs.umich.edu tickNextIdle += clock; 4756046Sgblack@eecs.umich.edu 4766046Sgblack@eecs.umich.edu reschedule(busIdleEvent, tickNextIdle, true); 4776046Sgblack@eecs.umich.edu } 4786046Sgblack@eecs.umich.edu} 4796046Sgblack@eecs.umich.edu 4806046Sgblack@eecs.umich.eduvoid 4816046Sgblack@eecs.umich.eduBus::recvRetry(Port::PortId id) 4826046Sgblack@eecs.umich.edu{ 4836046Sgblack@eecs.umich.edu // we got a retry from a peer that we tried to send something to 4846046Sgblack@eecs.umich.edu // and failed, but we sent it on the account of someone else, and 4856046Sgblack@eecs.umich.edu // that source port should be on our retry list, however if the 4866046Sgblack@eecs.umich.edu // bus is released before this happens and the retry (from the bus 4876046Sgblack@eecs.umich.edu // point of view) is successful then this no longer holds and we 4886046Sgblack@eecs.umich.edu // could in fact have an empty retry list 4895647Sgblack@eecs.umich.edu if (retryList.empty()) 4905647Sgblack@eecs.umich.edu return; 4915647Sgblack@eecs.umich.edu 4925647Sgblack@eecs.umich.edu // if the bus isn't busy 4935647Sgblack@eecs.umich.edu if (curTick() >= tickNextIdle) { 4945647Sgblack@eecs.umich.edu // note that we do not care who told us to retry at the moment, we 4955647Sgblack@eecs.umich.edu // merely let the first one on the retry list go 4965647Sgblack@eecs.umich.edu retryWaiting(); 4975647Sgblack@eecs.umich.edu } 4985647Sgblack@eecs.umich.edu} 4995647Sgblack@eecs.umich.edu 5005647Sgblack@eecs.umich.eduint 5015647Sgblack@eecs.umich.eduBus::findPort(Addr addr) 5025647Sgblack@eecs.umich.edu{ 5035648Sgblack@eecs.umich.edu /* An interval tree would be a better way to do this. --ali. */ 5045648Sgblack@eecs.umich.edu int dest_id; 5055648Sgblack@eecs.umich.edu 5065848Sgblack@eecs.umich.edu dest_id = checkPortCache(addr); 5075848Sgblack@eecs.umich.edu if (dest_id != Port::INVALID_PORT_ID) 5085848Sgblack@eecs.umich.edu return dest_id; 5095648Sgblack@eecs.umich.edu 5105848Sgblack@eecs.umich.edu // Check normal port ranges 5115648Sgblack@eecs.umich.edu PortIter i = portMap.find(RangeSize(addr,1)); 5125648Sgblack@eecs.umich.edu if (i != portMap.end()) { 5135848Sgblack@eecs.umich.edu dest_id = i->second; 5145648Sgblack@eecs.umich.edu updatePortCache(dest_id, i->first.start, i->first.end); 5155648Sgblack@eecs.umich.edu return dest_id; 5165848Sgblack@eecs.umich.edu } 5175648Sgblack@eecs.umich.edu 5185648Sgblack@eecs.umich.edu // Check if this matches the default range 5195647Sgblack@eecs.umich.edu if (useDefaultRange) { 5205647Sgblack@eecs.umich.edu AddrRangeIter a_end = defaultRange.end(); 5215647Sgblack@eecs.umich.edu for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 5225647Sgblack@eecs.umich.edu if (*i == addr) { 5235647Sgblack@eecs.umich.edu DPRINTF(Bus, " found addr %#llx on default\n", addr); 5245647Sgblack@eecs.umich.edu return defaultPortId; 5255647Sgblack@eecs.umich.edu } 5265647Sgblack@eecs.umich.edu } 5275647Sgblack@eecs.umich.edu } else if (defaultPortId != Port::INVALID_PORT_ID) { 5285647Sgblack@eecs.umich.edu DPRINTF(Bus, "Unable to find destination for addr %#llx, " 5295648Sgblack@eecs.umich.edu "will use default port\n", addr); 5305647Sgblack@eecs.umich.edu return defaultPortId; 5315647Sgblack@eecs.umich.edu } 5325647Sgblack@eecs.umich.edu 5336041Sgblack@eecs.umich.edu // we should use the range for the default port and it did not 5346041Sgblack@eecs.umich.edu // match, or the default port is not set 5356041Sgblack@eecs.umich.edu fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 5366041Sgblack@eecs.umich.edu name()); 5376041Sgblack@eecs.umich.edu} 5386041Sgblack@eecs.umich.edu 5396041Sgblack@eecs.umich.eduTick 5406041Sgblack@eecs.umich.eduBus::recvAtomic(PacketPtr pkt) 5416041Sgblack@eecs.umich.edu{ 5426041Sgblack@eecs.umich.edu DPRINTF(Bus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 5436041Sgblack@eecs.umich.edu slavePorts[pkt->getSrc()]->name(), pkt->getAddr(), 5446041Sgblack@eecs.umich.edu pkt->cmdString()); 5456041Sgblack@eecs.umich.edu 5466041Sgblack@eecs.umich.edu // forward to all snoopers but the source 5476041Sgblack@eecs.umich.edu std::pair<MemCmd, Tick> snoop_result = forwardAtomic(pkt, pkt->getSrc()); 5486041Sgblack@eecs.umich.edu MemCmd snoop_response_cmd = snoop_result.first; 5496041Sgblack@eecs.umich.edu Tick snoop_response_latency = snoop_result.second; 5506041Sgblack@eecs.umich.edu 5516041Sgblack@eecs.umich.edu // even if we had a snoop response, we must continue and also 5525654Sgblack@eecs.umich.edu // perform the actual request at the destination 5535704Snate@binkert.org int dest_id = findPort(pkt->getAddr()); 5545654Sgblack@eecs.umich.edu 5555654Sgblack@eecs.umich.edu // forward the request to the appropriate destination 5565689Sgblack@eecs.umich.edu Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 5575689Sgblack@eecs.umich.edu 5585654Sgblack@eecs.umich.edu // if we got a response from a snooper, restore it here 5595689Sgblack@eecs.umich.edu if (snoop_response_cmd != MemCmd::InvalidCmd) { 5605655Sgblack@eecs.umich.edu // no one else should have responded 5615689Sgblack@eecs.umich.edu assert(!pkt->isResponse()); 5625689Sgblack@eecs.umich.edu pkt->cmd = snoop_response_cmd; 5635655Sgblack@eecs.umich.edu response_latency = snoop_response_latency; 5645689Sgblack@eecs.umich.edu } 5655655Sgblack@eecs.umich.edu 5665689Sgblack@eecs.umich.edu pkt->finishTime = curTick() + response_latency; 5675689Sgblack@eecs.umich.edu return response_latency; 5685655Sgblack@eecs.umich.edu} 5695689Sgblack@eecs.umich.edu 5705654Sgblack@eecs.umich.eduTick 5715654Sgblack@eecs.umich.eduBus::recvAtomicSnoop(PacketPtr pkt) 5725654Sgblack@eecs.umich.edu{ 5735654Sgblack@eecs.umich.edu DPRINTF(Bus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", 5745654Sgblack@eecs.umich.edu masterPorts[pkt->getSrc()]->name(), pkt->getAddr(), 5755704Snate@binkert.org pkt->cmdString()); 5765654Sgblack@eecs.umich.edu 5775704Snate@binkert.org // forward to all snoopers 5785655Sgblack@eecs.umich.edu std::pair<MemCmd, Tick> snoop_result = 5795655Sgblack@eecs.umich.edu forwardAtomic(pkt, Port::INVALID_PORT_ID); 5805655Sgblack@eecs.umich.edu MemCmd snoop_response_cmd = snoop_result.first; 5815655Sgblack@eecs.umich.edu Tick snoop_response_latency = snoop_result.second; 5825689Sgblack@eecs.umich.edu 5835655Sgblack@eecs.umich.edu if (snoop_response_cmd != MemCmd::InvalidCmd) 5845655Sgblack@eecs.umich.edu pkt->cmd = snoop_response_cmd; 5855689Sgblack@eecs.umich.edu 5865691Sgblack@eecs.umich.edu pkt->finishTime = curTick() + snoop_response_latency; 5875655Sgblack@eecs.umich.edu return snoop_response_latency; 5885689Sgblack@eecs.umich.edu} 5895691Sgblack@eecs.umich.edu 5905655Sgblack@eecs.umich.edustd::pair<MemCmd, Tick> 5915655Sgblack@eecs.umich.eduBus::forwardAtomic(PacketPtr pkt, int exclude_slave_port_id) 5925655Sgblack@eecs.umich.edu{ 5935655Sgblack@eecs.umich.edu // the packet may be changed on snoops, record the original source 5945655Sgblack@eecs.umich.edu // and command to enable us to restore it between snoops so that 5955655Sgblack@eecs.umich.edu // additional snoops can take place properly 5965689Sgblack@eecs.umich.edu Packet::NodeID orig_src_id = pkt->getSrc(); 5975691Sgblack@eecs.umich.edu MemCmd orig_cmd = pkt->cmd; 5985655Sgblack@eecs.umich.edu MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 5995689Sgblack@eecs.umich.edu Tick snoop_response_latency = 0; 6005655Sgblack@eecs.umich.edu 6015655Sgblack@eecs.umich.edu for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 6025655Sgblack@eecs.umich.edu SlavePort *p = *s; 6035654Sgblack@eecs.umich.edu // we could have gotten this request from a snooping master 6045654Sgblack@eecs.umich.edu // (corresponding to our own slave port that is also in 6055654Sgblack@eecs.umich.edu // snoopPorts) and should not send it back to where it came 6065704Snate@binkert.org // from 6075654Sgblack@eecs.umich.edu if (exclude_slave_port_id == Port::INVALID_PORT_ID || 6085704Snate@binkert.org p->getId() != exclude_slave_port_id) { 6095655Sgblack@eecs.umich.edu Tick latency = p->sendAtomicSnoop(pkt); 6105655Sgblack@eecs.umich.edu // in contrast to a functional access, we have to keep on 6115689Sgblack@eecs.umich.edu // going as all snoopers must be updated even if we get a 6125655Sgblack@eecs.umich.edu // response 6135655Sgblack@eecs.umich.edu if (pkt->isResponse()) { 6145689Sgblack@eecs.umich.edu // response from snoop agent 6155655Sgblack@eecs.umich.edu assert(pkt->cmd != orig_cmd); 6165655Sgblack@eecs.umich.edu assert(pkt->memInhibitAsserted()); 6175689Sgblack@eecs.umich.edu // should only happen once 6185655Sgblack@eecs.umich.edu assert(snoop_response_cmd == MemCmd::InvalidCmd); 6195655Sgblack@eecs.umich.edu // save response state 6205655Sgblack@eecs.umich.edu snoop_response_cmd = pkt->cmd; 6215655Sgblack@eecs.umich.edu snoop_response_latency = latency; 6225655Sgblack@eecs.umich.edu // restore original packet state for remaining snoopers 6235655Sgblack@eecs.umich.edu pkt->cmd = orig_cmd; 6245655Sgblack@eecs.umich.edu pkt->setSrc(orig_src_id); 6255689Sgblack@eecs.umich.edu pkt->clearDest(); 6265655Sgblack@eecs.umich.edu } 6275655Sgblack@eecs.umich.edu } 6285655Sgblack@eecs.umich.edu } 6295655Sgblack@eecs.umich.edu 6305655Sgblack@eecs.umich.edu // the packet is restored as part of the loop and any potential 6315655Sgblack@eecs.umich.edu // snoop response is part of the returned pair 6325655Sgblack@eecs.umich.edu return std::make_pair(snoop_response_cmd, snoop_response_latency); 6335654Sgblack@eecs.umich.edu} 6345654Sgblack@eecs.umich.edu 6355647Sgblack@eecs.umich.eduvoid 6365647Sgblack@eecs.umich.eduBus::recvFunctional(PacketPtr pkt) 6375647Sgblack@eecs.umich.edu{ 6385647Sgblack@eecs.umich.edu if (!pkt->isPrint()) { 6395647Sgblack@eecs.umich.edu // don't do DPRINTFs on PrintReq as it clutters up the output 640 DPRINTF(Bus, 641 "recvFunctional: packet src %s addr 0x%x cmd %s\n", 642 slavePorts[pkt->getSrc()]->name(), pkt->getAddr(), 643 pkt->cmdString()); 644 } 645 646 // forward to all snoopers but the source 647 forwardFunctional(pkt, pkt->getSrc()); 648 649 // there is no need to continue if the snooping has found what we 650 // were looking for and the packet is already a response 651 if (!pkt->isResponse()) { 652 int dest_id = findPort(pkt->getAddr()); 653 654 masterPorts[dest_id]->sendFunctional(pkt); 655 } 656} 657 658void 659Bus::recvFunctionalSnoop(PacketPtr pkt) 660{ 661 if (!pkt->isPrint()) { 662 // don't do DPRINTFs on PrintReq as it clutters up the output 663 DPRINTF(Bus, 664 "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", 665 masterPorts[pkt->getSrc()]->name(), pkt->getAddr(), 666 pkt->cmdString()); 667 } 668 669 // forward to all snoopers 670 forwardFunctional(pkt, Port::INVALID_PORT_ID); 671} 672 673void 674Bus::forwardFunctional(PacketPtr pkt, int exclude_slave_port_id) 675{ 676 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 677 SlavePort *p = *s; 678 // we could have gotten this request from a snooping master 679 // (corresponding to our own slave port that is also in 680 // snoopPorts) and should not send it back to where it came 681 // from 682 if (exclude_slave_port_id == Port::INVALID_PORT_ID || 683 p->getId() != exclude_slave_port_id) 684 p->sendFunctionalSnoop(pkt); 685 686 // if we get a response we are done 687 if (pkt->isResponse()) { 688 break; 689 } 690 } 691} 692 693/** Function called by the port when the bus is receiving a range change.*/ 694void 695Bus::recvRangeChange(Port::PortId id) 696{ 697 AddrRangeList ranges; 698 AddrRangeIter iter; 699 700 if (inRecvRangeChange.count(id)) 701 return; 702 inRecvRangeChange.insert(id); 703 704 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 705 706 clearPortCache(); 707 if (id == defaultPortId) { 708 defaultRange.clear(); 709 // Only try to update these ranges if the user set a default responder. 710 if (useDefaultRange) { 711 AddrRangeList ranges = 712 masterPorts[id]->getSlavePort().getAddrRanges(); 713 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 714 defaultRange.push_back(*iter); 715 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 716 iter->start, iter->end); 717 } 718 } 719 } else { 720 721 assert(id < masterPorts.size() && id >= 0); 722 MasterPort *port = masterPorts[id]; 723 724 // Clean out any previously existent ids 725 for (PortIter portIter = portMap.begin(); 726 portIter != portMap.end(); ) { 727 if (portIter->second == id) 728 portMap.erase(portIter++); 729 else 730 portIter++; 731 } 732 733 ranges = port->getSlavePort().getAddrRanges(); 734 735 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 736 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 737 iter->start, iter->end, id); 738 if (portMap.insert(*iter, id) == portMap.end()) { 739 int conflict_id = portMap.find(*iter)->second; 740 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 741 name(), masterPorts[id]->getSlavePort().name(), 742 masterPorts[conflict_id]->getSlavePort().name()); 743 } 744 } 745 } 746 DPRINTF(BusAddrRanges, "port list has %d entries\n", portMap.size()); 747 748 // tell all our neighbouring master ports that our address range 749 // has changed 750 for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 751 ++p) 752 (*p)->sendRangeChange(); 753 754 inRecvRangeChange.erase(id); 755} 756 757AddrRangeList 758Bus::getAddrRanges(Port::PortId id) 759{ 760 AddrRangeList ranges; 761 762 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 763 764 for (AddrRangeIter dflt_iter = defaultRange.begin(); 765 dflt_iter != defaultRange.end(); dflt_iter++) { 766 ranges.push_back(*dflt_iter); 767 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 768 dflt_iter->end); 769 } 770 for (PortIter portIter = portMap.begin(); 771 portIter != portMap.end(); portIter++) { 772 bool subset = false; 773 for (AddrRangeIter dflt_iter = defaultRange.begin(); 774 dflt_iter != defaultRange.end(); dflt_iter++) { 775 if ((portIter->first.start < dflt_iter->start && 776 portIter->first.end >= dflt_iter->start) || 777 (portIter->first.start < dflt_iter->end && 778 portIter->first.end >= dflt_iter->end)) 779 fatal("Devices can not set ranges that itersect the default set\ 780 but are not a subset of the default set.\n"); 781 if (portIter->first.start >= dflt_iter->start && 782 portIter->first.end <= dflt_iter->end) { 783 subset = true; 784 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 785 portIter->first.start, portIter->first.end); 786 } 787 } 788 if (portIter->second != id && !subset) { 789 ranges.push_back(portIter->first); 790 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 791 portIter->first.start, portIter->first.end); 792 } 793 } 794 795 return ranges; 796} 797 798bool 799Bus::isSnooping(Port::PortId id) const 800{ 801 // in essence, answer the question if there are snooping ports 802 return !snoopPorts.empty(); 803} 804 805unsigned 806Bus::findBlockSize(Port::PortId id) 807{ 808 if (cachedBlockSizeValid) 809 return cachedBlockSize; 810 811 unsigned max_bs = 0; 812 813 PortIter p_end = portMap.end(); 814 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 815 unsigned tmp_bs = masterPorts[p_iter->second]->peerBlockSize(); 816 if (tmp_bs > max_bs) 817 max_bs = tmp_bs; 818 } 819 820 for (SlavePortConstIter s = snoopPorts.begin(); s != snoopPorts.end(); 821 ++s) { 822 unsigned tmp_bs = (*s)->peerBlockSize(); 823 if (tmp_bs > max_bs) 824 max_bs = tmp_bs; 825 } 826 if (max_bs == 0) 827 max_bs = defaultBlockSize; 828 829 if (max_bs != 64) 830 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 831 cachedBlockSize = max_bs; 832 cachedBlockSizeValid = true; 833 return max_bs; 834} 835 836 837unsigned int 838Bus::drain(Event * de) 839{ 840 //We should check that we're not "doing" anything, and that noone is 841 //waiting. We might be idle but have someone waiting if the device we 842 //contacted for a retry didn't actually retry. 843 if (!retryList.empty() || (curTick() < tickNextIdle && 844 busIdleEvent.scheduled())) { 845 drainEvent = de; 846 return 1; 847 } 848 return 0; 849} 850 851void 852Bus::startup() 853{ 854 if (tickNextIdle < curTick()) 855 tickNextIdle = (curTick() / clock) * clock + clock; 856} 857 858Bus * 859BusParams::create() 860{ 861 return new Bus(this); 862} 863