12SN/A/*
214027Stiago.muck@arm.com * Copyright (c) 2015, 2019 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
4511793Sbrandon.potter@amd.com#include "cpu/testers/memtest/memtest.hh"
4611793Sbrandon.potter@amd.com
4710348Sandreas.hansson@arm.com#include "base/random.hh"
48146SN/A#include "base/statistics.hh"
4911800Sbrandon.potter@amd.com#include "base/trace.hh"
508232Snate@binkert.org#include "debug/MemTest.hh"
5110688Sandreas.hansson@arm.com#include "sim/sim_exit.hh"
52695SN/A#include "sim/stats.hh"
538832SAli.Saidi@ARM.com#include "sim/system.hh"
542SN/A
552SN/Ausing namespace std;
562SN/A
5710688Sandreas.hansson@arm.comunsigned int TESTER_ALLOCATOR = 0;
581298SN/A
593187SN/Abool
608975Sandreas.hansson@arm.comMemTest::CpuPort::recvTimingResp(PacketPtr pkt)
613187SN/A{
6210688Sandreas.hansson@arm.com    memtest.completeRequest(pkt);
633187SN/A    return true;
643187SN/A}
653187SN/A
663187SN/Avoid
6710713Sandreas.hansson@arm.comMemTest::CpuPort::recvReqRetry()
683187SN/A{
6910688Sandreas.hansson@arm.com    memtest.recvRetry();
703187SN/A}
713187SN/A
7210688Sandreas.hansson@arm.combool
733349SN/AMemTest::sendPkt(PacketPtr pkt) {
743262SN/A    if (atomic) {
7510688Sandreas.hansson@arm.com        port.sendAtomic(pkt);
763262SN/A        completeRequest(pkt);
777544SN/A    } else {
7810688Sandreas.hansson@arm.com        if (!port.sendTimingReq(pkt)) {
7910688Sandreas.hansson@arm.com            retryPkt = pkt;
8010688Sandreas.hansson@arm.com            return false;
817544SN/A        }
823262SN/A    }
8310688Sandreas.hansson@arm.com    return true;
843262SN/A}
853262SN/A
865034SN/AMemTest::MemTest(const Params *p)
8713892Sgabeblack@google.com    : ClockedObject(p),
8812085Sspwilson2@wisc.edu      tickEvent([this]{ tick(); }, name()),
8912085Sspwilson2@wisc.edu      noRequestEvent([this]{ noRequest(); }, name()),
9012085Sspwilson2@wisc.edu      noResponseEvent([this]{ noResponse(); }, name()),
9110688Sandreas.hansson@arm.com      port("port", *this),
9210688Sandreas.hansson@arm.com      retryPkt(nullptr),
9310688Sandreas.hansson@arm.com      size(p->size),
9410688Sandreas.hansson@arm.com      interval(p->interval),
955034SN/A      percentReads(p->percent_reads),
965034SN/A      percentFunctional(p->percent_functional),
975034SN/A      percentUncacheable(p->percent_uncacheable),
9812680Sgiacomo.travaglini@arm.com      masterId(p->system->getMasterId(this)),
9910688Sandreas.hansson@arm.com      blockSize(p->system->cacheLineSize()),
10010688Sandreas.hansson@arm.com      blockAddrMask(blockSize - 1),
1015034SN/A      progressInterval(p->progress_interval),
10210688Sandreas.hansson@arm.com      progressCheck(p->progress_check),
1035034SN/A      nextProgressMessage(p->progress_interval),
1045034SN/A      maxLoads(p->max_loads),
10510688Sandreas.hansson@arm.com      atomic(p->system->isAtomicMode()),
10610688Sandreas.hansson@arm.com      suppressFuncWarnings(p->suppress_func_warnings)
1072SN/A{
1087544SN/A    id = TESTER_ALLOCATOR++;
10910688Sandreas.hansson@arm.com    fatal_if(id >= blockSize, "Too many testers, only %d allowed\n",
11010688Sandreas.hansson@arm.com             blockSize - 1);
1117544SN/A
1122SN/A    baseAddr1 = 0x100000;
1132SN/A    baseAddr2 = 0x400000;
1142SN/A    uncacheAddr = 0x800000;
1152SN/A
1162SN/A    // set up counters
1172SN/A    numReads = 0;
1188436SBrad.Beckmann@amd.com    numWrites = 0;
1191298SN/A
12010688Sandreas.hansson@arm.com    // kick things into action
12110688Sandreas.hansson@arm.com    schedule(tickEvent, curTick());
12210688Sandreas.hansson@arm.com    schedule(noRequestEvent, clockEdge(progressCheck));
1233187SN/A}
1243187SN/A
12513784Sgabeblack@google.comPort &
12613784Sgabeblack@google.comMemTest::getPort(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
13113892Sgabeblack@google.com        return ClockedObject::getPort(if_name, idx);
1323187SN/A}
1333187SN/A
1343187SN/Avoid
13510688Sandreas.hansson@arm.comMemTest::completeRequest(PacketPtr pkt, bool functional)
1362SN/A{
13712749Sgiacomo.travaglini@arm.com    const RequestPtr &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
18810688Sandreas.hansson@arm.com    // the packet will delete the data
1893187SN/A    delete pkt;
19010688Sandreas.hansson@arm.com
19114027Stiago.muck@arm.com    // finally shift the response timeout forward if we are still
19214027Stiago.muck@arm.com    // expecting responses; deschedule it otherwise
19314027Stiago.muck@arm.com    if (outstandingAddrs.size() != 0)
19414027Stiago.muck@arm.com        reschedule(noResponseEvent, clockEdge(progressCheck));
19514027Stiago.muck@arm.com    else if (noResponseEvent.scheduled())
19614027Stiago.muck@arm.com        deschedule(noResponseEvent);
1972SN/A}
1982SN/A
1992SN/Avoid
2002SN/AMemTest::regStats()
2012SN/A{
20213892Sgabeblack@google.com    ClockedObject::regStats();
20311523Sdavid.guillen@arm.com
204729SN/A    using namespace Stats;
2052SN/A
206695SN/A    numReadsStat
2072SN/A        .name(name() + ".num_reads")
2082SN/A        .desc("number of read accesses completed")
2092SN/A        ;
2102SN/A
211695SN/A    numWritesStat
2122SN/A        .name(name() + ".num_writes")
2132SN/A        .desc("number of write accesses completed")
2142SN/A        ;
2152SN/A}
2162SN/A
2172SN/Avoid
2182SN/AMemTest::tick()
2192SN/A{
22010688Sandreas.hansson@arm.com    // we should never tick if we are waiting for a retry
22110688Sandreas.hansson@arm.com    assert(!retryPkt);
2222SN/A
22310688Sandreas.hansson@arm.com    // create a new request
22410348Sandreas.hansson@arm.com    unsigned cmd = random_mt.random(0, 100);
22510688Sandreas.hansson@arm.com    uint8_t data = random_mt.random<uint8_t>();
22610688Sandreas.hansson@arm.com    bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
22710348Sandreas.hansson@arm.com    unsigned base = random_mt.random(0, 1);
2285736SN/A    Request::Flags flags;
2293187SN/A    Addr paddr;
2302SN/A
23110688Sandreas.hansson@arm.com    // generate a unique address
23210688Sandreas.hansson@arm.com    do {
23310688Sandreas.hansson@arm.com        unsigned offset = random_mt.random<unsigned>(0, size - 1);
2349301Snilay@cs.wisc.edu
23510688Sandreas.hansson@arm.com        // use the tester id as offset within the block for false sharing
23610688Sandreas.hansson@arm.com        offset = blockAlign(offset);
23710688Sandreas.hansson@arm.com        offset += id;
23810688Sandreas.hansson@arm.com
23910688Sandreas.hansson@arm.com        if (uncacheable) {
24010688Sandreas.hansson@arm.com            flags.set(Request::UNCACHEABLE);
24110688Sandreas.hansson@arm.com            paddr = uncacheAddr + offset;
24210688Sandreas.hansson@arm.com        } else  {
24310688Sandreas.hansson@arm.com            paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
24410688Sandreas.hansson@arm.com        }
24510688Sandreas.hansson@arm.com    } while (outstandingAddrs.find(paddr) != outstandingAddrs.end());
2469301Snilay@cs.wisc.edu
24710348Sandreas.hansson@arm.com    bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
24810348Sandreas.hansson@arm.com        !uncacheable;
24912749Sgiacomo.travaglini@arm.com    RequestPtr req = std::make_shared<Request>(paddr, 1, flags, masterId);
25011435Smitch.hayenga@arm.com    req->setContext(id);
2512SN/A
25210688Sandreas.hansson@arm.com    outstandingAddrs.insert(paddr);
25310688Sandreas.hansson@arm.com
25410688Sandreas.hansson@arm.com    // sanity check
25510688Sandreas.hansson@arm.com    panic_if(outstandingAddrs.size() > 100,
25610688Sandreas.hansson@arm.com             "Tester %s has more than 100 outstanding requests\n", name());
25710688Sandreas.hansson@arm.com
25810688Sandreas.hansson@arm.com    PacketPtr pkt = nullptr;
25910688Sandreas.hansson@arm.com    uint8_t *pkt_data = new uint8_t[1];
2603187SN/A
2612SN/A    if (cmd < percentReads) {
26210688Sandreas.hansson@arm.com        // start by ensuring there is a reference value if we have not
26310688Sandreas.hansson@arm.com        // seen this address before
26410688Sandreas.hansson@arm.com        uint8_t M5_VAR_USED ref_data = 0;
26510688Sandreas.hansson@arm.com        auto ref = referenceData.find(req->getPaddr());
26610688Sandreas.hansson@arm.com        if (ref == referenceData.end()) {
26710688Sandreas.hansson@arm.com            referenceData[req->getPaddr()] = 0;
26810688Sandreas.hansson@arm.com        } else {
26910688Sandreas.hansson@arm.com            ref_data = ref->second;
27010688Sandreas.hansson@arm.com        }
2713187SN/A
2724628SN/A        DPRINTF(MemTest,
27310688Sandreas.hansson@arm.com                "Initiating %sread at addr %x (blk %x) expecting %x\n",
27410688Sandreas.hansson@arm.com                do_functional ? "functional " : "", req->getPaddr(),
27510688Sandreas.hansson@arm.com                blockAlign(req->getPaddr()), ref_data);
2763187SN/A
27710688Sandreas.hansson@arm.com        pkt = new Packet(req, MemCmd::ReadReq);
27810688Sandreas.hansson@arm.com        pkt->dataDynamic(pkt_data);
27910688Sandreas.hansson@arm.com    } else {
28010688Sandreas.hansson@arm.com        DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n",
28110688Sandreas.hansson@arm.com                do_functional ? "functional " : "", req->getPaddr(),
28210688Sandreas.hansson@arm.com                blockAlign(req->getPaddr()), data);
2833187SN/A
28410688Sandreas.hansson@arm.com        pkt = new Packet(req, MemCmd::WriteReq);
28510688Sandreas.hansson@arm.com        pkt->dataDynamic(pkt_data);
28610688Sandreas.hansson@arm.com        pkt_data[0] = data;
28710688Sandreas.hansson@arm.com    }
28810688Sandreas.hansson@arm.com
28910688Sandreas.hansson@arm.com    // there is no point in ticking if we are waiting for a retry
29010688Sandreas.hansson@arm.com    bool keep_ticking = true;
29110688Sandreas.hansson@arm.com    if (do_functional) {
29210688Sandreas.hansson@arm.com        pkt->setSuppressFuncError();
29310688Sandreas.hansson@arm.com        port.sendFunctional(pkt);
29410688Sandreas.hansson@arm.com        completeRequest(pkt, true);
2953187SN/A    } else {
29610688Sandreas.hansson@arm.com        keep_ticking = sendPkt(pkt);
29710688Sandreas.hansson@arm.com    }
2981298SN/A
29910688Sandreas.hansson@arm.com    if (keep_ticking) {
30010688Sandreas.hansson@arm.com        // schedule the next tick
30110688Sandreas.hansson@arm.com        schedule(tickEvent, clockEdge(interval));
3024628SN/A
30310688Sandreas.hansson@arm.com        // finally shift the timeout for sending of requests forwards
30410688Sandreas.hansson@arm.com        // as we have successfully sent a packet
30510688Sandreas.hansson@arm.com        reschedule(noRequestEvent, clockEdge(progressCheck), true);
30610688Sandreas.hansson@arm.com    } else {
30710688Sandreas.hansson@arm.com        DPRINTF(MemTest, "Waiting for retry\n");
3083187SN/A    }
30914027Stiago.muck@arm.com
31014027Stiago.muck@arm.com    // Schedule noResponseEvent now if we are expecting a response
31114027Stiago.muck@arm.com    if (!noResponseEvent.scheduled() && (outstandingAddrs.size() != 0))
31214027Stiago.muck@arm.com        schedule(noResponseEvent, clockEdge(progressCheck));
3132SN/A}
3142SN/A
3152SN/Avoid
31610688Sandreas.hansson@arm.comMemTest::noRequest()
3172SN/A{
31810688Sandreas.hansson@arm.com    panic("%s did not send a request for %d cycles", name(), progressCheck);
31910688Sandreas.hansson@arm.com}
32010688Sandreas.hansson@arm.com
32110688Sandreas.hansson@arm.comvoid
32210688Sandreas.hansson@arm.comMemTest::noResponse()
32310688Sandreas.hansson@arm.com{
32410688Sandreas.hansson@arm.com    panic("%s did not see a response for %d cycles", name(), progressCheck);
32510688Sandreas.hansson@arm.com}
32610688Sandreas.hansson@arm.com
32710688Sandreas.hansson@arm.comvoid
32810688Sandreas.hansson@arm.comMemTest::recvRetry()
32910688Sandreas.hansson@arm.com{
33010688Sandreas.hansson@arm.com    assert(retryPkt);
33110688Sandreas.hansson@arm.com    if (port.sendTimingReq(retryPkt)) {
33210688Sandreas.hansson@arm.com        DPRINTF(MemTest, "Proceeding after successful retry\n");
33310688Sandreas.hansson@arm.com
33410688Sandreas.hansson@arm.com        retryPkt = nullptr;
33510688Sandreas.hansson@arm.com        // kick things into action again
33610688Sandreas.hansson@arm.com        schedule(tickEvent, clockEdge(interval));
33714027Stiago.muck@arm.com        reschedule(noRequestEvent, clockEdge(progressCheck), true);
3383187SN/A    }
3392SN/A}
3402SN/A
3415315SN/AMemTest *
3425315SN/AMemTestParams::create()
3435315SN/A{
3445315SN/A    return new MemTest(this);
3455315SN/A}
346