X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fbus.hh;h=705a3a999cd2a9d6df943b49cd8abd717a4db14d;hb=8573a69d8f7bf7b3f074e3e0ac64994801c551be;hp=94068d897bc8103879d0d0495618fe691c4a98a5;hpb=46d9adb68c96b94ae25bbe92d34e375daf532ece;p=gem5.git diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 94068d897..705a3a999 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 ARM Limited + * Copyright (c) 2011-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -51,11 +51,10 @@ #ifndef __MEM_BUS_HH__ #define __MEM_BUS_HH__ -#include +#include #include -#include "base/range.hh" -#include "base/range_map.hh" +#include "base/addr_range_map.hh" #include "base/types.hh" #include "mem/mem_object.hh" #include "params/BaseBus.hh" @@ -74,46 +73,169 @@ class BaseBus : public MemObject protected: - /** the clock speed for the bus */ - int clock; - /** cycles of overhead per transaction */ - int headerCycles; - /** the width of the bus in bytes */ - int width; - /** the next tick at which the bus will be idle */ - Tick tickNextIdle; - - Event * drainEvent; - - typedef range_map::iterator PortMapIter; - typedef range_map::const_iterator PortMapConstIter; - range_map portMap; - - AddrRangeList defaultRange; - /** - * Determine if the bus is to be considered occupied when being - * presented with a packet from a specific port. If so, the port - * in question is also added to the retry list. + * A bus layer is an internal bus structure with its own flow + * control and arbitration. Hence, a single-layer bus mimics a + * traditional off-chip tri-state bus (like PCI), where only one + * set of wires are shared. For on-chip buses, a good starting + * point is to have three layers, for requests, responses, and + * snoop responses respectively (snoop requests are instantaneous + * and do not need any flow control or arbitration). This case is + * similar to AHB and some OCP configurations. * - * @param port Source port on the bus presenting the packet + * As a further extensions beyond the three-layer bus, a future + * multi-layer bus has with one layer per connected slave port + * provides a full or partial crossbar, like AXI, OCP, PCIe etc. * - * @return True if the bus is to be considered occupied + * The template parameter, PortClass, indicates the destination + * port type for the bus. The retry list holds either master ports + * or slave ports, depending on the direction of the layer. Thus, + * a request layer has a retry list containing slave ports, + * whereas a response layer holds master ports. */ - bool isOccupied(Port* port); + template + class Layer : public Drainable + { - /** - * Deal with a destination port accepting a packet by potentially - * removing the source port from the retry list (if retrying) and - * occupying the bus accordingly. - * - * @param busy_time Time to spend as a result of a successful send - */ - void succeededTiming(Tick busy_time); + public: + + /** + * Create a bus layer and give it a name. The bus layer uses + * the bus an event manager. + * + * @param _bus the bus this layer belongs to + * @param _name the layer's name + */ + Layer(BaseBus& _bus, const std::string& _name); + + /** + * Drain according to the normal semantics, so that the bus + * can tell the layer to drain, and pass an event to signal + * back when drained. + * + * @param de drain event to call once drained + * + * @return 1 if busy or waiting to retry, or 0 if idle + */ + unsigned int drain(DrainManager *dm); + + /** + * Get the bus layer's name + */ + const std::string name() const { return bus.name() + _name; } + + + /** + * Determine if the bus layer accepts a packet from a specific + * port. If not, the port in question is also added to the + * retry list. In either case the state of the layer is updated + * accordingly. + * + * @param port Source port resenting the packet + * + * @return True if the bus layer accepts the packet + */ + bool tryTiming(PortClass* port); + + /** + * Deal with a destination port accepting a packet by potentially + * removing the source port from the retry list (if retrying) and + * occupying the bus layer accordingly. + * + * @param busy_time Time to spend as a result of a successful send + */ + void succeededTiming(Tick busy_time); + + /** + * Deal with a destination port not accepting a packet by + * potentially adding the source port to the retry list (if + * not already at the front) and occupying the bus layer + * accordingly. + * + * @param busy_time Time to spend as a result of a failed send + */ + void failedTiming(PortClass* port, Tick busy_time); + + /** Occupy the bus layer until until */ + void occupyLayer(Tick until); + + /** + * Send a retry to the port at the head of the retryList. The + * caller must ensure that the list is not empty. + */ + void retryWaiting(); + + /** + * Handler a retry from a neighbouring module. Eventually this + * should be all encapsulated in the bus. This wraps + * retryWaiting by verifying that there are ports waiting + * before calling retryWaiting. + */ + void recvRetry(); + + private: + + /** The bus this layer is a part of. */ + BaseBus& bus; + + /** A name for this layer. */ + std::string _name; + + /** + * We declare an enum to track the state of the bus layer. The + * starting point is an idle state where the bus layer is + * waiting for a packet to arrive. Upon arrival, the bus layer + * transitions to the busy state, where it remains either + * until the packet transfer is done, or the header time is + * spent. Once the bus layer leaves the busy state, it can + * either go back to idle, if no packets have arrived while it + * was busy, or the bus layer goes on to retry the first port + * on the retryList. A similar transition takes place from + * idle to retry if the bus layer receives a retry from one of + * its connected ports. The retry state lasts until the port + * in questions calls sendTiming and returns control to the + * bus layer, or goes to a busy state if the port does not + * immediately react to the retry by calling sendTiming. + */ + enum State { IDLE, BUSY, RETRY }; + + /** track the state of the bus layer */ + State state; + + /** manager to signal when drained */ + DrainManager *drainManager; + + /** + * An array of ports that retry should be called + * on because the original send failed for whatever reason. + */ + std::deque retryList; + + /** + * Release the bus layer after being occupied and return to an + * idle state where we proceed to send a retry to any + * potential waiting port, or drain if asked to do so. + */ + void releaseLayer(); + + /** event used to schedule a release of the layer */ + EventWrapper releaseEvent; + + }; + + /** cycles of overhead per transaction */ + const Cycles headerCycles; + /** the width of the bus in bytes */ + const uint32_t width; + + typedef AddrRangeMap::iterator PortMapIter; + typedef AddrRangeMap::const_iterator PortMapConstIter; + AddrRangeMap portMap; - /** Timing function called by port when it is once again able to process - * requests. */ - void recvRetry(); + /** all contigous ranges seen by this bus */ + AddrRangeList busRanges; + + AddrRange defaultRange; /** * Function called by the port when the bus is recieving a range change. @@ -133,25 +255,21 @@ class BaseBus : public MemObject struct PortCache { bool valid; PortID id; - Addr start; - Addr end; + AddrRange range; }; PortCache portCache[3]; // Checks the cache and returns the id of the port that has the requested // address within its range - inline PortID checkPortCache(Addr addr) { - if (portCache[0].valid && addr >= portCache[0].start && - addr < portCache[0].end) { + inline PortID checkPortCache(Addr addr) const { + if (portCache[0].valid && portCache[0].range.contains(addr)) { return portCache[0].id; } - if (portCache[1].valid && addr >= portCache[1].start && - addr < portCache[1].end) { + if (portCache[1].valid && portCache[1].range.contains(addr)) { return portCache[1].id; } - if (portCache[2].valid && addr >= portCache[2].start && - addr < portCache[2].end) { + if (portCache[2].valid && portCache[2].range.contains(addr)) { return portCache[2].id; } @@ -159,21 +277,18 @@ class BaseBus : public MemObject } // Clears the earliest entry of the cache and inserts a new port entry - inline void updatePortCache(short id, Addr start, Addr end) { + inline void updatePortCache(short id, const AddrRange& range) { portCache[2].valid = portCache[1].valid; portCache[2].id = portCache[1].id; - portCache[2].start = portCache[1].start; - portCache[2].end = portCache[1].end; + portCache[2].range = portCache[1].range; portCache[1].valid = portCache[0].valid; portCache[1].id = portCache[0].id; - portCache[1].start = portCache[0].start; - portCache[1].end = portCache[0].end; + portCache[1].range = portCache[0].range; portCache[0].valid = true; portCache[0].id = id; - portCache[0].start = start; - portCache[0].end = end; + portCache[0].range = range; } // Clears the cache. Needs to be called in constructor. @@ -190,41 +305,31 @@ class BaseBus : public MemObject */ AddrRangeList getAddrRanges() const; - /** Calculate the timing parameters for the packet. Updates the - * firstWordTime and finishTime fields of the packet object. - * Returns the tick at which the packet header is completed (which - * will be all that is sent if the target rejects the packet). - */ - Tick calcPacketTiming(PacketPtr pkt); - - /** Occupy the bus until until */ - void occupyBus(Tick until); - /** - * Release the bus after being occupied and return to an idle - * state where we proceed to send a retry to any potential waiting - * port, or drain if asked to do so. + * Calculate the timing parameters for the packet. Updates the + * busFirstWordDelay and busLastWordDelay fields of the packet + * object with the relative number of ticks required to transmit + * the header and the first word, and the last word, respectively. */ - void releaseBus(); + void calcPacketTiming(PacketPtr pkt); /** - * Send a retry to the port at the head of the retryList. The - * caller must ensure that the list is not empty. + * Ask everyone on the bus what their size is and determine the + * bus size as either the maximum, or if no device specifies a + * block size return the default. + * + * @return the max of all the sizes or the default if none is set */ - void retryWaiting(); + unsigned deviceBlockSize() const; /** - * Ask everyone on the bus what their size is - * - * @return the max of all the sizes + * Remember for each of the master ports of the bus if we got an + * address range from the connected slave. For convenience, also + * keep track of if we got ranges from all the slave modules or + * not. */ - unsigned findBlockSize(); - - // event used to schedule a release of the bus - EventWrapper busIdleEvent; - - bool inRetry; - std::set inRecvRangeChange; + std::vector gotAddrRanges; + bool gotAllAddrRanges; /** The master and slave ports of the bus */ std::vector slavePorts; @@ -236,29 +341,6 @@ class BaseBus : public MemObject typedef std::vector::const_iterator SlavePortConstIter; typedef std::vector::const_iterator MasterPortConstIter; - /** An array of pointers to ports that retry should be called on because the - * original send failed for whatever reason.*/ - std::list retryList; - - void addToRetryList(Port* port) - { - if (!inRetry) { - // The device wasn't retrying a packet, or wasn't at an - // appropriate time. - retryList.push_back(port); - } else { - if (!retryList.empty() && port == retryList.front()) { - // The device was retrying a packet. It didn't work, - // so we'll leave it at the head of the retry list. - inRetry = false; - } else { - // We are in retry, but not for this port, put it at - // the end. - retryList.push_back(port); - } - } - } - /** Port that handles requests that don't match any of the interfaces.*/ PortID defaultPortID; @@ -266,11 +348,9 @@ class BaseBus : public MemObject address not handled by another port and not in default device's range will cause a fatal error. If false, just send all addresses not handled by another port to default device. */ - bool useDefaultRange; + const bool useDefaultRange; - unsigned defaultBlockSize; - unsigned cachedBlockSize; - bool cachedBlockSizeValid; + uint32_t blockSize; BaseBus(const BaseBusParams *p); @@ -278,13 +358,15 @@ class BaseBus : public MemObject public: - /** A function used to return the port associated with this bus object. */ - virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1); - virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1); + virtual void init(); - virtual void startup(); + /** A function used to return the port associated with this bus object. */ + BaseMasterPort& getMasterPort(const std::string& if_name, + PortID idx = InvalidPortID); + BaseSlavePort& getSlavePort(const std::string& if_name, + PortID idx = InvalidPortID); - unsigned int drain(Event *de); + virtual unsigned int drain(DrainManager *dm) = 0; };