coherent_xbar.cc revision 3210
11689SN/A/* 21689SN/A * Copyright (c) 2006 The Regents of The University of Michigan 31689SN/A * All rights reserved. 41689SN/A * 51689SN/A * Redistribution and use in source and binary forms, with or without 61689SN/A * modification, are permitted provided that the following conditions are 71689SN/A * met: redistributions of source code must retain the above copyright 81689SN/A * notice, this list of conditions and the following disclaimer; 91689SN/A * redistributions in binary form must reproduce the above copyright 101689SN/A * notice, this list of conditions and the following disclaimer in the 111689SN/A * documentation and/or other materials provided with the distribution; 121689SN/A * neither the name of the copyright holders nor the names of its 131689SN/A * contributors may be used to endorse or promote products derived from 141689SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 291689SN/A */ 301689SN/A 311060SN/A/** 321060SN/A * @file 331060SN/A * Definition of a bus object. 341060SN/A */ 351689SN/A 361060SN/A 371060SN/A#include "base/misc.hh" 381755SN/A#include "base/trace.hh" 391755SN/A#include "mem/bus.hh" 401060SN/A#include "sim/builder.hh" 411060SN/A 421060SN/APort * 431681SN/ABus::getPort(const std::string &if_name, int idx) 441060SN/A{ 451060SN/A if (if_name == "default") 461060SN/A if (defaultPort == NULL) { 471858SN/A defaultPort = new BusPort(csprintf("%s-default",name()), this, 481717SN/A defaultId); 492190SN/A return defaultPort; 501717SN/A } else 511717SN/A fatal("Default port already set\n"); 521060SN/A 531060SN/A // if_name ignored? forced to be empty? 542190SN/A int id = interfaces.size(); 551060SN/A BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 561060SN/A interfaces.push_back(bp); 571060SN/A return bp; 581060SN/A} 591060SN/A 601060SN/A/** Get the ranges of anyone other buses that we are connected to. */ 611060SN/Avoid 621464SN/ABus::init() 631061SN/A{ 641858SN/A std::vector<Port*>::iterator intIter; 651061SN/A 661061SN/A for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 671061SN/A (*intIter)->sendStatusChange(Port::RangeChange); 681060SN/A} 691681SN/A 701685SN/ABus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 711681SN/A{ 721060SN/A assert(!scheduled()); 731060SN/A} 741060SN/A 751755SN/Avoid Bus::BusFreeEvent::process() 761060SN/A{ 771060SN/A bus->recvRetry(0); 781060SN/A} 791060SN/A 801060SN/Aconst char * Bus::BusFreeEvent::description() 811061SN/A{ 821060SN/A return "bus became available"; 831060SN/A} 841060SN/A 851060SN/Avoid 861060SN/ABus::occupyBus(int numCycles) 871060SN/A{ 881060SN/A //Move up when the bus will next be free 891060SN/A //We avoid the use of divide by adding repeatedly 901060SN/A //This should be faster if the value is updated frequently, but should 911060SN/A //be may be slower otherwise. 921060SN/A 931060SN/A //Bring tickNextIdle up to the present tick 941060SN/A //There is some potential ambiguity where a cycle starts, which might make 951060SN/A //a difference when devices are acting right around a cycle boundary. Using 961060SN/A //a < allows things which happen exactly on a cycle boundary to take up only 971755SN/A //the following cycle. Anthing that happens later will have to "wait" for the 981060SN/A //end of that cycle, and then start using the bus after that. 991060SN/A while (tickNextIdle < curTick) 1001755SN/A tickNextIdle += clock; 1011060SN/A //Advance it numCycles bus cycles. 1021060SN/A //XXX Should this use the repeating add trick as well? 1031060SN/A tickNextIdle += (numCycles * clock); 1041060SN/A if (!busIdle.scheduled()) { 1051060SN/A busIdle.schedule(tickNextIdle); 1061060SN/A } else { 1071060SN/A busIdle.reschedule(tickNextIdle); 1081060SN/A } 1091060SN/A DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", curTick, tickNextIdle); 1101060SN/A} 1111060SN/A 1121060SN/A/** Function called by the port when the bus is receiving a Timing 1131060SN/A * transaction.*/ 1141060SN/Abool 1151060SN/ABus::recvTiming(Packet *pkt) 1161060SN/A{ 1171060SN/A Port *port; 1181060SN/A DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", 1191060SN/A pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 1201060SN/A 1211060SN/A Port *pktPort = interfaces[pkt->getSrc()]; 1221060SN/A 1231060SN/A short dest = pkt->getDest(); 1241755SN/A if (dest == Packet::Broadcast) { 1251755SN/A if (timingSnoop(pkt)) { 1261060SN/A pkt->flags |= SNOOP_COMMIT; 1271684SN/A bool success = timingSnoop(pkt); 1281684SN/A assert(success); 1291684SN/A if (pkt->flags & SATISFIED) { 1301684SN/A //Cache-Cache transfer occuring 1311060SN/A if (retryingPort) { 1321060SN/A retryList.pop_front(); 1331060SN/A retryingPort = NULL; 1341060SN/A } 1351060SN/A return true; 1361060SN/A } 1371060SN/A port = findPort(pkt->getAddr(), pkt->getSrc()); 1381060SN/A } else { 1391060SN/A //Snoop didn't succeed 1401060SN/A addToRetryList(pktPort); 1411060SN/A return false; 1421060SN/A } 1431060SN/A } else { 1441858SN/A assert(dest >= 0 && dest < interfaces.size()); 1451060SN/A assert(dest != pkt->getSrc()); // catch infinite loops 1461060SN/A port = interfaces[dest]; 1471060SN/A } 1481060SN/A 1491060SN/A // The packet will be sent. Figure out how long it occupies the bus. 1501060SN/A int numCycles = 0; 1511060SN/A // Requests need one cycle to send an address 1521681SN/A if (pkt->isRequest()) 1532245SN/A numCycles++; 1541060SN/A else if (pkt->isResponse() || pkt->hasData()) { 1551060SN/A // If a packet has data, it needs ceil(size/width) cycles to send it 1561681SN/A // We're using the "adding instead of dividing" trick again here 1572245SN/A if (pkt->hasData()) { 1581060SN/A int dataSize = pkt->getSize(); 1591060SN/A for (int transmitted = 0; transmitted < dataSize; 1601681SN/A transmitted += width) { 1611060SN/A numCycles++; 1621060SN/A } 1631681SN/A } else { 1641060SN/A // If the packet didn't have data, it must have been a response. 1652190SN/A // Those use the bus for one cycle to send their data. 1662190SN/A numCycles++; 1671060SN/A } 1681060SN/A } 1691060SN/A 1701060SN/A occupyBus(numCycles); 1711060SN/A 1721060SN/A if (port->sendTiming(pkt)) { 1731060SN/A // Packet was successfully sent. Return true. 1741060SN/A // Also take care of retries 1752455SN/A if (retryingPort) { 1761060SN/A retryList.pop_front(); 1772455SN/A retryingPort = NULL; 1781060SN/A } 1792455SN/A return true; 1802455SN/A } 1812455SN/A 1821060SN/A // Packet not successfully sent. Leave or put it on the retry list. 1831060SN/A addToRetryList(pktPort); 1841060SN/A return false; 1852455SN/A} 1861060SN/A 1872455SN/Avoid 1881060SN/ABus::recvRetry(int id) 1892455SN/A{ 1902455SN/A // If there's anything waiting... 1912455SN/A if (retryList.size()) { 1921060SN/A retryingPort = retryList.front(); 1931060SN/A retryingPort->sendRetry(); 1941060SN/A // If the retryingPort pointer isn't null, sendTiming wasn't called 1951060SN/A if (retryingPort) { 1961060SN/A warn("sendRetry didn't call sendTiming\n"); 1971060SN/A retryList.pop_front(); 1981060SN/A retryingPort = NULL; 1991060SN/A } 2001060SN/A } 2011060SN/A} 2021061SN/A 2031060SN/APort * 2041060SN/ABus::findPort(Addr addr, int id) 2051060SN/A{ 2061060SN/A /* An interval tree would be a better way to do this. --ali. */ 2071060SN/A int dest_id = -1; 2081060SN/A int i = 0; 2091060SN/A bool found = false; 2101060SN/A AddrRangeIter iter; 2111060SN/A 2121060SN/A while (i < portList.size() && !found) 2131060SN/A { 2141060SN/A if (portList[i].range == addr) { 2151061SN/A dest_id = portList[i].portId; 2161060SN/A found = true; 2171060SN/A DPRINTF(Bus, " found addr %#llx on device %d\n", addr, dest_id); 2181060SN/A } 2191060SN/A i++; 2201060SN/A } 2211060SN/A 2221060SN/A // Check if this matches the default range 2231060SN/A if (dest_id == -1) { 2241061SN/A for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) { 2251060SN/A if (*iter == addr) { 2261060SN/A DPRINTF(Bus, " found addr %#llx on default\n", addr); 2271060SN/A return defaultPort; 2281060SN/A } 2291062SN/A } 2301062SN/A panic("Unable to find destination for addr: %#llx", addr); 2311062SN/A } 2321060SN/A 2331060SN/A 2341060SN/A // we shouldn't be sending this back to where it came from 2351060SN/A assert(dest_id != id); 2361060SN/A 2371060SN/A return interfaces[dest_id]; 2381060SN/A} 2391060SN/A 2401060SN/Astd::vector<int> 2411061SN/ABus::findSnoopPorts(Addr addr, int id) 2421060SN/A{ 2431060SN/A int i = 0; 2441060SN/A AddrRangeIter iter; 2451061SN/A std::vector<int> ports; 2461060SN/A 2471060SN/A while (i < portSnoopList.size()) 2481060SN/A { 2491060SN/A if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) { 2501060SN/A //Careful to not overlap ranges 2511060SN/A //or snoop will be called more than once on the port 2521060SN/A ports.push_back(portSnoopList[i].portId); 2531060SN/A DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr, 2541060SN/A portSnoopList[i].portId); 2551060SN/A } 2561060SN/A i++; 2571060SN/A } 2581060SN/A return ports; 2591060SN/A} 2601060SN/A 2611060SN/Avoid 2621060SN/ABus::atomicSnoop(Packet *pkt) 2631060SN/A{ 2641060SN/A std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 2651060SN/A 2661060SN/A while (!ports.empty()) 2671060SN/A { 2681060SN/A interfaces[ports.back()]->sendAtomic(pkt); 2691060SN/A ports.pop_back(); 2701060SN/A } 2711060SN/A} 2721060SN/A 2731060SN/Abool 2741060SN/ABus::timingSnoop(Packet *pkt) 2751060SN/A{ 2761060SN/A std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc()); 2771060SN/A bool success = true; 2781060SN/A 2791060SN/A while (!ports.empty() && success) 2801060SN/A { 2811060SN/A success = interfaces[ports.back()]->sendTiming(pkt); 2821060SN/A ports.pop_back(); 2831060SN/A } 2841060SN/A 2851060SN/A return success; 2861060SN/A} 2871060SN/A 2881060SN/A 2891060SN/A/** Function called by the port when the bus is receiving a Atomic 2901060SN/A * transaction.*/ 2911060SN/ATick 2921060SN/ABus::recvAtomic(Packet *pkt) 2931060SN/A{ 2941060SN/A DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 2951060SN/A pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 2961060SN/A assert(pkt->getDest() == Packet::Broadcast); 2971060SN/A atomicSnoop(pkt); 2981061SN/A return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); 2991060SN/A} 3001061SN/A 3011060SN/A/** Function called by the port when the bus is receiving a Functional 3021061SN/A * transaction.*/ 3031060SN/Avoid 3041061SN/ABus::recvFunctional(Packet *pkt) 3051060SN/A{ 3061061SN/A DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 3071060SN/A pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 3081060SN/A assert(pkt->getDest() == Packet::Broadcast); 3091060SN/A atomicSnoop(pkt); 3101060SN/A findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); 3111060SN/A} 3121060SN/A 3131060SN/A/** Function called by the port when the bus is receiving a status change.*/ 3141060SN/Avoid 3151060SN/ABus::recvStatusChange(Port::Status status, int id) 3161060SN/A{ 3171060SN/A AddrRangeList ranges; 3181060SN/A AddrRangeList snoops; 3191060SN/A int x; 3201060SN/A AddrRangeIter iter; 3211060SN/A 3221060SN/A assert(status == Port::RangeChange && 3231060SN/A "The other statuses need to be implemented."); 3241060SN/A 3252190SN/A DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 3261060SN/A 3271060SN/A if (id == defaultId) { 3281681SN/A defaultRange.clear(); 3291681SN/A defaultPort->getPeerAddressRanges(ranges, snoops); 3302190SN/A assert(snoops.size() == 0); 3312190SN/A for(iter = ranges.begin(); iter != ranges.end(); iter++) { 3322190SN/A defaultRange.push_back(*iter); 3332190SN/A DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 3342190SN/A iter->start, iter->end); 3351681SN/A } 3361681SN/A } else { 3371060SN/A 3381060SN/A assert((id < interfaces.size() && id >= 0) || id == -1); 3391060SN/A Port *port = interfaces[id]; 3401858SN/A std::vector<DevMap>::iterator portIter; 3411060SN/A std::vector<DevMap>::iterator snoopIter; 3421060SN/A 3431060SN/A // Clean out any previously existent ids 3441060SN/A for (portIter = portList.begin(); portIter != portList.end(); ) { 3451060SN/A if (portIter->portId == id) 3461060SN/A portIter = portList.erase(portIter); 3471060SN/A else 3481060SN/A portIter++; 3491060SN/A } 3501060SN/A 3512190SN/A for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) { 3521060SN/A if (snoopIter->portId == id) 3531060SN/A snoopIter = portSnoopList.erase(snoopIter); 3541060SN/A else 3551060SN/A snoopIter++; 3561060SN/A } 3571060SN/A 3581060SN/A port->getPeerAddressRanges(ranges, snoops); 3591060SN/A 3601060SN/A for(iter = snoops.begin(); iter != snoops.end(); iter++) { 3611060SN/A DevMap dm; 3621060SN/A dm.portId = id; 3631060SN/A dm.range = *iter; 3641060SN/A 3651060SN/A DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n", 366 dm.range.start, dm.range.end, id); 367 portSnoopList.push_back(dm); 368 } 369 370 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 371 DevMap dm; 372 dm.portId = id; 373 dm.range = *iter; 374 375 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 376 dm.range.start, dm.range.end, id); 377 portList.push_back(dm); 378 } 379 } 380 DPRINTF(MMU, "port list has %d entries\n", portList.size()); 381 382 // tell all our peers that our address range has changed. 383 // Don't tell the device that caused this change, it already knows 384 for (x = 0; x < interfaces.size(); x++) 385 if (x != id) 386 interfaces[x]->sendStatusChange(Port::RangeChange); 387 388 if (id != defaultId && defaultPort) 389 defaultPort->sendStatusChange(Port::RangeChange); 390} 391 392void 393Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) 394{ 395 std::vector<DevMap>::iterator portIter; 396 AddrRangeIter dflt_iter; 397 bool subset; 398 399 resp.clear(); 400 snoop.clear(); 401 402 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 403 404 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 405 dflt_iter++) { 406 resp.push_back(*dflt_iter); 407 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",dflt_iter->start, 408 dflt_iter->end); 409 } 410 for (portIter = portList.begin(); portIter != portList.end(); portIter++) { 411 subset = false; 412 for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end(); 413 dflt_iter++) { 414 if ((portIter->range.start < dflt_iter->start && 415 portIter->range.end >= dflt_iter->start) || 416 (portIter->range.start < dflt_iter->end && 417 portIter->range.end >= dflt_iter->end)) 418 fatal("Devices can not set ranges that itersect the default set\ 419 but are not a subset of the default set.\n"); 420 if (portIter->range.start >= dflt_iter->start && 421 portIter->range.end <= dflt_iter->end) { 422 subset = true; 423 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 424 portIter->range.start, portIter->range.end); 425 } 426 } 427 if (portIter->portId != id && !subset) { 428 resp.push_back(portIter->range); 429 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 430 portIter->range.start, portIter->range.end); 431 } 432 } 433} 434 435BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) 436 437 Param<int> bus_id; 438 Param<int> clock; 439 Param<int> width; 440 441END_DECLARE_SIM_OBJECT_PARAMS(Bus) 442 443BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) 444 INIT_PARAM(bus_id, "a globally unique bus id"), 445 INIT_PARAM(clock, "bus clock speed"), 446 INIT_PARAM(width, "width of the bus (bits)") 447END_INIT_SIM_OBJECT_PARAMS(Bus) 448 449CREATE_SIM_OBJECT(Bus) 450{ 451 return new Bus(getInstanceName(), bus_id, clock, width); 452} 453 454REGISTER_SIM_OBJECT("Bus", Bus) 455