coherent_xbar.cc revision 4912
12SN/A/* 22190SN/A * Copyright (c) 2006 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665SN/A * 282665SN/A * Authors: Ali Saidi 292SN/A */ 302SN/A 312680Sktlim@umich.edu/** 322680Sktlim@umich.edu * @file 332SN/A * Definition of a bus object. 346329Sgblack@eecs.umich.edu */ 353453Sgblack@eecs.umich.edu 366216Snate@binkert.org#include <algorithm> 371858SN/A#include <limits> 386658Snate@binkert.org 392423SN/A#include "base/misc.hh" 406216Snate@binkert.org#include "base/trace.hh" 412190SN/A#include "mem/bus.hh" 42217SN/A#include "sim/builder.hh" 432SN/A 442190SN/APort * 452190SN/ABus::getPort(const std::string &if_name, int idx) 463453Sgblack@eecs.umich.edu{ 473453Sgblack@eecs.umich.edu if (if_name == "default") { 486022Sgblack@eecs.umich.edu if (defaultPort == NULL) { 493453Sgblack@eecs.umich.edu defaultPort = new BusPort(csprintf("%s-default",name()), this, 502190SN/A defaultId); 512313SN/A cachedBlockSizeValid = false; 522235SN/A return defaultPort; 532423SN/A } else 542521SN/A fatal("Default port already set\n"); 552521SN/A } 562190SN/A int id; 572190SN/A if (if_name == "functional") { 583548Sgblack@eecs.umich.edu if (!funcPort) { 593548Sgblack@eecs.umich.edu id = maxId++; 603548Sgblack@eecs.umich.edu funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 613548Sgblack@eecs.umich.edu funcPortId = id; 622330SN/A interfaces[id] = funcPort; 632SN/A } 642680Sktlim@umich.edu return funcPort; 652680Sktlim@umich.edu } 662680Sktlim@umich.edu 672680Sktlim@umich.edu // if_name ignored? forced to be empty? 682680Sktlim@umich.edu id = maxId++; 692680Sktlim@umich.edu assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 702680Sktlim@umich.edu BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 712680Sktlim@umich.edu interfaces[id] = bp; 722680Sktlim@umich.edu cachedBlockSizeValid = false; 732680Sktlim@umich.edu return bp; 742680Sktlim@umich.edu} 752682Sktlim@umich.edu 762680Sktlim@umich.eduvoid 772680Sktlim@umich.eduBus::deletePortRefs(Port *p) 782680Sktlim@umich.edu{ 792680Sktlim@umich.edu 802680Sktlim@umich.edu BusPort *bp = dynamic_cast<BusPort*>(p); 812SN/A if (bp == NULL) 822107SN/A panic("Couldn't convert Port* to BusPort*\n"); 832107SN/A // If this is our one functional port 842190SN/A if (funcPort == bp) 852455SN/A return; 862455SN/A interfaces.erase(bp->getId()); 872159SN/A delete bp; 882SN/A} 896029Ssteve.reinhardt@amd.com 90246SN/A/** Get the ranges of anyone other buses that we are connected to. */ 91246SN/Avoid 92246SN/ABus::init() 93246SN/A{ 94246SN/A m5::hash_map<short,BusPort*>::iterator intIter; 95246SN/A 96246SN/A for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 972190SN/A intIter->second->sendStatusChange(Port::RangeChange); 98246SN/A} 99246SN/A 100246SN/ABus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 101246SN/A{} 102246SN/A 103246SN/Avoid Bus::BusFreeEvent::process() 104246SN/A{ 1052SN/A bus->recvRetry(-1); 1062680Sktlim@umich.edu} 1072423SN/A 1082190SN/Aconst char * Bus::BusFreeEvent::description() 109180SN/A{ 1105712Shsul@eecs.umich.edu return "bus became available"; 1112190SN/A} 1125715Shsul@eecs.umich.edu 1135715Shsul@eecs.umich.eduvoid Bus::occupyBus(PacketPtr pkt) 1145715Shsul@eecs.umich.edu{ 1155714Shsul@eecs.umich.edu //Bring tickNextIdle up to the present tick 1165714Shsul@eecs.umich.edu //There is some potential ambiguity where a cycle starts, which might make 1175714Shsul@eecs.umich.edu //a difference when devices are acting right around a cycle boundary. Using 1185714Shsul@eecs.umich.edu //a < allows things which happen exactly on a cycle boundary to take up 1195714Shsul@eecs.umich.edu //only the following cycle. Anything that happens later will have to "wait" 1206022Sgblack@eecs.umich.edu //for the end of that cycle, and then start using the bus after that. 1212190SN/A if (tickNextIdle < curTick) { 1226022Sgblack@eecs.umich.edu tickNextIdle = curTick; 1232521SN/A if (tickNextIdle % clock != 0) 1244997Sgblack@eecs.umich.edu tickNextIdle = curTick - (curTick % clock) + clock; 1254997Sgblack@eecs.umich.edu } 1265803Snate@binkert.org 1273548Sgblack@eecs.umich.edu // The packet will be sent. Figure out how long it occupies the bus, and 1282654SN/A // how much of that time is for the first "word", aka bus width. 1292521SN/A int numCycles = 0; 1302521SN/A // Requests need one cycle to send an address 1315499Ssaidi@eecs.umich.edu if (pkt->isRequest()) 1323673Srdreslin@umich.edu numCycles++; 1335497Ssaidi@eecs.umich.edu else if (pkt->isResponse() || pkt->hasData()) { 1342190SN/A // If a packet has data, it needs ceil(size/width) cycles to send it 1352518SN/A // We're using the "adding instead of dividing" trick again here 1362518SN/A if (pkt->hasData()) { 1372190SN/A int dataSize = pkt->getSize(); 1382190SN/A numCycles += dataSize/width; 1392190SN/A if (dataSize % width) 1402190SN/A numCycles++; 1412159SN/A } else { 1422235SN/A // If the packet didn't have data, it must have been a response. 1432103SN/A // Those use the bus for one cycle to send their data. 144393SN/A numCycles++; 145393SN/A } 1462190SN/A } 147393SN/A 148393SN/A // The first word will be delivered after the current tick, the delivery 1495250Sksewell@umich.edu // of the address if any, and one bus cycle to deliver the data 150393SN/A pkt->firstWordTime = 151393SN/A tickNextIdle + 1525250Sksewell@umich.edu pkt->isRequest() ? clock : 0 + 1532159SN/A clock; 1542159SN/A 1552190SN/A //Advance it numCycles bus cycles. 1562159SN/A //XXX Should this use the repeated addition trick as well? 1572159SN/A tickNextIdle += (numCycles * clock); 1582680Sktlim@umich.edu if (!busIdle.scheduled()) { 1592159SN/A busIdle.schedule(tickNextIdle); 1602190SN/A } else { 1612159SN/A busIdle.reschedule(tickNextIdle); 1622190SN/A } 1632190SN/A DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1642159SN/A curTick, tickNextIdle); 1652235SN/A 1662313SN/A // The bus will become idle once the current packet is delivered. 1672235SN/A pkt->finishTime = tickNextIdle; 1682235SN/A} 1692235SN/A 1702235SN/A/** Function called by the port when the bus is receiving a Timing 1712235SN/A * transaction.*/ 1722254SN/Abool 1732254SN/ABus::recvTiming(PacketPtr pkt) 1742254SN/A{ 1752235SN/A short src = pkt->getSrc(); 1762235SN/A DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 1772235SN/A src, pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 1782254SN/A 1792190SN/A BusPort *src_port = (src == defaultId) ? defaultPort : interfaces[src]; 1802159SN/A 1812680Sktlim@umich.edu // If the bus is busy, or other devices are in line ahead of the current 1822159SN/A // one, put this device on the retry list. 1832190SN/A if (!(pkt->isResponse() || pkt->isExpressSnoop()) && 1842159SN/A (tickNextIdle > curTick || 1852159SN/A (retryList.size() && (!inRetry || src_port != retryList.front())))) 1862159SN/A { 1872159SN/A addToRetryList(src_port); 1882190SN/A DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n"); 1892159SN/A return false; 1902455SN/A } 1912159SN/A 1922455SN/A occupyBus(pkt); 1932159SN/A 1942190SN/A short dest = pkt->getDest(); 1952159SN/A int dest_port_id; 1962455SN/A Port *dest_port; 1972159SN/A 1982455SN/A if (dest == Packet::Broadcast) { 1992455SN/A dest_port_id = findPort(pkt->getAddr()); 2002190SN/A dest_port = interfaces[dest_port_id]; 2012159SN/A for (SnoopIter s_iter = snoopPorts.begin(); 2022190SN/A s_iter != snoopPorts.end(); 2032159SN/A s_iter++) { 2042190SN/A BusPort *p = *s_iter; 2052159SN/A if (p != dest_port && p != src_port) { 2062190SN/A#ifndef NDEBUG 2072159SN/A // cache is not allowed to refuse snoop 2082447SN/A bool success = p->sendTiming(pkt); 2092447SN/A assert(success); 2102447SN/A#else 2112447SN/A // avoid unused variable warning 2125260Sksewell@umich.edu p->sendTiming(pkt); 2135260Sksewell@umich.edu#endif 2145260Sksewell@umich.edu } 2155260Sksewell@umich.edu } 2165260Sksewell@umich.edu } else { 2175260Sksewell@umich.edu assert(dest >= 0 && dest < maxId); 2185260Sksewell@umich.edu assert(dest != src); // catch infinite loops 2195260Sksewell@umich.edu dest_port_id = dest; 2204172Ssaidi@eecs.umich.edu dest_port = interfaces[dest_port_id]; 2214172Ssaidi@eecs.umich.edu } 2222190SN/A 2232159SN/A if (dest_port_id == src) { 2244172Ssaidi@eecs.umich.edu // Must be forwarded snoop up from below... 2252190SN/A assert(dest == Packet::Broadcast); 2263468Sgblack@eecs.umich.edu } else { 2272190SN/A // send to actual target 2286313Sgblack@eecs.umich.edu if (!dest_port->sendTiming(pkt)) { 2296313Sgblack@eecs.umich.edu // Packet not successfully sent. Leave or put it on the retry list. 2306313Sgblack@eecs.umich.edu // illegal to block responses... can lead to deadlock 2316221Snate@binkert.org assert(!pkt->isResponse()); 2326221Snate@binkert.org DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", src); 2336221Snate@binkert.org addToRetryList(src_port); 2346221Snate@binkert.org return false; 2356221Snate@binkert.org } 2364661Sksewell@umich.edu // send OK, fall through 2376221Snate@binkert.org } 2386221Snate@binkert.org 2396221Snate@binkert.org // Packet was successfully sent. 2406221Snate@binkert.org // Also take care of retries 2414661Sksewell@umich.edu if (inRetry) { 2422235SN/A DPRINTF(Bus, "Remove retry from list %d\n", src); 2432235SN/A retryList.front()->onRetryList(false); 2442190SN/A retryList.pop_front(); 2452190SN/A inRetry = false; 2462190SN/A } 2472159SN/A return true; 2482235SN/A} 2492190SN/A 2502190SN/Avoid 2512159SN/ABus::recvRetry(int id) 2522235SN/A{ 2532190SN/A // If there's anything waiting, and the bus isn't busy... 2542834Sksewell@umich.edu if (retryList.size() && curTick >= tickNextIdle) { 2554111Sgblack@eecs.umich.edu //retryingPort = retryList.front(); 2564111Sgblack@eecs.umich.edu inRetry = true; 2572834Sksewell@umich.edu DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 2582834Sksewell@umich.edu retryList.front()->sendRetry(); 2592834Sksewell@umich.edu // If inRetry is still true, sendTiming wasn't called 2602834Sksewell@umich.edu if (inRetry) 2612159SN/A { 2622525SN/A retryList.front()->onRetryList(false); 2635217Ssaidi@eecs.umich.edu retryList.pop_front(); 2645217Ssaidi@eecs.umich.edu inRetry = false; 2652159SN/A 2662159SN/A //Bring tickNextIdle up to the present 2672682Sktlim@umich.edu while (tickNextIdle < curTick) 2682682Sktlim@umich.edu tickNextIdle += clock; 2692682Sktlim@umich.edu 2702682Sktlim@umich.edu //Burn a cycle for the missed grant. 2712682Sktlim@umich.edu tickNextIdle += clock; 2722682Sktlim@umich.edu 2732682Sktlim@umich.edu busIdle.reschedule(tickNextIdle, true); 2742682Sktlim@umich.edu } 2752682Sktlim@umich.edu } 2762682Sktlim@umich.edu //If we weren't able to drain before, we might be able to now. 2772680Sktlim@umich.edu if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 2782680Sktlim@umich.edu drainEvent->process(); 2792190SN/A // Clear the drain event once we're done with it. 2802190SN/A drainEvent = NULL; 2812680Sktlim@umich.edu } 2822680Sktlim@umich.edu} 2832159SN/A 2842190SN/Aint 2852680Sktlim@umich.eduBus::findPort(Addr addr) 2862SN/A{ 2872SN/A /* An interval tree would be a better way to do this. --ali. */ 2882SN/A int dest_id = -1; 2892680Sktlim@umich.edu 2902SN/A PortIter i = portMap.find(RangeSize(addr,1)); 2915712Shsul@eecs.umich.edu if (i != portMap.end()) 2922SN/A dest_id = i->second; 2935715Shsul@eecs.umich.edu 2945715Shsul@eecs.umich.edu // Check if this matches the default range 2955715Shsul@eecs.umich.edu if (dest_id == -1) { 2965714Shsul@eecs.umich.edu for (AddrRangeIter iter = defaultRange.begin(); 2975714Shsul@eecs.umich.edu iter != defaultRange.end(); iter++) { 2985714Shsul@eecs.umich.edu if (*iter == addr) { 2995714Shsul@eecs.umich.edu DPRINTF(Bus, " found addr %#llx on default\n", addr); 3005714Shsul@eecs.umich.edu return defaultId; 3016022Sgblack@eecs.umich.edu } 3021917SN/A } 3036022Sgblack@eecs.umich.edu 3042521SN/A if (responderSet) { 3054997Sgblack@eecs.umich.edu panic("Unable to find destination for addr (user set default " 3064997Sgblack@eecs.umich.edu "responder): %#llx", addr); 3075803Snate@binkert.org } else { 3083548Sgblack@eecs.umich.edu DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " 3093548Sgblack@eecs.umich.edu "default port", addr); 3102654SN/A 3112680Sktlim@umich.edu return defaultId; 3122521SN/A } 3135499Ssaidi@eecs.umich.edu } 3143673Srdreslin@umich.edu 3155497Ssaidi@eecs.umich.edu return dest_id; 3162SN/A} 3172680Sktlim@umich.edu 3182518SN/A 3192680Sktlim@umich.edu/** Function called by the port when the bus is receiving a Atomic 3202SN/A * transaction.*/ 3212SN/ATick 3222680Sktlim@umich.eduBus::recvAtomic(PacketPtr pkt) 323595SN/A{ 3242680Sktlim@umich.edu DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 3252SN/A pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3262190SN/A assert(pkt->getDest() == Packet::Broadcast); 3272190SN/A assert(pkt->isRequest()); 3282680Sktlim@umich.edu 3292SN/A // Variables for recording original command and snoop response (if 3302190SN/A // any)... if a snooper respondes, we will need to restore 3315250Sksewell@umich.edu // original command so that additional snoops can take place 3322SN/A // properly 3332190SN/A MemCmd orig_cmd = pkt->cmd; 3345250Sksewell@umich.edu MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 335217SN/A Tick snoop_response_latency = 0; 3361858SN/A int orig_src = pkt->getSrc(); 3372680Sktlim@umich.edu 3382190SN/A int target_port_id = findPort(pkt->getAddr()); 3392190SN/A Port *target_port = interfaces[target_port_id]; 3402680Sktlim@umich.edu 3412680Sktlim@umich.edu SnoopIter s_end = snoopPorts.end(); 3422190SN/A for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 3432680Sktlim@umich.edu BusPort *p = *s_iter; 3442190SN/A // same port should not have both target addresses and snooping 3452680Sktlim@umich.edu assert(p != target_port); 3462190SN/A if (p->getId() != pkt->getSrc()) { 3472680Sktlim@umich.edu Tick latency = p->sendAtomic(pkt); 3482190SN/A if (pkt->isResponse()) { 3492235SN/A // response from snoop agent 3502680Sktlim@umich.edu assert(pkt->cmd != orig_cmd); 3512235SN/A assert(pkt->memInhibitAsserted()); 3522680Sktlim@umich.edu // should only happen once 3532680Sktlim@umich.edu assert(snoop_response_cmd == MemCmd::InvalidCmd); 3542254SN/A // save response state 3552680Sktlim@umich.edu snoop_response_cmd = pkt->cmd; 3562680Sktlim@umich.edu snoop_response_latency = latency; 3572235SN/A // restore original packet state for remaining snoopers 3582190SN/A pkt->cmd = orig_cmd; 3592680Sktlim@umich.edu pkt->setSrc(orig_src); 3602SN/A pkt->setDest(Packet::Broadcast); 3612190SN/A } 3622680Sktlim@umich.edu } 3632SN/A } 3642680Sktlim@umich.edu 365716SN/A Tick response_latency = 0; 3662SN/A 3672SN/A // we can get requests sent up from the memory side of the bus for 3682SN/A // snooping... don't send them back down! 3692SN/A if (target_port_id != pkt->getSrc()) { 3702680Sktlim@umich.edu response_latency = target_port->sendAtomic(pkt); 3712SN/A } 3722455SN/A 3732680Sktlim@umich.edu // if we got a response from a snooper, restore it here 3742SN/A if (snoop_response_cmd != MemCmd::InvalidCmd) { 3752455SN/A // no one else should have responded 3762680Sktlim@umich.edu assert(!pkt->isResponse()); 3772SN/A assert(pkt->cmd == orig_cmd); 3782SN/A pkt->cmd = snoop_response_cmd; 3792680Sktlim@umich.edu response_latency = snoop_response_latency; 3802SN/A } 3812455SN/A 3822680Sktlim@umich.edu // why do we have this packet field and the return value both??? 3832SN/A pkt->finishTime = curTick + response_latency; 3842455SN/A return response_latency; 3852680Sktlim@umich.edu} 3862SN/A 3872680Sktlim@umich.edu/** Function called by the port when the bus is receiving a Functional 3882SN/A * transaction.*/ 3892680Sktlim@umich.eduvoid 3902206SN/ABus::recvFunctional(PacketPtr pkt) 3912680Sktlim@umich.edu{ 3922252SN/A DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 3932680Sktlim@umich.edu pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3942SN/A assert(pkt->getDest() == Packet::Broadcast); 3952680Sktlim@umich.edu 3962447SN/A int port_id = findPort(pkt->getAddr()); 3972680Sktlim@umich.edu Port *port = interfaces[port_id]; 3982447SN/A // The packet may be changed by another bus on snoops, restore the 3995260Sksewell@umich.edu // id after each 4005260Sksewell@umich.edu int src_id = pkt->getSrc(); 4015260Sksewell@umich.edu 4025260Sksewell@umich.edu assert(pkt->isRequest()); // hasn't already been satisfied 4035260Sksewell@umich.edu 4045260Sksewell@umich.edu for (SnoopIter s_iter = snoopPorts.begin(); 4055592Sgblack@eecs.umich.edu s_iter != snoopPorts.end(); 4065260Sksewell@umich.edu s_iter++) { 4074172Ssaidi@eecs.umich.edu BusPort *p = *s_iter; 4084172Ssaidi@eecs.umich.edu if (p != port && p->getId() != src_id) { 4094172Ssaidi@eecs.umich.edu p->sendFunctional(pkt); 4102159SN/A } 4112680Sktlim@umich.edu if (pkt->isResponse()) { 4122SN/A break; 4134172Ssaidi@eecs.umich.edu } 4144172Ssaidi@eecs.umich.edu pkt->setSrc(src_id); 4152SN/A } 4163468Sgblack@eecs.umich.edu 4172680Sktlim@umich.edu // If the snooping hasn't found what we were looking for, keep going. 4182SN/A if (!pkt->isResponse() && port_id != pkt->getSrc()) { 4196313Sgblack@eecs.umich.edu port->sendFunctional(pkt); 4206313Sgblack@eecs.umich.edu } 4216313Sgblack@eecs.umich.edu} 4226313Sgblack@eecs.umich.edu 4236313Sgblack@eecs.umich.edu/** Function called by the port when the bus is receiving a status change.*/ 4246313Sgblack@eecs.umich.eduvoid 4252190SN/ABus::recvStatusChange(Port::Status status, int id) 4262680Sktlim@umich.edu{ 4272190SN/A AddrRangeList ranges; 4282190SN/A bool snoops; 4292680Sktlim@umich.edu AddrRangeIter iter; 4302SN/A 4312190SN/A assert(status == Port::RangeChange && 4322680Sktlim@umich.edu "The other statuses need to be implemented."); 4332190SN/A 4341858SN/A DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 4354111Sgblack@eecs.umich.edu 4364111Sgblack@eecs.umich.edu if (id == defaultId) { 4374111Sgblack@eecs.umich.edu defaultRange.clear(); 4382680Sktlim@umich.edu // Only try to update these ranges if the user set a default responder. 4392SN/A if (responderSet) { 4402SN/A defaultPort->getPeerAddressRanges(ranges, snoops); 4412SN/A assert(snoops == false); 4422190SN/A for(iter = ranges.begin(); iter != ranges.end(); iter++) { 443 defaultRange.push_back(*iter); 444 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 445 iter->start, iter->end); 446 } 447 } 448 } else { 449 450 assert((id < maxId && id >= 0) || id == defaultId); 451 BusPort *port = interfaces[id]; 452 453 // Clean out any previously existent ids 454 for (PortIter portIter = portMap.begin(); 455 portIter != portMap.end(); ) { 456 if (portIter->second == id) 457 portMap.erase(portIter++); 458 else 459 portIter++; 460 } 461 462 for (SnoopIter s_iter = snoopPorts.begin(); 463 s_iter != snoopPorts.end(); ) { 464 if ((*s_iter)->getId() == id) 465 s_iter = snoopPorts.erase(s_iter); 466 else 467 s_iter++; 468 } 469 470 port->getPeerAddressRanges(ranges, snoops); 471 472 if (snoops) { 473 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 474 snoopPorts.push_back(port); 475 } 476 477 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 478 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 479 iter->start, iter->end, id); 480 if (portMap.insert(*iter, id) == portMap.end()) 481 panic("Two devices with same range\n"); 482 483 } 484 } 485 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 486 487 // tell all our peers that our address range has changed. 488 // Don't tell the device that caused this change, it already knows 489 m5::hash_map<short,BusPort*>::iterator intIter; 490 491 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 492 if (intIter->first != id && intIter->first != funcPortId) 493 intIter->second->sendStatusChange(Port::RangeChange); 494 495 if (id != defaultId && defaultPort) 496 defaultPort->sendStatusChange(Port::RangeChange); 497} 498 499void 500Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 501{ 502 resp.clear(); 503 snoop = false; 504 505 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 506 507 for (AddrRangeIter dflt_iter = defaultRange.begin(); 508 dflt_iter != defaultRange.end(); dflt_iter++) { 509 resp.push_back(*dflt_iter); 510 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 511 dflt_iter->end); 512 } 513 for (PortIter portIter = portMap.begin(); 514 portIter != portMap.end(); portIter++) { 515 bool subset = false; 516 for (AddrRangeIter dflt_iter = defaultRange.begin(); 517 dflt_iter != defaultRange.end(); dflt_iter++) { 518 if ((portIter->first.start < dflt_iter->start && 519 portIter->first.end >= dflt_iter->start) || 520 (portIter->first.start < dflt_iter->end && 521 portIter->first.end >= dflt_iter->end)) 522 fatal("Devices can not set ranges that itersect the default set\ 523 but are not a subset of the default set.\n"); 524 if (portIter->first.start >= dflt_iter->start && 525 portIter->first.end <= dflt_iter->end) { 526 subset = true; 527 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 528 portIter->first.start, portIter->first.end); 529 } 530 } 531 if (portIter->second != id && !subset) { 532 resp.push_back(portIter->first); 533 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 534 portIter->first.start, portIter->first.end); 535 } 536 } 537 538 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 539 s_iter++) { 540 if ((*s_iter)->getId() != id) { 541 snoop = true; 542 break; 543 } 544 } 545} 546 547int 548Bus::findBlockSize(int id) 549{ 550 if (cachedBlockSizeValid) 551 return cachedBlockSize; 552 553 int max_bs = -1; 554 555 for (PortIter portIter = portMap.begin(); 556 portIter != portMap.end(); portIter++) { 557 int tmp_bs = interfaces[portIter->second]->peerBlockSize(); 558 if (tmp_bs > max_bs) 559 max_bs = tmp_bs; 560 } 561 for (SnoopIter s_iter = snoopPorts.begin(); 562 s_iter != snoopPorts.end(); s_iter++) { 563 int tmp_bs = (*s_iter)->peerBlockSize(); 564 if (tmp_bs > max_bs) 565 max_bs = tmp_bs; 566 } 567 if (max_bs <= 0) 568 max_bs = defaultBlockSize; 569 570 if (max_bs != 64) 571 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 572 cachedBlockSize = max_bs; 573 cachedBlockSizeValid = true; 574 return max_bs; 575} 576 577 578unsigned int 579Bus::drain(Event * de) 580{ 581 //We should check that we're not "doing" anything, and that noone is 582 //waiting. We might be idle but have someone waiting if the device we 583 //contacted for a retry didn't actually retry. 584 if (curTick >= tickNextIdle && retryList.size() == 0) { 585 return 0; 586 } else { 587 drainEvent = de; 588 return 1; 589 } 590} 591 592void 593Bus::startup() 594{ 595 if (tickNextIdle < curTick) 596 tickNextIdle = (curTick / clock) * clock + clock; 597} 598 599BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 600 601 Param<int> bus_id; 602 Param<int> clock; 603 Param<int> width; 604 Param<bool> responder_set; 605 Param<int> block_size; 606 607END_DECLARE_SIM_OBJECT_PARAMS(Bus) 608 609BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 610 INIT_PARAM(bus_id, "a globally unique bus id"), 611 INIT_PARAM(clock, "bus clock speed"), 612 INIT_PARAM(width, "width of the bus (bits)"), 613 INIT_PARAM(responder_set, "Is a default responder set by the user"), 614 INIT_PARAM(block_size, "Default blocksize if no device has one") 615END_INIT_SIM_OBJECT_PARAMS(Bus) 616 617CREATE_SIM_OBJECT(Bus) 618{ 619 return new Bus(getInstanceName(), bus_id, clock, width, responder_set, 620 block_size); 621} 622 623REGISTER_SIM_OBJECT("Bus", Bus) 624