memtest.cc revision 8922
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"
40146SN/A#include "base/statistics.hh"
417632SBrad.Beckmann@amd.com#include "cpu/testers/memtest/memtest.hh"
428232Snate@binkert.org#include "debug/MemTest.hh"
433348SN/A#include "mem/mem_object.hh"
448229Snate@binkert.org#include "mem/packet.hh"
453348SN/A#include "mem/port.hh"
463348SN/A#include "mem/request.hh"
4756SN/A#include "sim/sim_events.hh"
48695SN/A#include "sim/stats.hh"
498832SAli.Saidi@ARM.com#include "sim/system.hh"
502SN/A
512SN/Ausing namespace std;
522SN/A
531298SN/Aint TESTER_ALLOCATOR=0;
541298SN/A
553187SN/Abool
563349SN/AMemTest::CpuPort::recvTiming(PacketPtr pkt)
573187SN/A{
584898SN/A    if (pkt->isResponse()) {
594898SN/A        memtest->completeRequest(pkt);
604898SN/A    } else {
614898SN/A        // must be snoop upcall
624898SN/A        assert(pkt->isRequest());
634898SN/A        assert(pkt->getDest() == Packet::Broadcast);
644898SN/A    }
653187SN/A    return true;
663187SN/A}
673187SN/A
683187SN/ATick
693349SN/AMemTest::CpuPort::recvAtomic(PacketPtr pkt)
703187SN/A{
714895SN/A    // must be snoop upcall
724895SN/A    assert(pkt->isRequest());
734895SN/A    assert(pkt->getDest() == Packet::Broadcast);
747823Ssteve.reinhardt@amd.com    return curTick();
753187SN/A}
763187SN/A
773187SN/Avoid
783349SN/AMemTest::CpuPort::recvFunctional(PacketPtr pkt)
793187SN/A{
803204SN/A    //Do nothing if we see one come through
817823Ssteve.reinhardt@amd.com//    if (curTick() != 0)//Supress warning durring initialization
823340SN/A//        warn("Functional Writes not implemented in MemTester\n");
833262SN/A    //Need to find any response values that intersect and update
843204SN/A    return;
853187SN/A}
863187SN/A
873187SN/Avoid
883187SN/AMemTest::CpuPort::recvRetry()
893187SN/A{
903187SN/A    memtest->doRetry();
913187SN/A}
923187SN/A
933262SN/Avoid
943349SN/AMemTest::sendPkt(PacketPtr pkt) {
953262SN/A    if (atomic) {
963262SN/A        cachePort.sendAtomic(pkt);
973262SN/A        completeRequest(pkt);
983262SN/A    }
993262SN/A    else if (!cachePort.sendTiming(pkt)) {
1007544SN/A        DPRINTF(MemTest, "accessRetry setting to true\n");
1017544SN/A
1027544SN/A        //
1037544SN/A        // dma requests should never be retried
1047544SN/A        //
1057544SN/A        if (issueDmas) {
1067544SN/A            panic("Nacked DMA requests are not supported\n");
1077544SN/A        }
1083262SN/A        accessRetry = true;
1093262SN/A        retryPkt = pkt;
1107544SN/A    } else {
1117544SN/A        if (issueDmas) {
1127544SN/A            dmaOutstanding = true;
1137544SN/A        }
1143262SN/A    }
1153262SN/A
1163262SN/A}
1173262SN/A
1185034SN/AMemTest::MemTest(const Params *p)
1195034SN/A    : MemObject(p),
1202SN/A      tickEvent(this),
1213187SN/A      cachePort("test", this),
1223187SN/A      funcPort("functional", this),
1238853Sandreas.hansson@arm.com      funcProxy(funcPort),
1243187SN/A      retryPkt(NULL),
1253187SN/A//      mainMem(main_mem),
1263187SN/A//      checkMem(check_mem),
1275034SN/A      size(p->memory_size),
1285034SN/A      percentReads(p->percent_reads),
1295034SN/A      percentFunctional(p->percent_functional),
1305034SN/A      percentUncacheable(p->percent_uncacheable),
1317544SN/A      issueDmas(p->issue_dmas),
1328832SAli.Saidi@ARM.com      masterId(p->sys->getMasterId(name())),
1335034SN/A      progressInterval(p->progress_interval),
1345034SN/A      nextProgressMessage(p->progress_interval),
1355034SN/A      percentSourceUnaligned(p->percent_source_unaligned),
1365034SN/A      percentDestUnaligned(p->percent_dest_unaligned),
1375034SN/A      maxLoads(p->max_loads),
1388436SBrad.Beckmann@amd.com      atomic(p->atomic),
1398436SBrad.Beckmann@amd.com      suppress_func_warnings(p->suppress_func_warnings)
1402SN/A{
1417544SN/A    id = TESTER_ALLOCATOR++;
1427544SN/A
1433187SN/A    // Needs to be masked off once we know the block size.
1445034SN/A    traceBlockAddr = p->trace_addr;
1452SN/A    baseAddr1 = 0x100000;
1462SN/A    baseAddr2 = 0x400000;
1472SN/A    uncacheAddr = 0x800000;
1482SN/A
1492SN/A    // set up counters
1502SN/A    noResponseCycles = 0;
1512SN/A    numReads = 0;
1528436SBrad.Beckmann@amd.com    numWrites = 0;
1535606SN/A    schedule(tickEvent, 0);
1541298SN/A
1553187SN/A    accessRetry = false;
1567544SN/A    dmaOutstanding = false;
1573187SN/A}
1583187SN/A
1598922Swilliam.wang@arm.comMasterPort &
1608922Swilliam.wang@arm.comMemTest::getMasterPort(const std::string &if_name, int idx)
1613187SN/A{
1623187SN/A    if (if_name == "functional")
1638922Swilliam.wang@arm.com        return funcPort;
1643187SN/A    else if (if_name == "test")
1658922Swilliam.wang@arm.com        return cachePort;
1663187SN/A    else
1678922Swilliam.wang@arm.com        return MemObject::getMasterPort(if_name, idx);
1683187SN/A}
1693187SN/A
1703187SN/Avoid
1713187SN/AMemTest::init()
1723187SN/A{
1733187SN/A    // By the time init() is called, the ports should be hooked up.
1743187SN/A    blockSize = cachePort.peerBlockSize();
1753187SN/A    blockAddrMask = blockSize - 1;
1763187SN/A    traceBlockAddr = blockAddr(traceBlockAddr);
1773187SN/A
1784579SN/A    // initial memory contents for both physical memory and functional
1794579SN/A    // memory should be 0; no need to initialize them.
1802SN/A}
1812SN/A
1822SN/A
1832SN/Avoid
1843349SN/AMemTest::completeRequest(PacketPtr pkt)
1852SN/A{
1864628SN/A    Request *req = pkt->req;
1874628SN/A
1887544SN/A    if (issueDmas) {
1897544SN/A        dmaOutstanding = false;
1907544SN/A    }
1917544SN/A
1928436SBrad.Beckmann@amd.com    DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n",
1934628SN/A            pkt->isWrite() ? "write" : "read",
1948436SBrad.Beckmann@amd.com            req->getPaddr(), blockAddr(req->getPaddr()),
1958436SBrad.Beckmann@amd.com            pkt->isError() ? "error" : "success");
1964628SN/A
1973187SN/A    MemTestSenderState *state =
1983187SN/A        dynamic_cast<MemTestSenderState *>(pkt->senderState);
1993187SN/A
2003187SN/A    uint8_t *data = state->data;
2013187SN/A    uint8_t *pkt_data = pkt->getPtr<uint8_t>();
2023187SN/A
2031298SN/A    //Remove the address from the list of outstanding
2044628SN/A    std::set<unsigned>::iterator removeAddr =
2054628SN/A        outstandingAddrs.find(req->getPaddr());
2061298SN/A    assert(removeAddr != outstandingAddrs.end());
2071298SN/A    outstandingAddrs.erase(removeAddr);
2081298SN/A
2098436SBrad.Beckmann@amd.com    if (pkt->isError()) {
2108436SBrad.Beckmann@amd.com        if (!suppress_func_warnings) {
2118436SBrad.Beckmann@amd.com          warn("Functional Access failed for %x at %x\n",
2128436SBrad.Beckmann@amd.com               pkt->isWrite() ? "write" : "read", req->getPaddr());
2132SN/A        }
2148436SBrad.Beckmann@amd.com    } else {
2158436SBrad.Beckmann@amd.com        if (pkt->isRead()) {
2168436SBrad.Beckmann@amd.com            if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
2178436SBrad.Beckmann@amd.com                panic("%s: read of %x (blk %x) @ cycle %d "
2188436SBrad.Beckmann@amd.com                      "returns %x, expected %x\n", name(),
2198436SBrad.Beckmann@amd.com                      req->getPaddr(), blockAddr(req->getPaddr()), curTick(),
2208436SBrad.Beckmann@amd.com                      *pkt_data, *data);
2218436SBrad.Beckmann@amd.com            }
2222SN/A
2238436SBrad.Beckmann@amd.com            numReads++;
2248436SBrad.Beckmann@amd.com            numReadsStat++;
2252SN/A
2268436SBrad.Beckmann@amd.com            if (numReads == (uint64_t)nextProgressMessage) {
2278436SBrad.Beckmann@amd.com                ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n",
2288436SBrad.Beckmann@amd.com                         name(), numReads, numWrites, curTick());
2298436SBrad.Beckmann@amd.com                nextProgressMessage += progressInterval;
2308436SBrad.Beckmann@amd.com            }
2318436SBrad.Beckmann@amd.com
2328436SBrad.Beckmann@amd.com            if (maxLoads != 0 && numReads >= maxLoads)
2338436SBrad.Beckmann@amd.com                exitSimLoop("maximum number of loads reached");
2348436SBrad.Beckmann@amd.com        } else {
2358436SBrad.Beckmann@amd.com            assert(pkt->isWrite());
2368853Sandreas.hansson@arm.com            funcProxy.writeBlob(req->getPaddr(), pkt_data, req->getSize());
2378436SBrad.Beckmann@amd.com            numWrites++;
2388436SBrad.Beckmann@amd.com            numWritesStat++;
2392SN/A        }
2402SN/A    }
2412SN/A
2422SN/A    noResponseCycles = 0;
2433187SN/A    delete state;
2442SN/A    delete [] data;
2453187SN/A    delete pkt->req;
2463187SN/A    delete pkt;
2472SN/A}
2482SN/A
2492SN/Avoid
2502SN/AMemTest::regStats()
2512SN/A{
252729SN/A    using namespace Stats;
2532SN/A
254695SN/A    numReadsStat
2552SN/A        .name(name() + ".num_reads")
2562SN/A        .desc("number of read accesses completed")
2572SN/A        ;
2582SN/A
259695SN/A    numWritesStat
2602SN/A        .name(name() + ".num_writes")
2612SN/A        .desc("number of write accesses completed")
2622SN/A        ;
2632SN/A
264695SN/A    numCopiesStat
2652SN/A        .name(name() + ".num_copies")
2662SN/A        .desc("number of copy accesses completed")
2672SN/A        ;
2682SN/A}
2692SN/A
2702SN/Avoid
2712SN/AMemTest::tick()
2722SN/A{
2732SN/A    if (!tickEvent.scheduled())
2747823Ssteve.reinhardt@amd.com        schedule(tickEvent, curTick() + ticks(1));
2752SN/A
2761298SN/A    if (++noResponseCycles >= 500000) {
2777544SN/A        if (issueDmas) {
2787544SN/A            cerr << "DMA tester ";
2797544SN/A        }
2807823Ssteve.reinhardt@amd.com        cerr << name() << ": deadlocked at cycle " << curTick() << endl;
2812SN/A        fatal("");
2822SN/A    }
2832SN/A
2847544SN/A    if (accessRetry || (issueDmas && dmaOutstanding)) {
2857544SN/A        DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n");
2862SN/A        return;
2872SN/A    }
2882SN/A
2892SN/A    //make new request
2901899SN/A    unsigned cmd = random() % 100;
2911899SN/A    unsigned offset = random() % size;
2922SN/A    unsigned base = random() % 2;
2932SN/A    uint64_t data = random();
2942SN/A    unsigned access_size = random() % 4;
2955736SN/A    bool uncacheable = (random() % 100) < percentUncacheable;
2962SN/A
2977544SN/A    unsigned dma_access_size = random() % 4;
2987544SN/A
2991298SN/A    //If we aren't doing copies, use id as offset, and do a false sharing
3001298SN/A    //mem tester
3013187SN/A    //We can eliminate the lower bits of the offset, and then use the id
3023187SN/A    //to offset within the blks
3034628SN/A    offset = blockAddr(offset);
3043187SN/A    offset += id;
3053187SN/A    access_size = 0;
3067544SN/A    dma_access_size = 0;
3071298SN/A
3083187SN/A    Request *req = new Request();
3095736SN/A    Request::Flags flags;
3103187SN/A    Addr paddr;
3112SN/A
3125736SN/A    if (uncacheable) {
3135736SN/A        flags.set(Request::UNCACHEABLE);
3143187SN/A        paddr = uncacheAddr + offset;
3157544SN/A    } else  {
3163187SN/A        paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
3172SN/A    }
3187657Ssteve.reinhardt@amd.com    bool do_functional = (random() % 100 < percentFunctional) && !uncacheable;
3192SN/A
3207544SN/A    if (issueDmas) {
3217544SN/A        paddr &= ~((1 << dma_access_size) - 1);
3228832SAli.Saidi@ARM.com        req->setPhys(paddr, 1 << dma_access_size, flags, masterId);
3237544SN/A        req->setThreadContext(id,0);
3247544SN/A    } else {
3257544SN/A        paddr &= ~((1 << access_size) - 1);
3268832SAli.Saidi@ARM.com        req->setPhys(paddr, 1 << access_size, flags, masterId);
3277544SN/A        req->setThreadContext(id,0);
3287544SN/A    }
3297544SN/A    assert(req->getSize() == 1);
3303187SN/A
3313187SN/A    uint8_t *result = new uint8_t[8];
3322SN/A
3332SN/A    if (cmd < percentReads) {
3342SN/A        // read
3351298SN/A
3364628SN/A        // For now we only allow one outstanding request per address
3374628SN/A        // per tester This means we assume CPU does write forwarding
3384628SN/A        // to reads that alias something in the cpu store buffer.
3393282SN/A        if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
3404203SN/A            delete [] result;
3413282SN/A            delete req;
3423282SN/A            return;
3433282SN/A        }
3444628SN/A
3454628SN/A        outstandingAddrs.insert(paddr);
3461298SN/A
3473187SN/A        // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
3488853Sandreas.hansson@arm.com        funcProxy.readBlob(req->getPaddr(), result, req->getSize());
3493187SN/A
3504628SN/A        DPRINTF(MemTest,
3517657Ssteve.reinhardt@amd.com                "id %d initiating %sread at addr %x (blk %x) expecting %x\n",
3527657Ssteve.reinhardt@amd.com                id, do_functional ? "functional " : "", req->getPaddr(),
3537657Ssteve.reinhardt@amd.com                blockAddr(req->getPaddr()), *result);
3543187SN/A
3554022SN/A        PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
3564660SN/A        pkt->setSrc(0);
3573187SN/A        pkt->dataDynamicArray(new uint8_t[req->getSize()]);
3583187SN/A        MemTestSenderState *state = new MemTestSenderState(result);
3593187SN/A        pkt->senderState = state;
3603187SN/A
3617657Ssteve.reinhardt@amd.com        if (do_functional) {
3628436SBrad.Beckmann@amd.com            assert(pkt->needsResponse());
3638436SBrad.Beckmann@amd.com            pkt->setSuppressFuncError();
3643187SN/A            cachePort.sendFunctional(pkt);
3653204SN/A            completeRequest(pkt);
366145SN/A        } else {
3673262SN/A            sendPkt(pkt);
368145SN/A        }
3693187SN/A    } else {
3702SN/A        // write
3711298SN/A
3724628SN/A        // For now we only allow one outstanding request per addreess
3734628SN/A        // per tester.  This means we assume CPU does write forwarding
3744628SN/A        // to reads that alias something in the cpu store buffer.
3753282SN/A        if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
3763283SN/A            delete [] result;
3773282SN/A            delete req;
3783282SN/A            return;
3793282SN/A        }
3803282SN/A
3814628SN/A        outstandingAddrs.insert(paddr);
3821298SN/A
3837657Ssteve.reinhardt@amd.com        DPRINTF(MemTest, "initiating %swrite at addr %x (blk %x) value %x\n",
3847657Ssteve.reinhardt@amd.com                do_functional ? "functional " : "", req->getPaddr(),
3857657Ssteve.reinhardt@amd.com                blockAddr(req->getPaddr()), data & 0xff);
3864628SN/A
3874022SN/A        PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
3884660SN/A        pkt->setSrc(0);
3893187SN/A        uint8_t *pkt_data = new uint8_t[req->getSize()];
3903187SN/A        pkt->dataDynamicArray(pkt_data);
3913187SN/A        memcpy(pkt_data, &data, req->getSize());
3923187SN/A        MemTestSenderState *state = new MemTestSenderState(result);
3933187SN/A        pkt->senderState = state;
3943187SN/A
3957657Ssteve.reinhardt@amd.com        if (do_functional) {
3968436SBrad.Beckmann@amd.com            pkt->setSuppressFuncError();
3973187SN/A            cachePort.sendFunctional(pkt);
3983262SN/A            completeRequest(pkt);
399145SN/A        } else {
4003262SN/A            sendPkt(pkt);
401145SN/A        }
4023187SN/A    }
4032SN/A}
4042SN/A
4052SN/Avoid
4063187SN/AMemTest::doRetry()
4072SN/A{
4083187SN/A    if (cachePort.sendTiming(retryPkt)) {
4097544SN/A        DPRINTF(MemTest, "accessRetry setting to false\n");
4103187SN/A        accessRetry = false;
4113187SN/A        retryPkt = NULL;
4123187SN/A    }
4132SN/A}
4142SN/A
4155314SN/A
4165314SN/Avoid
4175314SN/AMemTest::printAddr(Addr a)
4185314SN/A{
4195314SN/A    cachePort.printAddr(a);
4205314SN/A}
4215315SN/A
4225315SN/A
4235315SN/AMemTest *
4245315SN/AMemTestParams::create()
4255315SN/A{
4265315SN/A    return new MemTest(this);
4275315SN/A}
428