style: eliminate explicit boolean comparisons
[gem5.git] / src / mem / packet.hh
index d1774e5a8126ee74d860d91d2fb8510dda2465b8..19c7e63970183307ec28c0d43cb0021ca5533820 100644 (file)
@@ -12,7 +12,7 @@
  * modified or unmodified, in source code or in binary form.
  *
  * Copyright (c) 2006 The Regents of The University of Michigan
- * Copyright (c) 2010 Advanced Micro Devices, Inc.
+ * Copyright (c) 2010,2015 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -86,7 +86,8 @@ class MemCmd
         ReadRespWithInvalidate,
         WriteReq,
         WriteResp,
-        Writeback,
+        WritebackDirty,
+        WritebackClean,
         CleanEvict,
         SoftPFReq,
         HardPFReq,
@@ -110,6 +111,8 @@ class MemCmd
         SwapResp,
         MessageReq,
         MessageResp,
+        MemFenceReq,
+        MemFenceResp,
         // Error responses
         // @TODO these should be classified as responses rather than
         // requests; coding them as requests initially for backwards
@@ -136,10 +139,11 @@ class MemCmd
         IsWrite,        //!< Data flows from requester to responder
         IsUpgrade,
         IsInvalidate,
-        NeedsExclusive, //!< Requires exclusive copy to complete in-cache
+        NeedsWritable,  //!< Requires writable copy to complete in-cache
         IsRequest,      //!< Issued by requester
         IsResponse,     //!< Issue by responder
         NeedsResponse,  //!< Requester needs response from target
+        IsEviction,
         IsSWPrefetch,
         IsHWPrefetch,
         IsLlsc,         //!< Alpha/MIPS LL or SC access
@@ -185,9 +189,16 @@ class MemCmd
     bool isUpgrade() const         { return testCmdAttrib(IsUpgrade); }
     bool isRequest() const         { return testCmdAttrib(IsRequest); }
     bool isResponse() const        { return testCmdAttrib(IsResponse); }
-    bool needsExclusive() const    { return testCmdAttrib(NeedsExclusive); }
+    bool needsWritable() const     { return testCmdAttrib(NeedsWritable); }
     bool needsResponse() const     { return testCmdAttrib(NeedsResponse); }
     bool isInvalidate() const      { return testCmdAttrib(IsInvalidate); }
+    bool isEviction() const        { return testCmdAttrib(IsEviction); }
+
+    /**
+     * A writeback is an eviction that carries data.
+     */
+    bool isWriteback() const       { return testCmdAttrib(IsEviction) &&
+                                            testCmdAttrib(HasData); }
 
     /**
      * Check if this particular packet type carries payload data. Note
@@ -204,7 +215,7 @@ class MemCmd
     bool isPrint() const        { return testCmdAttrib(IsPrint); }
     bool isFlush() const        { return testCmdAttrib(IsFlush); }
 
-    const Command
+    Command
     responseCommand() const
     {
         return commandInfo[cmd].response;
@@ -241,15 +252,22 @@ class Packet : public Printable
         // Flags to transfer across when copying a packet
         COPY_FLAGS             = 0x0000000F,
 
-        SHARED                 = 0x00000001,
+        // Does this packet have sharers (which means it should not be
+        // considered writable) or not. See setHasSharers below.
+        HAS_SHARERS            = 0x00000001,
+
         // Special control flags
         /// Special timing-mode atomic snoop for multi-level coherence.
         EXPRESS_SNOOP          = 0x00000002,
-        /// Does supplier have exclusive copy?
-        /// Useful for multi-level coherence.
-        SUPPLY_EXCLUSIVE       = 0x00000004,
-        // Snoop response flags
-        MEM_INHIBIT            = 0x00000008,
+
+        /// Allow a responding cache to inform the cache hierarchy
+        /// that it had a writable copy before responding. See
+        /// setResponderHadWritable below.
+        RESPONDER_HAD_WRITABLE = 0x00000004,
+
+        // Snoop co-ordination flag to indicate that a cache is
+        // responding to a snoop. See setCacheResponding below.
+        CACHE_RESPONDING       = 0x00000008,
 
         /// Are the 'addr' and 'size' fields valid?
         VALID_ADDR             = 0x00000100,
@@ -319,6 +337,14 @@ class Packet : public Printable
      */
     uint32_t headerDelay;
 
+    /**
+     * Keep track of the extra delay incurred by snooping upwards
+     * before sending a request down the memory system. This is used
+     * by the coherent crossbar to account for the additional request
+     * delay.
+     */
+    uint32_t snoopDelay;
+
     /**
      * The extra pipelining delay from seeing the packet until the end of
      * payload is transmitted by the component that provided it (if
@@ -476,31 +502,118 @@ class Packet : public Printable
     bool isUpgrade()  const          { return cmd.isUpgrade(); }
     bool isRequest() const           { return cmd.isRequest(); }
     bool isResponse() const          { return cmd.isResponse(); }
-    bool needsExclusive() const      { return cmd.needsExclusive(); }
+    bool needsWritable() const
+    {
+        // we should never check if a response needsWritable, the
+        // request has this flag, and for a response we should rather
+        // look at the hasSharers flag (if not set, the response is to
+        // be considered writable)
+        assert(isRequest());
+        return cmd.needsWritable();
+    }
     bool needsResponse() const       { return cmd.needsResponse(); }
     bool isInvalidate() const        { return cmd.isInvalidate(); }
+    bool isEviction() const          { return cmd.isEviction(); }
+    bool isWriteback() const         { return cmd.isWriteback(); }
     bool hasData() const             { return cmd.hasData(); }
+    bool hasRespData() const
+    {
+        MemCmd resp_cmd = cmd.responseCommand();
+        return resp_cmd.hasData();
+    }
     bool isLLSC() const              { return cmd.isLLSC(); }
     bool isError() const             { return cmd.isError(); }
     bool isPrint() const             { return cmd.isPrint(); }
     bool isFlush() const             { return cmd.isFlush(); }
 
-    // Snoop flags
-    void assertMemInhibit()
+    //@{
+    /// Snoop flags
+    /**
+     * Set the cacheResponding flag. This is used by the caches to
+     * signal another cache that they are responding to a request. A
+     * cache will only respond to snoops if it has the line in either
+     * Modified or Owned state. Note that on snoop hits we always pass
+     * the line as Modified and never Owned. In the case of an Owned
+     * line we proceed to invalidate all other copies.
+     *
+     * On a cache fill (see Cache::handleFill), we check hasSharers
+     * first, ignoring the cacheResponding flag if hasSharers is set.
+     * A line is consequently allocated as:
+     *
+     * hasSharers cacheResponding state
+     * true       false           Shared
+     * true       true            Shared
+     * false      false           Exclusive
+     * false      true            Modified
+     */
+    void setCacheResponding()
     {
         assert(isRequest());
-        assert(!flags.isSet(MEM_INHIBIT));
-        flags.set(MEM_INHIBIT);
-    }
-    bool memInhibitAsserted() const { return flags.isSet(MEM_INHIBIT); }
-    void assertShared()             { flags.set(SHARED); }
-    bool sharedAsserted() const     { return flags.isSet(SHARED); }
-
-    // Special control flags
-    void setExpressSnoop()          { flags.set(EXPRESS_SNOOP); }
-    bool isExpressSnoop() const     { return flags.isSet(EXPRESS_SNOOP); }
-    void setSupplyExclusive()       { flags.set(SUPPLY_EXCLUSIVE); }
-    bool isSupplyExclusive() const  { return flags.isSet(SUPPLY_EXCLUSIVE); }
+        assert(!flags.isSet(CACHE_RESPONDING));
+        flags.set(CACHE_RESPONDING);
+    }
+    bool cacheResponding() const { return flags.isSet(CACHE_RESPONDING); }
+    /**
+     * On fills, the hasSharers flag is used by the caches in
+     * combination with the cacheResponding flag, as clarified
+     * above. If the hasSharers flag is not set, the packet is passing
+     * writable. Thus, a response from a memory passes the line as
+     * writable by default.
+     *
+     * The hasSharers flag is also used by upstream caches to inform a
+     * downstream cache that they have the block (by calling
+     * setHasSharers on snoop request packets that hit in upstream
+     * cachs tags or MSHRs). If the snoop packet has sharers, a
+     * downstream cache is prevented from passing a dirty line upwards
+     * if it was not explicitly asked for a writable copy. See
+     * Cache::satisfyCpuSideRequest.
+     *
+     * The hasSharers flag is also used on writebacks, in
+     * combination with the WritbackClean or WritebackDirty commands,
+     * to allocate the block downstream either as:
+     *
+     * command        hasSharers state
+     * WritebackDirty false      Modified
+     * WritebackDirty true       Owned
+     * WritebackClean false      Exclusive
+     * WritebackClean true       Shared
+     */
+    void setHasSharers()    { flags.set(HAS_SHARERS); }
+    bool hasSharers() const { return flags.isSet(HAS_SHARERS); }
+    //@}
+
+    /**
+     * The express snoop flag is used for two purposes. Firstly, it is
+     * used to bypass flow control for normal (non-snoop) requests
+     * going downstream in the memory system. In cases where a cache
+     * is responding to a snoop from another cache (it had a dirty
+     * line), but the line is not writable (and there are possibly
+     * other copies), the express snoop flag is set by the downstream
+     * cache to invalidate all other copies in zero time. Secondly,
+     * the express snoop flag is also set to be able to distinguish
+     * snoop packets that came from a downstream cache, rather than
+     * snoop packets from neighbouring caches.
+     */
+    void setExpressSnoop()      { flags.set(EXPRESS_SNOOP); }
+    bool isExpressSnoop() const { return flags.isSet(EXPRESS_SNOOP); }
+
+    /**
+     * On responding to a snoop request (which only happens for
+     * Modified or Owned lines), make sure that we can transform an
+     * Owned response to a Modified one. If this flag is not set, the
+     * responding cache had the line in the Owned state, and there are
+     * possibly other Shared copies in the memory system. A downstream
+     * cache helps in orchestrating the invalidation of these copies
+     * by sending out the appropriate express snoops.
+     */
+    void setResponderHadWritable()
+    {
+        assert(cacheResponding());
+        flags.set(RESPONDER_HAD_WRITABLE);
+    }
+    bool responderHadWritable() const
+    { return flags.isSet(RESPONDER_HAD_WRITABLE); }
+
     void setSuppressFuncError()     { flags.set(SUPPRESS_FUNC_ERROR); }
     bool suppressFuncError() const  { return flags.isSet(SUPPRESS_FUNC_ERROR); }
     void setBlockCached()          { flags.set(BLOCK_CACHED); }
@@ -547,6 +660,12 @@ class Packet : public Printable
         return _isSecure;
     }
 
+    /**
+     * Accessor function to atomic op.
+     */
+    AtomicOpFunctor *getAtomicOp() const { return req->getAtomicOpFunctor(); }
+    bool isAtomicOp() const { return req->isAtomic(); }
+
     /**
      * It has been determined that the SC packet should successfully update
      * memory. Therefore, convert this SC packet to a normal write.
@@ -578,7 +697,7 @@ class Packet : public Printable
      */
     Packet(const RequestPtr _req, MemCmd _cmd)
         :  cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false),
-           size(0), headerDelay(0), payloadDelay(0),
+           size(0), headerDelay(0), snoopDelay(0), payloadDelay(0),
            senderState(NULL)
     {
         if (req->hasPaddr()) {
@@ -599,7 +718,7 @@ class Packet : public Printable
      */
     Packet(const RequestPtr _req, MemCmd _cmd, int _blkSize)
         :  cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false),
-           headerDelay(0), payloadDelay(0),
+           headerDelay(0), snoopDelay(0), payloadDelay(0),
            senderState(NULL)
     {
         if (req->hasPaddr()) {
@@ -624,6 +743,7 @@ class Packet : public Printable
            addr(pkt->addr), _isSecure(pkt->_isSecure), size(pkt->size),
            bytesValid(pkt->bytesValid),
            headerDelay(pkt->headerDelay),
+           snoopDelay(0),
            payloadDelay(pkt->payloadDelay),
            senderState(pkt->senderState)
     {
@@ -763,6 +883,12 @@ class Packet : public Printable
     }
 
 
+  public:
+    /**
+     * @{
+     * @name Data accessor mehtods
+     */
+
     /**
      * Set the data pointer to the following value that should not be
      * freed. Static data allows us to do a single memcpy even if
@@ -841,15 +967,50 @@ class Packet : public Printable
     }
 
     /**
-     * return the value of what is pointed to in the packet.
+     * Get the data in the packet byte swapped from big endian to
+     * host endian.
+     */
+    template <typename T>
+    T getBE() const;
+
+    /**
+     * Get the data in the packet byte swapped from little endian to
+     * host endian.
+     */
+    template <typename T>
+    T getLE() const;
+
+    /**
+     * Get the data in the packet byte swapped from the specified
+     * endianness.
+     */
+    template <typename T>
+    T get(ByteOrder endian) const;
+
+    /**
+     * Get the data in the packet byte swapped from guest to host
+     * endian.
      */
     template <typename T>
     T get() const;
 
+    /** Set the value in the data pointer to v as big endian. */
+    template <typename T>
+    void setBE(T v);
+
+    /** Set the value in the data pointer to v as little endian. */
+    template <typename T>
+    void setLE(T v);
+
     /**
-     * set the value in the data pointer to v.
+     * Set the value in the data pointer to v using the specified
+     * endianness.
      */
     template <typename T>
+    void set(T v, ByteOrder endian);
+
+    /** Set the value in the data pointer to v as guest endian. */
+    template <typename T>
     void set(T v);
 
     /**
@@ -916,11 +1077,27 @@ class Packet : public Printable
     void
     allocate()
     {
-        assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA));
-        flags.set(DYNAMIC_DATA);
-        data = new uint8_t[getSize()];
+        // if either this command or the response command has a data
+        // payload, actually allocate space
+        if (hasData() || hasRespData()) {
+            assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA));
+            flags.set(DYNAMIC_DATA);
+            data = new uint8_t[getSize()];
+        }
     }
 
+    /** @} */
+
+  private: // Private data accessor methods
+    /** Get the data in the packet without byte swapping. */
+    template <typename T>
+    T getRaw() const;
+
+    /** Set the value in the data pointer to v without byte swapping. */
+    template <typename T>
+    void setRaw(T v);
+
+  public:
     /**
      * Check a functional request against a memory value stored in
      * another packet (i.e. an in-transit request or
@@ -942,24 +1119,23 @@ class Packet : public Printable
     }
 
     /**
-     * Is this request notification of a clean or dirty eviction from the cache.
+     * Does the request need to check for cached copies of the same block
+     * in the memory hierarchy above.
      **/
     bool
-    evictingBlock() const
+    mustCheckAbove() const
     {
-        return (cmd == MemCmd::Writeback ||
-                cmd == MemCmd::CleanEvict);
+        return cmd == MemCmd::HardPFReq || isEviction();
     }
 
     /**
-     * Does the request need to check for cached copies of the same block
-     * in the memory hierarchy above.
-     **/
+     * Is this packet a clean eviction, including both actual clean
+     * evict packets, but also clean writebacks.
+     */
     bool
-    mustCheckAbove() const
+    isCleanEviction() const
     {
-        return (cmd == MemCmd::HardPFReq ||
-                evictingBlock());
+        return cmd == MemCmd::CleanEvict || cmd == MemCmd::WritebackClean;
     }
 
     /**