memtest.cc revision 10713
12SN/A/*
210688Sandreas.hansson@arm.com * Copyright (c) 2015 ARM Limited
310688Sandreas.hansson@arm.com * All rights reserved
410688Sandreas.hansson@arm.com *
510688Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
610688Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
710688Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
810688Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
910688Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
1010688Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
1110688Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
1210688Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
1310688Sandreas.hansson@arm.com *
141762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
152SN/A * All rights reserved.
162SN/A *
172SN/A * Redistribution and use in source and binary forms, with or without
182SN/A * modification, are permitted provided that the following conditions are
192SN/A * met: redistributions of source code must retain the above copyright
202SN/A * notice, this list of conditions and the following disclaimer;
212SN/A * redistributions in binary form must reproduce the above copyright
222SN/A * notice, this list of conditions and the following disclaimer in the
232SN/A * documentation and/or other materials provided with the distribution;
242SN/A * neither the name of the copyright holders nor the names of its
252SN/A * contributors may be used to endorse or promote products derived from
262SN/A * this software without specific prior written permission.
272SN/A *
282SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Erik Hallnor
412665SN/A *          Steve Reinhardt
4210688Sandreas.hansson@arm.com *          Andreas Hansson
432SN/A */
442SN/A
4510348Sandreas.hansson@arm.com#include "base/random.hh"
46146SN/A#include "base/statistics.hh"
477632SBrad.Beckmann@amd.com#include "cpu/testers/memtest/memtest.hh"
488232Snate@binkert.org#include "debug/MemTest.hh"
493348SN/A#include "mem/mem_object.hh"
5010688Sandreas.hansson@arm.com#include "sim/sim_exit.hh"
51695SN/A#include "sim/stats.hh"
528832SAli.Saidi@ARM.com#include "sim/system.hh"
532SN/A
542SN/Ausing namespace std;
552SN/A
5610688Sandreas.hansson@arm.comunsigned int TESTER_ALLOCATOR = 0;
571298SN/A
583187SN/Abool
598975Sandreas.hansson@arm.comMemTest::CpuPort::recvTimingResp(PacketPtr pkt)
603187SN/A{
6110688Sandreas.hansson@arm.com    memtest.completeRequest(pkt);
623187SN/A    return true;
633187SN/A}
643187SN/A
653187SN/Avoid
6610713Sandreas.hansson@arm.comMemTest::CpuPort::recvReqRetry()
673187SN/A{
6810688Sandreas.hansson@arm.com    memtest.recvRetry();
693187SN/A}
703187SN/A
7110688Sandreas.hansson@arm.combool
723349SN/AMemTest::sendPkt(PacketPtr pkt) {
733262SN/A    if (atomic) {
7410688Sandreas.hansson@arm.com        port.sendAtomic(pkt);
753262SN/A        completeRequest(pkt);
767544SN/A    } else {
7710688Sandreas.hansson@arm.com        if (!port.sendTimingReq(pkt)) {
7810688Sandreas.hansson@arm.com            retryPkt = pkt;
7910688Sandreas.hansson@arm.com            return false;
807544SN/A        }
813262SN/A    }
8210688Sandreas.hansson@arm.com    return true;
833262SN/A}
843262SN/A
855034SN/AMemTest::MemTest(const Params *p)
865034SN/A    : MemObject(p),
872SN/A      tickEvent(this),
8810688Sandreas.hansson@arm.com      noRequestEvent(this),
8910688Sandreas.hansson@arm.com      noResponseEvent(this),
9010688Sandreas.hansson@arm.com      port("port", *this),
9110688Sandreas.hansson@arm.com      retryPkt(nullptr),
9210688Sandreas.hansson@arm.com      size(p->size),
9310688Sandreas.hansson@arm.com      interval(p->interval),
945034SN/A      percentReads(p->percent_reads),
955034SN/A      percentFunctional(p->percent_functional),
965034SN/A      percentUncacheable(p->percent_uncacheable),
9710688Sandreas.hansson@arm.com      masterId(p->system->getMasterId(name())),
9810688Sandreas.hansson@arm.com      blockSize(p->system->cacheLineSize()),
9910688Sandreas.hansson@arm.com      blockAddrMask(blockSize - 1),
1005034SN/A      progressInterval(p->progress_interval),
10110688Sandreas.hansson@arm.com      progressCheck(p->progress_check),
1025034SN/A      nextProgressMessage(p->progress_interval),
1035034SN/A      maxLoads(p->max_loads),
10410688Sandreas.hansson@arm.com      atomic(p->system->isAtomicMode()),
10510688Sandreas.hansson@arm.com      suppressFuncWarnings(p->suppress_func_warnings)
1062SN/A{
1077544SN/A    id = TESTER_ALLOCATOR++;
10810688Sandreas.hansson@arm.com    fatal_if(id >= blockSize, "Too many testers, only %d allowed\n",
10910688Sandreas.hansson@arm.com             blockSize - 1);
1107544SN/A
1112SN/A    baseAddr1 = 0x100000;
1122SN/A    baseAddr2 = 0x400000;
1132SN/A    uncacheAddr = 0x800000;
1142SN/A
1152SN/A    // set up counters
1162SN/A    numReads = 0;
1178436SBrad.Beckmann@amd.com    numWrites = 0;
1181298SN/A
11910688Sandreas.hansson@arm.com    // kick things into action
12010688Sandreas.hansson@arm.com    schedule(tickEvent, curTick());
12110688Sandreas.hansson@arm.com    schedule(noRequestEvent, clockEdge(progressCheck));
12210688Sandreas.hansson@arm.com    schedule(noResponseEvent, clockEdge(progressCheck));
1233187SN/A}
1243187SN/A
1259294Sandreas.hansson@arm.comBaseMasterPort &
1269294Sandreas.hansson@arm.comMemTest::getMasterPort(const std::string &if_name, PortID idx)
1273187SN/A{
12810688Sandreas.hansson@arm.com    if (if_name == "port")
12910688Sandreas.hansson@arm.com        return port;
1303187SN/A    else
1318922Swilliam.wang@arm.com        return MemObject::getMasterPort(if_name, idx);
1323187SN/A}
1333187SN/A
1343187SN/Avoid
13510688Sandreas.hansson@arm.comMemTest::completeRequest(PacketPtr pkt, bool functional)
1362SN/A{
1374628SN/A    Request *req = pkt->req;
13810688Sandreas.hansson@arm.com    assert(req->getSize() == 1);
1394628SN/A
14010688Sandreas.hansson@arm.com    // this address is no longer outstanding
14110688Sandreas.hansson@arm.com    auto remove_addr = outstandingAddrs.find(req->getPaddr());
14210688Sandreas.hansson@arm.com    assert(remove_addr != outstandingAddrs.end());
14310688Sandreas.hansson@arm.com    outstandingAddrs.erase(remove_addr);
1447544SN/A
14510688Sandreas.hansson@arm.com    DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n",
1464628SN/A            pkt->isWrite() ? "write" : "read",
14710688Sandreas.hansson@arm.com            req->getPaddr(), blockAlign(req->getPaddr()),
1488436SBrad.Beckmann@amd.com            pkt->isError() ? "error" : "success");
1494628SN/A
15010688Sandreas.hansson@arm.com    const uint8_t *pkt_data = pkt->getConstPtr<uint8_t>();
1511298SN/A
1528436SBrad.Beckmann@amd.com    if (pkt->isError()) {
15310688Sandreas.hansson@arm.com        if (!functional || !suppressFuncWarnings) {
15410688Sandreas.hansson@arm.com            warn("%s access failed at %#x\n",
15510688Sandreas.hansson@arm.com                 pkt->isWrite() ? "Write" : "Read", req->getPaddr());
1562SN/A        }
1578436SBrad.Beckmann@amd.com    } else {
1588436SBrad.Beckmann@amd.com        if (pkt->isRead()) {
15910688Sandreas.hansson@arm.com            uint8_t ref_data = referenceData[req->getPaddr()];
16010688Sandreas.hansson@arm.com            if (pkt_data[0] != ref_data) {
1618436SBrad.Beckmann@amd.com                panic("%s: read of %x (blk %x) @ cycle %d "
1628436SBrad.Beckmann@amd.com                      "returns %x, expected %x\n", name(),
16310688Sandreas.hansson@arm.com                      req->getPaddr(), blockAlign(req->getPaddr()), curTick(),
16410688Sandreas.hansson@arm.com                      pkt_data[0], ref_data);
1658436SBrad.Beckmann@amd.com            }
1662SN/A
1678436SBrad.Beckmann@amd.com            numReads++;
1688436SBrad.Beckmann@amd.com            numReadsStat++;
1692SN/A
1708436SBrad.Beckmann@amd.com            if (numReads == (uint64_t)nextProgressMessage) {
1718436SBrad.Beckmann@amd.com                ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n",
1728436SBrad.Beckmann@amd.com                         name(), numReads, numWrites, curTick());
1738436SBrad.Beckmann@amd.com                nextProgressMessage += progressInterval;
1748436SBrad.Beckmann@amd.com            }
1758436SBrad.Beckmann@amd.com
1768436SBrad.Beckmann@amd.com            if (maxLoads != 0 && numReads >= maxLoads)
1778436SBrad.Beckmann@amd.com                exitSimLoop("maximum number of loads reached");
1788436SBrad.Beckmann@amd.com        } else {
1798436SBrad.Beckmann@amd.com            assert(pkt->isWrite());
18010688Sandreas.hansson@arm.com
18110688Sandreas.hansson@arm.com            // update the reference data
18210688Sandreas.hansson@arm.com            referenceData[req->getPaddr()] = pkt_data[0];
1838436SBrad.Beckmann@amd.com            numWrites++;
1848436SBrad.Beckmann@amd.com            numWritesStat++;
1852SN/A        }
1862SN/A    }
1872SN/A
1883187SN/A    delete pkt->req;
18910688Sandreas.hansson@arm.com
19010688Sandreas.hansson@arm.com    // the packet will delete the data
1913187SN/A    delete pkt;
19210688Sandreas.hansson@arm.com
19310688Sandreas.hansson@arm.com    // finally shift the response timeout forward
19410688Sandreas.hansson@arm.com    reschedule(noResponseEvent, clockEdge(progressCheck), true);
1952SN/A}
1962SN/A
1972SN/Avoid
1982SN/AMemTest::regStats()
1992SN/A{
200729SN/A    using namespace Stats;
2012SN/A
202695SN/A    numReadsStat
2032SN/A        .name(name() + ".num_reads")
2042SN/A        .desc("number of read accesses completed")
2052SN/A        ;
2062SN/A
207695SN/A    numWritesStat
2082SN/A        .name(name() + ".num_writes")
2092SN/A        .desc("number of write accesses completed")
2102SN/A        ;
2112SN/A}
2122SN/A
2132SN/Avoid
2142SN/AMemTest::tick()
2152SN/A{
21610688Sandreas.hansson@arm.com    // we should never tick if we are waiting for a retry
21710688Sandreas.hansson@arm.com    assert(!retryPkt);
2182SN/A
21910688Sandreas.hansson@arm.com    // create a new request
22010348Sandreas.hansson@arm.com    unsigned cmd = random_mt.random(0, 100);
22110688Sandreas.hansson@arm.com    uint8_t data = random_mt.random<uint8_t>();
22210688Sandreas.hansson@arm.com    bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
22310348Sandreas.hansson@arm.com    unsigned base = random_mt.random(0, 1);
2245736SN/A    Request::Flags flags;
2253187SN/A    Addr paddr;
2262SN/A
22710688Sandreas.hansson@arm.com    // generate a unique address
22810688Sandreas.hansson@arm.com    do {
22910688Sandreas.hansson@arm.com        unsigned offset = random_mt.random<unsigned>(0, size - 1);
2309301Snilay@cs.wisc.edu
23110688Sandreas.hansson@arm.com        // use the tester id as offset within the block for false sharing
23210688Sandreas.hansson@arm.com        offset = blockAlign(offset);
23310688Sandreas.hansson@arm.com        offset += id;
23410688Sandreas.hansson@arm.com
23510688Sandreas.hansson@arm.com        if (uncacheable) {
23610688Sandreas.hansson@arm.com            flags.set(Request::UNCACHEABLE);
23710688Sandreas.hansson@arm.com            paddr = uncacheAddr + offset;
23810688Sandreas.hansson@arm.com        } else  {
23910688Sandreas.hansson@arm.com            paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
24010688Sandreas.hansson@arm.com        }
24110688Sandreas.hansson@arm.com    } while (outstandingAddrs.find(paddr) != outstandingAddrs.end());
2429301Snilay@cs.wisc.edu
24310348Sandreas.hansson@arm.com    bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
24410348Sandreas.hansson@arm.com        !uncacheable;
24510688Sandreas.hansson@arm.com    Request *req = new Request(paddr, 1, flags, masterId);
24610688Sandreas.hansson@arm.com    req->setThreadContext(id, 0);
2472SN/A
24810688Sandreas.hansson@arm.com    outstandingAddrs.insert(paddr);
24910688Sandreas.hansson@arm.com
25010688Sandreas.hansson@arm.com    // sanity check
25110688Sandreas.hansson@arm.com    panic_if(outstandingAddrs.size() > 100,
25210688Sandreas.hansson@arm.com             "Tester %s has more than 100 outstanding requests\n", name());
25310688Sandreas.hansson@arm.com
25410688Sandreas.hansson@arm.com    PacketPtr pkt = nullptr;
25510688Sandreas.hansson@arm.com    uint8_t *pkt_data = new uint8_t[1];
2563187SN/A
2572SN/A    if (cmd < percentReads) {
25810688Sandreas.hansson@arm.com        // start by ensuring there is a reference value if we have not
25910688Sandreas.hansson@arm.com        // seen this address before
26010688Sandreas.hansson@arm.com        uint8_t M5_VAR_USED ref_data = 0;
26110688Sandreas.hansson@arm.com        auto ref = referenceData.find(req->getPaddr());
26210688Sandreas.hansson@arm.com        if (ref == referenceData.end()) {
26310688Sandreas.hansson@arm.com            referenceData[req->getPaddr()] = 0;
26410688Sandreas.hansson@arm.com        } else {
26510688Sandreas.hansson@arm.com            ref_data = ref->second;
26610688Sandreas.hansson@arm.com        }
2673187SN/A
2684628SN/A        DPRINTF(MemTest,
26910688Sandreas.hansson@arm.com                "Initiating %sread at addr %x (blk %x) expecting %x\n",
27010688Sandreas.hansson@arm.com                do_functional ? "functional " : "", req->getPaddr(),
27110688Sandreas.hansson@arm.com                blockAlign(req->getPaddr()), ref_data);
2723187SN/A
27310688Sandreas.hansson@arm.com        pkt = new Packet(req, MemCmd::ReadReq);
27410688Sandreas.hansson@arm.com        pkt->dataDynamic(pkt_data);
27510688Sandreas.hansson@arm.com    } else {
27610688Sandreas.hansson@arm.com        DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n",
27710688Sandreas.hansson@arm.com                do_functional ? "functional " : "", req->getPaddr(),
27810688Sandreas.hansson@arm.com                blockAlign(req->getPaddr()), data);
2793187SN/A
28010688Sandreas.hansson@arm.com        pkt = new Packet(req, MemCmd::WriteReq);
28110688Sandreas.hansson@arm.com        pkt->dataDynamic(pkt_data);
28210688Sandreas.hansson@arm.com        pkt_data[0] = data;
28310688Sandreas.hansson@arm.com    }
28410688Sandreas.hansson@arm.com
28510688Sandreas.hansson@arm.com    // there is no point in ticking if we are waiting for a retry
28610688Sandreas.hansson@arm.com    bool keep_ticking = true;
28710688Sandreas.hansson@arm.com    if (do_functional) {
28810688Sandreas.hansson@arm.com        pkt->setSuppressFuncError();
28910688Sandreas.hansson@arm.com        port.sendFunctional(pkt);
29010688Sandreas.hansson@arm.com        completeRequest(pkt, true);
2913187SN/A    } else {
29210688Sandreas.hansson@arm.com        keep_ticking = sendPkt(pkt);
29310688Sandreas.hansson@arm.com    }
2941298SN/A
29510688Sandreas.hansson@arm.com    if (keep_ticking) {
29610688Sandreas.hansson@arm.com        // schedule the next tick
29710688Sandreas.hansson@arm.com        schedule(tickEvent, clockEdge(interval));
2984628SN/A
29910688Sandreas.hansson@arm.com        // finally shift the timeout for sending of requests forwards
30010688Sandreas.hansson@arm.com        // as we have successfully sent a packet
30110688Sandreas.hansson@arm.com        reschedule(noRequestEvent, clockEdge(progressCheck), true);
30210688Sandreas.hansson@arm.com    } else {
30310688Sandreas.hansson@arm.com        DPRINTF(MemTest, "Waiting for retry\n");
3043187SN/A    }
3052SN/A}
3062SN/A
3072SN/Avoid
30810688Sandreas.hansson@arm.comMemTest::noRequest()
3092SN/A{
31010688Sandreas.hansson@arm.com    panic("%s did not send a request for %d cycles", name(), progressCheck);
31110688Sandreas.hansson@arm.com}
31210688Sandreas.hansson@arm.com
31310688Sandreas.hansson@arm.comvoid
31410688Sandreas.hansson@arm.comMemTest::noResponse()
31510688Sandreas.hansson@arm.com{
31610688Sandreas.hansson@arm.com    panic("%s did not see a response for %d cycles", name(), progressCheck);
31710688Sandreas.hansson@arm.com}
31810688Sandreas.hansson@arm.com
31910688Sandreas.hansson@arm.comvoid
32010688Sandreas.hansson@arm.comMemTest::recvRetry()
32110688Sandreas.hansson@arm.com{
32210688Sandreas.hansson@arm.com    assert(retryPkt);
32310688Sandreas.hansson@arm.com    if (port.sendTimingReq(retryPkt)) {
32410688Sandreas.hansson@arm.com        DPRINTF(MemTest, "Proceeding after successful retry\n");
32510688Sandreas.hansson@arm.com
32610688Sandreas.hansson@arm.com        retryPkt = nullptr;
32710688Sandreas.hansson@arm.com        // kick things into action again
32810688Sandreas.hansson@arm.com        schedule(tickEvent, clockEdge(interval));
3293187SN/A    }
3302SN/A}
3312SN/A
3325315SN/AMemTest *
3335315SN/AMemTestParams::create()
3345315SN/A{
3355315SN/A    return new MemTest(this);
3365315SN/A}
337