xbar.hh revision 5354
12381SN/A/* 22592SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 37636Ssteve.reinhardt@amd.com * All rights reserved. 42381SN/A * 52381SN/A * Redistribution and use in source and binary forms, with or without 62381SN/A * modification, are permitted provided that the following conditions are 72381SN/A * met: redistributions of source code must retain the above copyright 82381SN/A * notice, this list of conditions and the following disclaimer; 92381SN/A * redistributions in binary form must reproduce the above copyright 102381SN/A * notice, this list of conditions and the following disclaimer in the 112381SN/A * documentation and/or other materials provided with the distribution; 122381SN/A * neither the name of the copyright holders nor the names of its 132381SN/A * contributors may be used to endorse or promote products derived from 142381SN/A * this software without specific prior written permission. 152381SN/A * 162381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272381SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Ron Dreslinski 292665Ssaidi@eecs.umich.edu * Ali Saidi 302665Ssaidi@eecs.umich.edu */ 312665Ssaidi@eecs.umich.edu 322381SN/A/** 332381SN/A * @file 342381SN/A * Declaration of a bus object. 352381SN/A */ 362662Sstever@eecs.umich.edu 372381SN/A#ifndef __MEM_BUS_HH__ 382381SN/A#define __MEM_BUS_HH__ 392381SN/A 402381SN/A#include <string> 412381SN/A#include <set> 428229Snate@binkert.org#include <list> 433348Sbinkertn@umich.edu#include <inttypes.h> 443348Sbinkertn@umich.edu 453348Sbinkertn@umich.edu#include "base/range.hh" 465735Snate@binkert.org#include "base/hashmap.hh" 474024Sbinkertn@umich.edu#include "base/range_map.hh" 484610Ssaidi@eecs.umich.edu#include "mem/mem_object.hh" 495735Snate@binkert.org#include "mem/packet.hh" 503940Ssaidi@eecs.umich.edu#include "mem/port.hh" 515314Sstever@gmail.com#include "mem/request.hh" 526216Snate@binkert.org#include "sim/eventq.hh" 532392SN/A#include "params/Bus.hh" 544167Sbinkertn@umich.edu 552394SN/Aclass Bus : public MemObject 562394SN/A{ 573349Sbinkertn@umich.edu /** Declaration of the buses port type, one will be instantiated for each 582394SN/A of the interfaces connecting to the bus. */ 592812Srdreslin@umich.edu class BusPort : public Port 602812Srdreslin@umich.edu { 614022Sstever@eecs.umich.edu bool _onRetryList; 624022Sstever@eecs.umich.edu 635735Snate@binkert.org /** A pointer to the bus to which this port belongs. */ 645735Snate@binkert.org Bus *bus; 654022Sstever@eecs.umich.edu 665735Snate@binkert.org /** A id to keep track of the intercafe ID this port is connected to. */ 675735Snate@binkert.org int id; 685735Snate@binkert.org 694022Sstever@eecs.umich.edu public: 704022Sstever@eecs.umich.edu 714022Sstever@eecs.umich.edu /** Constructor for the BusPort.*/ 724022Sstever@eecs.umich.edu BusPort(const std::string &_name, Bus *_bus, int _id) 734473Sstever@eecs.umich.edu : Port(_name, _bus), _onRetryList(false), bus(_bus), id(_id) 745319Sstever@gmail.com { } 754022Sstever@eecs.umich.edu 764022Sstever@eecs.umich.edu bool onRetryList() 774022Sstever@eecs.umich.edu { return _onRetryList; } 784022Sstever@eecs.umich.edu 794022Sstever@eecs.umich.edu void onRetryList(bool newVal) 804022Sstever@eecs.umich.edu { _onRetryList = newVal; } 814022Sstever@eecs.umich.edu 824022Sstever@eecs.umich.edu int getId() { return id; } 834022Sstever@eecs.umich.edu 844022Sstever@eecs.umich.edu protected: 857465Ssteve.reinhardt@amd.com 864628Sstever@eecs.umich.edu /** When reciving a timing request from the peer port (at id), 877465Ssteve.reinhardt@amd.com pass it to the bus. */ 887465Ssteve.reinhardt@amd.com virtual bool recvTiming(PacketPtr pkt) 894022Sstever@eecs.umich.edu { pkt->setSrc(id); return bus->recvTiming(pkt); } 904022Sstever@eecs.umich.edu 914626Sstever@eecs.umich.edu /** When reciving a Atomic requestfrom the peer port (at id), 924626Sstever@eecs.umich.edu pass it to the bus. */ 937669Ssteve.reinhardt@amd.com virtual Tick recvAtomic(PacketPtr pkt) 944626Sstever@eecs.umich.edu { pkt->setSrc(id); return bus->recvAtomic(pkt); } 954040Ssaidi@eecs.umich.edu 964040Ssaidi@eecs.umich.edu /** When reciving a Functional requestfrom the peer port (at id), 975650Sgblack@eecs.umich.edu pass it to the bus. */ 985650Sgblack@eecs.umich.edu virtual void recvFunctional(PacketPtr pkt) 994870Sstever@eecs.umich.edu { pkt->setSrc(id); bus->recvFunctional(pkt); } 1004870Sstever@eecs.umich.edu 1014870Sstever@eecs.umich.edu /** When reciving a status changefrom the peer port (at id), 1024870Sstever@eecs.umich.edu pass it to the bus. */ 1034870Sstever@eecs.umich.edu virtual void recvStatusChange(Status status) 1044870Sstever@eecs.umich.edu { bus->recvStatusChange(status, id); } 1054870Sstever@eecs.umich.edu 1068436SBrad.Beckmann@amd.com /** When reciving a retry from the peer port (at id), 1078436SBrad.Beckmann@amd.com pass it to the bus. */ 1085314Sstever@gmail.com virtual void recvRetry() 1095314Sstever@gmail.com { bus->recvRetry(id); } 1108184Ssomayeh@cs.wisc.edu 1114022Sstever@eecs.umich.edu // This should return all the 'owned' addresses that are 1124022Sstever@eecs.umich.edu // downstream from this bus, yes? That is, the union of all 1134022Sstever@eecs.umich.edu // the 'owned' address ranges of all the other interfaces on 1144022Sstever@eecs.umich.edu // this bus... 1155735Snate@binkert.org virtual void getDeviceAddressRanges(AddrRangeList &resp, 1165735Snate@binkert.org bool &snoop) 1175735Snate@binkert.org { bus->addressRanges(resp, snoop, id); } 1184022Sstever@eecs.umich.edu 1194022Sstever@eecs.umich.edu // Ask the bus to ask everyone on the bus what their block size is and 1204626Sstever@eecs.umich.edu // take the max of it. This might need to be changed a bit if we ever 1214626Sstever@eecs.umich.edu // support multiple block sizes. 1227465Ssteve.reinhardt@amd.com virtual int deviceBlockSize() 1234626Sstever@eecs.umich.edu { return bus->findBlockSize(id); } 1244022Sstever@eecs.umich.edu 1254626Sstever@eecs.umich.edu }; 1264626Sstever@eecs.umich.edu 1274626Sstever@eecs.umich.edu class BusFreeEvent : public Event 1284626Sstever@eecs.umich.edu { 1294022Sstever@eecs.umich.edu Bus * bus; 1304022Sstever@eecs.umich.edu 1316076Sgblack@eecs.umich.edu public: 1324626Sstever@eecs.umich.edu BusFreeEvent(Bus * _bus); 1334870Sstever@eecs.umich.edu void process(); 1345314Sstever@gmail.com const char *description() const; 1358184Ssomayeh@cs.wisc.edu }; 1364022Sstever@eecs.umich.edu 1374022Sstever@eecs.umich.edu /** a globally unique id for this bus. */ 1384022Sstever@eecs.umich.edu int busId; 1395735Snate@binkert.org /** the clock speed for the bus */ 1405735Snate@binkert.org int clock; 1415735Snate@binkert.org /** cycles of overhead per transaction */ 1425735Snate@binkert.org int headerCycles; 1435735Snate@binkert.org /** the width of the bus in bytes */ 1445735Snate@binkert.org int width; 1455735Snate@binkert.org /** the next tick at which the bus will be idle */ 1464022Sstever@eecs.umich.edu Tick tickNextIdle; 1475735Snate@binkert.org 1485735Snate@binkert.org Event * drainEvent; 1494022Sstever@eecs.umich.edu 1505735Snate@binkert.org 1514022Sstever@eecs.umich.edu static const int defaultId = -3; //Make it unique from Broadcast 1524022Sstever@eecs.umich.edu 1534022Sstever@eecs.umich.edu typedef range_map<Addr,int>::iterator PortIter; 1545735Snate@binkert.org range_map<Addr, int> portMap; 1554022Sstever@eecs.umich.edu 1564022Sstever@eecs.umich.edu AddrRangeList defaultRange; 1574022Sstever@eecs.umich.edu 1584022Sstever@eecs.umich.edu typedef std::vector<BusPort*>::iterator SnoopIter; 1594022Sstever@eecs.umich.edu std::vector<BusPort*> snoopPorts; 1604022Sstever@eecs.umich.edu 1615735Snate@binkert.org /** Function called by the port when the bus is recieving a Timing 1625735Snate@binkert.org transaction.*/ 1635735Snate@binkert.org bool recvTiming(PacketPtr pkt); 1644022Sstever@eecs.umich.edu 1654022Sstever@eecs.umich.edu /** Function called by the port when the bus is recieving a Atomic 1664022Sstever@eecs.umich.edu transaction.*/ 1674022Sstever@eecs.umich.edu Tick recvAtomic(PacketPtr pkt); 1684022Sstever@eecs.umich.edu 1694022Sstever@eecs.umich.edu /** Function called by the port when the bus is recieving a Functional 1707465Ssteve.reinhardt@amd.com transaction.*/ 1717465Ssteve.reinhardt@amd.com void recvFunctional(PacketPtr pkt); 1724022Sstever@eecs.umich.edu 1734022Sstever@eecs.umich.edu /** Timing function called by port when it is once again able to process 1744870Sstever@eecs.umich.edu * requests. */ 1754022Sstever@eecs.umich.edu void recvRetry(int id); 1764022Sstever@eecs.umich.edu 1774022Sstever@eecs.umich.edu /** Function called by the port when the bus is recieving a status change.*/ 1784626Sstever@eecs.umich.edu void recvStatusChange(Port::Status status, int id); 1796102Sgblack@eecs.umich.edu 1804870Sstever@eecs.umich.edu /** Find which port connected to this bus (if any) should be given a packet 1815314Sstever@gmail.com * with this address. 1828184Ssomayeh@cs.wisc.edu * @param addr Address to find port for. 1834022Sstever@eecs.umich.edu * @return id of port that the packet should be sent out of. 1845735Snate@binkert.org */ 1855735Snate@binkert.org int findPort(Addr addr); 1865735Snate@binkert.org 1874022Sstever@eecs.umich.edu // Cache for the findPort function storing recently used ports from portMap 1884022Sstever@eecs.umich.edu struct PortCache { 1894022Sstever@eecs.umich.edu bool valid; 1905735Snate@binkert.org int id; 1915735Snate@binkert.org Addr start; 1924022Sstever@eecs.umich.edu Addr end; 1934022Sstever@eecs.umich.edu }; 1945735Snate@binkert.org 1955735Snate@binkert.org PortCache portCache[3]; 1965735Snate@binkert.org 1974022Sstever@eecs.umich.edu // Checks the cache and returns the id of the port that has the requested 1985735Snate@binkert.org // address within its range 1995735Snate@binkert.org inline int checkPortCache(Addr addr) { 2004022Sstever@eecs.umich.edu if (portCache[0].valid && addr >= portCache[0].start && 2014022Sstever@eecs.umich.edu addr < portCache[0].end) { 2022381SN/A return portCache[0].id; 2032662Sstever@eecs.umich.edu } 2042662Sstever@eecs.umich.edu if (portCache[1].valid && addr >= portCache[1].start && 2052662Sstever@eecs.umich.edu addr < portCache[1].end) { 2062662Sstever@eecs.umich.edu return portCache[1].id; 2072662Sstever@eecs.umich.edu } 2082381SN/A if (portCache[2].valid && addr >= portCache[2].start && 2095314Sstever@gmail.com addr < portCache[2].end) { 2102381SN/A return portCache[2].id; 2112813Srdreslin@umich.edu } 2125735Snate@binkert.org 2135735Snate@binkert.org return -1; 2145735Snate@binkert.org } 2154022Sstever@eecs.umich.edu 2165735Snate@binkert.org // Clears the earliest entry of the cache and inserts a new port entry 2175735Snate@binkert.org inline void updatePortCache(short id, Addr start, Addr end) { 2185735Snate@binkert.org portCache[2].valid = portCache[1].valid; 2195735Snate@binkert.org portCache[2].id = portCache[1].id; 2205735Snate@binkert.org portCache[2].start = portCache[1].start; 2215735Snate@binkert.org portCache[2].end = portCache[1].end; 2225735Snate@binkert.org 2235735Snate@binkert.org portCache[1].valid = portCache[0].valid; 2245735Snate@binkert.org portCache[1].id = portCache[0].id; 2255735Snate@binkert.org portCache[1].start = portCache[0].start; 2265735Snate@binkert.org portCache[1].end = portCache[0].end; 2275735Snate@binkert.org 2285735Snate@binkert.org portCache[0].valid = true; 2295735Snate@binkert.org portCache[0].id = id; 2305735Snate@binkert.org portCache[0].start = start; 2315735Snate@binkert.org portCache[0].end = end; 2325735Snate@binkert.org } 2335735Snate@binkert.org 2345735Snate@binkert.org // Clears the cache. Needs to be called in constructor. 2355735Snate@binkert.org inline void clearPortCache() { 2365735Snate@binkert.org portCache[2].valid = false; 2375735Snate@binkert.org portCache[1].valid = false; 2385735Snate@binkert.org portCache[0].valid = false; 2395735Snate@binkert.org } 2405735Snate@binkert.org 2415735Snate@binkert.org /** Process address range request. 2425735Snate@binkert.org * @param resp addresses that we can respond to 2435735Snate@binkert.org * @param snoop addresses that we would like to snoop 2445735Snate@binkert.org * @param id ide of the busport that made the request. 2458436SBrad.Beckmann@amd.com */ 2468436SBrad.Beckmann@amd.com void addressRanges(AddrRangeList &resp, bool &snoop, int id); 2478436SBrad.Beckmann@amd.com 2485735Snate@binkert.org /** Prepare a packet to be sent on the bus. The header finishes at tick 2495735Snate@binkert.org * headerTime 2505735Snate@binkert.org */ 2515735Snate@binkert.org void preparePacket(PacketPtr pkt, Tick & headerTime); 2524022Sstever@eecs.umich.edu 2534022Sstever@eecs.umich.edu /** Occupy the bus until until */ 2545735Snate@binkert.org void occupyBus(Tick until); 2554870Sstever@eecs.umich.edu 2564870Sstever@eecs.umich.edu /** Ask everyone on the bus what their size is 2575735Snate@binkert.org * @param id id of the busport that made the request 2584870Sstever@eecs.umich.edu * @return the max of all the sizes 2594870Sstever@eecs.umich.edu */ 2602566SN/A int findBlockSize(int id); 2615735Snate@binkert.org 2625735Snate@binkert.org BusFreeEvent busIdle; 2635735Snate@binkert.org 2645735Snate@binkert.org bool inRetry; 2655735Snate@binkert.org std::set<int> inRecvStatusChange; 2665735Snate@binkert.org 2672566SN/A /** max number of bus ids we've handed out so far */ 2682566SN/A short maxId; 2692566SN/A 2705735Snate@binkert.org /** An array of pointers to the peer port interfaces 2715735Snate@binkert.org connected to this bus.*/ 2722381SN/A m5::hash_map<short,BusPort*> interfaces; 2732381SN/A 2745735Snate@binkert.org /** An array of pointers to ports that retry should be called on because the 2756227Snate@binkert.org * original send failed for whatever reason.*/ 2762381SN/A std::list<BusPort*> retryList; 2775735Snate@binkert.org 2785735Snate@binkert.org void addToRetryList(BusPort * port) 2795735Snate@binkert.org { 2805735Snate@binkert.org if (!inRetry) { 2815735Snate@binkert.org // The device wasn't retrying a packet, or wasn't at an appropriate 2825735Snate@binkert.org // time. 2835735Snate@binkert.org assert(!port->onRetryList()); 2842381SN/A port->onRetryList(true); 2855735Snate@binkert.org retryList.push_back(port); 2865735Snate@binkert.org } else { 2875735Snate@binkert.org if (port->onRetryList()) { 2885735Snate@binkert.org // The device was retrying a packet. It didn't work, so we'll leave 2895735Snate@binkert.org // it at the head of the retry list. 2905735Snate@binkert.org assert(port == retryList.front()); 2915735Snate@binkert.org inRetry = false; 2925735Snate@binkert.org } 2932641Sstever@eecs.umich.edu else { 2945735Snate@binkert.org port->onRetryList(true); 2955735Snate@binkert.org retryList.push_back(port); 2964870Sstever@eecs.umich.edu } 2974870Sstever@eecs.umich.edu } 2984870Sstever@eecs.umich.edu } 2994870Sstever@eecs.umich.edu 3004870Sstever@eecs.umich.edu /** Port that handles requests that don't match any of the interfaces.*/ 3014870Sstever@eecs.umich.edu BusPort *defaultPort; 3028668Sgeoffrey.blake@arm.com 3038668Sgeoffrey.blake@arm.com BusPort *funcPort; 3048668Sgeoffrey.blake@arm.com int funcPortId; 3058668Sgeoffrey.blake@arm.com 3068668Sgeoffrey.blake@arm.com /** Has the user specified their own default responder? */ 3078668Sgeoffrey.blake@arm.com bool responderSet; 3088668Sgeoffrey.blake@arm.com 3092641Sstever@eecs.umich.edu int defaultBlockSize; 3105735Snate@binkert.org int cachedBlockSize; 3112811Srdreslin@umich.edu bool cachedBlockSizeValid; 3122811Srdreslin@umich.edu 3135735Snate@binkert.org // Cache for the peer port interfaces 3143218Sgblack@eecs.umich.edu struct BusCache { 3153218Sgblack@eecs.umich.edu bool valid; 3165735Snate@binkert.org short id; 3173218Sgblack@eecs.umich.edu BusPort *port; 3183218Sgblack@eecs.umich.edu }; 3195735Snate@binkert.org 3205735Snate@binkert.org BusCache busCache[3]; 3215735Snate@binkert.org 3222623SN/A // Checks the peer port interfaces cache for the port id and returns 3235735Snate@binkert.org // a pointer to the matching port 3245735Snate@binkert.org inline BusPort* checkBusCache(short id) { 3255735Snate@binkert.org if (busCache[0].valid && id == busCache[0].id) { 3265735Snate@binkert.org return busCache[0].port; 3275735Snate@binkert.org } 3285735Snate@binkert.org if (busCache[1].valid && id == busCache[1].id) { 3295735Snate@binkert.org return busCache[1].port; 3305735Snate@binkert.org } 3315735Snate@binkert.org if (busCache[2].valid && id == busCache[2].id) { 3325735Snate@binkert.org return busCache[2].port; 3335735Snate@binkert.org } 3342641Sstever@eecs.umich.edu 3352641Sstever@eecs.umich.edu return NULL; 3362641Sstever@eecs.umich.edu } 3375315Sstever@gmail.com 3385315Sstever@gmail.com // Replaces the earliest entry in the cache with a new entry 3395315Sstever@gmail.com inline void updateBusCache(short id, BusPort *port) { 3405315Sstever@gmail.com busCache[2].valid = busCache[1].valid; 3415735Snate@binkert.org busCache[2].id = busCache[1].id; 3425735Snate@binkert.org busCache[2].port = busCache[1].port; 3435735Snate@binkert.org 3445735Snate@binkert.org busCache[1].valid = busCache[0].valid; 3455735Snate@binkert.org busCache[1].id = busCache[0].id; 3465735Snate@binkert.org busCache[1].port = busCache[0].port; 3475735Snate@binkert.org 3485735Snate@binkert.org busCache[0].valid = true; 3495314Sstever@gmail.com busCache[0].id = id; 3505314Sstever@gmail.com busCache[0].port = port; 3515314Sstever@gmail.com } 3525735Snate@binkert.org 3535314Sstever@gmail.com // Invalidates the cache. Needs to be called in constructor. 3545314Sstever@gmail.com inline void clearBusCache() { 3555314Sstever@gmail.com busCache[2].valid = false; 3565314Sstever@gmail.com busCache[1].valid = false; 3575314Sstever@gmail.com busCache[0].valid = false; 3585314Sstever@gmail.com } 3595314Sstever@gmail.com 3605314Sstever@gmail.com 3615314Sstever@gmail.com public: 3625314Sstever@gmail.com 3635314Sstever@gmail.com /** A function used to return the port associated with this bus object. */ 3645314Sstever@gmail.com virtual Port *getPort(const std::string &if_name, int idx = -1); 3655314Sstever@gmail.com virtual void deletePortRefs(Port *p); 3665314Sstever@gmail.com 3675735Snate@binkert.org virtual void init(); 3685735Snate@binkert.org virtual void startup(); 3695735Snate@binkert.org 3705314Sstever@gmail.com unsigned int drain(Event *de); 3715315Sstever@gmail.com 3725735Snate@binkert.org Bus(const BusParams *p) 3735735Snate@binkert.org : MemObject(p), busId(p->bus_id), clock(p->clock), 3745315Sstever@gmail.com headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 3755735Snate@binkert.org drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), 3765735Snate@binkert.org defaultPort(NULL), funcPort(NULL), funcPortId(-4), 3775314Sstever@gmail.com responderSet(p->responder_set), defaultBlockSize(p->block_size), 3785314Sstever@gmail.com cachedBlockSize(0), cachedBlockSizeValid(false) 3795735Snate@binkert.org { 3805735Snate@binkert.org //width, clock period, and header cycles must be positive 3815735Snate@binkert.org if (width <= 0) 3825735Snate@binkert.org fatal("Bus width must be positive\n"); 3835314Sstever@gmail.com if (clock <= 0) 3845735Snate@binkert.org fatal("Bus clock period must be positive\n"); 3855735Snate@binkert.org if (headerCycles <= 0) 3865735Snate@binkert.org fatal("Number of header cycles must be positive\n"); 3875315Sstever@gmail.com clearBusCache(); 3885735Snate@binkert.org clearPortCache(); 3895735Snate@binkert.org } 3905314Sstever@gmail.com 3915735Snate@binkert.org}; 3925735Snate@binkert.org 3935735Snate@binkert.org#endif //__MEM_BUS_HH__ 3945735Snate@binkert.org