coherent_xbar.cc revision 4879
12135SN/A/* 22135SN/A * Copyright (c) 2006 The Regents of The University of Michigan 35268Sksewell@umich.edu * All rights reserved. 45268Sksewell@umich.edu * 55268Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 65268Sksewell@umich.edu * modification, are permitted provided that the following conditions are 75268Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 85268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 95268Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 105268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 115268Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 125268Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 135268Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 145268Sksewell@umich.edu * this software without specific prior written permission. 155268Sksewell@umich.edu * 165268Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175268Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185268Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195268Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205268Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215268Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225268Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235268Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245268Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255268Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265268Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275268Sksewell@umich.edu * 285268Sksewell@umich.edu * Authors: Ali Saidi 295268Sksewell@umich.edu */ 302706Sksewell@umich.edu 312038SN/A/** 322038SN/A * @file 332038SN/A * Definition of a bus object. 342038SN/A */ 352038SN/A 362038SN/A#include <algorithm> 372038SN/A#include <limits> 382135SN/A 392038SN/A#include "base/misc.hh" 402038SN/A#include "base/trace.hh" 412038SN/A#include "mem/bus.hh" 422038SN/A#include "sim/builder.hh" 432038SN/A 442038SN/APort * 452038SN/ABus::getPort(const std::string &if_name, int idx) 462038SN/A{ 472038SN/A if (if_name == "default") { 482038SN/A if (defaultPort == NULL) { 492686Sksewell@umich.edu defaultPort = new BusPort(csprintf("%s-default",name()), this, 502686Sksewell@umich.edu defaultId); 512686Sksewell@umich.edu cachedBlockSizeValid = false; 522686Sksewell@umich.edu return defaultPort; 532686Sksewell@umich.edu } else 542686Sksewell@umich.edu fatal("Default port already set\n"); 552686Sksewell@umich.edu } 562686Sksewell@umich.edu int id; 572686Sksewell@umich.edu if (if_name == "functional") { 582686Sksewell@umich.edu if (!funcPort) { 592686Sksewell@umich.edu id = maxId++; 602686Sksewell@umich.edu funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 612686Sksewell@umich.edu funcPortId = id; 622686Sksewell@umich.edu interfaces[id] = funcPort; 632038SN/A } 642038SN/A return funcPort; 652038SN/A } 662038SN/A 672686Sksewell@umich.edu // if_name ignored? forced to be empty? 682038SN/A id = maxId++; 692686Sksewell@umich.edu assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 702686Sksewell@umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 712686Sksewell@umich.edu interfaces[id] = bp; 722686Sksewell@umich.edu cachedBlockSizeValid = false; 732686Sksewell@umich.edu return bp; 742686Sksewell@umich.edu} 752686Sksewell@umich.edu 762686Sksewell@umich.eduvoid 772686Sksewell@umich.eduBus::deletePortRefs(Port *p) 782686Sksewell@umich.edu{ 792686Sksewell@umich.edu 802686Sksewell@umich.edu BusPort *bp = dynamic_cast<BusPort*>(p); 812686Sksewell@umich.edu if (bp == NULL) 822686Sksewell@umich.edu panic("Couldn't convert Port* to BusPort*\n"); 832686Sksewell@umich.edu // If this is our one functional port 842686Sksewell@umich.edu if (funcPort == bp) 852686Sksewell@umich.edu return; 862038SN/A interfaces.erase(bp->getId()); 872038SN/A delete bp; 882038SN/A} 899554Sandreas.hansson@arm.com 909554Sandreas.hansson@arm.com/** Get the ranges of anyone other buses that we are connected to. */ 919554Sandreas.hansson@arm.comvoid 929554Sandreas.hansson@arm.comBus::init() 939554Sandreas.hansson@arm.com{ 942686Sksewell@umich.edu m5::hash_map<short,BusPort*>::iterator intIter; 954661Sksewell@umich.edu 964661Sksewell@umich.edu for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 974661Sksewell@umich.edu intIter->second->sendStatusChange(Port::RangeChange); 984661Sksewell@umich.edu} 995222Sksewell@umich.edu 1005222Sksewell@umich.eduBus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 1015222Sksewell@umich.edu{} 1025222Sksewell@umich.edu 1034661Sksewell@umich.eduvoid Bus::BusFreeEvent::process() 1042038SN/A{ 1052686Sksewell@umich.edu bus->recvRetry(-1); 1062686Sksewell@umich.edu} 1072686Sksewell@umich.edu 1082686Sksewell@umich.educonst char * Bus::BusFreeEvent::description() 1092686Sksewell@umich.edu{ 1102686Sksewell@umich.edu return "bus became available"; 1112686Sksewell@umich.edu} 1126314Sgblack@eecs.umich.edu 1132686Sksewell@umich.eduvoid Bus::occupyBus(PacketPtr pkt) 1142686Sksewell@umich.edu{ 1156314Sgblack@eecs.umich.edu //Bring tickNextIdle up to the present tick 1162686Sksewell@umich.edu //There is some potential ambiguity where a cycle starts, which might make 1176314Sgblack@eecs.umich.edu //a difference when devices are acting right around a cycle boundary. Using 1186314Sgblack@eecs.umich.edu //a < allows things which happen exactly on a cycle boundary to take up 1196314Sgblack@eecs.umich.edu //only the following cycle. Anything that happens later will have to "wait" 1202686Sksewell@umich.edu //for the end of that cycle, and then start using the bus after that. 1212686Sksewell@umich.edu if (tickNextIdle < curTick) { 1222686Sksewell@umich.edu tickNextIdle = curTick; 1232686Sksewell@umich.edu if (tickNextIdle % clock != 0) 1242686Sksewell@umich.edu tickNextIdle = curTick - (curTick % clock) + clock; 1252686Sksewell@umich.edu } 1262686Sksewell@umich.edu 1272686Sksewell@umich.edu // The packet will be sent. Figure out how long it occupies the bus, and 1282686Sksewell@umich.edu // how much of that time is for the first "word", aka bus width. 1292687Sksewell@umich.edu int numCycles = 0; 1302686Sksewell@umich.edu // Requests need one cycle to send an address 1312686Sksewell@umich.edu if (pkt->isRequest()) 1322686Sksewell@umich.edu numCycles++; 1332686Sksewell@umich.edu else if (pkt->isResponse() || pkt->hasData()) { 1346314Sgblack@eecs.umich.edu // If a packet has data, it needs ceil(size/width) cycles to send it 1352686Sksewell@umich.edu // We're using the "adding instead of dividing" trick again here 1366314Sgblack@eecs.umich.edu if (pkt->hasData()) { 1376314Sgblack@eecs.umich.edu int dataSize = pkt->getSize(); 1382686Sksewell@umich.edu numCycles += dataSize/width; 1392686Sksewell@umich.edu if (dataSize % width) 1406314Sgblack@eecs.umich.edu numCycles++; 1412686Sksewell@umich.edu } else { 1422686Sksewell@umich.edu // If the packet didn't have data, it must have been a response. 1436383Sgblack@eecs.umich.edu // Those use the bus for one cycle to send their data. 1446383Sgblack@eecs.umich.edu numCycles++; 1452686Sksewell@umich.edu } 1464675Sksewell@umich.edu } 1474675Sksewell@umich.edu 1482686Sksewell@umich.edu // The first word will be delivered after the current tick, the delivery 1496383Sgblack@eecs.umich.edu // of the address if any, and one bus cycle to deliver the data 1502686Sksewell@umich.edu pkt->firstWordTime = 1512686Sksewell@umich.edu tickNextIdle + 1522686Sksewell@umich.edu pkt->isRequest() ? clock : 0 + 1532686Sksewell@umich.edu clock; 1542686Sksewell@umich.edu 1552686Sksewell@umich.edu //Advance it numCycles bus cycles. 1562686Sksewell@umich.edu //XXX Should this use the repeated addition trick as well? 1572686Sksewell@umich.edu tickNextIdle += (numCycles * clock); 1582686Sksewell@umich.edu if (!busIdle.scheduled()) { 1592687Sksewell@umich.edu busIdle.schedule(tickNextIdle); 1602686Sksewell@umich.edu } else { 1612686Sksewell@umich.edu busIdle.reschedule(tickNextIdle); 1626383Sgblack@eecs.umich.edu } 1632686Sksewell@umich.edu DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1644661Sksewell@umich.edu curTick, tickNextIdle); 1652686Sksewell@umich.edu 1662686Sksewell@umich.edu // The bus will become idle once the current packet is delivered. 1672686Sksewell@umich.edu pkt->finishTime = tickNextIdle; 1686383Sgblack@eecs.umich.edu} 1692686Sksewell@umich.edu 1702686Sksewell@umich.edu/** Function called by the port when the bus is receiving a Timing 1712686Sksewell@umich.edu * transaction.*/ 1722686Sksewell@umich.edubool 1732686Sksewell@umich.eduBus::recvTiming(PacketPtr pkt) 1742686Sksewell@umich.edu{ 1752686Sksewell@umich.edu Port *port; 1762686Sksewell@umich.edu DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 1772686Sksewell@umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 1782686Sksewell@umich.edu 1795222Sksewell@umich.edu BusPort *pktPort; 1802686Sksewell@umich.edu if (pkt->getSrc() == defaultId) 1812686Sksewell@umich.edu pktPort = defaultPort; 1828738Sgblack@eecs.umich.edu else pktPort = interfaces[pkt->getSrc()]; 1838564Sgblack@eecs.umich.edu 1842686Sksewell@umich.edu // If the bus is busy, or other devices are in line ahead of the current 1852686Sksewell@umich.edu // one, put this device on the retry list. 1862686Sksewell@umich.edu if (tickNextIdle > curTick || 1872686Sksewell@umich.edu (retryList.size() && (!inRetry || pktPort != retryList.front()))) 1882686Sksewell@umich.edu { 1892686Sksewell@umich.edu addToRetryList(pktPort); 1902686Sksewell@umich.edu DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n"); 1912686Sksewell@umich.edu return false; 1922686Sksewell@umich.edu } 1932686Sksewell@umich.edu 1942686Sksewell@umich.edu short dest = pkt->getDest(); 1952686Sksewell@umich.edu 1962686Sksewell@umich.edu // Make sure to clear the snoop commit flag so it doesn't think an 1972686Sksewell@umich.edu // access has been handled twice. 1988564Sgblack@eecs.umich.edu if (dest == Packet::Broadcast) { 1998738Sgblack@eecs.umich.edu port = findPort(pkt->getAddr(), pkt->getSrc()); 2008564Sgblack@eecs.umich.edu timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]); 2018564Sgblack@eecs.umich.edu 2028564Sgblack@eecs.umich.edu if (pkt->memInhibitAsserted()) { 2038564Sgblack@eecs.umich.edu //Cache-Cache transfer occuring 2042686Sksewell@umich.edu if (inRetry) { 2052686Sksewell@umich.edu retryList.front()->onRetryList(false); 2062686Sksewell@umich.edu retryList.pop_front(); 2072686Sksewell@umich.edu inRetry = false; 2082686Sksewell@umich.edu } 2092686Sksewell@umich.edu occupyBus(pkt); 2102686Sksewell@umich.edu DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n"); 2112686Sksewell@umich.edu return true; 2122686Sksewell@umich.edu } 2132135SN/A } else { 2143951Sgblack@eecs.umich.edu assert(dest >= 0 && dest < maxId); 2152038SN/A assert(dest != pkt->getSrc()); // catch infinite loops 2162038SN/A port = interfaces[dest]; 2172135SN/A } 2182686Sksewell@umich.edu 2192084SN/A occupyBus(pkt); 2202084SN/A 2212686Sksewell@umich.edu if (port) { 2222686Sksewell@umich.edu if (port->sendTiming(pkt)) { 2232607SN/A // Packet was successfully sent. Return true. 2242686Sksewell@umich.edu // Also take care of retries 2258588Sgblack@eecs.umich.edu if (inRetry) { 2262686Sksewell@umich.edu DPRINTF(Bus, "Remove retry from list %d\n", 2278588Sgblack@eecs.umich.edu retryList.front()->getId()); 2282686Sksewell@umich.edu retryList.front()->onRetryList(false); 2292686Sksewell@umich.edu retryList.pop_front(); 2302686Sksewell@umich.edu inRetry = false; 2318588Sgblack@eecs.umich.edu } 2328588Sgblack@eecs.umich.edu return true; 2332686Sksewell@umich.edu } 2348588Sgblack@eecs.umich.edu 2352686Sksewell@umich.edu // Packet not successfully sent. Leave or put it on the retry list. 2362686Sksewell@umich.edu DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", 2372686Sksewell@umich.edu pktPort->getId()); 2388588Sgblack@eecs.umich.edu addToRetryList(pktPort); 2392686Sksewell@umich.edu return false; 2402686Sksewell@umich.edu } 2412686Sksewell@umich.edu else { 2422686Sksewell@umich.edu //Forwarding up from responder, just return true; 2432686Sksewell@umich.edu DPRINTF(Bus, "recvTiming: can we be here?\n"); 2442686Sksewell@umich.edu return true; 2452686Sksewell@umich.edu } 2462686Sksewell@umich.edu} 2472686Sksewell@umich.edu 2482686Sksewell@umich.eduvoid 2492686Sksewell@umich.eduBus::recvRetry(int id) 2502686Sksewell@umich.edu{ 2512686Sksewell@umich.edu DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name()); 2522686Sksewell@umich.edu // If there's anything waiting, and the bus isn't busy... 2533951Sgblack@eecs.umich.edu if (retryList.size() && curTick >= tickNextIdle) { 2542686Sksewell@umich.edu //retryingPort = retryList.front(); 2552686Sksewell@umich.edu inRetry = true; 2562686Sksewell@umich.edu DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 2572686Sksewell@umich.edu retryList.front()->sendRetry(); 2582607SN/A // If inRetry is still true, sendTiming wasn't called 2592607SN/A if (inRetry) 2602607SN/A { 2612686Sksewell@umich.edu retryList.front()->onRetryList(false); 2622686Sksewell@umich.edu retryList.pop_front(); 2632686Sksewell@umich.edu inRetry = false; 2642686Sksewell@umich.edu 2658588Sgblack@eecs.umich.edu //Bring tickNextIdle up to the present 2662686Sksewell@umich.edu while (tickNextIdle < curTick) 2672686Sksewell@umich.edu tickNextIdle += clock; 2688588Sgblack@eecs.umich.edu 2692686Sksewell@umich.edu //Burn a cycle for the missed grant. 2702686Sksewell@umich.edu tickNextIdle += clock; 2719999Sclt67@cornell.edu 2729999Sclt67@cornell.edu busIdle.reschedule(tickNextIdle, true); 2732686Sksewell@umich.edu } 2749999Sclt67@cornell.edu } 2759999Sclt67@cornell.edu //If we weren't able to drain before, we might be able to now. 2762686Sksewell@umich.edu if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 2772686Sksewell@umich.edu drainEvent->process(); 2782686Sksewell@umich.edu // Clear the drain event once we're done with it. 2792686Sksewell@umich.edu drainEvent = NULL; 2802686Sksewell@umich.edu } 2812686Sksewell@umich.edu} 2828588Sgblack@eecs.umich.edu 2832686Sksewell@umich.eduPort * 2848588Sgblack@eecs.umich.eduBus::findPort(Addr addr, int id) 2852686Sksewell@umich.edu{ 2868588Sgblack@eecs.umich.edu /* An interval tree would be a better way to do this. --ali. */ 2872686Sksewell@umich.edu int dest_id = -1; 2888588Sgblack@eecs.umich.edu 2892686Sksewell@umich.edu PortIter i = portMap.find(RangeSize(addr,1)); 2902686Sksewell@umich.edu if (i != portMap.end()) 2912686Sksewell@umich.edu dest_id = i->second; 2922686Sksewell@umich.edu 2932686Sksewell@umich.edu // Check if this matches the default range 2942686Sksewell@umich.edu if (dest_id == -1) { 2952686Sksewell@umich.edu for (AddrRangeIter iter = defaultRange.begin(); 2962686Sksewell@umich.edu iter != defaultRange.end(); iter++) { 2972686Sksewell@umich.edu if (*iter == addr) { 2982686Sksewell@umich.edu DPRINTF(Bus, " found addr %#llx on default\n", addr); 2992686Sksewell@umich.edu return defaultPort; 3002686Sksewell@umich.edu } 3012686Sksewell@umich.edu } 3022686Sksewell@umich.edu 3032686Sksewell@umich.edu if (responderSet) { 3043951Sgblack@eecs.umich.edu panic("Unable to find destination for addr (user set default " 3052686Sksewell@umich.edu "responder): %#llx", addr); 3062686Sksewell@umich.edu } else { 3072686Sksewell@umich.edu DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " 3082686Sksewell@umich.edu "default port", addr); 3092686Sksewell@umich.edu 3102686Sksewell@umich.edu return defaultPort; 3112686Sksewell@umich.edu } 3123951Sgblack@eecs.umich.edu } 3132607SN/A 3142607SN/A 3152607SN/A // we shouldn't be sending this back to where it came from 3162607SN/A // do the snoop access and then we should terminate 3172607SN/A // the cyclical call. 3182607SN/A if (dest_id == id) 3192573SN/A return 0; 3202135SN/A 3213951Sgblack@eecs.umich.edu return interfaces[dest_id]; 3222084SN/A} 3232084SN/A 3242135SN/Avoid 3252135SN/ABus::functionalSnoop(PacketPtr pkt, Port *responder) 3262038SN/A{ 3272607SN/A // The packet may be changed by another bus on snoops, restore the 3282686Sksewell@umich.edu // id after each 3292686Sksewell@umich.edu int src_id = pkt->getSrc(); 3302686Sksewell@umich.edu 3312686Sksewell@umich.edu assert(pkt->isRequest()); // hasn't already been satisfied 3322686Sksewell@umich.edu 3332686Sksewell@umich.edu for (SnoopIter s_iter = snoopPorts.begin(); 3342686Sksewell@umich.edu s_iter != snoopPorts.end(); 3352686Sksewell@umich.edu s_iter++) { 3368588Sgblack@eecs.umich.edu BusPort *p = *s_iter; 3372686Sksewell@umich.edu if (p != responder && p->getId() != src_id) { 3382686Sksewell@umich.edu p->sendFunctional(pkt); 3392686Sksewell@umich.edu } 3408588Sgblack@eecs.umich.edu if (pkt->isResponse()) { 3412686Sksewell@umich.edu break; 3422686Sksewell@umich.edu } 3432686Sksewell@umich.edu pkt->setSrc(src_id); 3442686Sksewell@umich.edu } 3452686Sksewell@umich.edu} 3468588Sgblack@eecs.umich.edu 3472686Sksewell@umich.edubool 3482686Sksewell@umich.eduBus::timingSnoop(PacketPtr pkt, Port* responder) 3492686Sksewell@umich.edu{ 3502686Sksewell@umich.edu for (SnoopIter s_iter = snoopPorts.begin(); 3512686Sksewell@umich.edu s_iter != snoopPorts.end(); 3522686Sksewell@umich.edu s_iter++) { 3532686Sksewell@umich.edu BusPort *p = *s_iter; 3542686Sksewell@umich.edu if (p != responder && p->getId() != pkt->getSrc()) { 3552686Sksewell@umich.edu bool success = p->sendTiming(pkt); 3562686Sksewell@umich.edu if (!success) 3572686Sksewell@umich.edu return false; 3588588Sgblack@eecs.umich.edu } 3592686Sksewell@umich.edu } 3602686Sksewell@umich.edu 3612686Sksewell@umich.edu return true; 3622686Sksewell@umich.edu} 3632686Sksewell@umich.edu 3642686Sksewell@umich.edu 3652686Sksewell@umich.edu/** Function called by the port when the bus is receiving a Atomic 3662686Sksewell@umich.edu * transaction.*/ 3672686Sksewell@umich.eduTick 3682686Sksewell@umich.eduBus::recvAtomic(PacketPtr pkt) 3693951Sgblack@eecs.umich.edu{ 3702686Sksewell@umich.edu DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 3712686Sksewell@umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3722686Sksewell@umich.edu assert(pkt->getDest() == Packet::Broadcast); 3732686Sksewell@umich.edu assert(pkt->isRequest()); 3742607SN/A 3752608SN/A // Variables for recording original command and snoop response (if 376 // any)... if a snooper respondes, we will need to restore 377 // original command so that additional snoops can take place 378 // properly 379 MemCmd orig_cmd = pkt->cmd; 380 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 381 Tick snoop_response_latency = 0; 382 int orig_src = pkt->getSrc(); 383 384 Port *target_port = findPort(pkt->getAddr(), pkt->getSrc()); 385 386 SnoopIter s_end = snoopPorts.end(); 387 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 388 BusPort *p = *s_iter; 389 // same port should not have both target addresses and snooping 390 assert(p != target_port); 391 if (p->getId() != pkt->getSrc()) { 392 Tick latency = p->sendAtomic(pkt); 393 if (pkt->isResponse()) { 394 // response from snoop agent 395 assert(pkt->cmd != orig_cmd); 396 assert(pkt->memInhibitAsserted()); 397 // should only happen once 398 assert(snoop_response_cmd == MemCmd::InvalidCmd); 399 // save response state 400 snoop_response_cmd = pkt->cmd; 401 snoop_response_latency = latency; 402 // restore original packet state for remaining snoopers 403 pkt->cmd = orig_cmd; 404 pkt->setSrc(orig_src); 405 pkt->setDest(Packet::Broadcast); 406 } 407 } 408 } 409 410 Tick response_latency = target_port->sendAtomic(pkt); 411 412 // if we got a response from a snooper, restore it here 413 if (snoop_response_cmd != MemCmd::InvalidCmd) { 414 // no one else should have responded 415 assert(!pkt->isResponse()); 416 assert(pkt->cmd == orig_cmd); 417 pkt->cmd = snoop_response_cmd; 418 response_latency = snoop_response_latency; 419 } 420 421 // why do we have this packet field and the return value both??? 422 pkt->finishTime = curTick + response_latency; 423 return response_latency; 424} 425 426/** Function called by the port when the bus is receiving a Functional 427 * transaction.*/ 428void 429Bus::recvFunctional(PacketPtr pkt) 430{ 431 DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 432 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 433 assert(pkt->getDest() == Packet::Broadcast); 434 435 Port* port = findPort(pkt->getAddr(), pkt->getSrc()); 436 functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]); 437 438 // If the snooping hasn't found what we were looking for, keep going. 439 if (!pkt->isResponse() && port) { 440 port->sendFunctional(pkt); 441 } 442} 443 444/** Function called by the port when the bus is receiving a status change.*/ 445void 446Bus::recvStatusChange(Port::Status status, int id) 447{ 448 AddrRangeList ranges; 449 bool snoops; 450 AddrRangeIter iter; 451 452 assert(status == Port::RangeChange && 453 "The other statuses need to be implemented."); 454 455 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 456 457 if (id == defaultId) { 458 defaultRange.clear(); 459 // Only try to update these ranges if the user set a default responder. 460 if (responderSet) { 461 defaultPort->getPeerAddressRanges(ranges, snoops); 462 assert(snoops == false); 463 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 464 defaultRange.push_back(*iter); 465 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 466 iter->start, iter->end); 467 } 468 } 469 } else { 470 471 assert((id < maxId && id >= 0) || id == defaultId); 472 BusPort *port = interfaces[id]; 473 474 // Clean out any previously existent ids 475 for (PortIter portIter = portMap.begin(); 476 portIter != portMap.end(); ) { 477 if (portIter->second == id) 478 portMap.erase(portIter++); 479 else 480 portIter++; 481 } 482 483 for (SnoopIter s_iter = snoopPorts.begin(); 484 s_iter != snoopPorts.end(); ) { 485 if ((*s_iter)->getId() == id) 486 s_iter = snoopPorts.erase(s_iter); 487 else 488 s_iter++; 489 } 490 491 port->getPeerAddressRanges(ranges, snoops); 492 493 if (snoops) { 494 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 495 snoopPorts.push_back(port); 496 } 497 498 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 499 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 500 iter->start, iter->end, id); 501 if (portMap.insert(*iter, id) == portMap.end()) 502 panic("Two devices with same range\n"); 503 504 } 505 } 506 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 507 508 // tell all our peers that our address range has changed. 509 // Don't tell the device that caused this change, it already knows 510 m5::hash_map<short,BusPort*>::iterator intIter; 511 512 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 513 if (intIter->first != id && intIter->first != funcPortId) 514 intIter->second->sendStatusChange(Port::RangeChange); 515 516 if (id != defaultId && defaultPort) 517 defaultPort->sendStatusChange(Port::RangeChange); 518} 519 520void 521Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 522{ 523 resp.clear(); 524 snoop = false; 525 526 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 527 528 for (AddrRangeIter dflt_iter = defaultRange.begin(); 529 dflt_iter != defaultRange.end(); dflt_iter++) { 530 resp.push_back(*dflt_iter); 531 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 532 dflt_iter->end); 533 } 534 for (PortIter portIter = portMap.begin(); 535 portIter != portMap.end(); portIter++) { 536 bool subset = false; 537 for (AddrRangeIter dflt_iter = defaultRange.begin(); 538 dflt_iter != defaultRange.end(); dflt_iter++) { 539 if ((portIter->first.start < dflt_iter->start && 540 portIter->first.end >= dflt_iter->start) || 541 (portIter->first.start < dflt_iter->end && 542 portIter->first.end >= dflt_iter->end)) 543 fatal("Devices can not set ranges that itersect the default set\ 544 but are not a subset of the default set.\n"); 545 if (portIter->first.start >= dflt_iter->start && 546 portIter->first.end <= dflt_iter->end) { 547 subset = true; 548 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 549 portIter->first.start, portIter->first.end); 550 } 551 } 552 if (portIter->second != id && !subset) { 553 resp.push_back(portIter->first); 554 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 555 portIter->first.start, portIter->first.end); 556 } 557 } 558 559 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 560 s_iter++) { 561 if ((*s_iter)->getId() != id) { 562 snoop = true; 563 break; 564 } 565 } 566} 567 568int 569Bus::findBlockSize(int id) 570{ 571 if (cachedBlockSizeValid) 572 return cachedBlockSize; 573 574 int max_bs = -1; 575 576 for (PortIter portIter = portMap.begin(); 577 portIter != portMap.end(); portIter++) { 578 int tmp_bs = interfaces[portIter->second]->peerBlockSize(); 579 if (tmp_bs > max_bs) 580 max_bs = tmp_bs; 581 } 582 for (SnoopIter s_iter = snoopPorts.begin(); 583 s_iter != snoopPorts.end(); s_iter++) { 584 int tmp_bs = (*s_iter)->peerBlockSize(); 585 if (tmp_bs > max_bs) 586 max_bs = tmp_bs; 587 } 588 if (max_bs <= 0) 589 max_bs = defaultBlockSize; 590 591 if (max_bs != 64) 592 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 593 cachedBlockSize = max_bs; 594 cachedBlockSizeValid = true; 595 return max_bs; 596} 597 598 599unsigned int 600Bus::drain(Event * de) 601{ 602 //We should check that we're not "doing" anything, and that noone is 603 //waiting. We might be idle but have someone waiting if the device we 604 //contacted for a retry didn't actually retry. 605 if (curTick >= tickNextIdle && retryList.size() == 0) { 606 return 0; 607 } else { 608 drainEvent = de; 609 return 1; 610 } 611} 612 613void 614Bus::startup() 615{ 616 if (tickNextIdle < curTick) 617 tickNextIdle = (curTick / clock) * clock + clock; 618} 619 620BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 621 622 Param<int> bus_id; 623 Param<int> clock; 624 Param<int> width; 625 Param<bool> responder_set; 626 Param<int> block_size; 627 628END_DECLARE_SIM_OBJECT_PARAMS(Bus) 629 630BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 631 INIT_PARAM(bus_id, "a globally unique bus id"), 632 INIT_PARAM(clock, "bus clock speed"), 633 INIT_PARAM(width, "width of the bus (bits)"), 634 INIT_PARAM(responder_set, "Is a default responder set by the user"), 635 INIT_PARAM(block_size, "Default blocksize if no device has one") 636END_INIT_SIM_OBJECT_PARAMS(Bus) 637 638CREATE_SIM_OBJECT(Bus) 639{ 640 return new Bus(getInstanceName(), bus_id, clock, width, responder_set, 641 block_size); 642} 643 644REGISTER_SIM_OBJECT("Bus", Bus) 645