MESI: Add queues for stalled requests
[gem5.git] / src / mem / port.hh
index b89c7dbd39986fd37290635cb9112050e3257ab0..98b3ad5f1b561e544290640dba505bd214888aa0 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2002-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -30,7 +42,7 @@
 
 /**
  * @file
- * Port Object Decleration. Ports are used to interface memory objects to
+ * Port Object Declaration. Ports are used to interface memory objects to
  * each other.  They will always come in pairs, and we refer to the other
  * port object as the peer.  These are used to make the design more
  * modular so that a specific interface between every type of objcet doesn't
 #define __MEM_PORT_HH__
 
 #include <list>
-#include <inttypes.h>
 
 #include "base/misc.hh"
 #include "base/range.hh"
+#include "base/types.hh"
 #include "mem/packet.hh"
 #include "mem/request.hh"
 
-/** This typedef is used to clean up the parameter list of
- * getDeviceAddressRanges() and getPeerAddressRanges().  It's declared
+/** This typedef is used to clean up getAddrRanges(). It's declared
  * outside the Port object since it's also used by some mem objects.
  * Eventually we should move this typedef to wherever Addr is
  * defined.
@@ -58,6 +69,8 @@
 typedef std::list<Range<Addr> > AddrRangeList;
 typedef std::list<Range<Addr> >::iterator AddrRangeIter;
 
+class MemObject;
+
 /**
  * Ports are used to interface memory objects to
  * each other.  They will always come in pairs, and we refer to the other
@@ -71,66 +84,67 @@ typedef std::list<Range<Addr> >::iterator AddrRangeIter;
  */
 class Port
 {
-  private:
-
+  protected:
     /** Descriptive name (for DPRINTF output) */
-    const std::string portName;
+    mutable std::string portName;
 
     /** A pointer to the peer port.  Ports always come in pairs, that way they
         can use a standardized interface to communicate between different
         memory objects. */
     Port *peer;
 
-  public:
+    /** A pointer to the MemObject that owns this port. This may not be set. */
+    MemObject *owner;
 
+  public:
     /**
      * Constructor.
      *
      * @param _name Port name for DPRINTF output.  Should include name
      * of memory system object to which the port belongs.
+     * @param _owner Pointer to the MemObject that owns this port.
+     * Will not necessarily be set.
      */
-    Port(const std::string &_name)
-        : portName(_name), peer(NULL)
-    { }
+    Port(const std::string &_name, MemObject *_owner);
 
     /** Return port name (for DPRINTF). */
     const std::string &name() const { return portName; }
 
-    virtual ~Port() {};
+    virtual ~Port();
 
-    // mey be better to use subclasses & RTTI?
-    /** Holds the ports status.  Currently just that a range recomputation needs
-     * to be done. */
-    enum Status {
-        RangeChange
-    };
+    void setName(const std::string &name)
+    { portName = name; }
 
-    /** Function to set the pointer for the peer port.
-        @todo should be called by the configuration stuff (python).
-    */
-    void setPeer(Port *port);
+    /** Function to set the pointer for the peer port. */
+    virtual void setPeer(Port *port);
 
-    /** Function to set the pointer for the peer port.
-        @todo should be called by the configuration stuff (python).
-    */
+    /** Function to get the pointer to the peer port. */
     Port *getPeer() { return peer; }
 
+    /** Function to set the owner of this port. */
+    void setOwner(MemObject *_owner);
+
+    /** Function to return the owner of this port. */
+    MemObject *getOwner() { return owner; }
+
+    bool isConnected() { return peer != NULL; }
+
   protected:
 
     /** These functions are protected because they should only be
      * called by a peer port, never directly by any outside object. */
 
     /** Called to recive a timing call from the peer port. */
-    virtual bool recvTiming(Packet *pkt) = 0;
+    virtual bool recvTiming(PacketPtr pkt) = 0;
 
     /** Called to recive a atomic call from the peer port. */
-    virtual Tick recvAtomic(Packet *pkt) = 0;
+    virtual Tick recvAtomic(PacketPtr pkt) = 0;
 
     /** Called to recive a functional call from the peer port. */
-    virtual void recvFunctional(Packet *pkt) = 0;
+    virtual void recvFunctional(PacketPtr pkt) = 0;
 
-    /** Called to recieve a status change from the peer port. */
-    virtual void recvStatusChange(Status status) = 0;
+    /** Called to recieve an address range change from the peer port. */
+    virtual void recvRangeChange() = 0;
 
     /** Called by a peer port if the send was unsuccesful, and had to
         wait.  This shouldn't be valid for response paths (IO Devices).
@@ -140,22 +154,36 @@ class Port
 
     /** Called by a peer port in order to determine the block size of the
         device connected to this port.  It sometimes doesn't make sense for
-        this function to be called, a DMA interface doesn't really have a
-        block size, so it is defaulted to a panic.
+        this function to be called, so it just returns 0. Anytthing that is
+        concerned with the size should just ignore that.
     */
-    virtual int deviceBlockSize() { panic("??"); }
-
-    /** The peer port is requesting us to reply with a list of the ranges we
-        are responsible for.
-        @param resp is a list of ranges responded to
-        @param snoop is a list of ranges snooped
-    */
-    virtual void getDeviceAddressRanges(AddrRangeList &resp,
-            AddrRangeList &snoop)
-    { panic("??"); }
+    virtual unsigned deviceBlockSize() const { return 0; }
 
   public:
 
+    /**
+     * Get a list of the non-overlapping address ranges we are
+     * responsible for. The default implementation returns an empty
+     * list and thus no address ranges. Any slave port must override
+     * this function and return a populated list with at least one
+     * item.
+     *
+     * @return a list of ranges responded to
+     */
+    virtual AddrRangeList getAddrRanges()
+    { AddrRangeList ranges; return ranges; }
+
+    /**
+     * Determine if this port is snooping or not. The default
+     * implementation returns false and thus tells the neighbour we
+     * are not snooping. Any port that is to snoop (e.g. a cache
+     * connected to a bus) has to override this function.
+     *
+     * @return true if the port should be considered a snooper
+     */
+    virtual bool isSnooping()
+    { return false; }
+
     /** Function called by associated memory device (cache, memory, iodevice)
         in order to send a timing request to the port.  Simply calls the peer
         port receive function.
@@ -165,14 +193,14 @@ class Port
         case a cache has a higher priority request come in while waiting for
         the bus to arbitrate.
     */
-    bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); }
+    bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); }
 
     /** Function called by the associated device to send an atomic
      *   access, an access in which the data is moved and the state is
      *   updated in one cycle, without interleaving with other memory
      *   accesses.  Returns estimated latency of access.
      */
-    Tick sendAtomic(Packet *pkt)
+    Tick sendAtomic(PacketPtr pkt)
         { return peer->recvAtomic(pkt); }
 
     /** Function called by the associated device to send a functional access,
@@ -180,13 +208,14 @@ class Port
         memory system, without affecting the current state of any block or
         moving the block.
     */
-    void sendFunctional(Packet *pkt)
+    void sendFunctional(PacketPtr pkt)
         { return peer->recvFunctional(pkt); }
 
-    /** Called by the associated device to send a status change to the device
-        connected to the peer interface.
-    */
-    void sendStatusChange(Status status) {peer->recvStatusChange(status); }
+    /**
+     * Called by the associated device to send a status range to the
+     * peer interface.
+     */
+    void sendRangeChange() const { peer->recvRangeChange(); }
 
     /** When a timing access doesn't return a success, some time later the
         Retry will be sent.
@@ -196,13 +225,7 @@ class Port
     /** Called by the associated device if it wishes to find out the blocksize
         of the device on attached to the peer port.
     */
-    int peerBlockSize() { return peer->deviceBlockSize(); }
-
-    /** Called by the associated device if it wishes to find out the address
-        ranges connected to the peer ports devices.
-    */
-    void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
-    { peer->getDeviceAddressRanges(resp, snoop); }
+    unsigned peerBlockSize() const { return peer->deviceBlockSize(); }
 
     /** This function is a wrapper around sendFunctional()
         that breaks a larger, arbitrarily aligned access into
@@ -225,43 +248,16 @@ class Port
     */
     virtual void memsetBlob(Addr addr, uint8_t val, int size);
 
+    /** Inject a PrintReq for the given address to print the state of
+     * that address throughout the memory system.  For debugging.
+     */
+    void printAddr(Addr a);
+
   private:
 
     /** Internal helper function for read/writeBlob().
      */
-    void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd);
-};
-
-/** A simple functional port that is only meant for one way communication to
- * physical memory. It is only meant to be used to load data into memory before
- * the simulation begins.
- */
-
-class FunctionalPort : public Port
-{
-  public:
-    FunctionalPort(const std::string &_name)
-        : Port(_name)
-    {}
-
-    virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); }
-    virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); }
-    virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
-    virtual void recvStatusChange(Status status) {}
-
-    template <typename T>
-    inline void write(Addr addr, T d)
-    {
-        writeBlob(addr, (uint8_t*)&d, sizeof(T));
-    }
-
-    template <typename T>
-    inline T read(Addr addr)
-    {
-        T d;
-        readBlob(addr, (uint8_t*)&d, sizeof(T));
-        return d;
-    }
+    void blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd);
 };
 
 #endif //__MEM_PORT_HH__