memtest.cc revision 10348
12SN/A/*
21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A *
282665SN/A * Authors: Erik Hallnor
292665SN/A *          Steve Reinhardt
302SN/A */
312SN/A
322SN/A// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
332SN/A
341298SN/A#include <iomanip>
351298SN/A#include <set>
361259SN/A#include <string>
372SN/A#include <vector>
382SN/A
39146SN/A#include "base/misc.hh"
4010348Sandreas.hansson@arm.com#include "base/random.hh"
41146SN/A#include "base/statistics.hh"
427632SBrad.Beckmann@amd.com#include "cpu/testers/memtest/memtest.hh"
438232Snate@binkert.org#include "debug/MemTest.hh"
443348SN/A#include "mem/mem_object.hh"
458229Snate@binkert.org#include "mem/packet.hh"
463348SN/A#include "mem/port.hh"
473348SN/A#include "mem/request.hh"
4856SN/A#include "sim/sim_events.hh"
49695SN/A#include "sim/stats.hh"
508832SAli.Saidi@ARM.com#include "sim/system.hh"
512SN/A
522SN/Ausing namespace std;
532SN/A
541298SN/Aint TESTER_ALLOCATOR=0;
551298SN/A
563187SN/Abool
578975Sandreas.hansson@arm.comMemTest::CpuPort::recvTimingResp(PacketPtr pkt)
583187SN/A{
598948Sandreas.hansson@arm.com    memtest->completeRequest(pkt);
603187SN/A    return true;
613187SN/A}
623187SN/A
633187SN/Avoid
643187SN/AMemTest::CpuPort::recvRetry()
653187SN/A{
663187SN/A    memtest->doRetry();
673187SN/A}
683187SN/A
693262SN/Avoid
703349SN/AMemTest::sendPkt(PacketPtr pkt) {
713262SN/A    if (atomic) {
723262SN/A        cachePort.sendAtomic(pkt);
733262SN/A        completeRequest(pkt);
743262SN/A    }
758975Sandreas.hansson@arm.com    else if (!cachePort.sendTimingReq(pkt)) {
767544SN/A        DPRINTF(MemTest, "accessRetry setting to true\n");
777544SN/A
787544SN/A        //
797544SN/A        // dma requests should never be retried
807544SN/A        //
817544SN/A        if (issueDmas) {
827544SN/A            panic("Nacked DMA requests are not supported\n");
837544SN/A        }
843262SN/A        accessRetry = true;
853262SN/A        retryPkt = pkt;
867544SN/A    } else {
877544SN/A        if (issueDmas) {
887544SN/A            dmaOutstanding = true;
897544SN/A        }
903262SN/A    }
913262SN/A
923262SN/A}
933262SN/A
945034SN/AMemTest::MemTest(const Params *p)
955034SN/A    : MemObject(p),
962SN/A      tickEvent(this),
973187SN/A      cachePort("test", this),
983187SN/A      funcPort("functional", this),
999814Sandreas.hansson@arm.com      funcProxy(funcPort, p->sys->cacheLineSize()),
1003187SN/A      retryPkt(NULL),
1013187SN/A//      mainMem(main_mem),
1023187SN/A//      checkMem(check_mem),
1035034SN/A      size(p->memory_size),
1045034SN/A      percentReads(p->percent_reads),
1055034SN/A      percentFunctional(p->percent_functional),
1065034SN/A      percentUncacheable(p->percent_uncacheable),
1077544SN/A      issueDmas(p->issue_dmas),
1088832SAli.Saidi@ARM.com      masterId(p->sys->getMasterId(name())),
1099814Sandreas.hansson@arm.com      blockSize(p->sys->cacheLineSize()),
1105034SN/A      progressInterval(p->progress_interval),
1115034SN/A      nextProgressMessage(p->progress_interval),
1125034SN/A      percentSourceUnaligned(p->percent_source_unaligned),
1135034SN/A      percentDestUnaligned(p->percent_dest_unaligned),
1145034SN/A      maxLoads(p->max_loads),
1158436SBrad.Beckmann@amd.com      atomic(p->atomic),
1168436SBrad.Beckmann@amd.com      suppress_func_warnings(p->suppress_func_warnings)
1172SN/A{
1187544SN/A    id = TESTER_ALLOCATOR++;
1197544SN/A
1203187SN/A    // Needs to be masked off once we know the block size.
1215034SN/A    traceBlockAddr = p->trace_addr;
1222SN/A    baseAddr1 = 0x100000;
1232SN/A    baseAddr2 = 0x400000;
1242SN/A    uncacheAddr = 0x800000;
1252SN/A
1269814Sandreas.hansson@arm.com    blockAddrMask = blockSize - 1;
1279814Sandreas.hansson@arm.com    traceBlockAddr = blockAddr(traceBlockAddr);
1289814Sandreas.hansson@arm.com
1292SN/A    // set up counters
1302SN/A    noResponseCycles = 0;
1312SN/A    numReads = 0;
1328436SBrad.Beckmann@amd.com    numWrites = 0;
1335606SN/A    schedule(tickEvent, 0);
1341298SN/A
1353187SN/A    accessRetry = false;
1367544SN/A    dmaOutstanding = false;
1373187SN/A}
1383187SN/A
1399294Sandreas.hansson@arm.comBaseMasterPort &
1409294Sandreas.hansson@arm.comMemTest::getMasterPort(const std::string &if_name, PortID idx)
1413187SN/A{
1423187SN/A    if (if_name == "functional")
1438922Swilliam.wang@arm.com        return funcPort;
1443187SN/A    else if (if_name == "test")
1458922Swilliam.wang@arm.com        return cachePort;
1463187SN/A    else
1478922Swilliam.wang@arm.com        return MemObject::getMasterPort(if_name, idx);
1483187SN/A}
1493187SN/A
1503187SN/Avoid
1513187SN/AMemTest::init()
1523187SN/A{
1534579SN/A    // initial memory contents for both physical memory and functional
1544579SN/A    // memory should be 0; no need to initialize them.
1552SN/A}
1562SN/A
1572SN/A
1582SN/Avoid
1593349SN/AMemTest::completeRequest(PacketPtr pkt)
1602SN/A{
1614628SN/A    Request *req = pkt->req;
1624628SN/A
1637544SN/A    if (issueDmas) {
1647544SN/A        dmaOutstanding = false;
1657544SN/A    }
1667544SN/A
1678436SBrad.Beckmann@amd.com    DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n",
1684628SN/A            pkt->isWrite() ? "write" : "read",
1698436SBrad.Beckmann@amd.com            req->getPaddr(), blockAddr(req->getPaddr()),
1708436SBrad.Beckmann@amd.com            pkt->isError() ? "error" : "success");
1714628SN/A
1723187SN/A    MemTestSenderState *state =
1733187SN/A        dynamic_cast<MemTestSenderState *>(pkt->senderState);
1743187SN/A
1753187SN/A    uint8_t *data = state->data;
1763187SN/A    uint8_t *pkt_data = pkt->getPtr<uint8_t>();
1773187SN/A
1781298SN/A    //Remove the address from the list of outstanding
1794628SN/A    std::set<unsigned>::iterator removeAddr =
1804628SN/A        outstandingAddrs.find(req->getPaddr());
1811298SN/A    assert(removeAddr != outstandingAddrs.end());
1821298SN/A    outstandingAddrs.erase(removeAddr);
1831298SN/A
1848436SBrad.Beckmann@amd.com    if (pkt->isError()) {
1858436SBrad.Beckmann@amd.com        if (!suppress_func_warnings) {
1869301Snilay@cs.wisc.edu          warn("Functional %s access failed at %#x\n",
1878436SBrad.Beckmann@amd.com               pkt->isWrite() ? "write" : "read", req->getPaddr());
1882SN/A        }
1898436SBrad.Beckmann@amd.com    } else {
1908436SBrad.Beckmann@amd.com        if (pkt->isRead()) {
1918436SBrad.Beckmann@amd.com            if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
1928436SBrad.Beckmann@amd.com                panic("%s: read of %x (blk %x) @ cycle %d "
1938436SBrad.Beckmann@amd.com                      "returns %x, expected %x\n", name(),
1948436SBrad.Beckmann@amd.com                      req->getPaddr(), blockAddr(req->getPaddr()), curTick(),
1958436SBrad.Beckmann@amd.com                      *pkt_data, *data);
1968436SBrad.Beckmann@amd.com            }
1972SN/A
1988436SBrad.Beckmann@amd.com            numReads++;
1998436SBrad.Beckmann@amd.com            numReadsStat++;
2002SN/A
2018436SBrad.Beckmann@amd.com            if (numReads == (uint64_t)nextProgressMessage) {
2028436SBrad.Beckmann@amd.com                ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n",
2038436SBrad.Beckmann@amd.com                         name(), numReads, numWrites, curTick());
2048436SBrad.Beckmann@amd.com                nextProgressMessage += progressInterval;
2058436SBrad.Beckmann@amd.com            }
2068436SBrad.Beckmann@amd.com
2078436SBrad.Beckmann@amd.com            if (maxLoads != 0 && numReads >= maxLoads)
2088436SBrad.Beckmann@amd.com                exitSimLoop("maximum number of loads reached");
2098436SBrad.Beckmann@amd.com        } else {
2108436SBrad.Beckmann@amd.com            assert(pkt->isWrite());
2118853Sandreas.hansson@arm.com            funcProxy.writeBlob(req->getPaddr(), pkt_data, req->getSize());
2128436SBrad.Beckmann@amd.com            numWrites++;
2138436SBrad.Beckmann@amd.com            numWritesStat++;
2142SN/A        }
2152SN/A    }
2162SN/A
2172SN/A    noResponseCycles = 0;
2183187SN/A    delete state;
2192SN/A    delete [] data;
2203187SN/A    delete pkt->req;
2213187SN/A    delete pkt;
2222SN/A}
2232SN/A
2242SN/Avoid
2252SN/AMemTest::regStats()
2262SN/A{
227729SN/A    using namespace Stats;
2282SN/A
229695SN/A    numReadsStat
2302SN/A        .name(name() + ".num_reads")
2312SN/A        .desc("number of read accesses completed")
2322SN/A        ;
2332SN/A
234695SN/A    numWritesStat
2352SN/A        .name(name() + ".num_writes")
2362SN/A        .desc("number of write accesses completed")
2372SN/A        ;
2382SN/A
239695SN/A    numCopiesStat
2402SN/A        .name(name() + ".num_copies")
2412SN/A        .desc("number of copy accesses completed")
2422SN/A        ;
2432SN/A}
2442SN/A
2452SN/Avoid
2462SN/AMemTest::tick()
2472SN/A{
2482SN/A    if (!tickEvent.scheduled())
2499180Sandreas.hansson@arm.com        schedule(tickEvent, clockEdge(Cycles(1)));
2502SN/A
2511298SN/A    if (++noResponseCycles >= 500000) {
2527544SN/A        if (issueDmas) {
2537544SN/A            cerr << "DMA tester ";
2547544SN/A        }
2557823Ssteve.reinhardt@amd.com        cerr << name() << ": deadlocked at cycle " << curTick() << endl;
2562SN/A        fatal("");
2572SN/A    }
2582SN/A
2597544SN/A    if (accessRetry || (issueDmas && dmaOutstanding)) {
2607544SN/A        DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n");
2612SN/A        return;
2622SN/A    }
2632SN/A
2642SN/A    //make new request
26510348Sandreas.hansson@arm.com    unsigned cmd = random_mt.random(0, 100);
26610348Sandreas.hansson@arm.com    unsigned offset = random_mt.random<unsigned>(0, size - 1);
26710348Sandreas.hansson@arm.com    unsigned base = random_mt.random(0, 1);
26810348Sandreas.hansson@arm.com    uint64_t data = random_mt.random<uint64_t>();
26910348Sandreas.hansson@arm.com    unsigned access_size = random_mt.random(0, 3);
27010348Sandreas.hansson@arm.com    bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
2712SN/A
27210348Sandreas.hansson@arm.com    unsigned dma_access_size = random_mt.random(0, 3);
2737544SN/A
2741298SN/A    //If we aren't doing copies, use id as offset, and do a false sharing
2751298SN/A    //mem tester
2763187SN/A    //We can eliminate the lower bits of the offset, and then use the id
2773187SN/A    //to offset within the blks
2784628SN/A    offset = blockAddr(offset);
2793187SN/A    offset += id;
2803187SN/A    access_size = 0;
2817544SN/A    dma_access_size = 0;
2821298SN/A
2835736SN/A    Request::Flags flags;
2843187SN/A    Addr paddr;
2852SN/A
2865736SN/A    if (uncacheable) {
2875736SN/A        flags.set(Request::UNCACHEABLE);
2883187SN/A        paddr = uncacheAddr + offset;
2897544SN/A    } else  {
2903187SN/A        paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
2912SN/A    }
2929301Snilay@cs.wisc.edu
2939301Snilay@cs.wisc.edu    // For now we only allow one outstanding request per address
2949301Snilay@cs.wisc.edu    // per tester This means we assume CPU does write forwarding
2959301Snilay@cs.wisc.edu    // to reads that alias something in the cpu store buffer.
2969301Snilay@cs.wisc.edu    if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
2979301Snilay@cs.wisc.edu        return;
2989301Snilay@cs.wisc.edu    }
2999301Snilay@cs.wisc.edu
30010348Sandreas.hansson@arm.com    bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
30110348Sandreas.hansson@arm.com        !uncacheable;
3029301Snilay@cs.wisc.edu    Request *req = new Request();
3039301Snilay@cs.wisc.edu    uint8_t *result = new uint8_t[8];
3042SN/A
3057544SN/A    if (issueDmas) {
3067544SN/A        paddr &= ~((1 << dma_access_size) - 1);
3078832SAli.Saidi@ARM.com        req->setPhys(paddr, 1 << dma_access_size, flags, masterId);
3087544SN/A        req->setThreadContext(id,0);
3097544SN/A    } else {
3107544SN/A        paddr &= ~((1 << access_size) - 1);
3118832SAli.Saidi@ARM.com        req->setPhys(paddr, 1 << access_size, flags, masterId);
3127544SN/A        req->setThreadContext(id,0);
3137544SN/A    }
3147544SN/A    assert(req->getSize() == 1);
3153187SN/A
3162SN/A    if (cmd < percentReads) {
3172SN/A        // read
3184628SN/A        outstandingAddrs.insert(paddr);
3191298SN/A
3203187SN/A        // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
3218853Sandreas.hansson@arm.com        funcProxy.readBlob(req->getPaddr(), result, req->getSize());
3223187SN/A
3234628SN/A        DPRINTF(MemTest,
3247657Ssteve.reinhardt@amd.com                "id %d initiating %sread at addr %x (blk %x) expecting %x\n",
3257657Ssteve.reinhardt@amd.com                id, do_functional ? "functional " : "", req->getPaddr(),
3267657Ssteve.reinhardt@amd.com                blockAddr(req->getPaddr()), *result);
3273187SN/A
3288949Sandreas.hansson@arm.com        PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
3293187SN/A        pkt->dataDynamicArray(new uint8_t[req->getSize()]);
3303187SN/A        MemTestSenderState *state = new MemTestSenderState(result);
3313187SN/A        pkt->senderState = state;
3323187SN/A
3337657Ssteve.reinhardt@amd.com        if (do_functional) {
3348436SBrad.Beckmann@amd.com            assert(pkt->needsResponse());
3358436SBrad.Beckmann@amd.com            pkt->setSuppressFuncError();
3363187SN/A            cachePort.sendFunctional(pkt);
3373204SN/A            completeRequest(pkt);
338145SN/A        } else {
3393262SN/A            sendPkt(pkt);
340145SN/A        }
3413187SN/A    } else {
3422SN/A        // write
3434628SN/A        outstandingAddrs.insert(paddr);
3441298SN/A
3457657Ssteve.reinhardt@amd.com        DPRINTF(MemTest, "initiating %swrite at addr %x (blk %x) value %x\n",
3467657Ssteve.reinhardt@amd.com                do_functional ? "functional " : "", req->getPaddr(),
3477657Ssteve.reinhardt@amd.com                blockAddr(req->getPaddr()), data & 0xff);
3484628SN/A
3498949Sandreas.hansson@arm.com        PacketPtr pkt = new Packet(req, MemCmd::WriteReq);
3503187SN/A        uint8_t *pkt_data = new uint8_t[req->getSize()];
3513187SN/A        pkt->dataDynamicArray(pkt_data);
3523187SN/A        memcpy(pkt_data, &data, req->getSize());
3533187SN/A        MemTestSenderState *state = new MemTestSenderState(result);
3543187SN/A        pkt->senderState = state;
3553187SN/A
3567657Ssteve.reinhardt@amd.com        if (do_functional) {
3578436SBrad.Beckmann@amd.com            pkt->setSuppressFuncError();
3583187SN/A            cachePort.sendFunctional(pkt);
3593262SN/A            completeRequest(pkt);
360145SN/A        } else {
3613262SN/A            sendPkt(pkt);
362145SN/A        }
3633187SN/A    }
3642SN/A}
3652SN/A
3662SN/Avoid
3673187SN/AMemTest::doRetry()
3682SN/A{
3698975Sandreas.hansson@arm.com    if (cachePort.sendTimingReq(retryPkt)) {
3707544SN/A        DPRINTF(MemTest, "accessRetry setting to false\n");
3713187SN/A        accessRetry = false;
3723187SN/A        retryPkt = NULL;
3733187SN/A    }
3742SN/A}
3752SN/A
3765314SN/A
3775314SN/Avoid
3785314SN/AMemTest::printAddr(Addr a)
3795314SN/A{
3805314SN/A    cachePort.printAddr(a);
3815314SN/A}
3825315SN/A
3835315SN/A
3845315SN/AMemTest *
3855315SN/AMemTestParams::create()
3865315SN/A{
3875315SN/A    return new MemTest(this);
3885315SN/A}
389