memtest.cc revision 13784:1941dc118243
16757SAli.Saidi@ARM.com/*
212495Sgiacomo.travaglini@arm.com * Copyright (c) 2015 ARM Limited
36757SAli.Saidi@ARM.com * All rights reserved
46757SAli.Saidi@ARM.com *
57111Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
67111Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
77111Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
87111Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
97111Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
107111Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
117111Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
127111Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
137111Sgblack@eecs.umich.edu *
146757SAli.Saidi@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
156757SAli.Saidi@ARM.com * All rights reserved.
166757SAli.Saidi@ARM.com *
176757SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
186757SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
196757SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
206757SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
216757SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
226757SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
236757SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
246757SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
256757SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
266757SAli.Saidi@ARM.com * this software without specific prior written permission.
276757SAli.Saidi@ARM.com *
286757SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
296757SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
306757SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
316757SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
326757SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
336757SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
346757SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
356757SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
366757SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
376757SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
386757SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
396735Sgblack@eecs.umich.edu *
4011793Sbrandon.potter@amd.com * Authors: Erik Hallnor
4111793Sbrandon.potter@amd.com *          Steve Reinhardt
4210474Sandreas.hansson@arm.com *          Andreas Hansson
436757SAli.Saidi@ARM.com */
446757SAli.Saidi@ARM.com
457707Sgblack@eecs.umich.edu#include "cpu/testers/memtest/memtest.hh"
4610037SARM gem5 Developers
478782Sgblack@eecs.umich.edu#include "base/random.hh"
488782Sgblack@eecs.umich.edu#include "base/statistics.hh"
4911793Sbrandon.potter@amd.com#include "base/trace.hh"
508887Sgeoffrey.blake@arm.com#include "debug/MemTest.hh"
516757SAli.Saidi@ARM.com#include "mem/mem_object.hh"
528706Sandreas.hansson@arm.com#include "sim/sim_exit.hh"
538782Sgblack@eecs.umich.edu#include "sim/stats.hh"
547749SAli.Saidi@ARM.com#include "sim/system.hh"
556735Sgblack@eecs.umich.edu
566735Sgblack@eecs.umich.eduusing namespace std;
576735Sgblack@eecs.umich.edu
586735Sgblack@eecs.umich.eduunsigned int TESTER_ALLOCATOR = 0;
596735Sgblack@eecs.umich.edu
606735Sgblack@eecs.umich.edubool
619058Satgutier@umich.eduMemTest::CpuPort::recvTimingResp(PacketPtr pkt)
626735Sgblack@eecs.umich.edu{
638886SAli.Saidi@ARM.com    memtest.completeRequest(pkt);
6410474Sandreas.hansson@arm.com    return true;
658286SAli.Saidi@ARM.com}
666735Sgblack@eecs.umich.edu
676735Sgblack@eecs.umich.eduvoid
687707Sgblack@eecs.umich.eduMemTest::CpuPort::recvReqRetry()
697707Sgblack@eecs.umich.edu{
707707Sgblack@eecs.umich.edu    memtest.recvRetry();
718806Sgblack@eecs.umich.edu}
728806Sgblack@eecs.umich.edu
738806Sgblack@eecs.umich.edubool
748806Sgblack@eecs.umich.eduMemTest::sendPkt(PacketPtr pkt) {
758706Sandreas.hansson@arm.com    if (atomic) {
767693SAli.Saidi@ARM.com        port.sendAtomic(pkt);
777693SAli.Saidi@ARM.com        completeRequest(pkt);
787693SAli.Saidi@ARM.com    } else {
7910037SARM gem5 Developers        if (!port.sendTimingReq(pkt)) {
8010037SARM gem5 Developers            retryPkt = pkt;
8110037SARM gem5 Developers            return false;
8210037SARM gem5 Developers        }
8310037SARM gem5 Developers    }
8410037SARM gem5 Developers    return true;
857693SAli.Saidi@ARM.com}
8610037SARM gem5 Developers
877693SAli.Saidi@ARM.comMemTest::MemTest(const Params *p)
887693SAli.Saidi@ARM.com    : MemObject(p),
8910037SARM gem5 Developers      tickEvent([this]{ tick(); }, name()),
9010318Sandreas.hansson@arm.com      noRequestEvent([this]{ noRequest(); }, name()),
9110037SARM gem5 Developers      noResponseEvent([this]{ noResponse(); }, name()),
9210037SARM gem5 Developers      port("port", *this),
9310037SARM gem5 Developers      retryPkt(nullptr),
9410037SARM gem5 Developers      size(p->size),
9510037SARM gem5 Developers      interval(p->interval),
9610037SARM gem5 Developers      percentReads(p->percent_reads),
9710037SARM gem5 Developers      percentFunctional(p->percent_functional),
9810037SARM gem5 Developers      percentUncacheable(p->percent_uncacheable),
9910037SARM gem5 Developers      masterId(p->system->getMasterId(this)),
10010037SARM gem5 Developers      blockSize(p->system->cacheLineSize()),
10110037SARM gem5 Developers      blockAddrMask(blockSize - 1),
10210037SARM gem5 Developers      progressInterval(p->progress_interval),
10310037SARM gem5 Developers      progressCheck(p->progress_check),
10410037SARM gem5 Developers      nextProgressMessage(p->progress_interval),
10510037SARM gem5 Developers      maxLoads(p->max_loads),
10610037SARM gem5 Developers      atomic(p->system->isAtomicMode()),
10710037SARM gem5 Developers      suppressFuncWarnings(p->suppress_func_warnings)
10810037SARM gem5 Developers{
10910037SARM gem5 Developers    id = TESTER_ALLOCATOR++;
11010037SARM gem5 Developers    fatal_if(id >= blockSize, "Too many testers, only %d allowed\n",
11110037SARM gem5 Developers             blockSize - 1);
11210037SARM gem5 Developers
11310037SARM gem5 Developers    baseAddr1 = 0x100000;
11410037SARM gem5 Developers    baseAddr2 = 0x400000;
11510037SARM gem5 Developers    uncacheAddr = 0x800000;
11610037SARM gem5 Developers
11710037SARM gem5 Developers    // set up counters
11810037SARM gem5 Developers    numReads = 0;
1197693SAli.Saidi@ARM.com    numWrites = 0;
12010037SARM gem5 Developers
12110037SARM gem5 Developers    // kick things into action
12210037SARM gem5 Developers    schedule(tickEvent, curTick());
12310037SARM gem5 Developers    schedule(noRequestEvent, clockEdge(progressCheck));
12410037SARM gem5 Developers    schedule(noResponseEvent, clockEdge(progressCheck));
1257693SAli.Saidi@ARM.com}
1267650SAli.Saidi@ARM.com
12710037SARM gem5 DevelopersPort &
1286757SAli.Saidi@ARM.comMemTest::getPort(const std::string &if_name, PortID idx)
1296757SAli.Saidi@ARM.com{
1307693SAli.Saidi@ARM.com    if (if_name == "port")
1317693SAli.Saidi@ARM.com        return port;
1327693SAli.Saidi@ARM.com    else
1339920Syasuko.eckert@amd.com        return MemObject::getPort(if_name, idx);
13410037SARM gem5 Developers}
13510037SARM gem5 Developers
13610037SARM gem5 Developersvoid
13710037SARM gem5 DevelopersMemTest::completeRequest(PacketPtr pkt, bool functional)
13810037SARM gem5 Developers{
1398887Sgeoffrey.blake@arm.com    const RequestPtr &req = pkt->req;
1408887Sgeoffrey.blake@arm.com    assert(req->getSize() == 1);
1418887Sgeoffrey.blake@arm.com
1428887Sgeoffrey.blake@arm.com    // this address is no longer outstanding
1438887Sgeoffrey.blake@arm.com    auto remove_addr = outstandingAddrs.find(req->getPaddr());
1448887Sgeoffrey.blake@arm.com    assert(remove_addr != outstandingAddrs.end());
1458887Sgeoffrey.blake@arm.com    outstandingAddrs.erase(remove_addr);
1467693SAli.Saidi@ARM.com
1477693SAli.Saidi@ARM.com    DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n",
1487748SAli.Saidi@ARM.com            pkt->isWrite() ? "write" : "read",
1497748SAli.Saidi@ARM.com            req->getPaddr(), blockAlign(req->getPaddr()),
1507748SAli.Saidi@ARM.com            pkt->isError() ? "error" : "success");
1519920Syasuko.eckert@amd.com
1529431SAndreas.Sandberg@ARM.com    const uint8_t *pkt_data = pkt->getConstPtr<uint8_t>();
1538208SAli.Saidi@ARM.com
1549920Syasuko.eckert@amd.com    if (pkt->isError()) {
15513500Sgabeblack@google.com        if (!functional || !suppressFuncWarnings) {
1568208SAli.Saidi@ARM.com            warn("%s access failed at %#x\n",
15712109SRekai.GonzalezAlberquilla@arm.com                 pkt->isWrite() ? "Write" : "Read", req->getPaddr());
15812109SRekai.GonzalezAlberquilla@arm.com        }
15912109SRekai.GonzalezAlberquilla@arm.com    } else {
16010338SCurtis.Dunham@arm.com        if (pkt->isRead()) {
16110338SCurtis.Dunham@arm.com            uint8_t ref_data = referenceData[req->getPaddr()];
1629920Syasuko.eckert@amd.com            if (pkt_data[0] != ref_data) {
1639920Syasuko.eckert@amd.com                panic("%s: read of %x (blk %x) @ cycle %d "
1647748SAli.Saidi@ARM.com                      "returns %x, expected %x\n", name(),
1656759SAli.Saidi@ARM.com                      req->getPaddr(), blockAlign(req->getPaddr()), curTick(),
1667748SAli.Saidi@ARM.com                      pkt_data[0], ref_data);
1677748SAli.Saidi@ARM.com            }
1687748SAli.Saidi@ARM.com
1697748SAli.Saidi@ARM.com            numReads++;
1707749SAli.Saidi@ARM.com            numReadsStat++;
1717748SAli.Saidi@ARM.com
1727749SAli.Saidi@ARM.com            if (numReads == (uint64_t)nextProgressMessage) {
1737749SAli.Saidi@ARM.com                ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n",
17412406Sgabeblack@google.com                         name(), numReads, numWrites, curTick());
17512406Sgabeblack@google.com                nextProgressMessage += progressInterval;
1766759SAli.Saidi@ARM.com            }
1777752SWilliam.Wang@arm.com
17810037SARM gem5 Developers            if (maxLoads != 0 && numReads >= maxLoads)
17910037SARM gem5 Developers                exitSimLoop("maximum number of loads reached");
18010037SARM gem5 Developers        } else {
18110037SARM gem5 Developers            assert(pkt->isWrite());
18210037SARM gem5 Developers
18310037SARM gem5 Developers            // update the reference data
18410037SARM gem5 Developers            referenceData[req->getPaddr()] = pkt_data[0];
18510037SARM gem5 Developers            numWrites++;
18610037SARM gem5 Developers            numWritesStat++;
18712495Sgiacomo.travaglini@arm.com        }
18812495Sgiacomo.travaglini@arm.com    }
18912495Sgiacomo.travaglini@arm.com
19012495Sgiacomo.travaglini@arm.com    // the packet will delete the data
19112495Sgiacomo.travaglini@arm.com    delete pkt;
19212495Sgiacomo.travaglini@arm.com
19312495Sgiacomo.travaglini@arm.com    // finally shift the response timeout forward
19410037SARM gem5 Developers    reschedule(noResponseEvent, clockEdge(progressCheck), true);
19510037SARM gem5 Developers}
19610037SARM gem5 Developers
19710037SARM gem5 Developersvoid
19810037SARM gem5 DevelopersMemTest::regStats()
19910037SARM gem5 Developers{
20010037SARM gem5 Developers    MemObject::regStats();
20110037SARM gem5 Developers
20210037SARM gem5 Developers    using namespace Stats;
20310037SARM gem5 Developers
20410037SARM gem5 Developers    numReadsStat
20510037SARM gem5 Developers        .name(name() + ".num_reads")
20610037SARM gem5 Developers        .desc("number of read accesses completed")
20710037SARM gem5 Developers        ;
20813550Sgiacomo.travaglini@arm.com
20913550Sgiacomo.travaglini@arm.com    numWritesStat
21013550Sgiacomo.travaglini@arm.com        .name(name() + ".num_writes")
21113550Sgiacomo.travaglini@arm.com        .desc("number of write accesses completed")
21213550Sgiacomo.travaglini@arm.com        ;
21313550Sgiacomo.travaglini@arm.com}
21413550Sgiacomo.travaglini@arm.com
21513550Sgiacomo.travaglini@arm.comvoid
21613550Sgiacomo.travaglini@arm.comMemTest::tick()
21713550Sgiacomo.travaglini@arm.com{
21813550Sgiacomo.travaglini@arm.com    // we should never tick if we are waiting for a retry
21913550Sgiacomo.travaglini@arm.com    assert(!retryPkt);
22013550Sgiacomo.travaglini@arm.com
22113550Sgiacomo.travaglini@arm.com    // create a new request
22213550Sgiacomo.travaglini@arm.com    unsigned cmd = random_mt.random(0, 100);
22313550Sgiacomo.travaglini@arm.com    uint8_t data = random_mt.random<uint8_t>();
22413550Sgiacomo.travaglini@arm.com    bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
22513550Sgiacomo.travaglini@arm.com    unsigned base = random_mt.random(0, 1);
22613550Sgiacomo.travaglini@arm.com    Request::Flags flags;
22713550Sgiacomo.travaglini@arm.com    Addr paddr;
22813550Sgiacomo.travaglini@arm.com
22913550Sgiacomo.travaglini@arm.com    // generate a unique address
23013550Sgiacomo.travaglini@arm.com    do {
23113550Sgiacomo.travaglini@arm.com        unsigned offset = random_mt.random<unsigned>(0, size - 1);
23213550Sgiacomo.travaglini@arm.com
23313550Sgiacomo.travaglini@arm.com        // use the tester id as offset within the block for false sharing
23413550Sgiacomo.travaglini@arm.com        offset = blockAlign(offset);
23513550Sgiacomo.travaglini@arm.com        offset += id;
23613550Sgiacomo.travaglini@arm.com
23713550Sgiacomo.travaglini@arm.com        if (uncacheable) {
23813550Sgiacomo.travaglini@arm.com            flags.set(Request::UNCACHEABLE);
23910037SARM gem5 Developers            paddr = uncacheAddr + offset;
24010037SARM gem5 Developers        } else  {
24110190Sakash.bagdia@arm.com            paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
24210190Sakash.bagdia@arm.com        }
24310190Sakash.bagdia@arm.com    } while (outstandingAddrs.find(paddr) != outstandingAddrs.end());
24410190Sakash.bagdia@arm.com
24510190Sakash.bagdia@arm.com    bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
24610190Sakash.bagdia@arm.com        !uncacheable;
24710190Sakash.bagdia@arm.com    RequestPtr req = std::make_shared<Request>(paddr, 1, flags, masterId);
24810190Sakash.bagdia@arm.com    req->setContext(id);
24910190Sakash.bagdia@arm.com
25010190Sakash.bagdia@arm.com    outstandingAddrs.insert(paddr);
25110190Sakash.bagdia@arm.com
25210190Sakash.bagdia@arm.com    // sanity check
25311294Sandreas.hansson@arm.com    panic_if(outstandingAddrs.size() > 100,
25411149Smitch.hayenga@arm.com             "Tester %s has more than 100 outstanding requests\n", name());
25511149Smitch.hayenga@arm.com
25612712Sgiacomo.travaglini@arm.com    PacketPtr pkt = nullptr;
25711149Smitch.hayenga@arm.com    uint8_t *pkt_data = new uint8_t[1];
25811149Smitch.hayenga@arm.com
25910037SARM gem5 Developers    if (cmd < percentReads) {
26010190Sakash.bagdia@arm.com        // start by ensuring there is a reference value if we have not
26110037SARM gem5 Developers        // seen this address before
26210037SARM gem5 Developers        uint8_t M5_VAR_USED ref_data = 0;
26310037SARM gem5 Developers        auto ref = referenceData.find(req->getPaddr());
26410190Sakash.bagdia@arm.com        if (ref == referenceData.end()) {
26510037SARM gem5 Developers            referenceData[req->getPaddr()] = 0;
26610037SARM gem5 Developers        } else {
26710037SARM gem5 Developers            ref_data = ref->second;
26810037SARM gem5 Developers        }
26910037SARM gem5 Developers
27010037SARM gem5 Developers        DPRINTF(MemTest,
27112494Schuan.zhu@arm.com                "Initiating %sread at addr %x (blk %x) expecting %x\n",
27212494Schuan.zhu@arm.com                do_functional ? "functional " : "", req->getPaddr(),
27310037SARM gem5 Developers                blockAlign(req->getPaddr()), ref_data);
27412494Schuan.zhu@arm.com
27512494Schuan.zhu@arm.com        pkt = new Packet(req, MemCmd::ReadReq);
27612494Schuan.zhu@arm.com        pkt->dataDynamic(pkt_data);
27712496Sgiacomo.travaglini@arm.com    } else {
27812496Sgiacomo.travaglini@arm.com        DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n",
27912496Sgiacomo.travaglini@arm.com                do_functional ? "functional " : "", req->getPaddr(),
28012496Sgiacomo.travaglini@arm.com                blockAlign(req->getPaddr()), data);
28112496Sgiacomo.travaglini@arm.com
28212496Sgiacomo.travaglini@arm.com        pkt = new Packet(req, MemCmd::WriteReq);
28312496Sgiacomo.travaglini@arm.com        pkt->dataDynamic(pkt_data);
28412496Sgiacomo.travaglini@arm.com        pkt_data[0] = data;
28512496Sgiacomo.travaglini@arm.com    }
28612494Schuan.zhu@arm.com
28712494Schuan.zhu@arm.com    // there is no point in ticking if we are waiting for a retry
28812494Schuan.zhu@arm.com    bool keep_ticking = true;
28912494Schuan.zhu@arm.com    if (do_functional) {
29012494Schuan.zhu@arm.com        pkt->setSuppressFuncError();
29112494Schuan.zhu@arm.com        port.sendFunctional(pkt);
29212494Schuan.zhu@arm.com        completeRequest(pkt, true);
29312496Sgiacomo.travaglini@arm.com    } else {
29412496Sgiacomo.travaglini@arm.com        keep_ticking = sendPkt(pkt);
29512496Sgiacomo.travaglini@arm.com    }
29612496Sgiacomo.travaglini@arm.com
29712496Sgiacomo.travaglini@arm.com    if (keep_ticking) {
29812496Sgiacomo.travaglini@arm.com        // schedule the next tick
29912494Schuan.zhu@arm.com        schedule(tickEvent, clockEdge(interval));
30012496Sgiacomo.travaglini@arm.com
30112496Sgiacomo.travaglini@arm.com        // finally shift the timeout for sending of requests forwards
30212494Schuan.zhu@arm.com        // as we have successfully sent a packet
30312494Schuan.zhu@arm.com        reschedule(noRequestEvent, clockEdge(progressCheck), true);
30412494Schuan.zhu@arm.com    } else {
30512494Schuan.zhu@arm.com        DPRINTF(MemTest, "Waiting for retry\n");
30612494Schuan.zhu@arm.com    }
30712494Schuan.zhu@arm.com}
30812495Sgiacomo.travaglini@arm.com
30912495Sgiacomo.travaglini@arm.comvoid
31012494Schuan.zhu@arm.comMemTest::noRequest()
31112494Schuan.zhu@arm.com{
31212494Schuan.zhu@arm.com    panic("%s did not send a request for %d cycles", name(), progressCheck);
31312496Sgiacomo.travaglini@arm.com}
31412494Schuan.zhu@arm.com
31512496Sgiacomo.travaglini@arm.comvoid
31612496Sgiacomo.travaglini@arm.comMemTest::noResponse()
31712496Sgiacomo.travaglini@arm.com{
31812494Schuan.zhu@arm.com    panic("%s did not see a response for %d cycles", name(), progressCheck);
31912496Sgiacomo.travaglini@arm.com}
32012496Sgiacomo.travaglini@arm.com
32112496Sgiacomo.travaglini@arm.comvoid
32210037SARM gem5 DevelopersMemTest::recvRetry()
32310037SARM gem5 Developers{
32412496Sgiacomo.travaglini@arm.com    assert(retryPkt);
32512496Sgiacomo.travaglini@arm.com    if (port.sendTimingReq(retryPkt)) {
32610037SARM gem5 Developers        DPRINTF(MemTest, "Proceeding after successful retry\n");
32710037SARM gem5 Developers
32810037SARM gem5 Developers        retryPkt = nullptr;
32910037SARM gem5 Developers        // kick things into action again
33010037SARM gem5 Developers        schedule(tickEvent, clockEdge(interval));
33110037SARM gem5 Developers    }
33210037SARM gem5 Developers}
33310037SARM gem5 Developers
33410037SARM gem5 DevelopersMemTest *
33510037SARM gem5 DevelopersMemTestParams::create()
33610037SARM gem5 Developers{
33710037SARM gem5 Developers    return new MemTest(this);
33810037SARM gem5 Developers}
33910037SARM gem5 Developers