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
4111793Sbrandon.potter@amd.com#include "mem/mem_checker.hh"
4211793Sbrandon.potter@amd.com
4310612SMarco.Elver@ARM.com#include <cassert>
4410612SMarco.Elver@ARM.com
4510612SMarco.Elver@ARM.comvoid
4610612SMarco.Elver@ARM.comMemChecker::WriteCluster::startWrite(MemChecker::Serial serial, Tick _start,
4710612SMarco.Elver@ARM.com                                     uint8_t data)
4810612SMarco.Elver@ARM.com{
4910612SMarco.Elver@ARM.com    assert(!isComplete());
5010612SMarco.Elver@ARM.com
5110612SMarco.Elver@ARM.com    if (start == TICK_FUTURE) {
5210612SMarco.Elver@ARM.com        // Initialize a fresh write cluster
5310612SMarco.Elver@ARM.com        start = _start;
5410612SMarco.Elver@ARM.com    }
5510612SMarco.Elver@ARM.com    chatty_assert(start <= _start, "WriteClusters must filled in order!");
5610612SMarco.Elver@ARM.com
5710612SMarco.Elver@ARM.com    ++numIncomplete;
5810612SMarco.Elver@ARM.com
5910612SMarco.Elver@ARM.com    if (complete != TICK_FUTURE) {
6010612SMarco.Elver@ARM.com       // Reopen a closed write cluster
6110612SMarco.Elver@ARM.com        assert(_start < complete);  // should open a new write cluster, instead;
6210612SMarco.Elver@ARM.com        // also somewhat fishy wrt causality / ordering of calls vs time
6310612SMarco.Elver@ARM.com        // progression TODO: Check me!
6410612SMarco.Elver@ARM.com        complete = TICK_FUTURE;
6510612SMarco.Elver@ARM.com    }
6610612SMarco.Elver@ARM.com
6710612SMarco.Elver@ARM.com    // Create new transaction, and denote completion time to be in the future.
6810612SMarco.Elver@ARM.com    writes.insert(std::make_pair(serial,
6910612SMarco.Elver@ARM.com                  MemChecker::Transaction(serial, _start, TICK_FUTURE, data)));
7010612SMarco.Elver@ARM.com}
7110612SMarco.Elver@ARM.com
7210612SMarco.Elver@ARM.comvoid
7310612SMarco.Elver@ARM.comMemChecker::WriteCluster::completeWrite(MemChecker::Serial serial, Tick _complete)
7410612SMarco.Elver@ARM.com{
7510612SMarco.Elver@ARM.com    auto it = writes.find(serial);
7610612SMarco.Elver@ARM.com
7710612SMarco.Elver@ARM.com    if (it == writes.end()) {
7810612SMarco.Elver@ARM.com        warn("Could not locate write transaction: serial = %d, complete = %d\n",
7910612SMarco.Elver@ARM.com             serial, _complete);
8010612SMarco.Elver@ARM.com        return;
8110612SMarco.Elver@ARM.com    }
8210612SMarco.Elver@ARM.com
8310612SMarco.Elver@ARM.com    // Record completion time of the write
8410612SMarco.Elver@ARM.com    assert(it->second.complete == TICK_FUTURE);
8510612SMarco.Elver@ARM.com    it->second.complete = _complete;
8610612SMarco.Elver@ARM.com
8710612SMarco.Elver@ARM.com    // Update max completion time for the cluster
8810612SMarco.Elver@ARM.com    if (completeMax < _complete) {
8910612SMarco.Elver@ARM.com        completeMax = _complete;
9010612SMarco.Elver@ARM.com    }
9110612SMarco.Elver@ARM.com
9210612SMarco.Elver@ARM.com    if (--numIncomplete == 0) {
9310612SMarco.Elver@ARM.com        // All writes have completed, this cluster is now complete and will be
9410612SMarco.Elver@ARM.com        // assigned the max of completion tick values among all writes.
9510612SMarco.Elver@ARM.com        //
9610612SMarco.Elver@ARM.com        // Note that we cannot simply keep updating complete, because that would
9710612SMarco.Elver@ARM.com        // count the cluster as closed already.  Instead, we keep TICK_FUTURE
9810612SMarco.Elver@ARM.com        // until all writes have completed.
9910612SMarco.Elver@ARM.com        complete = completeMax;
10010612SMarco.Elver@ARM.com    }
10110612SMarco.Elver@ARM.com}
10210612SMarco.Elver@ARM.com
10310612SMarco.Elver@ARM.comvoid
10410612SMarco.Elver@ARM.comMemChecker::WriteCluster::abortWrite(MemChecker::Serial serial)
10510612SMarco.Elver@ARM.com{
10610612SMarco.Elver@ARM.com    if (!writes.erase(serial)) {
10710612SMarco.Elver@ARM.com        warn("Could not locate write transaction: serial = %d\n", serial);
10810612SMarco.Elver@ARM.com        return;
10910612SMarco.Elver@ARM.com    }
11010612SMarco.Elver@ARM.com
11110612SMarco.Elver@ARM.com    if (--numIncomplete == 0 && !writes.empty()) {
11210612SMarco.Elver@ARM.com        // This write cluster is now complete, and we can assign the current
11310612SMarco.Elver@ARM.com        // completeMax value.
11410612SMarco.Elver@ARM.com        complete = completeMax;
11510612SMarco.Elver@ARM.com    }
11610612SMarco.Elver@ARM.com
11710612SMarco.Elver@ARM.com    // Note: this WriteCluster is in pristine state if this was the only
11810612SMarco.Elver@ARM.com    // write present; the cluster will get reused through
11910612SMarco.Elver@ARM.com    // getIncompleteWriteCluster().
12010612SMarco.Elver@ARM.com}
12110612SMarco.Elver@ARM.com
12210612SMarco.Elver@ARM.comvoid
12310612SMarco.Elver@ARM.comMemChecker::ByteTracker::startRead(MemChecker::Serial serial, Tick start)
12410612SMarco.Elver@ARM.com{
12510612SMarco.Elver@ARM.com    outstandingReads.insert(std::make_pair(serial,
12610612SMarco.Elver@ARM.com            MemChecker::Transaction(serial, start, TICK_FUTURE)));
12710612SMarco.Elver@ARM.com}
12810612SMarco.Elver@ARM.com
12910612SMarco.Elver@ARM.combool
13010612SMarco.Elver@ARM.comMemChecker::ByteTracker::inExpectedData(Tick start, Tick complete, uint8_t data)
13110612SMarco.Elver@ARM.com{
13210612SMarco.Elver@ARM.com    _lastExpectedData.clear();
13310612SMarco.Elver@ARM.com
13410612SMarco.Elver@ARM.com    bool wc_overlap = true;
13510612SMarco.Elver@ARM.com
13610612SMarco.Elver@ARM.com    // Find the last value read from the location
13710612SMarco.Elver@ARM.com    const Transaction& last_obs =
13810612SMarco.Elver@ARM.com        *lastCompletedTransaction(&readObservations, start);
13910612SMarco.Elver@ARM.com    bool last_obs_valid = (last_obs.complete != TICK_INITIAL);
14010612SMarco.Elver@ARM.com
14110612SMarco.Elver@ARM.com    // Scan backwards through the write clusters to find the closest younger
14210612SMarco.Elver@ARM.com    // preceding & overlapping writes.
14310612SMarco.Elver@ARM.com    for (auto cluster = writeClusters.rbegin();
14410612SMarco.Elver@ARM.com         cluster != writeClusters.rend() && wc_overlap; ++cluster) {
14510612SMarco.Elver@ARM.com        for (const auto& addr_write : cluster->writes) {
14610612SMarco.Elver@ARM.com            const Transaction& write = addr_write.second;
14710612SMarco.Elver@ARM.com
14810612SMarco.Elver@ARM.com            if (write.complete < last_obs.start) {
14910612SMarco.Elver@ARM.com                // If this write transaction completed before the last
15010612SMarco.Elver@ARM.com                // observation, we ignore it as the last_observation has the
15110612SMarco.Elver@ARM.com                // correct value
15210612SMarco.Elver@ARM.com                continue;
15310612SMarco.Elver@ARM.com            }
15410612SMarco.Elver@ARM.com
15510612SMarco.Elver@ARM.com            if (write.data == data) {
15610612SMarco.Elver@ARM.com                // Found a match, end search.
15710612SMarco.Elver@ARM.com                return true;
15810612SMarco.Elver@ARM.com            }
15910612SMarco.Elver@ARM.com
16010612SMarco.Elver@ARM.com            // Record possible, but non-matching data for debugging
16110612SMarco.Elver@ARM.com            _lastExpectedData.push_back(write.data);
16210612SMarco.Elver@ARM.com
16310612SMarco.Elver@ARM.com            if (write.complete > start) {
16410612SMarco.Elver@ARM.com                // This write overlapped with the transaction we want to check
16510612SMarco.Elver@ARM.com                // -> continue checking the overlapping write cluster
16610612SMarco.Elver@ARM.com                continue;
16710612SMarco.Elver@ARM.com            }
16810612SMarco.Elver@ARM.com
16910612SMarco.Elver@ARM.com            // This write cluster has writes that have completed before the
17010612SMarco.Elver@ARM.com            // checked transaction. There is no need to check an earlier
17110612SMarco.Elver@ARM.com            // write-cluster -> set the exit condition for the outer loop
17210612SMarco.Elver@ARM.com            wc_overlap = false;
17310612SMarco.Elver@ARM.com
17410612SMarco.Elver@ARM.com            if (last_obs.complete < write.start) {
17510612SMarco.Elver@ARM.com                // We found a write which started after the last observed read,
17610612SMarco.Elver@ARM.com                // therefore we can not longer consider the value seen by the
17710612SMarco.Elver@ARM.com                // last observation as a valid expected value.
17810612SMarco.Elver@ARM.com                //
17910612SMarco.Elver@ARM.com                // Once all writes have been iterated through, we can check if
18010612SMarco.Elver@ARM.com                // the last observation is still valid to compare against.
18110612SMarco.Elver@ARM.com                last_obs_valid = false;
18210612SMarco.Elver@ARM.com            }
18310612SMarco.Elver@ARM.com        }
18410612SMarco.Elver@ARM.com    }
18510612SMarco.Elver@ARM.com
18610612SMarco.Elver@ARM.com    // We have not found any matching write, so far; check other sources of
18710612SMarco.Elver@ARM.com    // confirmation
18810612SMarco.Elver@ARM.com    if (last_obs_valid) {
18910612SMarco.Elver@ARM.com        // The last observation is not outdated according to the writes we have
19010612SMarco.Elver@ARM.com        // seen so far.
19110612SMarco.Elver@ARM.com        assert(last_obs.complete <= start);
19210612SMarco.Elver@ARM.com        if (last_obs.data == data) {
19310612SMarco.Elver@ARM.com            // Matched data from last observation -> all good
19410612SMarco.Elver@ARM.com            return true;
19510612SMarco.Elver@ARM.com        }
19610612SMarco.Elver@ARM.com        // Record non-matching, but possible value
19710612SMarco.Elver@ARM.com        _lastExpectedData.push_back(last_obs.data);
19810703Sstephan.diestelhorst@arm.com    } else {
19910703Sstephan.diestelhorst@arm.com        // We have not seen any valid observation, and the only writes
20010703Sstephan.diestelhorst@arm.com        // observed are overlapping, so anything (in particular the
20110703Sstephan.diestelhorst@arm.com        // initialisation value) goes
20210703Sstephan.diestelhorst@arm.com        // NOTE: We can overlap with multiple write clusters, here
20310703Sstephan.diestelhorst@arm.com        if (!writeClusters.empty() && wc_overlap) {
20410703Sstephan.diestelhorst@arm.com            // ensure that all write clusters really overlap this read
20510703Sstephan.diestelhorst@arm.com            assert(writeClusters.begin()->start < complete &&
20610703Sstephan.diestelhorst@arm.com                   writeClusters.rbegin()->complete > start);
20710703Sstephan.diestelhorst@arm.com            return true;
20810703Sstephan.diestelhorst@arm.com        }
20910612SMarco.Elver@ARM.com    }
21010612SMarco.Elver@ARM.com
21110612SMarco.Elver@ARM.com    if (_lastExpectedData.empty()) {
21210612SMarco.Elver@ARM.com        assert(last_obs.complete == TICK_INITIAL);
21310612SMarco.Elver@ARM.com        // We have not found any possible (non-matching data). Can happen in
21410612SMarco.Elver@ARM.com        // initial system state
21510612SMarco.Elver@ARM.com        DPRINTF(MemChecker, "no last observation nor write! start = %d, "\
21610612SMarco.Elver@ARM.com                "complete = %d, data = %#x\n", start, complete, data);
21710612SMarco.Elver@ARM.com        return true;
21810612SMarco.Elver@ARM.com    }
21910612SMarco.Elver@ARM.com    return false;
22010612SMarco.Elver@ARM.com}
22110612SMarco.Elver@ARM.com
22210612SMarco.Elver@ARM.combool
22310612SMarco.Elver@ARM.comMemChecker::ByteTracker::completeRead(MemChecker::Serial serial,
22410612SMarco.Elver@ARM.com                                      Tick complete, uint8_t data)
22510612SMarco.Elver@ARM.com{
22610612SMarco.Elver@ARM.com    auto it = outstandingReads.find(serial);
22710612SMarco.Elver@ARM.com
22810612SMarco.Elver@ARM.com    if (it == outstandingReads.end()) {
22910612SMarco.Elver@ARM.com        // Can happen if concurrent with reset_address_range
23010612SMarco.Elver@ARM.com        warn("Could not locate read transaction: serial = %d, complete = %d\n",
23110612SMarco.Elver@ARM.com             serial, complete);
23210612SMarco.Elver@ARM.com        return true;
23310612SMarco.Elver@ARM.com    }
23410612SMarco.Elver@ARM.com
23510612SMarco.Elver@ARM.com    Tick start = it->second.start;
23610612SMarco.Elver@ARM.com    outstandingReads.erase(it);
23710612SMarco.Elver@ARM.com
23810612SMarco.Elver@ARM.com    // Verify data
23910612SMarco.Elver@ARM.com    const bool result = inExpectedData(start, complete, data);
24010612SMarco.Elver@ARM.com
24110612SMarco.Elver@ARM.com    readObservations.emplace_back(serial, start, complete, data);
24210612SMarco.Elver@ARM.com    pruneTransactions();
24310612SMarco.Elver@ARM.com
24410612SMarco.Elver@ARM.com    return result;
24510612SMarco.Elver@ARM.com}
24610612SMarco.Elver@ARM.com
24710612SMarco.Elver@ARM.comMemChecker::WriteCluster*
24810612SMarco.Elver@ARM.comMemChecker::ByteTracker::getIncompleteWriteCluster()
24910612SMarco.Elver@ARM.com{
25010612SMarco.Elver@ARM.com    if (writeClusters.empty() || writeClusters.back().isComplete()) {
25110612SMarco.Elver@ARM.com        writeClusters.emplace_back();
25210612SMarco.Elver@ARM.com    }
25310612SMarco.Elver@ARM.com
25410612SMarco.Elver@ARM.com    return &writeClusters.back();
25510612SMarco.Elver@ARM.com}
25610612SMarco.Elver@ARM.com
25710612SMarco.Elver@ARM.comvoid
25810612SMarco.Elver@ARM.comMemChecker::ByteTracker::startWrite(MemChecker::Serial serial, Tick start,
25910612SMarco.Elver@ARM.com                                    uint8_t data)
26010612SMarco.Elver@ARM.com{
26110612SMarco.Elver@ARM.com    getIncompleteWriteCluster()->startWrite(serial, start, data);
26210612SMarco.Elver@ARM.com}
26310612SMarco.Elver@ARM.com
26410612SMarco.Elver@ARM.comvoid
26510612SMarco.Elver@ARM.comMemChecker::ByteTracker::completeWrite(MemChecker::Serial serial, Tick complete)
26610612SMarco.Elver@ARM.com{
26710612SMarco.Elver@ARM.com    getIncompleteWriteCluster()->completeWrite(serial, complete);
26810612SMarco.Elver@ARM.com    pruneTransactions();
26910612SMarco.Elver@ARM.com}
27010612SMarco.Elver@ARM.com
27110612SMarco.Elver@ARM.comvoid
27210612SMarco.Elver@ARM.comMemChecker::ByteTracker::abortWrite(MemChecker::Serial serial)
27310612SMarco.Elver@ARM.com{
27410612SMarco.Elver@ARM.com    getIncompleteWriteCluster()->abortWrite(serial);
27510612SMarco.Elver@ARM.com}
27610612SMarco.Elver@ARM.com
27710612SMarco.Elver@ARM.comvoid
27810612SMarco.Elver@ARM.comMemChecker::ByteTracker::pruneTransactions()
27910612SMarco.Elver@ARM.com{
28010612SMarco.Elver@ARM.com    // Obtain tick of first outstanding read. If there are no outstanding
28110612SMarco.Elver@ARM.com    // reads, we use curTick(), i.e. we will remove all readObservation except
28210612SMarco.Elver@ARM.com    // the most recent one.
28310612SMarco.Elver@ARM.com    const Tick before = outstandingReads.empty() ? curTick() :
28410612SMarco.Elver@ARM.com                        outstandingReads.begin()->second.start;
28510612SMarco.Elver@ARM.com
28610612SMarco.Elver@ARM.com    // Pruning of readObservations
28710612SMarco.Elver@ARM.com    readObservations.erase(readObservations.begin(),
28810612SMarco.Elver@ARM.com                           lastCompletedTransaction(&readObservations, before));
28910612SMarco.Elver@ARM.com
29010612SMarco.Elver@ARM.com    // Pruning of writeClusters
29110612SMarco.Elver@ARM.com    if (!writeClusters.empty()) {
29210612SMarco.Elver@ARM.com        writeClusters.erase(writeClusters.begin(),
29310612SMarco.Elver@ARM.com                            lastCompletedTransaction(&writeClusters, before));
29410612SMarco.Elver@ARM.com    }
29510612SMarco.Elver@ARM.com}
29610612SMarco.Elver@ARM.com
29710612SMarco.Elver@ARM.combool
29810612SMarco.Elver@ARM.comMemChecker::completeRead(MemChecker::Serial serial, Tick complete,
29910612SMarco.Elver@ARM.com                         Addr addr, size_t size, uint8_t *data)
30010612SMarco.Elver@ARM.com{
30110612SMarco.Elver@ARM.com    bool result = true;
30210612SMarco.Elver@ARM.com
30310612SMarco.Elver@ARM.com    DPRINTF(MemChecker,
30410612SMarco.Elver@ARM.com            "completing read: serial = %d, complete = %d, "
30510612SMarco.Elver@ARM.com            "addr = %#llx, size = %d\n", serial, complete, addr, size);
30610612SMarco.Elver@ARM.com
30710612SMarco.Elver@ARM.com    for (size_t i = 0; i < size; ++i) {
30810612SMarco.Elver@ARM.com        ByteTracker *tracker = getByteTracker(addr + i);
30910612SMarco.Elver@ARM.com
31010612SMarco.Elver@ARM.com        if (!tracker->completeRead(serial, complete, data[i])) {
31110612SMarco.Elver@ARM.com            // Generate error message, and aggregate all failures for the bytes
31210612SMarco.Elver@ARM.com            // considered in this transaction in one message.
31310612SMarco.Elver@ARM.com            if (result) {
31410612SMarco.Elver@ARM.com                result = false;
31510612SMarco.Elver@ARM.com                errorMessage = "";
31610612SMarco.Elver@ARM.com            } else {
31710612SMarco.Elver@ARM.com                errorMessage += "\n";
31810612SMarco.Elver@ARM.com            }
31910612SMarco.Elver@ARM.com
32010612SMarco.Elver@ARM.com            errorMessage += csprintf("  Read transaction for address %#llx "
32110612SMarco.Elver@ARM.com                                     "failed: received %#x, expected ",
32210612SMarco.Elver@ARM.com                                     (unsigned long long)(addr + i), data[i]);
32310612SMarco.Elver@ARM.com
32410612SMarco.Elver@ARM.com            for (size_t j = 0; j < tracker->lastExpectedData().size(); ++j) {
32510612SMarco.Elver@ARM.com                errorMessage +=
32610612SMarco.Elver@ARM.com                    csprintf("%#x%s",
32710612SMarco.Elver@ARM.com                             tracker->lastExpectedData()[j],
32810612SMarco.Elver@ARM.com                             (j == tracker->lastExpectedData().size() - 1)
32910612SMarco.Elver@ARM.com                             ? "" : "|");
33010612SMarco.Elver@ARM.com            }
33110612SMarco.Elver@ARM.com        }
33210612SMarco.Elver@ARM.com    }
33310612SMarco.Elver@ARM.com
33410612SMarco.Elver@ARM.com    if (!result) {
33510612SMarco.Elver@ARM.com        DPRINTF(MemChecker, "read of %#llx @ cycle %d failed:\n%s\n", addr,
33610612SMarco.Elver@ARM.com                complete, errorMessage);
33710612SMarco.Elver@ARM.com    }
33810612SMarco.Elver@ARM.com
33910612SMarco.Elver@ARM.com    return result;
34010612SMarco.Elver@ARM.com}
34110612SMarco.Elver@ARM.com
34210612SMarco.Elver@ARM.comvoid
34310612SMarco.Elver@ARM.comMemChecker::reset(Addr addr, size_t size)
34410612SMarco.Elver@ARM.com{
34510612SMarco.Elver@ARM.com    for (size_t i = 0; i < size; ++i) {
34610612SMarco.Elver@ARM.com        byte_trackers.erase(addr + i);
34710612SMarco.Elver@ARM.com    }
34810612SMarco.Elver@ARM.com}
34910612SMarco.Elver@ARM.com
35010612SMarco.Elver@ARM.comMemChecker*
35110612SMarco.Elver@ARM.comMemCheckerParams::create()
35210612SMarco.Elver@ARM.com{
35310612SMarco.Elver@ARM.com    return new MemChecker(this);
35410612SMarco.Elver@ARM.com}
355