mshr.hh revision 13351
12810SN/A/*
212599Snikos.nikoleris@arm.com * Copyright (c) 2012-2013, 2015-2016, 2018 ARM Limited
39663Suri.wiener@arm.com * All rights reserved.
49663Suri.wiener@arm.com *
59663Suri.wiener@arm.com * The license below extends only to copyright in the software and shall
69663Suri.wiener@arm.com * not be construed as granting a license to any other intellectual
79663Suri.wiener@arm.com * property including but not limited to intellectual property relating
89663Suri.wiener@arm.com * to a hardware implementation of the functionality of the software
99663Suri.wiener@arm.com * licensed hereunder.  You may use the software subject to the license
109663Suri.wiener@arm.com * terms below provided that you ensure that this notice is replicated
119663Suri.wiener@arm.com * unmodified and in its entirety in all distributions of the software,
129663Suri.wiener@arm.com * modified or unmodified, in source code or in binary form.
139663Suri.wiener@arm.com *
142810SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
152810SN/A * All rights reserved.
162810SN/A *
172810SN/A * Redistribution and use in source and binary forms, with or without
182810SN/A * modification, are permitted provided that the following conditions are
192810SN/A * met: redistributions of source code must retain the above copyright
202810SN/A * notice, this list of conditions and the following disclaimer;
212810SN/A * redistributions in binary form must reproduce the above copyright
222810SN/A * notice, this list of conditions and the following disclaimer in the
232810SN/A * documentation and/or other materials provided with the distribution;
242810SN/A * neither the name of the copyright holders nor the names of its
252810SN/A * contributors may be used to endorse or promote products derived from
262810SN/A * this software without specific prior written permission.
272810SN/A *
282810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392810SN/A *
402810SN/A * Authors: Erik Hallnor
4113349Snikos.nikoleris@arm.com *          Nikos Nikoleris
422810SN/A */
432810SN/A
442810SN/A/**
452810SN/A * @file
462810SN/A * Miss Status and Handling Register (MSHR) declaration.
472810SN/A */
482810SN/A
4910764Sandreas.hansson@arm.com#ifndef __MEM_CACHE_MSHR_HH__
5010764Sandreas.hansson@arm.com#define __MEM_CACHE_MSHR_HH__
512810SN/A
5212727Snikos.nikoleris@arm.com#include <cassert>
5312727Snikos.nikoleris@arm.com#include <iosfwd>
544626SN/A#include <list>
5512727Snikos.nikoleris@arm.com#include <string>
5613349Snikos.nikoleris@arm.com#include <vector>
574626SN/A
585314SN/A#include "base/printable.hh"
5912727Snikos.nikoleris@arm.com#include "base/types.hh"
6011375Sandreas.hansson@arm.com#include "mem/cache/queue_entry.hh"
6112727Snikos.nikoleris@arm.com#include "mem/packet.hh"
6213349Snikos.nikoleris@arm.com#include "mem/request.hh"
6312727Snikos.nikoleris@arm.com#include "sim/core.hh"
642810SN/A
6512724Snikos.nikoleris@arm.comclass BaseCache;
662810SN/A
672810SN/A/**
682810SN/A * Miss Status and handling Register. This class keeps all the information
693374SN/A * needed to handle a cache miss including a list of target requests.
709264Sdjordje.kovacevic@arm.com * @sa  \ref gem5MemorySystem "gem5 Memory System"
712810SN/A */
7211375Sandreas.hansson@arm.comclass MSHR : public QueueEntry, public Printable
734626SN/A{
744626SN/A
759725Sandreas.hansson@arm.com    /**
7611375Sandreas.hansson@arm.com     * Consider the queues friends to avoid making everything public.
779725Sandreas.hansson@arm.com     */
7811375Sandreas.hansson@arm.com    template<typename Entry>
7911375Sandreas.hansson@arm.com    friend class Queue;
809725Sandreas.hansson@arm.com    friend class MSHRQueue;
819725Sandreas.hansson@arm.com
829725Sandreas.hansson@arm.com  private:
839725Sandreas.hansson@arm.com
849725Sandreas.hansson@arm.com    /** Flag set by downstream caches */
859725Sandreas.hansson@arm.com    bool downstreamPending;
869725Sandreas.hansson@arm.com
8711284Sandreas.hansson@arm.com    /**
8811284Sandreas.hansson@arm.com     * Here we use one flag to track both if:
8911284Sandreas.hansson@arm.com     *
9011284Sandreas.hansson@arm.com     * 1. We are going to become owner or not, i.e., we will get the
9111284Sandreas.hansson@arm.com     * block in an ownership state (Owned or Modified) with BlkDirty
9211284Sandreas.hansson@arm.com     * set. This determines whether or not we are going to become the
9311284Sandreas.hansson@arm.com     * responder and ordering point for future requests that we snoop.
9411284Sandreas.hansson@arm.com     *
9511284Sandreas.hansson@arm.com     * 2. We know that we are going to get a writable block, i.e. we
9611284Sandreas.hansson@arm.com     * will get the block in writable state (Exclusive or Modified
9711284Sandreas.hansson@arm.com     * state) with BlkWritable set. That determines whether additional
9811284Sandreas.hansson@arm.com     * targets with needsWritable set will be able to be satisfied, or
9911284Sandreas.hansson@arm.com     * if not should be put on the deferred list to possibly wait for
10011284Sandreas.hansson@arm.com     * another request that does give us writable access.
10111284Sandreas.hansson@arm.com     *
10211284Sandreas.hansson@arm.com     * Condition 2 is actually just a shortcut that saves us from
10311284Sandreas.hansson@arm.com     * possibly building a deferred target list and calling
10411284Sandreas.hansson@arm.com     * promoteWritable() every time we get a writable block. Condition
10511284Sandreas.hansson@arm.com     * 1, tracking ownership, is what is important. However, we never
10611284Sandreas.hansson@arm.com     * receive ownership without marking the block dirty, and
10711284Sandreas.hansson@arm.com     * consequently use pendingModified to track both ownership and
10811284Sandreas.hansson@arm.com     * writability rather than having separate pendingDirty and
10911284Sandreas.hansson@arm.com     * pendingWritable flags.
11011284Sandreas.hansson@arm.com     */
11111284Sandreas.hansson@arm.com    bool pendingModified;
1129725Sandreas.hansson@arm.com
1139725Sandreas.hansson@arm.com    /** Did we snoop an invalidate while waiting for data? */
1149725Sandreas.hansson@arm.com    bool postInvalidate;
1159725Sandreas.hansson@arm.com
1169725Sandreas.hansson@arm.com    /** Did we snoop a read while waiting for data? */
1179725Sandreas.hansson@arm.com    bool postDowngrade;
1189725Sandreas.hansson@arm.com
1192810SN/A  public:
1204626SN/A
12113349Snikos.nikoleris@arm.com    /** Track if we sent this as a whole line write or not */
12213349Snikos.nikoleris@arm.com    bool wasWholeLineWrite;
12313349Snikos.nikoleris@arm.com
12411375Sandreas.hansson@arm.com    /** True if the entry is just a simple forward from an upper level */
12511375Sandreas.hansson@arm.com    bool isForward;
12611375Sandreas.hansson@arm.com
1274626SN/A    class Target {
1284626SN/A      public:
1295875Ssteve.reinhardt@amd.com
1305875Ssteve.reinhardt@amd.com        enum Source {
1315875Ssteve.reinhardt@amd.com            FromCPU,
1325875Ssteve.reinhardt@amd.com            FromSnoop,
1335875Ssteve.reinhardt@amd.com            FromPrefetcher
1345875Ssteve.reinhardt@amd.com        };
1355875Ssteve.reinhardt@amd.com
13610766Sandreas.hansson@arm.com        const Tick recvTime;  //!< Time when request was received (for stats)
13710766Sandreas.hansson@arm.com        const Tick readyTime; //!< Time when request is ready to be serviced
13810766Sandreas.hansson@arm.com        const Counter order;  //!< Global order (for memory consistency mgmt)
13910766Sandreas.hansson@arm.com        const PacketPtr pkt;  //!< Pending request packet.
14010766Sandreas.hansson@arm.com        const Source source;  //!< Request from cpu, memory, or prefetcher?
14111742Snikos.nikoleris@arm.com
14211742Snikos.nikoleris@arm.com        /**
14311742Snikos.nikoleris@arm.com         * We use this flag to track whether we have cleared the
14411742Snikos.nikoleris@arm.com         * downstreamPending flag for the MSHR of the cache above
14511742Snikos.nikoleris@arm.com         * where this packet originates from and guard noninitial
14611742Snikos.nikoleris@arm.com         * attempts to clear it.
14711742Snikos.nikoleris@arm.com         *
14811742Snikos.nikoleris@arm.com         * The flag markedPending needs to be updated when the
14911742Snikos.nikoleris@arm.com         * TargetList is in service which can be:
15011742Snikos.nikoleris@arm.com         * 1) during the Target instantiation if the MSHR is in
15111742Snikos.nikoleris@arm.com         * service and the target is not deferred,
15211742Snikos.nikoleris@arm.com         * 2) when the MSHR becomes in service if the target is not
15311742Snikos.nikoleris@arm.com         * deferred,
15411742Snikos.nikoleris@arm.com         * 3) or when the TargetList is promoted (deferredTargets ->
15511742Snikos.nikoleris@arm.com         * targets).
15611742Snikos.nikoleris@arm.com         */
15711742Snikos.nikoleris@arm.com        bool markedPending;
15811742Snikos.nikoleris@arm.com
15911741Snikos.nikoleris@arm.com        const bool allocOnFill;   //!< Should the response servicing this
16011741Snikos.nikoleris@arm.com                                  //!< target list allocate in the cache?
1614626SN/A
1625318SN/A        Target(PacketPtr _pkt, Tick _readyTime, Counter _order,
16311741Snikos.nikoleris@arm.com               Source _source, bool _markedPending, bool alloc_on_fill)
1647823Ssteve.reinhardt@amd.com            : recvTime(curTick()), readyTime(_readyTime), order(_order),
16511741Snikos.nikoleris@arm.com              pkt(_pkt), source(_source), markedPending(_markedPending),
16611741Snikos.nikoleris@arm.com              allocOnFill(alloc_on_fill)
1674626SN/A        {}
1684626SN/A    };
1694626SN/A
1704903SN/A    class TargetList : public std::list<Target> {
1714903SN/A
1724903SN/A      public:
17311284Sandreas.hansson@arm.com        bool needsWritable;
1744903SN/A        bool hasUpgrade;
17511741Snikos.nikoleris@arm.com        /** Set when the response should allocate on fill */
17611741Snikos.nikoleris@arm.com        bool allocOnFill;
17712715Snikos.nikoleris@arm.com        /**
17812715Snikos.nikoleris@arm.com         * Determine whether there was at least one non-snooping
17912715Snikos.nikoleris@arm.com         * target coming from another cache.
18012715Snikos.nikoleris@arm.com         */
18112715Snikos.nikoleris@arm.com        bool hasFromCache;
1824903SN/A
1834903SN/A        TargetList();
18411740Snikos.nikoleris@arm.com
18511740Snikos.nikoleris@arm.com        /**
18611740Snikos.nikoleris@arm.com         * Use the provided packet and the source to update the
18711740Snikos.nikoleris@arm.com         * flags of this TargetList.
18811740Snikos.nikoleris@arm.com         *
18911740Snikos.nikoleris@arm.com         * @param pkt Packet considered for the flag update
19011740Snikos.nikoleris@arm.com         * @param source Indicates the source of the packet
19111741Snikos.nikoleris@arm.com         * @param alloc_on_fill Whether the pkt would allocate on a fill
19211740Snikos.nikoleris@arm.com         */
19311741Snikos.nikoleris@arm.com        void updateFlags(PacketPtr pkt, Target::Source source,
19411741Snikos.nikoleris@arm.com                         bool alloc_on_fill);
19511740Snikos.nikoleris@arm.com
19613349Snikos.nikoleris@arm.com        /**
19713349Snikos.nikoleris@arm.com         * Reset state
19813349Snikos.nikoleris@arm.com         *
19913349Snikos.nikoleris@arm.com         * @param blk_addr Address of the cache block
20013349Snikos.nikoleris@arm.com         * @param blk_size Size of the cache block
20113349Snikos.nikoleris@arm.com         */
20213349Snikos.nikoleris@arm.com        void init(Addr blk_addr, Addr blk_size) {
20313349Snikos.nikoleris@arm.com            blkAddr = blk_addr;
20413349Snikos.nikoleris@arm.com            blkSize = blk_size;
20513349Snikos.nikoleris@arm.com            writesBitmap.resize(blk_size);
20613349Snikos.nikoleris@arm.com
20713349Snikos.nikoleris@arm.com            resetFlags();
20813349Snikos.nikoleris@arm.com        }
20913349Snikos.nikoleris@arm.com
21012715Snikos.nikoleris@arm.com        void resetFlags() {
21113349Snikos.nikoleris@arm.com            onlyWrites = true;
21213349Snikos.nikoleris@arm.com            std::fill(writesBitmap.begin(), writesBitmap.end(), false);
21313349Snikos.nikoleris@arm.com
21412715Snikos.nikoleris@arm.com            needsWritable = false;
21512715Snikos.nikoleris@arm.com            hasUpgrade = false;
21612715Snikos.nikoleris@arm.com            allocOnFill = false;
21712715Snikos.nikoleris@arm.com            hasFromCache = false;
21812715Snikos.nikoleris@arm.com        }
21911740Snikos.nikoleris@arm.com
22011740Snikos.nikoleris@arm.com        /**
22111740Snikos.nikoleris@arm.com         * Goes through the list of targets and uses them to populate
22211740Snikos.nikoleris@arm.com         * the flags of this TargetList. When the function returns the
22311740Snikos.nikoleris@arm.com         * flags are consistent with the properties of packets in the
22411740Snikos.nikoleris@arm.com         * list.
22511740Snikos.nikoleris@arm.com         */
22611740Snikos.nikoleris@arm.com        void populateFlags();
22711740Snikos.nikoleris@arm.com
22811741Snikos.nikoleris@arm.com        /**
22913349Snikos.nikoleris@arm.com         * Add the specified packet in the TargetList. This function
23013349Snikos.nikoleris@arm.com         * stores information related to the added packet and updates
23113349Snikos.nikoleris@arm.com         * accordingly the flags.
23213349Snikos.nikoleris@arm.com         *
23313349Snikos.nikoleris@arm.com         * @param pkt Packet considered for adding
23413349Snikos.nikoleris@arm.com         */
23513349Snikos.nikoleris@arm.com        void updateWriteFlags(PacketPtr pkt) {
23613349Snikos.nikoleris@arm.com             const Request::FlagsType noMergeFlags =
23713349Snikos.nikoleris@arm.com                 Request::UNCACHEABLE |
23813349Snikos.nikoleris@arm.com                 Request::STRICT_ORDER | Request::MMAPPED_IPR |
23913349Snikos.nikoleris@arm.com                 Request::PRIVILEGED | Request::LLSC |
24013349Snikos.nikoleris@arm.com                 Request::MEM_SWAP | Request::MEM_SWAP_COND |
24113349Snikos.nikoleris@arm.com                 Request::SECURE;
24213349Snikos.nikoleris@arm.com
24313349Snikos.nikoleris@arm.com             // if we have already seen writes for the full block stop
24413349Snikos.nikoleris@arm.com             // here, this might be a full line write followed by
24513349Snikos.nikoleris@arm.com             // other compatible requests (e.g., reads)
24613349Snikos.nikoleris@arm.com             if (!isWholeLineWrite()) {
24713349Snikos.nikoleris@arm.com                 bool can_merge_write = pkt->isWrite() &&
24813349Snikos.nikoleris@arm.com                     ((pkt->req->getFlags() & noMergeFlags) == 0);
24913349Snikos.nikoleris@arm.com                 onlyWrites &= can_merge_write;
25013349Snikos.nikoleris@arm.com                 if (onlyWrites) {
25113349Snikos.nikoleris@arm.com                     auto offset = pkt->getOffset(blkSize);
25213349Snikos.nikoleris@arm.com                     auto begin = writesBitmap.begin() + offset;
25313349Snikos.nikoleris@arm.com                     std::fill(begin, begin + pkt->getSize(), true);
25413349Snikos.nikoleris@arm.com                 }
25513349Snikos.nikoleris@arm.com             }
25613349Snikos.nikoleris@arm.com         }
25713349Snikos.nikoleris@arm.com
25813349Snikos.nikoleris@arm.com        /**
25911741Snikos.nikoleris@arm.com         * Tests if the flags of this TargetList have their default
26011741Snikos.nikoleris@arm.com         * values.
26113349Snikos.nikoleris@arm.com         *
26213349Snikos.nikoleris@arm.com         * @return True if the TargetList are reset, false otherwise.
26311741Snikos.nikoleris@arm.com         */
26411741Snikos.nikoleris@arm.com        bool isReset() const {
26512715Snikos.nikoleris@arm.com            return !needsWritable && !hasUpgrade && !allocOnFill &&
26613349Snikos.nikoleris@arm.com                !hasFromCache && onlyWrites;
26711741Snikos.nikoleris@arm.com        }
26811741Snikos.nikoleris@arm.com
26911741Snikos.nikoleris@arm.com        /**
27011741Snikos.nikoleris@arm.com         * Add the specified packet in the TargetList. This function
27111741Snikos.nikoleris@arm.com         * stores information related to the added packet and updates
27211741Snikos.nikoleris@arm.com         * accordingly the flags.
27311741Snikos.nikoleris@arm.com         *
27411741Snikos.nikoleris@arm.com         * @param pkt Packet considered for adding
27511741Snikos.nikoleris@arm.com         * @param readTime Tick at which the packet is processed by this cache
27611741Snikos.nikoleris@arm.com         * @param order A counter giving a unique id to each target
27711741Snikos.nikoleris@arm.com         * @param source Indicates the source agent of the packet
27811741Snikos.nikoleris@arm.com         * @param markPending Set for deferred targets or pending MSHRs
27911741Snikos.nikoleris@arm.com         * @param alloc_on_fill Whether it should allocate on a fill
28011741Snikos.nikoleris@arm.com         */
2815318SN/A        void add(PacketPtr pkt, Tick readyTime, Counter order,
28213349Snikos.nikoleris@arm.com                 Target::Source source, bool markPending, bool alloc_on_fill);
28311357Sstephan.diestelhorst@arm.com
28411357Sstephan.diestelhorst@arm.com        /**
28511357Sstephan.diestelhorst@arm.com         * Convert upgrades to the equivalent request if the cache line they
28611357Sstephan.diestelhorst@arm.com         * refer to would have been invalid (Upgrade -> ReadEx, SC* -> Fail).
28711357Sstephan.diestelhorst@arm.com         * Used to rejig ordering between targets waiting on an MSHR. */
2884903SN/A        void replaceUpgrades();
28911357Sstephan.diestelhorst@arm.com
2904908SN/A        void clearDownstreamPending();
29112791Snikos.nikoleris@arm.com        void clearDownstreamPending(iterator begin, iterator end);
29212823Srmk35@cl.cam.ac.uk        bool trySatisfyFunctional(PacketPtr pkt);
2935314SN/A        void print(std::ostream &os, int verbosity,
2945314SN/A                   const std::string &prefix) const;
29513349Snikos.nikoleris@arm.com
29613349Snikos.nikoleris@arm.com        /**
29713349Snikos.nikoleris@arm.com         * Check if this list contains only compatible writes, and if they
29813349Snikos.nikoleris@arm.com         * span the entire cache line. This is used as part of the
29913349Snikos.nikoleris@arm.com         * miss-packet creation. Note that new requests may arrive after a
30013349Snikos.nikoleris@arm.com         * miss-packet has been created, and for the fill we therefore use
30113349Snikos.nikoleris@arm.com         * the wasWholeLineWrite field.
30213349Snikos.nikoleris@arm.com         */
30313349Snikos.nikoleris@arm.com        bool isWholeLineWrite() const
30413349Snikos.nikoleris@arm.com        {
30513349Snikos.nikoleris@arm.com            return onlyWrites &&
30613349Snikos.nikoleris@arm.com                std::all_of(writesBitmap.begin(),
30713349Snikos.nikoleris@arm.com                            writesBitmap.end(), [](bool i) { return i; });
30813349Snikos.nikoleris@arm.com        }
30913349Snikos.nikoleris@arm.com
31013349Snikos.nikoleris@arm.com      private:
31113349Snikos.nikoleris@arm.com        /** Address of the cache block for this list of targets. */
31213349Snikos.nikoleris@arm.com        Addr blkAddr;
31313349Snikos.nikoleris@arm.com
31413349Snikos.nikoleris@arm.com        /** Size of the cache block. */
31513349Snikos.nikoleris@arm.com        Addr blkSize;
31613349Snikos.nikoleris@arm.com
31713349Snikos.nikoleris@arm.com        /** Are we only dealing with writes. */
31813349Snikos.nikoleris@arm.com        bool onlyWrites;
31913349Snikos.nikoleris@arm.com
32013349Snikos.nikoleris@arm.com        // NOTE: std::vector<bool> might not meet satisfy the
32113349Snikos.nikoleris@arm.com        // ForwardIterator requirement and therefore cannot be used
32213349Snikos.nikoleris@arm.com        // for writesBitmap.
32313349Snikos.nikoleris@arm.com        /**
32413349Snikos.nikoleris@arm.com         * Track which bytes are written by requests in this target
32513349Snikos.nikoleris@arm.com         * list.
32613349Snikos.nikoleris@arm.com         */
32713349Snikos.nikoleris@arm.com        std::vector<char> writesBitmap;
3284903SN/A    };
3294903SN/A
3302810SN/A    /** A list of MSHRs. */
3312810SN/A    typedef std::list<MSHR *> List;
3322810SN/A    /** MSHR list iterator. */
3332810SN/A    typedef List::iterator Iterator;
3344903SN/A
3357667Ssteve.reinhardt@amd.com    /** The pending* and post* flags are only valid if inService is
3367667Ssteve.reinhardt@amd.com     *  true.  Using the accessor functions lets us detect if these
3377667Ssteve.reinhardt@amd.com     *  flags are accessed improperly.
3387667Ssteve.reinhardt@amd.com     */
3397667Ssteve.reinhardt@amd.com
34011284Sandreas.hansson@arm.com    /** True if we need to get a writable copy of the block. */
34111284Sandreas.hansson@arm.com    bool needsWritable() const { return targets.needsWritable; }
3429725Sandreas.hansson@arm.com
34312599Snikos.nikoleris@arm.com    bool isCleaning() const {
34412599Snikos.nikoleris@arm.com        PacketPtr pkt = targets.front().pkt;
34512599Snikos.nikoleris@arm.com        return pkt->isClean();
34612599Snikos.nikoleris@arm.com    }
34712599Snikos.nikoleris@arm.com
34811284Sandreas.hansson@arm.com    bool isPendingModified() const {
34911284Sandreas.hansson@arm.com        assert(inService); return pendingModified;
3507667Ssteve.reinhardt@amd.com    }
3517667Ssteve.reinhardt@amd.com
3527667Ssteve.reinhardt@amd.com    bool hasPostInvalidate() const {
3537667Ssteve.reinhardt@amd.com        assert(inService); return postInvalidate;
3547667Ssteve.reinhardt@amd.com    }
3557667Ssteve.reinhardt@amd.com
3567667Ssteve.reinhardt@amd.com    bool hasPostDowngrade() const {
3577667Ssteve.reinhardt@amd.com        assert(inService); return postDowngrade;
3587667Ssteve.reinhardt@amd.com    }
3594665SN/A
36012724Snikos.nikoleris@arm.com    bool sendPacket(BaseCache &cache);
36111375Sandreas.hansson@arm.com
36211741Snikos.nikoleris@arm.com    bool allocOnFill() const {
36311741Snikos.nikoleris@arm.com        return targets.allocOnFill;
36411741Snikos.nikoleris@arm.com    }
36512715Snikos.nikoleris@arm.com
36612715Snikos.nikoleris@arm.com    /**
36712715Snikos.nikoleris@arm.com     * Determine if there are non-deferred requests from other caches
36812715Snikos.nikoleris@arm.com     *
36912715Snikos.nikoleris@arm.com     * @return true if any of the targets is from another cache
37012715Snikos.nikoleris@arm.com     */
37112715Snikos.nikoleris@arm.com    bool hasFromCache() const {
37212715Snikos.nikoleris@arm.com        return targets.hasFromCache;
37312715Snikos.nikoleris@arm.com    }
37412715Snikos.nikoleris@arm.com
3759725Sandreas.hansson@arm.com  private:
37612793Snikos.nikoleris@arm.com    /**
37712793Snikos.nikoleris@arm.com     * Promotes deferred targets that satisfy a predicate
37812793Snikos.nikoleris@arm.com     *
37912793Snikos.nikoleris@arm.com     * Deferred targets are promoted to the target list if they
38012793Snikos.nikoleris@arm.com     * satisfy a given condition. The operation stops at the first
38112793Snikos.nikoleris@arm.com     * deferred target that doesn't satisfy the condition.
38212793Snikos.nikoleris@arm.com     *
38312793Snikos.nikoleris@arm.com     * @param pred A condition on a Target
38412793Snikos.nikoleris@arm.com     */
38512793Snikos.nikoleris@arm.com    void promoteIf(const std::function<bool (Target &)>& pred);
3864668SN/A
3872810SN/A    /**
3882810SN/A     * Pointer to this MSHR on the ready list.
3892810SN/A     * @sa MissQueue, MSHRQueue::readyList
3902810SN/A     */
3912810SN/A    Iterator readyIter;
3924626SN/A
3932810SN/A    /**
3942810SN/A     * Pointer to this MSHR on the allocated list.
3952810SN/A     * @sa MissQueue, MSHRQueue::allocatedList
3962810SN/A     */
3972810SN/A    Iterator allocIter;
3982810SN/A
3993374SN/A    /** List of all requests that match the address */
4009725Sandreas.hansson@arm.com    TargetList targets;
4012810SN/A
4029725Sandreas.hansson@arm.com    TargetList deferredTargets;
4034665SN/A
4049725Sandreas.hansson@arm.com  public:
40513349Snikos.nikoleris@arm.com    /**
40613349Snikos.nikoleris@arm.com     * Check if this MSHR contains only compatible writes, and if they
40713349Snikos.nikoleris@arm.com     * span the entire cache line. This is used as part of the
40813349Snikos.nikoleris@arm.com     * miss-packet creation. Note that new requests may arrive after a
40913349Snikos.nikoleris@arm.com     * miss-packet has been created, and for the fill we therefore use
41013349Snikos.nikoleris@arm.com     * the wasWholeLineWrite field.
41113349Snikos.nikoleris@arm.com     */
41213349Snikos.nikoleris@arm.com    bool isWholeLineWrite() const {
41313349Snikos.nikoleris@arm.com        return targets.isWholeLineWrite();
41413349Snikos.nikoleris@arm.com    }
4154626SN/A
4162810SN/A    /**
4172810SN/A     * Allocate a miss to this MSHR.
41810764Sandreas.hansson@arm.com     * @param blk_addr The address of the block.
41910764Sandreas.hansson@arm.com     * @param blk_size The number of bytes to request.
42010764Sandreas.hansson@arm.com     * @param pkt The original miss.
42110764Sandreas.hansson@arm.com     * @param when_ready When should the MSHR be ready to act upon.
42210764Sandreas.hansson@arm.com     * @param _order The logical order of this MSHR
42311197Sandreas.hansson@arm.com     * @param alloc_on_fill Should the cache allocate a block on fill
4242810SN/A     */
42510764Sandreas.hansson@arm.com    void allocate(Addr blk_addr, unsigned blk_size, PacketPtr pkt,
42611197Sandreas.hansson@arm.com                  Tick when_ready, Counter _order, bool alloc_on_fill);
4272810SN/A
42811375Sandreas.hansson@arm.com    void markInService(bool pending_modified_resp);
4294908SN/A
4305318SN/A    void clearDownstreamPending();
4315318SN/A
4322810SN/A    /**
4332810SN/A     * Mark this MSHR as free.
4342810SN/A     */
4352810SN/A    void deallocate();
4362810SN/A
4372810SN/A    /**
4383374SN/A     * Add a request to the list of targets.
4392810SN/A     * @param target The target.
4402810SN/A     */
44111197Sandreas.hansson@arm.com    void allocateTarget(PacketPtr target, Tick when, Counter order,
44211197Sandreas.hansson@arm.com                        bool alloc_on_fill);
4434902SN/A    bool handleSnoop(PacketPtr target, Counter order);
4442810SN/A
4452810SN/A    /** A simple constructor. */
4462810SN/A    MSHR();
4472810SN/A
4482810SN/A    /**
4492810SN/A     * Returns the current number of allocated targets.
4502810SN/A     * @return The current number of allocated targets.
4512810SN/A     */
4529725Sandreas.hansson@arm.com    int getNumTargets() const
4539725Sandreas.hansson@arm.com    { return targets.size() + deferredTargets.size(); }
4542810SN/A
4552810SN/A    /**
45611742Snikos.nikoleris@arm.com     * Extracts the subset of the targets that can be serviced given a
45711742Snikos.nikoleris@arm.com     * received response. This function returns the targets list
45811742Snikos.nikoleris@arm.com     * unless the response is a ReadRespWithInvalidate. The
45911742Snikos.nikoleris@arm.com     * ReadRespWithInvalidate is only invalidating response that its
46011742Snikos.nikoleris@arm.com     * invalidation was not expected when the request (a
46111742Snikos.nikoleris@arm.com     * ReadSharedReq) was sent out. For ReadRespWithInvalidate we can
46211742Snikos.nikoleris@arm.com     * safely service only the first FromCPU target and all FromSnoop
46311742Snikos.nikoleris@arm.com     * targets (inform all snoopers that we no longer have the block).
46411742Snikos.nikoleris@arm.com     *
46511742Snikos.nikoleris@arm.com     * @param pkt The response from the downstream memory
46611742Snikos.nikoleris@arm.com     */
46711742Snikos.nikoleris@arm.com    TargetList extractServiceableTargets(PacketPtr pkt);
46811742Snikos.nikoleris@arm.com
46911742Snikos.nikoleris@arm.com    /**
4704899SN/A     * Returns true if there are targets left.
4714899SN/A     * @return true if there are targets
4724899SN/A     */
4739725Sandreas.hansson@arm.com    bool hasTargets() const { return !targets.empty(); }
4744899SN/A
4754899SN/A    /**
4762810SN/A     * Returns a reference to the first target.
4772810SN/A     * @return A pointer to the first target.
4782810SN/A     */
4799725Sandreas.hansson@arm.com    Target *getTarget()
4805730SSteve.Reinhardt@amd.com    {
4815730SSteve.Reinhardt@amd.com        assert(hasTargets());
4829725Sandreas.hansson@arm.com        return &targets.front();
4835730SSteve.Reinhardt@amd.com    }
4842810SN/A
4852810SN/A    /**
4862810SN/A     * Pop first target.
4872810SN/A     */
4882810SN/A    void popTarget()
4892810SN/A    {
4909725Sandreas.hansson@arm.com        targets.pop_front();
4912810SN/A    }
4922810SN/A
4934665SN/A    bool promoteDeferredTargets();
4944665SN/A
49512792Snikos.nikoleris@arm.com    /**
49612792Snikos.nikoleris@arm.com     * Promotes deferred targets that do not require writable
49712792Snikos.nikoleris@arm.com     *
49812793Snikos.nikoleris@arm.com     * Move targets from the deferred targets list to the target list
49912793Snikos.nikoleris@arm.com     * starting from the first deferred target until the first target
50012793Snikos.nikoleris@arm.com     * that is a cache maintenance operation or needs a writable copy
50112793Snikos.nikoleris@arm.com     * of the block
50212793Snikos.nikoleris@arm.com     */
50312793Snikos.nikoleris@arm.com    void promoteReadable();
50412793Snikos.nikoleris@arm.com
50512793Snikos.nikoleris@arm.com    /**
50612793Snikos.nikoleris@arm.com     * Promotes deferred targets that do not require writable
50712793Snikos.nikoleris@arm.com     *
50812792Snikos.nikoleris@arm.com     * Requests in the deferred target list are moved to the target
50912792Snikos.nikoleris@arm.com     * list up until the first target that is a cache maintenance
51012792Snikos.nikoleris@arm.com     * operation or needs a writable copy of the block
51112792Snikos.nikoleris@arm.com     */
51211284Sandreas.hansson@arm.com    void promoteWritable();
5134668SN/A
51412823Srmk35@cl.cam.ac.uk    bool trySatisfyFunctional(PacketPtr pkt);
5154920SN/A
5162810SN/A    /**
51713351Snikos.nikoleris@arm.com     * Adds a delay relative to the current tick to the current MSHR
51813351Snikos.nikoleris@arm.com     * @param delay_ticks the desired delay in ticks
51913351Snikos.nikoleris@arm.com     */
52013351Snikos.nikoleris@arm.com    void delay(Tick delay_ticks)
52113351Snikos.nikoleris@arm.com    {
52213351Snikos.nikoleris@arm.com        assert(readyTime <= curTick());
52313351Snikos.nikoleris@arm.com        readyTime = curTick() + delay_ticks;
52413351Snikos.nikoleris@arm.com    }
52513351Snikos.nikoleris@arm.com
52613351Snikos.nikoleris@arm.com    /**
5275314SN/A     * Prints the contents of this MSHR for debugging.
5282810SN/A     */
5295314SN/A    void print(std::ostream &os,
5305314SN/A               int verbosity = 0,
5315314SN/A               const std::string &prefix = "") const;
5329663Suri.wiener@arm.com    /**
5339663Suri.wiener@arm.com     * A no-args wrapper of print(std::ostream...)  meant to be
5349663Suri.wiener@arm.com     * invoked from DPRINTFs avoiding string overheads in fast mode
5359663Suri.wiener@arm.com     *
5369663Suri.wiener@arm.com     * @return string with mshr fields + [deferred]targets
5379663Suri.wiener@arm.com     */
5389663Suri.wiener@arm.com    std::string print() const;
5392810SN/A};
5402810SN/A
54110764Sandreas.hansson@arm.com#endif // __MEM_CACHE_MSHR_HH__
542