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