xbar.cc revision 8715
16019Shines@cs.fsu.edu/* 210037SARM gem5 Developers * Copyright (c) 2011 ARM Limited 37399SAli.Saidi@ARM.com * All rights reserved 47399SAli.Saidi@ARM.com * 57399SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 67399SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual 77399SAli.Saidi@ARM.com * property including but not limited to intellectual property relating 87399SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software 97399SAli.Saidi@ARM.com * licensed hereunder. You may use the software subject to the license 107399SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated 117399SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software, 127399SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form. 137399SAli.Saidi@ARM.com * 146019Shines@cs.fsu.edu * Copyright (c) 2006 The Regents of The University of Michigan 156019Shines@cs.fsu.edu * All rights reserved. 166019Shines@cs.fsu.edu * 176019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without 186019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are 196019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright 206019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer; 216019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright 226019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the 236019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution; 246019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its 256019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from 266019Shines@cs.fsu.edu * this software without specific prior written permission. 276019Shines@cs.fsu.edu * 286019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 296019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 306019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 316019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 326019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 336019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 356019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 376019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 396019Shines@cs.fsu.edu * 407399SAli.Saidi@ARM.com * Authors: Ali Saidi 416019Shines@cs.fsu.edu * Andreas Hansson 426019Shines@cs.fsu.edu */ 436019Shines@cs.fsu.edu 446019Shines@cs.fsu.edu/** 456019Shines@cs.fsu.edu * @file 466019Shines@cs.fsu.edu * Definition of a bus object. 476019Shines@cs.fsu.edu */ 488229Snate@binkert.org 496019Shines@cs.fsu.edu#include "base/misc.hh" 506019Shines@cs.fsu.edu#include "base/trace.hh" 5110687SAndreas.Sandberg@ARM.com#include "debug/Bus.hh" 526019Shines@cs.fsu.edu#include "debug/BusAddrRanges.hh" 5310037SARM gem5 Developers#include "debug/MMU.hh" 546019Shines@cs.fsu.edu#include "mem/bus.hh" 556116Snate@binkert.org 5610463SAndreas.Sandberg@ARM.comBus::Bus(const BusParams *p) 576019Shines@cs.fsu.edu : MemObject(p), busId(p->bus_id), clock(p->clock), 586019Shines@cs.fsu.edu headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 596019Shines@cs.fsu.edu drainEvent(NULL), busIdle(this), inRetry(false), defaultPortId(-1), 606019Shines@cs.fsu.edu useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size), 616019Shines@cs.fsu.edu cachedBlockSize(0), cachedBlockSizeValid(false) 627404SAli.Saidi@ARM.com{ 6310037SARM gem5 Developers //width, clock period, and header cycles must be positive 6410037SARM gem5 Developers if (width <= 0) 657404SAli.Saidi@ARM.com fatal("Bus width must be positive\n"); 666019Shines@cs.fsu.edu if (clock <= 0) 676019Shines@cs.fsu.edu fatal("Bus clock period must be positive\n"); 687294Sgblack@eecs.umich.edu if (headerCycles <= 0) 697294Sgblack@eecs.umich.edu fatal("Number of header cycles must be positive\n"); 7010037SARM gem5 Developers clearPortCache(); 717294Sgblack@eecs.umich.edu} 727294Sgblack@eecs.umich.edu 737294Sgblack@eecs.umich.eduPort * 7410037SARM gem5 DevelopersBus::getPort(const std::string &if_name, int idx) 7510037SARM gem5 Developers{ 7610037SARM gem5 Developers std::string portName; 7710037SARM gem5 Developers int id = interfaces.size(); 787294Sgblack@eecs.umich.edu if (if_name == "default") { 7910037SARM gem5 Developers if (defaultPortId == -1) { 807404SAli.Saidi@ARM.com defaultPortId = id; 8110037SARM gem5 Developers portName = csprintf("%s-default", name()); 827294Sgblack@eecs.umich.edu } else 837294Sgblack@eecs.umich.edu fatal("Default port already set on %s\n", name()); 847294Sgblack@eecs.umich.edu } else { 8510037SARM gem5 Developers portName = csprintf("%s-p%d", name(), id); 8610037SARM gem5 Developers } 8710037SARM gem5 Developers BusPort *bp = new BusPort(portName, this, id); 8810037SARM gem5 Developers interfaces.push_back(bp); 8910037SARM gem5 Developers cachedBlockSizeValid = false; 9010037SARM gem5 Developers return bp; 9110037SARM gem5 Developers} 9210037SARM gem5 Developers 9310037SARM gem5 Developersvoid 9410037SARM gem5 DevelopersBus::init() 957294Sgblack@eecs.umich.edu{ 966019Shines@cs.fsu.edu std::vector<BusPort*>::iterator intIter; 9710037SARM gem5 Developers 9810037SARM gem5 Developers // iterate over our interfaces and determine which of our neighbours 9910037SARM gem5 Developers // are snooping and add them as snoopers 10010037SARM gem5 Developers for (intIter = interfaces.begin(); intIter != interfaces.end(); 10110037SARM gem5 Developers intIter++) { 10210037SARM gem5 Developers if ((*intIter)->getPeer()->isSnooping()) { 10310037SARM gem5 Developers DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", 1047436Sdam.sunwoo@arm.com (*intIter)->getPeer()->name()); 1057404SAli.Saidi@ARM.com snoopPorts.push_back(*intIter); 10610037SARM gem5 Developers } 10710037SARM gem5 Developers } 1086019Shines@cs.fsu.edu} 1097399SAli.Saidi@ARM.com 1107734SAli.Saidi@ARM.comBus::BusFreeEvent::BusFreeEvent(Bus *_bus) 1117734SAli.Saidi@ARM.com : bus(_bus) 1127734SAli.Saidi@ARM.com{} 1137734SAli.Saidi@ARM.com 1147734SAli.Saidi@ARM.comvoid 1157734SAli.Saidi@ARM.comBus::BusFreeEvent::process() 1167734SAli.Saidi@ARM.com{ 1177734SAli.Saidi@ARM.com bus->recvRetry(-1); 1187734SAli.Saidi@ARM.com} 1197734SAli.Saidi@ARM.com 1207734SAli.Saidi@ARM.comconst char * 1217734SAli.Saidi@ARM.comBus::BusFreeEvent::description() const 1227734SAli.Saidi@ARM.com{ 1237734SAli.Saidi@ARM.com return "bus became available"; 1247734SAli.Saidi@ARM.com} 1257734SAli.Saidi@ARM.com 1267734SAli.Saidi@ARM.comTick 1277734SAli.Saidi@ARM.comBus::calcPacketTiming(PacketPtr pkt) 1287734SAli.Saidi@ARM.com{ 1297734SAli.Saidi@ARM.com // Bring tickNextIdle up to the present tick. 1306019Shines@cs.fsu.edu // There is some potential ambiguity where a cycle starts, which 1316019Shines@cs.fsu.edu // might make a difference when devices are acting right around a 1326019Shines@cs.fsu.edu // cycle boundary. Using a < allows things which happen exactly on 1336019Shines@cs.fsu.edu // a cycle boundary to take up only the following cycle. Anything 13410463SAndreas.Sandberg@ARM.com // that happens later will have to "wait" for the end of that 13510463SAndreas.Sandberg@ARM.com // cycle, and then start using the bus after that. 13610463SAndreas.Sandberg@ARM.com if (tickNextIdle < curTick()) { 1377697SAli.Saidi@ARM.com tickNextIdle = curTick(); 1387404SAli.Saidi@ARM.com if (tickNextIdle % clock != 0) 1398527SAli.Saidi@ARM.com tickNextIdle = curTick() - (curTick() % clock) + clock; 1408527SAli.Saidi@ARM.com } 1416019Shines@cs.fsu.edu 14210037SARM gem5 Developers Tick headerTime = tickNextIdle + headerCycles * clock; 14310037SARM gem5 Developers 1446019Shines@cs.fsu.edu // The packet will be sent. Figure out how long it occupies the bus, and 1459535Smrinmoy.ghosh@arm.com // how much of that time is for the first "word", aka bus width. 1469535Smrinmoy.ghosh@arm.com int numCycles = 0; 1479535Smrinmoy.ghosh@arm.com if (pkt->hasData()) { 14810037SARM gem5 Developers // If a packet has data, it needs ceil(size/width) cycles to send it 14910037SARM gem5 Developers int dataSize = pkt->getSize(); 15010037SARM gem5 Developers numCycles += dataSize/width; 1519535Smrinmoy.ghosh@arm.com if (dataSize % width) 15210037SARM gem5 Developers numCycles++; 15310037SARM gem5 Developers } 1549535Smrinmoy.ghosh@arm.com 15510037SARM gem5 Developers // The first word will be delivered after the current tick, the delivery 15610037SARM gem5 Developers // of the address if any, and one bus cycle to deliver the data 15710037SARM gem5 Developers pkt->firstWordTime = headerTime + clock; 1589535Smrinmoy.ghosh@arm.com 1596019Shines@cs.fsu.edu pkt->finishTime = headerTime + numCycles * clock; 16010037SARM gem5 Developers 16110194SGeoffrey.Blake@arm.com return headerTime; 16210194SGeoffrey.Blake@arm.com} 16310037SARM gem5 Developers 16410037SARM gem5 Developersvoid Bus::occupyBus(Tick until) 16510037SARM gem5 Developers{ 16610717Sandreas.hansson@arm.com if (until == 0) { 16710717Sandreas.hansson@arm.com // shortcut for express snoop packets 16810717Sandreas.hansson@arm.com return; 16910037SARM gem5 Developers } 1706019Shines@cs.fsu.edu 1716019Shines@cs.fsu.edu tickNextIdle = until; 1727404SAli.Saidi@ARM.com reschedule(busIdle, tickNextIdle, true); 1737404SAli.Saidi@ARM.com 17410037SARM gem5 Developers DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 17510037SARM gem5 Developers curTick(), tickNextIdle); 17610037SARM gem5 Developers} 17710037SARM gem5 Developers 17810037SARM gem5 Developers/** Function called by the port when the bus is receiving a Timing 17910037SARM gem5 Developers * transaction.*/ 18010037SARM gem5 Developersbool 18110037SARM gem5 DevelopersBus::recvTiming(PacketPtr pkt) 18210037SARM gem5 Developers{ 18310037SARM gem5 Developers short src = pkt->getSrc(); 18410037SARM gem5 Developers 18510037SARM gem5 Developers BusPort *src_port = interfaces[src]; 18610037SARM gem5 Developers 18710037SARM gem5 Developers // If the bus is busy, or other devices are in line ahead of the current 18810037SARM gem5 Developers // one, put this device on the retry list. 18910037SARM gem5 Developers if (!pkt->isExpressSnoop() && 19010037SARM gem5 Developers (tickNextIdle > curTick() || 19110037SARM gem5 Developers (retryList.size() && (!inRetry || src_port != retryList.front())))) 19210037SARM gem5 Developers { 19310037SARM gem5 Developers addToRetryList(src_port); 19410037SARM gem5 Developers DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n", 19510037SARM gem5 Developers src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 19610037SARM gem5 Developers return false; 19710037SARM gem5 Developers } 19810037SARM gem5 Developers 19910037SARM gem5 Developers DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", 20010037SARM gem5 Developers src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 20110037SARM gem5 Developers 20210037SARM gem5 Developers Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); 20310037SARM gem5 Developers Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; 20410037SARM gem5 Developers 20510037SARM gem5 Developers short dest = pkt->getDest(); 20610037SARM gem5 Developers int dest_port_id; 20710037SARM gem5 Developers Port *dest_port; 2087404SAli.Saidi@ARM.com 2097404SAli.Saidi@ARM.com if (dest == Packet::Broadcast) { 2107404SAli.Saidi@ARM.com dest_port_id = findPort(pkt->getAddr()); 2117404SAli.Saidi@ARM.com dest_port = interfaces[dest_port_id]; 21210037SARM gem5 Developers SnoopIter s_end = snoopPorts.end(); 2137404SAli.Saidi@ARM.com for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 21410037SARM gem5 Developers BusPort *p = *s_iter; 21510037SARM gem5 Developers if (p != dest_port && p != src_port) { 2167404SAli.Saidi@ARM.com // cache is not allowed to refuse snoop 2177404SAli.Saidi@ARM.com bool success M5_VAR_USED = p->sendTiming(pkt); 2187404SAli.Saidi@ARM.com assert(success); 21910037SARM gem5 Developers } 2207404SAli.Saidi@ARM.com } 22110037SARM gem5 Developers } else { 2227404SAli.Saidi@ARM.com assert(dest < interfaces.size()); 2237404SAli.Saidi@ARM.com assert(dest != src); // catch infinite loops 2247404SAli.Saidi@ARM.com dest_port_id = dest; 22510037SARM gem5 Developers dest_port = interfaces[dest_port_id]; 22610037SARM gem5 Developers } 2277404SAli.Saidi@ARM.com 22810037SARM gem5 Developers if (dest_port_id == src) { 2297404SAli.Saidi@ARM.com // Must be forwarded snoop up from below... 23010037SARM gem5 Developers assert(dest == Packet::Broadcast); 23110037SARM gem5 Developers } else { 23210037SARM gem5 Developers // send to actual target 2337404SAli.Saidi@ARM.com if (!dest_port->sendTiming(pkt)) { 23410037SARM gem5 Developers // Packet not successfully sent. Leave or put it on the retry list. 2357404SAli.Saidi@ARM.com // illegal to block responses... can lead to deadlock 2368527SAli.Saidi@ARM.com assert(!pkt->isResponse()); 2376019Shines@cs.fsu.edu // It's also illegal to force a transaction to retry after 2386019Shines@cs.fsu.edu // someone else has committed to respond. 23910037SARM gem5 Developers assert(!pkt->memInhibitAsserted()); 24010037SARM gem5 Developers DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 2416019Shines@cs.fsu.edu src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2426019Shines@cs.fsu.edu addToRetryList(src_port); 2436019Shines@cs.fsu.edu occupyBus(headerFinishTime); 2446019Shines@cs.fsu.edu return false; 2457694SAli.Saidi@ARM.com } 2467694SAli.Saidi@ARM.com // send OK, fall through... pkt may have been deleted by 2477694SAli.Saidi@ARM.com // target at this point, so it should *not* be referenced 2487694SAli.Saidi@ARM.com // again. We'll set it to NULL here just to be safe. 2497694SAli.Saidi@ARM.com pkt = NULL; 2507694SAli.Saidi@ARM.com } 2517694SAli.Saidi@ARM.com 2527694SAli.Saidi@ARM.com occupyBus(packetFinishTime); 2537694SAli.Saidi@ARM.com 2547694SAli.Saidi@ARM.com // Packet was successfully sent. 2558733Sgeoffrey.blake@arm.com // Also take care of retries 2568733Sgeoffrey.blake@arm.com if (inRetry) { 2578733Sgeoffrey.blake@arm.com DPRINTF(Bus, "Remove retry from list %d\n", src); 2588733Sgeoffrey.blake@arm.com retryList.front()->onRetryList(false); 25910037SARM gem5 Developers retryList.pop_front(); 26010037SARM gem5 Developers inRetry = false; 2618733Sgeoffrey.blake@arm.com } 2627436Sdam.sunwoo@arm.com return true; 2637436Sdam.sunwoo@arm.com} 2647436Sdam.sunwoo@arm.com 26510037SARM gem5 Developersvoid 2667436Sdam.sunwoo@arm.comBus::recvRetry(int id) 2677436Sdam.sunwoo@arm.com{ 2687436Sdam.sunwoo@arm.com // If there's anything waiting, and the bus isn't busy... 26910037SARM gem5 Developers if (retryList.size() && curTick() >= tickNextIdle) { 27010037SARM gem5 Developers //retryingPort = retryList.front(); 2717436Sdam.sunwoo@arm.com inRetry = true; 2727436Sdam.sunwoo@arm.com DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 2737436Sdam.sunwoo@arm.com retryList.front()->sendRetry(); 2747436Sdam.sunwoo@arm.com // If inRetry is still true, sendTiming wasn't called 2757436Sdam.sunwoo@arm.com if (inRetry) 2767404SAli.Saidi@ARM.com { 2778733Sgeoffrey.blake@arm.com retryList.front()->onRetryList(false); 27810037SARM gem5 Developers retryList.pop_front(); 2797404SAli.Saidi@ARM.com inRetry = false; 2807404SAli.Saidi@ARM.com 28110037SARM gem5 Developers //Bring tickNextIdle up to the present 28210037SARM gem5 Developers while (tickNextIdle < curTick()) 2837404SAli.Saidi@ARM.com tickNextIdle += clock; 28410037SARM gem5 Developers 28510037SARM gem5 Developers //Burn a cycle for the missed grant. 28610037SARM gem5 Developers tickNextIdle += clock; 28710037SARM gem5 Developers 28810037SARM gem5 Developers reschedule(busIdle, tickNextIdle, true); 2899738Sandreas@sandberg.pp.se } 2906116Snate@binkert.org } 2919439SAndreas.Sandberg@ARM.com //If we weren't able to drain before, we might be able to now. 2929439SAndreas.Sandberg@ARM.com if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) { 2936019Shines@cs.fsu.edu drainEvent->process(); 2946019Shines@cs.fsu.edu // Clear the drain event once we're done with it. 2956019Shines@cs.fsu.edu drainEvent = NULL; 2966019Shines@cs.fsu.edu } 2976019Shines@cs.fsu.edu} 2987749SAli.Saidi@ARM.com 29910463SAndreas.Sandberg@ARM.comint 30010463SAndreas.Sandberg@ARM.comBus::findPort(Addr addr) 3018922Swilliam.wang@arm.com{ 3028922Swilliam.wang@arm.com /* An interval tree would be a better way to do this. --ali. */ 3038922Swilliam.wang@arm.com int dest_id; 3048922Swilliam.wang@arm.com 3058922Swilliam.wang@arm.com dest_id = checkPortCache(addr); 3068922Swilliam.wang@arm.com if (dest_id != -1) 3078922Swilliam.wang@arm.com return dest_id; 3088922Swilliam.wang@arm.com 3098922Swilliam.wang@arm.com // Check normal port ranges 3108922Swilliam.wang@arm.com PortIter i = portMap.find(RangeSize(addr,1)); 3119294Sandreas.hansson@arm.com if (i != portMap.end()) { 3127781SAli.Saidi@ARM.com dest_id = i->second; 3137749SAli.Saidi@ARM.com updatePortCache(dest_id, i->first.start, i->first.end); 3147749SAli.Saidi@ARM.com return dest_id; 3157749SAli.Saidi@ARM.com } 3167749SAli.Saidi@ARM.com 3177749SAli.Saidi@ARM.com // Check if this matches the default range 31810037SARM gem5 Developers if (useDefaultRange) { 31910037SARM gem5 Developers AddrRangeIter a_end = defaultRange.end(); 3207749SAli.Saidi@ARM.com for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 32110037SARM gem5 Developers if (*i == addr) { 3227749SAli.Saidi@ARM.com DPRINTF(Bus, " found addr %#llx on default\n", addr); 32310037SARM gem5 Developers return defaultPortId; 32410037SARM gem5 Developers } 32510037SARM gem5 Developers } 32610037SARM gem5 Developers 32710037SARM gem5 Developers panic("Unable to find destination for addr %#llx\n", addr); 3287749SAli.Saidi@ARM.com } 3297749SAli.Saidi@ARM.com 33010037SARM gem5 Developers DPRINTF(Bus, "Unable to find destination for addr %#llx, " 3317749SAli.Saidi@ARM.com "will use default port\n", addr); 3327749SAli.Saidi@ARM.com return defaultPortId; 33310037SARM gem5 Developers} 33410037SARM gem5 Developers 33510037SARM gem5 Developers 33610037SARM gem5 Developers/** Function called by the port when the bus is receiving a Atomic 33710037SARM gem5 Developers * transaction.*/ 33810037SARM gem5 DevelopersTick 33910037SARM gem5 DevelopersBus::recvAtomic(PacketPtr pkt) 34010037SARM gem5 Developers{ 34110037SARM gem5 Developers DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 34210037SARM gem5 Developers pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3437749SAli.Saidi@ARM.com assert(pkt->getDest() == Packet::Broadcast); 3448299Schander.sudanthi@arm.com assert(pkt->isRequest()); 3458299Schander.sudanthi@arm.com 3468299Schander.sudanthi@arm.com // Variables for recording original command and snoop response (if 3478299Schander.sudanthi@arm.com // any)... if a snooper respondes, we will need to restore 3488299Schander.sudanthi@arm.com // original command so that additional snoops can take place 3497749SAli.Saidi@ARM.com // properly 35010037SARM gem5 Developers MemCmd orig_cmd = pkt->cmd; 35110037SARM gem5 Developers MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 35210037SARM gem5 Developers Tick snoop_response_latency = 0; 35310037SARM gem5 Developers int orig_src = pkt->getSrc(); 35410037SARM gem5 Developers 35510037SARM gem5 Developers int target_port_id = findPort(pkt->getAddr()); 35610037SARM gem5 Developers BusPort *target_port = interfaces[target_port_id]; 35710037SARM gem5 Developers 35810037SARM gem5 Developers SnoopIter s_end = snoopPorts.end(); 35910037SARM gem5 Developers for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 36010037SARM gem5 Developers BusPort *p = *s_iter; 36110037SARM gem5 Developers // same port should not have both target addresses and snooping 36210037SARM gem5 Developers assert(p != target_port); 3636019Shines@cs.fsu.edu if (p->getId() != pkt->getSrc()) { 3646019Shines@cs.fsu.edu Tick latency = p->sendAtomic(pkt); 3657811Ssteve.reinhardt@amd.com if (pkt->isResponse()) { 3666019Shines@cs.fsu.edu // response from snoop agent 3676019Shines@cs.fsu.edu assert(pkt->cmd != orig_cmd); 368 assert(pkt->memInhibitAsserted()); 369 // should only happen once 370 assert(snoop_response_cmd == MemCmd::InvalidCmd); 371 // save response state 372 snoop_response_cmd = pkt->cmd; 373 snoop_response_latency = latency; 374 // restore original packet state for remaining snoopers 375 pkt->cmd = orig_cmd; 376 pkt->setSrc(orig_src); 377 pkt->setDest(Packet::Broadcast); 378 } 379 } 380 } 381 382 Tick response_latency = 0; 383 384 // we can get requests sent up from the memory side of the bus for 385 // snooping... don't send them back down! 386 if (target_port_id != pkt->getSrc()) { 387 response_latency = target_port->sendAtomic(pkt); 388 } 389 390 // if we got a response from a snooper, restore it here 391 if (snoop_response_cmd != MemCmd::InvalidCmd) { 392 // no one else should have responded 393 assert(!pkt->isResponse()); 394 assert(pkt->cmd == orig_cmd); 395 pkt->cmd = snoop_response_cmd; 396 response_latency = snoop_response_latency; 397 } 398 399 // why do we have this packet field and the return value both??? 400 pkt->finishTime = curTick() + response_latency; 401 return response_latency; 402} 403 404/** Function called by the port when the bus is receiving a Functional 405 * transaction.*/ 406void 407Bus::recvFunctional(PacketPtr pkt) 408{ 409 assert(pkt->getDest() == Packet::Broadcast); 410 411 int port_id = findPort(pkt->getAddr()); 412 Port *port = interfaces[port_id]; 413 // The packet may be changed by another bus on snoops, restore the 414 // id after each 415 int src_id = pkt->getSrc(); 416 417 if (!pkt->isPrint()) { 418 // don't do DPRINTFs on PrintReq as it clutters up the output 419 DPRINTF(Bus, 420 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 421 src_id, port_id, pkt->getAddr(), 422 pkt->cmdString()); 423 } 424 425 assert(pkt->isRequest()); // hasn't already been satisfied 426 427 SnoopIter s_end = snoopPorts.end(); 428 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 429 BusPort *p = *s_iter; 430 if (p != port && p->getId() != src_id) { 431 p->sendFunctional(pkt); 432 } 433 if (pkt->isResponse()) { 434 break; 435 } 436 pkt->setSrc(src_id); 437 } 438 439 // If the snooping hasn't found what we were looking for, keep going. 440 if (!pkt->isResponse() && port_id != pkt->getSrc()) { 441 port->sendFunctional(pkt); 442 } 443} 444 445/** Function called by the port when the bus is receiving a range change.*/ 446void 447Bus::recvRangeChange(int id) 448{ 449 AddrRangeList ranges; 450 AddrRangeIter iter; 451 452 if (inRecvRangeChange.count(id)) 453 return; 454 inRecvRangeChange.insert(id); 455 456 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 457 458 clearPortCache(); 459 if (id == defaultPortId) { 460 defaultRange.clear(); 461 // Only try to update these ranges if the user set a default responder. 462 if (useDefaultRange) { 463 AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges(); 464 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 465 defaultRange.push_back(*iter); 466 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 467 iter->start, iter->end); 468 } 469 } 470 } else { 471 472 assert(id < interfaces.size() && id >= 0); 473 BusPort *port = interfaces[id]; 474 475 // Clean out any previously existent ids 476 for (PortIter portIter = portMap.begin(); 477 portIter != portMap.end(); ) { 478 if (portIter->second == id) 479 portMap.erase(portIter++); 480 else 481 portIter++; 482 } 483 484 ranges = port->getPeer()->getAddrRanges(); 485 486 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 487 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 488 iter->start, iter->end, id); 489 if (portMap.insert(*iter, id) == portMap.end()) { 490 int conflict_id = portMap.find(*iter)->second; 491 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 492 name(), interfaces[id]->getPeer()->name(), 493 interfaces[conflict_id]->getPeer()->name()); 494 } 495 } 496 } 497 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 498 499 // tell all our peers that our address range has changed. 500 // Don't tell the device that caused this change, it already knows 501 std::vector<BusPort*>::const_iterator intIter; 502 503 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 504 if ((*intIter)->getId() != id) 505 (*intIter)->sendRangeChange(); 506 507 inRecvRangeChange.erase(id); 508} 509 510AddrRangeList 511Bus::getAddrRanges(int id) 512{ 513 AddrRangeList ranges; 514 515 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 516 517 for (AddrRangeIter dflt_iter = defaultRange.begin(); 518 dflt_iter != defaultRange.end(); dflt_iter++) { 519 ranges.push_back(*dflt_iter); 520 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 521 dflt_iter->end); 522 } 523 for (PortIter portIter = portMap.begin(); 524 portIter != portMap.end(); portIter++) { 525 bool subset = false; 526 for (AddrRangeIter dflt_iter = defaultRange.begin(); 527 dflt_iter != defaultRange.end(); dflt_iter++) { 528 if ((portIter->first.start < dflt_iter->start && 529 portIter->first.end >= dflt_iter->start) || 530 (portIter->first.start < dflt_iter->end && 531 portIter->first.end >= dflt_iter->end)) 532 fatal("Devices can not set ranges that itersect the default set\ 533 but are not a subset of the default set.\n"); 534 if (portIter->first.start >= dflt_iter->start && 535 portIter->first.end <= dflt_iter->end) { 536 subset = true; 537 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 538 portIter->first.start, portIter->first.end); 539 } 540 } 541 if (portIter->second != id && !subset) { 542 ranges.push_back(portIter->first); 543 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 544 portIter->first.start, portIter->first.end); 545 } 546 } 547 548 return ranges; 549} 550 551bool 552Bus::isSnooping(int id) 553{ 554 // in essence, answer the question if there are other snooping 555 // ports rather than the port that is asking 556 bool snoop = false; 557 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 558 s_iter++) { 559 if ((*s_iter)->getId() != id) { 560 snoop = true; 561 break; 562 } 563 } 564 return snoop; 565} 566 567unsigned 568Bus::findBlockSize(int id) 569{ 570 if (cachedBlockSizeValid) 571 return cachedBlockSize; 572 573 unsigned max_bs = 0; 574 575 PortIter p_end = portMap.end(); 576 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 577 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 578 if (tmp_bs > max_bs) 579 max_bs = tmp_bs; 580 } 581 SnoopIter s_end = snoopPorts.end(); 582 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 583 unsigned tmp_bs = (*s_iter)->peerBlockSize(); 584 if (tmp_bs > max_bs) 585 max_bs = tmp_bs; 586 } 587 if (max_bs == 0) 588 max_bs = defaultBlockSize; 589 590 if (max_bs != 64) 591 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 592 cachedBlockSize = max_bs; 593 cachedBlockSizeValid = true; 594 return max_bs; 595} 596 597 598unsigned int 599Bus::drain(Event * de) 600{ 601 //We should check that we're not "doing" anything, and that noone is 602 //waiting. We might be idle but have someone waiting if the device we 603 //contacted for a retry didn't actually retry. 604 if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) { 605 drainEvent = de; 606 return 1; 607 } 608 return 0; 609} 610 611void 612Bus::startup() 613{ 614 if (tickNextIdle < curTick()) 615 tickNextIdle = (curTick() / clock) * clock + clock; 616} 617 618Bus * 619BusParams::create() 620{ 621 return new Bus(this); 622} 623