X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fbus.hh;h=97a65c8a92f4e5f66297a93955ed2a47c3d7b517;hb=2a1309f2134986edcbff846aff5951ec1e8df6e1;hp=f0dc67b1232b5cc507f7cc588fca67fb55c6d32f;hpb=a13d5af274a1847eaad649af226e643e86a3322d;p=gem5.git diff --git a/src/mem/bus.hh b/src/mem/bus.hh index f0dc67b12..97a65c8a9 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -38,107 +38,22 @@ #define __MEM_BUS_HH__ #include +#include #include -#include -#include "base/range.hh" #include "base/hashmap.hh" +#include "base/range.hh" #include "base/range_map.hh" +#include "base/types.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" #include "mem/port.hh" #include "mem/request.hh" +#include "params/Bus.hh" #include "sim/eventq.hh" class Bus : public MemObject { - /** a globally unique id for this bus. */ - int busId; - /** the clock speed for the bus */ - int clock; - /** the width of the bus in bytes */ - int width; - /** the next tick at which the bus will be idle */ - Tick tickNextIdle; - - Event * drainEvent; - - - static const int defaultId = -3; //Make it unique from Broadcast - - struct DevMap { - int portId; - Range range; - }; - range_map portMap; - AddrRangeList defaultRange; - std::vector portSnoopList; - - /** Function called by the port when the bus is recieving a Timing - transaction.*/ - bool recvTiming(PacketPtr pkt); - - /** Function called by the port when the bus is recieving a Atomic - transaction.*/ - Tick recvAtomic(PacketPtr pkt); - - /** Function called by the port when the bus is recieving a Functional - transaction.*/ - void recvFunctional(PacketPtr pkt); - - /** Timing function called by port when it is once again able to process - * requests. */ - void recvRetry(int id); - - /** Function called by the port when the bus is recieving a status change.*/ - void recvStatusChange(Port::Status status, int id); - - /** Find which port connected to this bus (if any) should be given a packet - * with this address. - * @param addr Address to find port for. - * @param id Id of the port this packet was received from (to prevent - * loops) - * @return pointer to port that the packet should be sent out of. - */ - Port *findPort(Addr addr, int id); - - /** Find all ports with a matching snoop range, except src port. Keep in mind - * that the ranges shouldn't overlap or you will get a double snoop to the same - * interface.and the cache will assert out. - * @param addr Address to find snoop prts for. - * @param id Id of the src port of the request to avoid calling snoop on src - * @return vector of IDs to snoop on - */ - std::vector findSnoopPorts(Addr addr, int id); - - /** Snoop all relevant ports atomicly. */ - Tick atomicSnoop(PacketPtr pkt, Port* responder); - - /** Snoop all relevant ports functionally. */ - void functionalSnoop(PacketPtr pkt, Port *responder); - - /** Call snoop on caches, be sure to set SNOOP_COMMIT bit if you want - * the snoop to happen - * @return True if succeds. - */ - bool timingSnoop(PacketPtr pkt, Port *responder); - - /** Process address range request. - * @param resp addresses that we can respond to - * @param snoop addresses that we would like to snoop - * @param id ide of the busport that made the request. - */ - void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id); - - /** Occupy the bus with transmitting the packet pkt */ - void occupyBus(PacketPtr pkt); - - /** Ask everyone on the bus what their size is - * @param id id of the busport that made the request - * @return the max of all the sizes - */ - int findBlockSize(int id); - /** Declaration of the buses port type, one will be instantiated for each of the interfaces connecting to the bus. */ class BusPort : public Port @@ -198,13 +113,13 @@ class Bus : public MemObject // the 'owned' address ranges of all the other interfaces on // this bus... virtual void getDeviceAddressRanges(AddrRangeList &resp, - AddrRangeList &snoop) + bool &snoop) { bus->addressRanges(resp, snoop, id); } // Ask the bus to ask everyone on the bus what their block size is and // take the max of it. This might need to be changed a bit if we ever // support multiple block sizes. - virtual int deviceBlockSize() + virtual unsigned deviceBlockSize() const { return bus->findBlockSize(id); } }; @@ -216,12 +131,140 @@ class Bus : public MemObject public: BusFreeEvent(Bus * _bus); void process(); - const char *description(); + const char *description() const; + }; + + /** a globally unique id for this bus. */ + int busId; + /** 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; + + + static const int defaultId = -3; //Make it unique from Broadcast + + typedef range_map::iterator PortIter; + range_map portMap; + + AddrRangeList defaultRange; + + typedef std::vector::iterator SnoopIter; + std::vector snoopPorts; + + /** Function called by the port when the bus is recieving a Timing + transaction.*/ + bool recvTiming(PacketPtr pkt); + + /** Function called by the port when the bus is recieving a Atomic + transaction.*/ + Tick recvAtomic(PacketPtr pkt); + + /** Function called by the port when the bus is recieving a Functional + transaction.*/ + void recvFunctional(PacketPtr pkt); + + /** Timing function called by port when it is once again able to process + * requests. */ + void recvRetry(int id); + + /** Function called by the port when the bus is recieving a status change.*/ + void recvStatusChange(Port::Status status, int id); + + /** Find which port connected to this bus (if any) should be given a packet + * with this address. + * @param addr Address to find port for. + * @return id of port that the packet should be sent out of. + */ + int findPort(Addr addr); + + // Cache for the findPort function storing recently used ports from portMap + struct PortCache { + bool valid; + int id; + Addr start; + Addr end; }; + PortCache portCache[3]; + + // Checks the cache and returns the id of the port that has the requested + // address within its range + inline int checkPortCache(Addr addr) { + if (portCache[0].valid && addr >= portCache[0].start && + addr < portCache[0].end) { + return portCache[0].id; + } + if (portCache[1].valid && addr >= portCache[1].start && + addr < portCache[1].end) { + return portCache[1].id; + } + if (portCache[2].valid && addr >= portCache[2].start && + addr < portCache[2].end) { + return portCache[2].id; + } + + return -1; + } + + // Clears the earliest entry of the cache and inserts a new port entry + inline void updatePortCache(short id, Addr start, Addr end) { + 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[1].valid = portCache[0].valid; + portCache[1].id = portCache[0].id; + portCache[1].start = portCache[0].start; + portCache[1].end = portCache[0].end; + + portCache[0].valid = true; + portCache[0].id = id; + portCache[0].start = start; + portCache[0].end = end; + } + + // Clears the cache. Needs to be called in constructor. + inline void clearPortCache() { + portCache[2].valid = false; + portCache[1].valid = false; + portCache[0].valid = false; + } + + /** Process address range request. + * @param resp addresses that we can respond to + * @param snoop addresses that we would like to snoop + * @param id ide of the busport that made the request. + */ + void addressRanges(AddrRangeList &resp, bool &snoop, int id); + + /** 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); + + /** Ask everyone on the bus what their size is + * @param id id of the busport that made the request + * @return the max of all the sizes + */ + unsigned findBlockSize(int id); + BusFreeEvent busIdle; bool inRetry; + std::set inRecvStatusChange; /** max number of bus ids we've handed out so far */ short maxId; @@ -265,10 +308,58 @@ class Bus : public MemObject /** Has the user specified their own default responder? */ bool responderSet; - int defaultBlockSize; - int cachedBlockSize; + unsigned defaultBlockSize; + unsigned cachedBlockSize; bool cachedBlockSizeValid; + // Cache for the peer port interfaces + struct BusCache { + bool valid; + short id; + BusPort *port; + }; + + BusCache busCache[3]; + + // Checks the peer port interfaces cache for the port id and returns + // a pointer to the matching port + inline BusPort* checkBusCache(short id) { + if (busCache[0].valid && id == busCache[0].id) { + return busCache[0].port; + } + if (busCache[1].valid && id == busCache[1].id) { + return busCache[1].port; + } + if (busCache[2].valid && id == busCache[2].id) { + return busCache[2].port; + } + + return NULL; + } + + // Replaces the earliest entry in the cache with a new entry + inline void updateBusCache(short id, BusPort *port) { + busCache[2].valid = busCache[1].valid; + busCache[2].id = busCache[1].id; + busCache[2].port = busCache[1].port; + + busCache[1].valid = busCache[0].valid; + busCache[1].id = busCache[0].id; + busCache[1].port = busCache[0].port; + + busCache[0].valid = true; + busCache[0].id = id; + busCache[0].port = port; + } + + // Invalidates the cache. Needs to be called in constructor. + inline void clearBusCache() { + busCache[2].valid = false; + busCache[1].valid = false; + busCache[0].valid = false; + } + + public: /** A function used to return the port associated with this bus object. */ @@ -276,22 +367,27 @@ class Bus : public MemObject virtual void deletePortRefs(Port *p); virtual void init(); + virtual void startup(); unsigned int drain(Event *de); - Bus(const std::string &n, int bus_id, int _clock, int _width, - bool responder_set, int dflt_blk_size) - : MemObject(n), busId(bus_id), clock(_clock), width(_width), - tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false), - maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4), - responderSet(responder_set), defaultBlockSize(dflt_blk_size), + Bus(const BusParams *p) + : MemObject(p), busId(p->bus_id), clock(p->clock), + headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), + drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), + defaultPort(NULL), funcPort(NULL), funcPortId(-4), + responderSet(p->responder_set), defaultBlockSize(p->block_size), cachedBlockSize(0), cachedBlockSizeValid(false) { - //Both the width and clock period must be positive + //width, clock period, and header cycles must be positive if (width <= 0) fatal("Bus width must be positive\n"); if (clock <= 0) fatal("Bus clock period must be positive\n"); + if (headerCycles <= 0) + fatal("Number of header cycles must be positive\n"); + clearBusCache(); + clearPortCache(); } };