110612SMarco.Elver@ARM.com/*
210612SMarco.Elver@ARM.com * Copyright (c) 2014 ARM Limited
310612SMarco.Elver@ARM.com * All rights reserved.
410612SMarco.Elver@ARM.com *
510612SMarco.Elver@ARM.com * The license below extends only to copyright in the software and shall
610612SMarco.Elver@ARM.com * not be construed as granting a license to any other intellectual
710612SMarco.Elver@ARM.com * property including but not limited to intellectual property relating
810612SMarco.Elver@ARM.com * to a hardware implementation of the functionality of the software
910612SMarco.Elver@ARM.com * licensed hereunder.  You may use the software subject to the license
1010612SMarco.Elver@ARM.com * terms below provided that you ensure that this notice is replicated
1110612SMarco.Elver@ARM.com * unmodified and in its entirety in all distributions of the software,
1210612SMarco.Elver@ARM.com * modified or unmodified, in source code or in binary form.
1310612SMarco.Elver@ARM.com *
1410612SMarco.Elver@ARM.com * Redistribution and use in source and binary forms, with or without
1510612SMarco.Elver@ARM.com * modification, are permitted provided that the following conditions are
1610612SMarco.Elver@ARM.com * met: redistributions of source code must retain the above copyright
1710612SMarco.Elver@ARM.com * notice, this list of conditions and the following disclaimer;
1810612SMarco.Elver@ARM.com * redistributions in binary form must reproduce the above copyright
1910612SMarco.Elver@ARM.com * notice, this list of conditions and the following disclaimer in the
2010612SMarco.Elver@ARM.com * documentation and/or other materials provided with the distribution;
2110612SMarco.Elver@ARM.com * neither the name of the copyright holders nor the names of its
2210612SMarco.Elver@ARM.com * contributors may be used to endorse or promote products derived from
2310612SMarco.Elver@ARM.com * this software without specific prior written permission.
2410612SMarco.Elver@ARM.com *
2510612SMarco.Elver@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610612SMarco.Elver@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710612SMarco.Elver@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810612SMarco.Elver@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910612SMarco.Elver@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010612SMarco.Elver@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110612SMarco.Elver@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210612SMarco.Elver@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310612SMarco.Elver@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410612SMarco.Elver@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510612SMarco.Elver@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610612SMarco.Elver@ARM.com *
3710612SMarco.Elver@ARM.com * Authors: Rune Holm
3810612SMarco.Elver@ARM.com *          Marco Elver
3910612SMarco.Elver@ARM.com */
4010612SMarco.Elver@ARM.com
4110612SMarco.Elver@ARM.com#ifndef __MEM_MEM_CHECKER_HH__
4210612SMarco.Elver@ARM.com#define __MEM_MEM_CHECKER_HH__
4310612SMarco.Elver@ARM.com
4410612SMarco.Elver@ARM.com#include <list>
4510612SMarco.Elver@ARM.com#include <map>
4610612SMarco.Elver@ARM.com#include <string>
4711168Sandreas.hansson@arm.com#include <unordered_map>
4810612SMarco.Elver@ARM.com#include <vector>
4910612SMarco.Elver@ARM.com
5012334Sgabeblack@google.com#include "base/logging.hh"
5111800Sbrandon.potter@amd.com#include "base/trace.hh"
5210612SMarco.Elver@ARM.com#include "base/types.hh"
5310612SMarco.Elver@ARM.com#include "debug/MemChecker.hh"
5410612SMarco.Elver@ARM.com#include "params/MemChecker.hh"
5510612SMarco.Elver@ARM.com#include "sim/core.hh"
5610612SMarco.Elver@ARM.com#include "sim/sim_object.hh"
5710612SMarco.Elver@ARM.com
5810612SMarco.Elver@ARM.com/**
5910612SMarco.Elver@ARM.com * MemChecker. Verifies that reads observe the values from permissible writes.
6010612SMarco.Elver@ARM.com * As memory operations have a start and completion time, we consider them as
6110612SMarco.Elver@ARM.com * transactions which have a start and end time. Because of this, the lifetimes
6210612SMarco.Elver@ARM.com * of transactions of memory operations may be overlapping -- we assume that if
6310612SMarco.Elver@ARM.com * there is overlap between writes, they could be reordered by the memory
6410612SMarco.Elver@ARM.com * subsystem, and a read could any of these.  For more detail, see comments of
6510612SMarco.Elver@ARM.com * inExpectedData().
6610612SMarco.Elver@ARM.com *
6710612SMarco.Elver@ARM.com * For simplicity, the permissible values a read can observe are only dependent
6810612SMarco.Elver@ARM.com * on the particular location, and we do not consider the effect of multi-byte
6910612SMarco.Elver@ARM.com * reads or writes. This precludes us from discovering single-copy atomicity
7010612SMarco.Elver@ARM.com * violations.
7110612SMarco.Elver@ARM.com*/
7210612SMarco.Elver@ARM.comclass MemChecker : public SimObject
7310612SMarco.Elver@ARM.com{
7410612SMarco.Elver@ARM.com  public:
7510612SMarco.Elver@ARM.com    /**
7610612SMarco.Elver@ARM.com     * The Serial type is used to be able to uniquely identify a transaction as
7710612SMarco.Elver@ARM.com     * it passes through the system. It's value is independent of any other
7810612SMarco.Elver@ARM.com     * system counters.
7910612SMarco.Elver@ARM.com     */
8010612SMarco.Elver@ARM.com    typedef uint64_t Serial;
8110612SMarco.Elver@ARM.com
8210612SMarco.Elver@ARM.com    static const Serial  SERIAL_INITIAL = 0; //!< Initial serial
8310612SMarco.Elver@ARM.com
8410612SMarco.Elver@ARM.com    /**
8510612SMarco.Elver@ARM.com     * The initial tick the system starts with. Must not be larger than the
8610612SMarco.Elver@ARM.com     * minimum value that curTick() could return at any time in the system's
8710612SMarco.Elver@ARM.com     * execution.
8810612SMarco.Elver@ARM.com     */
8910612SMarco.Elver@ARM.com    static const Tick    TICK_INITIAL   = 0;
9010612SMarco.Elver@ARM.com
9110612SMarco.Elver@ARM.com    /**
9210612SMarco.Elver@ARM.com     * The maximum value that curTick() could ever return.
9310612SMarco.Elver@ARM.com     */
9410612SMarco.Elver@ARM.com    static const Tick    TICK_FUTURE  = MaxTick;
9510612SMarco.Elver@ARM.com
9610612SMarco.Elver@ARM.com    /**
9710612SMarco.Elver@ARM.com     * Initial data value. No requirements.
9810612SMarco.Elver@ARM.com     */
9910612SMarco.Elver@ARM.com    static const uint8_t DATA_INITIAL   = 0x00;
10010612SMarco.Elver@ARM.com
10110612SMarco.Elver@ARM.com    /**
10210612SMarco.Elver@ARM.com     * The Transaction class captures the lifetimes of read and write
10310612SMarco.Elver@ARM.com     * operations, and the values they consumed or produced respectively.
10410612SMarco.Elver@ARM.com     */
10510612SMarco.Elver@ARM.com    class Transaction
10610612SMarco.Elver@ARM.com    {
10710612SMarco.Elver@ARM.com      public:
10810612SMarco.Elver@ARM.com
10910612SMarco.Elver@ARM.com        Transaction(Serial _serial,
11010612SMarco.Elver@ARM.com                    Tick _start, Tick _complete,
11110612SMarco.Elver@ARM.com                    uint8_t _data = DATA_INITIAL)
11210612SMarco.Elver@ARM.com            : serial(_serial),
11310612SMarco.Elver@ARM.com              start(_start), complete(_complete),
11410612SMarco.Elver@ARM.com              data(_data)
11510612SMarco.Elver@ARM.com        {}
11610612SMarco.Elver@ARM.com
11710612SMarco.Elver@ARM.com      public:
11810612SMarco.Elver@ARM.com        Serial serial; //!< Unique identifying serial
11910612SMarco.Elver@ARM.com        Tick start;    //!< Start tick
12010612SMarco.Elver@ARM.com        Tick complete; //!< Completion tick
12110612SMarco.Elver@ARM.com
12210612SMarco.Elver@ARM.com        /**
12310612SMarco.Elver@ARM.com         * Depending on the memory operation, the data value either represents:
12410612SMarco.Elver@ARM.com         * for writes, the value written upon start; for reads, the value read
12510612SMarco.Elver@ARM.com         * upon completion.
12610612SMarco.Elver@ARM.com         */
12710612SMarco.Elver@ARM.com        uint8_t data;
12810612SMarco.Elver@ARM.com
12910612SMarco.Elver@ARM.com        /**
13010612SMarco.Elver@ARM.com         * Orders Transactions for use with std::map.
13110612SMarco.Elver@ARM.com         */
13210612SMarco.Elver@ARM.com        bool operator<(const Transaction& rhs) const
13310612SMarco.Elver@ARM.com        { return serial < rhs.serial; }
13410612SMarco.Elver@ARM.com    };
13510612SMarco.Elver@ARM.com
13610612SMarco.Elver@ARM.com    /**
13710612SMarco.Elver@ARM.com     * The WriteCluster class captures sets of writes where all writes are
13810612SMarco.Elver@ARM.com     * overlapping with at least one other write. Capturing writes in this way
13910612SMarco.Elver@ARM.com     * simplifies pruning of writes.
14010612SMarco.Elver@ARM.com     */
14110612SMarco.Elver@ARM.com    class WriteCluster
14210612SMarco.Elver@ARM.com    {
14310612SMarco.Elver@ARM.com      public:
14410612SMarco.Elver@ARM.com        WriteCluster()
14510612SMarco.Elver@ARM.com            : start(TICK_FUTURE), complete(TICK_FUTURE),
14610612SMarco.Elver@ARM.com              completeMax(TICK_INITIAL), numIncomplete(0)
14710612SMarco.Elver@ARM.com        {}
14810612SMarco.Elver@ARM.com
14910612SMarco.Elver@ARM.com        /**
15010612SMarco.Elver@ARM.com         * Starts a write transaction.
15110612SMarco.Elver@ARM.com         *
15210612SMarco.Elver@ARM.com         * @param serial  Unique identifier of the write.
15310612SMarco.Elver@ARM.com         * @param _start  When the write was sent off to the memory subsystem.
15410612SMarco.Elver@ARM.com         * @param data    The data that this write passed to the memory
15510612SMarco.Elver@ARM.com         *                subsystem.
15610612SMarco.Elver@ARM.com         */
15710612SMarco.Elver@ARM.com        void startWrite(Serial serial, Tick _start, uint8_t data);
15810612SMarco.Elver@ARM.com
15910612SMarco.Elver@ARM.com        /**
16010612SMarco.Elver@ARM.com         * Completes a write transaction.
16110612SMarco.Elver@ARM.com         *
16210612SMarco.Elver@ARM.com         * @param serial    Unique identifier of a write *previously started*.
16310612SMarco.Elver@ARM.com         * @param _complete When the write was sent off to the memory
16410612SMarco.Elver@ARM.com         *                  subsystem.
16510612SMarco.Elver@ARM.com         */
16610612SMarco.Elver@ARM.com        void completeWrite(Serial serial, Tick _complete);
16710612SMarco.Elver@ARM.com
16810612SMarco.Elver@ARM.com        /**
16910612SMarco.Elver@ARM.com         * Aborts a write transaction.
17010612SMarco.Elver@ARM.com         *
17110612SMarco.Elver@ARM.com         * @param serial Unique identifier of a write *previously started*.
17210612SMarco.Elver@ARM.com         */
17310612SMarco.Elver@ARM.com        void abortWrite(Serial serial);
17410612SMarco.Elver@ARM.com
17510612SMarco.Elver@ARM.com        /**
17610612SMarco.Elver@ARM.com         * @return true if this cluster's write all completed, false otherwise.
17710612SMarco.Elver@ARM.com         */
17810612SMarco.Elver@ARM.com        bool isComplete() const { return complete != TICK_FUTURE; }
17910612SMarco.Elver@ARM.com
18010612SMarco.Elver@ARM.com      public:
18110612SMarco.Elver@ARM.com        Tick start;     //!< Start of earliest write in cluster
18210612SMarco.Elver@ARM.com        Tick complete;  //!< Completion of last write in cluster
18310612SMarco.Elver@ARM.com
18410612SMarco.Elver@ARM.com        /**
18510612SMarco.Elver@ARM.com         * Map of Serial --> Transaction of all writes in cluster; contains
18610612SMarco.Elver@ARM.com         * all, in-flight or already completed.
18710612SMarco.Elver@ARM.com         */
18811168Sandreas.hansson@arm.com        std::unordered_map<Serial, Transaction> writes;
18910612SMarco.Elver@ARM.com
19010612SMarco.Elver@ARM.com      private:
19110612SMarco.Elver@ARM.com        Tick completeMax;
19210612SMarco.Elver@ARM.com        size_t numIncomplete;
19310612SMarco.Elver@ARM.com    };
19410612SMarco.Elver@ARM.com
19510612SMarco.Elver@ARM.com    typedef std::list<Transaction> TransactionList;
19610612SMarco.Elver@ARM.com    typedef std::list<WriteCluster> WriteClusterList;
19710612SMarco.Elver@ARM.com
19810612SMarco.Elver@ARM.com    /**
19910612SMarco.Elver@ARM.com     * The ByteTracker keeps track of transactions for the *same byte* -- all
20010612SMarco.Elver@ARM.com     * outstanding reads, the completed reads (and what they observed) and write
20110612SMarco.Elver@ARM.com     * clusters (see WriteCluster).
20210612SMarco.Elver@ARM.com     */
20310612SMarco.Elver@ARM.com    class ByteTracker : public Named
20410612SMarco.Elver@ARM.com    {
20510612SMarco.Elver@ARM.com      public:
20610612SMarco.Elver@ARM.com
20710612SMarco.Elver@ARM.com        ByteTracker(Addr addr = 0, const MemChecker *parent = NULL)
20810612SMarco.Elver@ARM.com            : Named((parent != NULL ? parent->name() : "") +
20910612SMarco.Elver@ARM.com                     csprintf(".ByteTracker@%#llx", addr))
21010612SMarco.Elver@ARM.com        {
21110612SMarco.Elver@ARM.com            // The initial transaction has start == complete == TICK_INITIAL,
21210612SMarco.Elver@ARM.com            // indicating that there has been no real write to this location;
21310612SMarco.Elver@ARM.com            // therefore, upon checking, we do not expect any particular value.
21410612SMarco.Elver@ARM.com            readObservations.emplace_back(
21510612SMarco.Elver@ARM.com                    Transaction(SERIAL_INITIAL, TICK_INITIAL, TICK_INITIAL,
21610612SMarco.Elver@ARM.com                                DATA_INITIAL));
21710612SMarco.Elver@ARM.com        }
21810612SMarco.Elver@ARM.com
21910612SMarco.Elver@ARM.com        /**
22010612SMarco.Elver@ARM.com         * Starts a read transaction.
22110612SMarco.Elver@ARM.com         *
22210612SMarco.Elver@ARM.com         * @param serial  Unique identifier for the read.
22310612SMarco.Elver@ARM.com         * @param start   When the read was sent off to the memory subsystem.
22410612SMarco.Elver@ARM.com         */
22510612SMarco.Elver@ARM.com        void startRead(Serial serial, Tick start);
22610612SMarco.Elver@ARM.com
22710612SMarco.Elver@ARM.com        /**
22810612SMarco.Elver@ARM.com         * Given a start and end time (of any read transaction), this function
22910612SMarco.Elver@ARM.com         * iterates through all data that such a read is expected to see. The
23010612SMarco.Elver@ARM.com         * data parameter is the actual value that we observed, and the
23110612SMarco.Elver@ARM.com         * function immediately returns true when a match is found, false
23210612SMarco.Elver@ARM.com         * otherwise.
23310612SMarco.Elver@ARM.com         *
23410612SMarco.Elver@ARM.com         * The set of expected data are:
23510612SMarco.Elver@ARM.com         *
23610612SMarco.Elver@ARM.com         * 1. The last value observed by a read with a completion time before
23710612SMarco.Elver@ARM.com         *    this start time (if any).
23810612SMarco.Elver@ARM.com         *
23910612SMarco.Elver@ARM.com         * 2. The data produced by write transactions with a completion after
24010612SMarco.Elver@ARM.com         *    the last observed read start time. Only data produced in the
24110612SMarco.Elver@ARM.com         *    closest overlapping / earlier write cluster relative to this check
24210612SMarco.Elver@ARM.com         *    request is considered, as writes in separate clusters are not
24310612SMarco.Elver@ARM.com         *    reordered.
24410612SMarco.Elver@ARM.com         *
24510612SMarco.Elver@ARM.com         * @param start     Start time of transaction to validate.
24610612SMarco.Elver@ARM.com         * @param complete  End time of transaction to validate.
24710612SMarco.Elver@ARM.com         * @param data      The value that we have actually seen.
24810612SMarco.Elver@ARM.com         *
24910612SMarco.Elver@ARM.com         * @return          True if a match is found, false otherwise.
25010612SMarco.Elver@ARM.com         */
25110612SMarco.Elver@ARM.com        bool inExpectedData(Tick start, Tick complete, uint8_t data);
25210612SMarco.Elver@ARM.com
25310612SMarco.Elver@ARM.com        /**
25410612SMarco.Elver@ARM.com         * Completes a read transaction that is still outstanding.
25510612SMarco.Elver@ARM.com         *
25610612SMarco.Elver@ARM.com         * @param serial   Unique identifier of a read *previously started*.
25710612SMarco.Elver@ARM.com         * @param complete When the read got a response.
25810612SMarco.Elver@ARM.com         * @param data     The data returned by the memory subsystem.
25910612SMarco.Elver@ARM.com         */
26010612SMarco.Elver@ARM.com        bool completeRead(Serial serial, Tick complete, uint8_t data);
26110612SMarco.Elver@ARM.com
26210612SMarco.Elver@ARM.com        /**
26310612SMarco.Elver@ARM.com         * Starts a write transaction. Wrapper to startWrite of WriteCluster
26410612SMarco.Elver@ARM.com         * instance.
26510612SMarco.Elver@ARM.com         *
26610612SMarco.Elver@ARM.com         * @param serial  Unique identifier of the write.
26710612SMarco.Elver@ARM.com         * @param start   When the write was sent off to the memory subsystem.
26810612SMarco.Elver@ARM.com         * @param data    The data that this write passed to the memory
26910612SMarco.Elver@ARM.com         *                subsystem.
27010612SMarco.Elver@ARM.com         */
27110612SMarco.Elver@ARM.com        void startWrite(Serial serial, Tick start, uint8_t data);
27210612SMarco.Elver@ARM.com
27310612SMarco.Elver@ARM.com        /**
27410612SMarco.Elver@ARM.com         * Completes a write transaction. Wrapper to startWrite of WriteCluster
27510612SMarco.Elver@ARM.com         * instance.
27610612SMarco.Elver@ARM.com         *
27710612SMarco.Elver@ARM.com         * @param serial   Unique identifier of a write *previously started*.
27810612SMarco.Elver@ARM.com         * @param complete When the write was sent off to the memory subsystem.
27910612SMarco.Elver@ARM.com         */
28010612SMarco.Elver@ARM.com        void completeWrite(Serial serial, Tick complete);
28110612SMarco.Elver@ARM.com
28210612SMarco.Elver@ARM.com        /**
28310612SMarco.Elver@ARM.com         * Aborts a write transaction. Wrapper to abortWrite of WriteCluster
28410612SMarco.Elver@ARM.com         * instance.
28510612SMarco.Elver@ARM.com         *
28610612SMarco.Elver@ARM.com         * @param serial Unique identifier of a write *previously started*.
28710612SMarco.Elver@ARM.com         */
28810612SMarco.Elver@ARM.com        void abortWrite(Serial serial);
28910612SMarco.Elver@ARM.com
29010612SMarco.Elver@ARM.com        /**
29110612SMarco.Elver@ARM.com         * This function returns the expected data that inExpectedData iterated
29210612SMarco.Elver@ARM.com         * through in the last call. If inExpectedData last returned true, the
29310612SMarco.Elver@ARM.com         * set may be incomplete; if inExpectedData last returned false, the
29410612SMarco.Elver@ARM.com         * vector will contain the full set.
29510612SMarco.Elver@ARM.com         *
29610612SMarco.Elver@ARM.com         * @return Reference to internally maintained vector maintaining last
29710612SMarco.Elver@ARM.com         *         expected data that inExpectedData iterated through.
29810612SMarco.Elver@ARM.com         */
29910612SMarco.Elver@ARM.com        const std::vector<uint8_t>& lastExpectedData() const
30010612SMarco.Elver@ARM.com        { return _lastExpectedData; }
30110612SMarco.Elver@ARM.com
30210612SMarco.Elver@ARM.com      private:
30310612SMarco.Elver@ARM.com
30410612SMarco.Elver@ARM.com        /**
30510612SMarco.Elver@ARM.com         * Convenience function to return the most recent incomplete write
30610612SMarco.Elver@ARM.com         * cluster. Instantiates new write cluster if the most recent one has
30710612SMarco.Elver@ARM.com         * been completed.
30810612SMarco.Elver@ARM.com         *
30910612SMarco.Elver@ARM.com         * @return The most recent incomplete write cluster.
31010612SMarco.Elver@ARM.com         */
31110612SMarco.Elver@ARM.com        WriteCluster* getIncompleteWriteCluster();
31210612SMarco.Elver@ARM.com
31310612SMarco.Elver@ARM.com        /**
31410612SMarco.Elver@ARM.com         * Helper function to return an iterator to the entry of a container of
31510612SMarco.Elver@ARM.com         * Transaction compatible classes, before a certain tick.
31610612SMarco.Elver@ARM.com         *
31710612SMarco.Elver@ARM.com         * @param before Tick value which should be greater than the
31810612SMarco.Elver@ARM.com         *               completion tick of the returned element.
31910612SMarco.Elver@ARM.com         *
32010612SMarco.Elver@ARM.com         * @return Iterator into container.
32110612SMarco.Elver@ARM.com         */
32210612SMarco.Elver@ARM.com        template <class TList>
32310612SMarco.Elver@ARM.com        typename TList::iterator lastCompletedTransaction(TList *l, Tick before)
32410612SMarco.Elver@ARM.com        {
32510612SMarco.Elver@ARM.com            assert(!l->empty());
32610612SMarco.Elver@ARM.com
32710612SMarco.Elver@ARM.com            // Scanning backwards increases the chances of getting a match
32810612SMarco.Elver@ARM.com            // quicker.
32910612SMarco.Elver@ARM.com            auto it = l->end();
33010612SMarco.Elver@ARM.com
33110612SMarco.Elver@ARM.com            for (--it; it != l->begin() && it->complete >= before; --it);
33210612SMarco.Elver@ARM.com
33310612SMarco.Elver@ARM.com            return it;
33410612SMarco.Elver@ARM.com        }
33510612SMarco.Elver@ARM.com
33610612SMarco.Elver@ARM.com        /**
33710612SMarco.Elver@ARM.com         * Prunes no longer needed transactions. We only keep up to the last /
33810612SMarco.Elver@ARM.com         * most recent of each, readObservations and writeClusters, before the
33910612SMarco.Elver@ARM.com         * first outstanding read.
34010612SMarco.Elver@ARM.com         *
34110612SMarco.Elver@ARM.com         * It depends on the contention / overlap between memory operations to
34210612SMarco.Elver@ARM.com         * the same location of a particular workload how large each of them
34310612SMarco.Elver@ARM.com         * would grow.
34410612SMarco.Elver@ARM.com         */
34510612SMarco.Elver@ARM.com        void pruneTransactions();
34610612SMarco.Elver@ARM.com
34710612SMarco.Elver@ARM.com      private:
34810612SMarco.Elver@ARM.com
34910612SMarco.Elver@ARM.com        /**
35010612SMarco.Elver@ARM.com         * Maintains a map of Serial -> Transaction for all outstanding reads.
35110612SMarco.Elver@ARM.com         *
35210612SMarco.Elver@ARM.com         * Use an ordered map here, as this makes pruneTransactions() more
35310612SMarco.Elver@ARM.com         * efficient (find first outstanding read).
35410612SMarco.Elver@ARM.com         */
35510612SMarco.Elver@ARM.com        std::map<Serial, Transaction> outstandingReads;
35610612SMarco.Elver@ARM.com
35710612SMarco.Elver@ARM.com        /**
35810612SMarco.Elver@ARM.com         * List of completed reads, i.e. observations of reads.
35910612SMarco.Elver@ARM.com         */
36010612SMarco.Elver@ARM.com        TransactionList readObservations;
36110612SMarco.Elver@ARM.com
36210612SMarco.Elver@ARM.com        /**
36310612SMarco.Elver@ARM.com         * List of write clusters for this address.
36410612SMarco.Elver@ARM.com         */
36510612SMarco.Elver@ARM.com        WriteClusterList writeClusters;
36610612SMarco.Elver@ARM.com
36710612SMarco.Elver@ARM.com        /**
36810612SMarco.Elver@ARM.com         * See lastExpectedData().
36910612SMarco.Elver@ARM.com         */
37010612SMarco.Elver@ARM.com        std::vector<uint8_t> _lastExpectedData;
37110612SMarco.Elver@ARM.com    };
37210612SMarco.Elver@ARM.com
37310612SMarco.Elver@ARM.com  public:
37410612SMarco.Elver@ARM.com
37510612SMarco.Elver@ARM.com    MemChecker(const MemCheckerParams *p)
37610612SMarco.Elver@ARM.com        : SimObject(p),
37710612SMarco.Elver@ARM.com          nextSerial(SERIAL_INITIAL)
37810612SMarco.Elver@ARM.com    {}
37910612SMarco.Elver@ARM.com
38010612SMarco.Elver@ARM.com    virtual ~MemChecker() {}
38110612SMarco.Elver@ARM.com
38210612SMarco.Elver@ARM.com    /**
38310612SMarco.Elver@ARM.com     * Starts a read transaction.
38410612SMarco.Elver@ARM.com     *
38510612SMarco.Elver@ARM.com     * @param start  Tick this read was sent to the memory subsystem.
38610612SMarco.Elver@ARM.com     * @param addr   Address for read.
38710612SMarco.Elver@ARM.com     * @param size   Size of data expected.
38810612SMarco.Elver@ARM.com     *
38910612SMarco.Elver@ARM.com     * @return Serial representing the unique identifier for this transaction.
39010612SMarco.Elver@ARM.com     */
39110612SMarco.Elver@ARM.com    Serial startRead(Tick start, Addr addr, size_t size);
39210612SMarco.Elver@ARM.com
39310612SMarco.Elver@ARM.com    /**
39410612SMarco.Elver@ARM.com     * Starts a write transaction.
39510612SMarco.Elver@ARM.com     *
39610612SMarco.Elver@ARM.com     * @param start Tick when this write was sent to the memory subsystem.
39710612SMarco.Elver@ARM.com     * @param addr  Address for write.
39810612SMarco.Elver@ARM.com     * @param size  Size of data to be written.
39910612SMarco.Elver@ARM.com     * @param data  Pointer to size bytes, containing data to be written.
40010612SMarco.Elver@ARM.com     *
40110612SMarco.Elver@ARM.com     * @return Serial representing the unique identifier for this transaction.
40210612SMarco.Elver@ARM.com     */
40310612SMarco.Elver@ARM.com    Serial startWrite(Tick start, Addr addr, size_t size, const uint8_t *data);
40410612SMarco.Elver@ARM.com
40510612SMarco.Elver@ARM.com    /**
40610612SMarco.Elver@ARM.com     * Completes a previously started read transaction.
40710612SMarco.Elver@ARM.com     *
40810612SMarco.Elver@ARM.com     * @param serial    A serial of a read that was previously started and
40910612SMarco.Elver@ARM.com     *                  matches the address of the previously started read.
41010612SMarco.Elver@ARM.com     * @param complete  Tick we received the response from the memory subsystem.
41110612SMarco.Elver@ARM.com     * @param addr      Address for read.
41210612SMarco.Elver@ARM.com     * @param size      Size of data received.
41310612SMarco.Elver@ARM.com     * @param data      Pointer to size bytes, containing data received.
41410612SMarco.Elver@ARM.com     *
41510612SMarco.Elver@ARM.com     * @return True if the data we received is in the expected set, false
41610612SMarco.Elver@ARM.com     *         otherwise.
41710612SMarco.Elver@ARM.com     */
41810612SMarco.Elver@ARM.com    bool completeRead(Serial serial, Tick complete,
41910612SMarco.Elver@ARM.com                      Addr addr, size_t size, uint8_t *data);
42010612SMarco.Elver@ARM.com
42110612SMarco.Elver@ARM.com    /**
42210612SMarco.Elver@ARM.com     * Completes a previously started write transaction.
42310612SMarco.Elver@ARM.com     *
42410612SMarco.Elver@ARM.com     * @param serial    A serial of a write that was previously started and
42510612SMarco.Elver@ARM.com     *                  matches the address of the previously started write.
42610612SMarco.Elver@ARM.com     * @param complete  Tick we received acknowledgment of completion from the
42710612SMarco.Elver@ARM.com     *                  memory subsystem.
42810612SMarco.Elver@ARM.com     * @param addr      Address for write.
42910612SMarco.Elver@ARM.com     * @param size      The size of the data written.
43010612SMarco.Elver@ARM.com     */
43110612SMarco.Elver@ARM.com    void completeWrite(Serial serial, Tick complete, Addr addr, size_t size);
43210612SMarco.Elver@ARM.com
43310612SMarco.Elver@ARM.com    /**
43410612SMarco.Elver@ARM.com     * Aborts a previously started write transaction.
43510612SMarco.Elver@ARM.com     *
43610612SMarco.Elver@ARM.com     * @param serial    A serial of a write that was previously started and
43710612SMarco.Elver@ARM.com     *                  matches the address of the previously started write.
43810612SMarco.Elver@ARM.com     * @param addr      Address for write.
43910612SMarco.Elver@ARM.com     * @param size      The size of the data written.
44010612SMarco.Elver@ARM.com     */
44110612SMarco.Elver@ARM.com    void abortWrite(Serial serial, Addr addr, size_t size);
44210612SMarco.Elver@ARM.com
44310612SMarco.Elver@ARM.com    /**
44410612SMarco.Elver@ARM.com     * Resets the entire checker. Note that if there are transactions
44510612SMarco.Elver@ARM.com     * in-flight, this will cause a warning to be issued if these are completed
44610612SMarco.Elver@ARM.com     * after the reset. This does not reset nextSerial to avoid such a race
44710612SMarco.Elver@ARM.com     * condition: where a transaction started before a reset with serial S,
44810612SMarco.Elver@ARM.com     * then reset() was called, followed by a start of a transaction with the
44910612SMarco.Elver@ARM.com     * same serial S and then receive a completion of the transaction before
45010612SMarco.Elver@ARM.com     * the reset with serial S.
45110612SMarco.Elver@ARM.com     */
45210612SMarco.Elver@ARM.com    void reset()
45310612SMarco.Elver@ARM.com    { byte_trackers.clear(); }
45410612SMarco.Elver@ARM.com
45510612SMarco.Elver@ARM.com    /**
45610612SMarco.Elver@ARM.com     * Resets an address-range. This may be useful in case other unmonitored
45710612SMarco.Elver@ARM.com     * parts of the system caused modification to this memory, but we cannot
45810612SMarco.Elver@ARM.com     * track their written values.
45910612SMarco.Elver@ARM.com     *
46010612SMarco.Elver@ARM.com     * @param addr Address base.
46110612SMarco.Elver@ARM.com     * @param size Size of range to be invalidated.
46210612SMarco.Elver@ARM.com     */
46310612SMarco.Elver@ARM.com    void reset(Addr addr, size_t size);
46410612SMarco.Elver@ARM.com
46510612SMarco.Elver@ARM.com    /**
46610612SMarco.Elver@ARM.com     * In completeRead, if an error is encountered, this does not print nor
46710612SMarco.Elver@ARM.com     * cause an error, but instead should be handled by the caller. However, to
46810612SMarco.Elver@ARM.com     * record information about the cause of an error, completeRead creates an
46910612SMarco.Elver@ARM.com     * errorMessage. This function returns the last error that was detected in
47010612SMarco.Elver@ARM.com     * completeRead.
47110612SMarco.Elver@ARM.com     *
47210612SMarco.Elver@ARM.com     * @return Reference to string of error message.
47310612SMarco.Elver@ARM.com     */
47410612SMarco.Elver@ARM.com    const std::string& getErrorMessage() const { return errorMessage; }
47510612SMarco.Elver@ARM.com
47610612SMarco.Elver@ARM.com  private:
47710612SMarco.Elver@ARM.com    /**
47810612SMarco.Elver@ARM.com     * Returns the instance of ByteTracker for the requested location.
47910612SMarco.Elver@ARM.com     */
48010612SMarco.Elver@ARM.com    ByteTracker* getByteTracker(Addr addr)
48110612SMarco.Elver@ARM.com    {
48210612SMarco.Elver@ARM.com        auto it = byte_trackers.find(addr);
48310612SMarco.Elver@ARM.com        if (it == byte_trackers.end()) {
48410612SMarco.Elver@ARM.com            it = byte_trackers.insert(
48510612SMarco.Elver@ARM.com                std::make_pair(addr, ByteTracker(addr, this))).first;
48610612SMarco.Elver@ARM.com        }
48710612SMarco.Elver@ARM.com        return &it->second;
48810612SMarco.Elver@ARM.com    };
48910612SMarco.Elver@ARM.com
49010612SMarco.Elver@ARM.com  private:
49110612SMarco.Elver@ARM.com    /**
49210612SMarco.Elver@ARM.com     * Detailed error message of the last violation in completeRead.
49310612SMarco.Elver@ARM.com     */
49410612SMarco.Elver@ARM.com    std::string errorMessage;
49510612SMarco.Elver@ARM.com
49610612SMarco.Elver@ARM.com    /**
49710612SMarco.Elver@ARM.com     * Next distinct serial to be assigned to the next transaction to be
49810612SMarco.Elver@ARM.com     * started.
49910612SMarco.Elver@ARM.com     */
50010612SMarco.Elver@ARM.com    Serial nextSerial;
50110612SMarco.Elver@ARM.com
50210612SMarco.Elver@ARM.com    /**
50310612SMarco.Elver@ARM.com     * Maintain a map of address --> byte-tracker. Per-byte entries are
50410612SMarco.Elver@ARM.com     * initialized as needed.
50510612SMarco.Elver@ARM.com     *
50610612SMarco.Elver@ARM.com     * The required space for this obviously grows with the number of distinct
50710612SMarco.Elver@ARM.com     * addresses used for a particular workload. The used size is independent on
50810612SMarco.Elver@ARM.com     * the number of nodes in the system, those may affect the size of per-byte
50910612SMarco.Elver@ARM.com     * tracking information.
51010612SMarco.Elver@ARM.com     *
51110612SMarco.Elver@ARM.com     * Access via getByteTracker()!
51210612SMarco.Elver@ARM.com     */
51311168Sandreas.hansson@arm.com    std::unordered_map<Addr, ByteTracker> byte_trackers;
51410612SMarco.Elver@ARM.com};
51510612SMarco.Elver@ARM.com
51610612SMarco.Elver@ARM.cominline MemChecker::Serial
51710612SMarco.Elver@ARM.comMemChecker::startRead(Tick start, Addr addr, size_t size)
51810612SMarco.Elver@ARM.com{
51910612SMarco.Elver@ARM.com    DPRINTF(MemChecker,
52010612SMarco.Elver@ARM.com            "starting read: serial = %d, start = %d, addr = %#llx, "
52110612SMarco.Elver@ARM.com            "size = %d\n", nextSerial, start, addr , size);
52210612SMarco.Elver@ARM.com
52310612SMarco.Elver@ARM.com    for (size_t i = 0; i < size; ++i) {
52410612SMarco.Elver@ARM.com        getByteTracker(addr + i)->startRead(nextSerial, start);
52510612SMarco.Elver@ARM.com    }
52610612SMarco.Elver@ARM.com
52710612SMarco.Elver@ARM.com    return nextSerial++;
52810612SMarco.Elver@ARM.com}
52910612SMarco.Elver@ARM.com
53010612SMarco.Elver@ARM.cominline MemChecker::Serial
53110612SMarco.Elver@ARM.comMemChecker::startWrite(Tick start, Addr addr, size_t size, const uint8_t *data)
53210612SMarco.Elver@ARM.com{
53310612SMarco.Elver@ARM.com    DPRINTF(MemChecker,
53410612SMarco.Elver@ARM.com            "starting write: serial = %d, start = %d, addr = %#llx, "
53510612SMarco.Elver@ARM.com            "size = %d\n", nextSerial, start, addr, size);
53610612SMarco.Elver@ARM.com
53710612SMarco.Elver@ARM.com    for (size_t i = 0; i < size; ++i) {
53810612SMarco.Elver@ARM.com        getByteTracker(addr + i)->startWrite(nextSerial, start, data[i]);
53910612SMarco.Elver@ARM.com    }
54010612SMarco.Elver@ARM.com
54110612SMarco.Elver@ARM.com    return nextSerial++;
54210612SMarco.Elver@ARM.com}
54310612SMarco.Elver@ARM.com
54410612SMarco.Elver@ARM.cominline void
54510612SMarco.Elver@ARM.comMemChecker::completeWrite(MemChecker::Serial serial, Tick complete,
54610612SMarco.Elver@ARM.com                          Addr addr, size_t size)
54710612SMarco.Elver@ARM.com{
54810612SMarco.Elver@ARM.com    DPRINTF(MemChecker,
54910612SMarco.Elver@ARM.com            "completing write: serial = %d, complete = %d, "
55010612SMarco.Elver@ARM.com            "addr = %#llx, size = %d\n", serial, complete, addr, size);
55110612SMarco.Elver@ARM.com
55210612SMarco.Elver@ARM.com    for (size_t i = 0; i < size; ++i) {
55310612SMarco.Elver@ARM.com        getByteTracker(addr + i)->completeWrite(serial, complete);
55410612SMarco.Elver@ARM.com    }
55510612SMarco.Elver@ARM.com}
55610612SMarco.Elver@ARM.com
55710612SMarco.Elver@ARM.cominline void
55810612SMarco.Elver@ARM.comMemChecker::abortWrite(MemChecker::Serial serial, Addr addr, size_t size)
55910612SMarco.Elver@ARM.com{
56010612SMarco.Elver@ARM.com    DPRINTF(MemChecker,
56110612SMarco.Elver@ARM.com            "aborting write: serial = %d, addr = %#llx, size = %d\n",
56210612SMarco.Elver@ARM.com            serial, addr, size);
56310612SMarco.Elver@ARM.com
56410612SMarco.Elver@ARM.com    for (size_t i = 0; i < size; ++i) {
56510612SMarco.Elver@ARM.com        getByteTracker(addr + i)->abortWrite(serial);
56610612SMarco.Elver@ARM.com    }
56710612SMarco.Elver@ARM.com}
56810612SMarco.Elver@ARM.com
56910612SMarco.Elver@ARM.com#endif // __MEM_MEM_CHECKER_HH__
570