memtest.cc revision 7632
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"
423348SN/A#include "mem/mem_object.hh"
433348SN/A#include "mem/port.hh"
443348SN/A#include "mem/packet.hh"
453348SN/A#include "mem/request.hh"
4656SN/A#include "sim/sim_events.hh"
47695SN/A#include "sim/stats.hh"
482SN/A
492SN/Ausing namespace std;
502SN/A
511298SN/Aint TESTER_ALLOCATOR=0;
521298SN/A
533187SN/Abool
543349SN/AMemTest::CpuPort::recvTiming(PacketPtr pkt)
553187SN/A{
564898SN/A    if (pkt->isResponse()) {
574898SN/A        memtest->completeRequest(pkt);
584898SN/A    } else {
594898SN/A        // must be snoop upcall
604898SN/A        assert(pkt->isRequest());
614898SN/A        assert(pkt->getDest() == Packet::Broadcast);
624898SN/A    }
633187SN/A    return true;
643187SN/A}
653187SN/A
663187SN/ATick
673349SN/AMemTest::CpuPort::recvAtomic(PacketPtr pkt)
683187SN/A{
694895SN/A    // must be snoop upcall
704895SN/A    assert(pkt->isRequest());
714895SN/A    assert(pkt->getDest() == Packet::Broadcast);
723187SN/A    return curTick;
733187SN/A}
743187SN/A
753187SN/Avoid
763349SN/AMemTest::CpuPort::recvFunctional(PacketPtr pkt)
773187SN/A{
783204SN/A    //Do nothing if we see one come through
793340SN/A//    if (curTick != 0)//Supress warning durring initialization
803340SN/A//        warn("Functional Writes not implemented in MemTester\n");
813262SN/A    //Need to find any response values that intersect and update
823204SN/A    return;
833187SN/A}
843187SN/A
853187SN/Avoid
863187SN/AMemTest::CpuPort::recvStatusChange(Status status)
873187SN/A{
883647SN/A    if (status == RangeChange) {
893647SN/A        if (!snoopRangeSent) {
903647SN/A            snoopRangeSent = true;
913647SN/A            sendStatusChange(Port::RangeChange);
923647SN/A        }
933187SN/A        return;
943647SN/A    }
953187SN/A
963187SN/A    panic("MemTest doesn't expect recvStatusChange callback!");
973187SN/A}
983187SN/A
993187SN/Avoid
1003187SN/AMemTest::CpuPort::recvRetry()
1013187SN/A{
1023187SN/A    memtest->doRetry();
1033187SN/A}
1043187SN/A
1053262SN/Avoid
1063349SN/AMemTest::sendPkt(PacketPtr pkt) {
1073262SN/A    if (atomic) {
1083262SN/A        cachePort.sendAtomic(pkt);
1093262SN/A        completeRequest(pkt);
1103262SN/A    }
1113262SN/A    else if (!cachePort.sendTiming(pkt)) {
1127544SN/A        DPRINTF(MemTest, "accessRetry setting to true\n");
1137544SN/A
1147544SN/A        //
1157544SN/A        // dma requests should never be retried
1167544SN/A        //
1177544SN/A        if (issueDmas) {
1187544SN/A            panic("Nacked DMA requests are not supported\n");
1197544SN/A        }
1203262SN/A        accessRetry = true;
1213262SN/A        retryPkt = pkt;
1227544SN/A    } else {
1237544SN/A        if (issueDmas) {
1247544SN/A            dmaOutstanding = true;
1257544SN/A        }
1263262SN/A    }
1273262SN/A
1283262SN/A}
1293262SN/A
1305034SN/AMemTest::MemTest(const Params *p)
1315034SN/A    : MemObject(p),
1322SN/A      tickEvent(this),
1333187SN/A      cachePort("test", this),
1343187SN/A      funcPort("functional", this),
1353187SN/A      retryPkt(NULL),
1363187SN/A//      mainMem(main_mem),
1373187SN/A//      checkMem(check_mem),
1385034SN/A      size(p->memory_size),
1395034SN/A      percentReads(p->percent_reads),
1405034SN/A      percentFunctional(p->percent_functional),
1415034SN/A      percentUncacheable(p->percent_uncacheable),
1427544SN/A      issueDmas(p->issue_dmas),
1435034SN/A      progressInterval(p->progress_interval),
1445034SN/A      nextProgressMessage(p->progress_interval),
1455034SN/A      percentSourceUnaligned(p->percent_source_unaligned),
1465034SN/A      percentDestUnaligned(p->percent_dest_unaligned),
1475034SN/A      maxLoads(p->max_loads),
1485034SN/A      atomic(p->atomic)
1492SN/A{
1507544SN/A
1512SN/A    vector<string> cmd;
1522SN/A    cmd.push_back("/bin/ls");
1532SN/A    vector<string> null_vec;
1543187SN/A    //  thread = new SimpleThread(NULL, 0, NULL, 0, mainMem);
1552SN/A    curTick = 0;
1562SN/A
1573647SN/A    cachePort.snoopRangeSent = false;
1583647SN/A    funcPort.snoopRangeSent = true;
1593647SN/A
1607544SN/A    id = TESTER_ALLOCATOR++;
1617544SN/A
1623187SN/A    // Needs to be masked off once we know the block size.
1635034SN/A    traceBlockAddr = p->trace_addr;
1642SN/A    baseAddr1 = 0x100000;
1652SN/A    baseAddr2 = 0x400000;
1662SN/A    uncacheAddr = 0x800000;
1672SN/A
1682SN/A    // set up counters
1692SN/A    noResponseCycles = 0;
1702SN/A    numReads = 0;
1715606SN/A    schedule(tickEvent, 0);
1721298SN/A
1733187SN/A    accessRetry = false;
1747544SN/A    dmaOutstanding = false;
1753187SN/A}
1763187SN/A
1773187SN/APort *
1783187SN/AMemTest::getPort(const std::string &if_name, int idx)
1793187SN/A{
1803187SN/A    if (if_name == "functional")
1813187SN/A        return &funcPort;
1823187SN/A    else if (if_name == "test")
1833187SN/A        return &cachePort;
1843187SN/A    else
1853187SN/A        panic("No Such Port\n");
1863187SN/A}
1873187SN/A
1883187SN/Avoid
1893187SN/AMemTest::init()
1903187SN/A{
1913187SN/A    // By the time init() is called, the ports should be hooked up.
1923187SN/A    blockSize = cachePort.peerBlockSize();
1933187SN/A    blockAddrMask = blockSize - 1;
1943187SN/A    traceBlockAddr = blockAddr(traceBlockAddr);
1953187SN/A
1964579SN/A    // initial memory contents for both physical memory and functional
1974579SN/A    // memory should be 0; no need to initialize them.
1982SN/A}
1992SN/A
2002SN/A
2012SN/Avoid
2023349SN/AMemTest::completeRequest(PacketPtr pkt)
2032SN/A{
2044628SN/A    Request *req = pkt->req;
2054628SN/A
2067544SN/A    if (issueDmas) {
2077544SN/A        dmaOutstanding = false;
2087544SN/A    }
2097544SN/A
2104628SN/A    DPRINTF(MemTest, "completing %s at address %x (blk %x)\n",
2114628SN/A            pkt->isWrite() ? "write" : "read",
2124628SN/A            req->getPaddr(), blockAddr(req->getPaddr()));
2134628SN/A
2143187SN/A    MemTestSenderState *state =
2153187SN/A        dynamic_cast<MemTestSenderState *>(pkt->senderState);
2163187SN/A
2173187SN/A    uint8_t *data = state->data;
2183187SN/A    uint8_t *pkt_data = pkt->getPtr<uint8_t>();
2193187SN/A
2201298SN/A    //Remove the address from the list of outstanding
2214628SN/A    std::set<unsigned>::iterator removeAddr =
2224628SN/A        outstandingAddrs.find(req->getPaddr());
2231298SN/A    assert(removeAddr != outstandingAddrs.end());
2241298SN/A    outstandingAddrs.erase(removeAddr);
2251298SN/A
2265319SN/A    assert(pkt->isResponse());
2273187SN/A
2285319SN/A    if (pkt->isRead()) {
2293187SN/A        if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
2304626SN/A            panic("%s: read of %x (blk %x) @ cycle %d "
2314626SN/A                  "returns %x, expected %x\n", name(),
2324626SN/A                  req->getPaddr(), blockAddr(req->getPaddr()), curTick,
2334626SN/A                  *pkt_data, *data);
2342SN/A        }
2352SN/A
2362SN/A        numReads++;
237695SN/A        numReadsStat++;
2382SN/A
2396227SN/A        if (numReads == (uint64_t)nextProgressMessage) {
240695SN/A            ccprintf(cerr, "%s: completed %d read accesses @%d\n",
241695SN/A                     name(), numReads, curTick);
2422SN/A            nextProgressMessage += progressInterval;
2432SN/A        }
2442SN/A
2454893SN/A        if (maxLoads != 0 && numReads >= maxLoads)
2464628SN/A            exitSimLoop("maximum number of loads reached");
2475319SN/A    } else {
2485319SN/A        assert(pkt->isWrite());
249695SN/A        numWritesStat++;
2502SN/A    }
2512SN/A
2522SN/A    noResponseCycles = 0;
2533187SN/A    delete state;
2542SN/A    delete [] data;
2553187SN/A    delete pkt->req;
2563187SN/A    delete pkt;
2572SN/A}
2582SN/A
2592SN/Avoid
2602SN/AMemTest::regStats()
2612SN/A{
262729SN/A    using namespace Stats;
2632SN/A
264695SN/A    numReadsStat
2652SN/A        .name(name() + ".num_reads")
2662SN/A        .desc("number of read accesses completed")
2672SN/A        ;
2682SN/A
269695SN/A    numWritesStat
2702SN/A        .name(name() + ".num_writes")
2712SN/A        .desc("number of write accesses completed")
2722SN/A        ;
2732SN/A
274695SN/A    numCopiesStat
2752SN/A        .name(name() + ".num_copies")
2762SN/A        .desc("number of copy accesses completed")
2772SN/A        ;
2782SN/A}
2792SN/A
2802SN/Avoid
2812SN/AMemTest::tick()
2822SN/A{
2832SN/A    if (!tickEvent.scheduled())
2845606SN/A        schedule(tickEvent, curTick + ticks(1));
2852SN/A
2861298SN/A    if (++noResponseCycles >= 500000) {
2877544SN/A        if (issueDmas) {
2887544SN/A            cerr << "DMA tester ";
2897544SN/A        }
2902SN/A        cerr << name() << ": deadlocked at cycle " << curTick << endl;
2912SN/A        fatal("");
2922SN/A    }
2932SN/A
2947544SN/A    if (accessRetry || (issueDmas && dmaOutstanding)) {
2957544SN/A        DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n");
2962SN/A        return;
2972SN/A    }
2982SN/A
2992SN/A    //make new request
3001899SN/A    unsigned cmd = random() % 100;
3011899SN/A    unsigned offset = random() % size;
3022SN/A    unsigned base = random() % 2;
3032SN/A    uint64_t data = random();
3042SN/A    unsigned access_size = random() % 4;
3055736SN/A    bool uncacheable = (random() % 100) < percentUncacheable;
3062SN/A
3077544SN/A    unsigned dma_access_size = random() % 4;
3087544SN/A
3091298SN/A    //If we aren't doing copies, use id as offset, and do a false sharing
3101298SN/A    //mem tester
3113187SN/A    //We can eliminate the lower bits of the offset, and then use the id
3123187SN/A    //to offset within the blks
3134628SN/A    offset = blockAddr(offset);
3143187SN/A    offset += id;
3153187SN/A    access_size = 0;
3167544SN/A    dma_access_size = 0;
3171298SN/A
3183187SN/A    Request *req = new Request();
3195736SN/A    Request::Flags flags;
3203187SN/A    Addr paddr;
3212SN/A
3225736SN/A    if (uncacheable) {
3235736SN/A        flags.set(Request::UNCACHEABLE);
3243187SN/A        paddr = uncacheAddr + offset;
3257544SN/A    } else  {
3263187SN/A        paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
3272SN/A    }
3285736SN/A    bool probe = (random() % 100 < percentFunctional) && !uncacheable;
3292SN/A
3307544SN/A    if (issueDmas) {
3317544SN/A        paddr &= ~((1 << dma_access_size) - 1);
3327544SN/A        req->setPhys(paddr, 1 << dma_access_size, flags);
3337544SN/A        req->setThreadContext(id,0);
3347544SN/A    } else {
3357544SN/A        paddr &= ~((1 << access_size) - 1);
3367544SN/A        req->setPhys(paddr, 1 << access_size, flags);
3377544SN/A        req->setThreadContext(id,0);
3387544SN/A    }
3397544SN/A    assert(req->getSize() == 1);
3403187SN/A
3413187SN/A    uint8_t *result = new uint8_t[8];
3422SN/A
3432SN/A    if (cmd < percentReads) {
3442SN/A        // read
3451298SN/A
3464628SN/A        // For now we only allow one outstanding request per address
3474628SN/A        // per tester This means we assume CPU does write forwarding
3484628SN/A        // to reads that alias something in the cpu store buffer.
3493282SN/A        if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
3504203SN/A            delete [] result;
3513282SN/A            delete req;
3523282SN/A            return;
3533282SN/A        }
3544628SN/A
3554628SN/A        outstandingAddrs.insert(paddr);
3561298SN/A
3573187SN/A        // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
3583187SN/A        funcPort.readBlob(req->getPaddr(), result, req->getSize());
3593187SN/A
3604628SN/A        DPRINTF(MemTest,
3617544SN/A                "id %d initiating read at address %x (blk %x) expecting %x\n",
3627544SN/A                id, req->getPaddr(), blockAddr(req->getPaddr()), *result);
3633187SN/A
3644022SN/A        PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
3654660SN/A        pkt->setSrc(0);
3663187SN/A        pkt->dataDynamicArray(new uint8_t[req->getSize()]);
3673187SN/A        MemTestSenderState *state = new MemTestSenderState(result);
3683187SN/A        pkt->senderState = state;
3693187SN/A
370145SN/A        if (probe) {
3713187SN/A            cachePort.sendFunctional(pkt);
3723204SN/A            completeRequest(pkt);
373145SN/A        } else {
3743262SN/A            sendPkt(pkt);
375145SN/A        }
3763187SN/A    } else {
3772SN/A        // write
3781298SN/A
3794628SN/A        // For now we only allow one outstanding request per addreess
3804628SN/A        // per tester.  This means we assume CPU does write forwarding
3814628SN/A        // to reads that alias something in the cpu store buffer.
3823282SN/A        if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
3833283SN/A            delete [] result;
3843282SN/A            delete req;
3853282SN/A            return;
3863282SN/A        }
3873282SN/A
3884628SN/A        outstandingAddrs.insert(paddr);
3891298SN/A
3904628SN/A        DPRINTF(MemTest, "initiating write at address %x (blk %x) value %x\n",
3914628SN/A                req->getPaddr(), blockAddr(req->getPaddr()), data & 0xff);
3924628SN/A
3934022SN/A        PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
3944660SN/A        pkt->setSrc(0);
3953187SN/A        uint8_t *pkt_data = new uint8_t[req->getSize()];
3963187SN/A        pkt->dataDynamicArray(pkt_data);
3973187SN/A        memcpy(pkt_data, &data, req->getSize());
3983187SN/A        MemTestSenderState *state = new MemTestSenderState(result);
3993187SN/A        pkt->senderState = state;
4003187SN/A
4013187SN/A        funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());
4023187SN/A
403145SN/A        if (probe) {
4043187SN/A            cachePort.sendFunctional(pkt);
4053262SN/A            completeRequest(pkt);
406145SN/A        } else {
4073262SN/A            sendPkt(pkt);
408145SN/A        }
4093187SN/A    }
4102SN/A}
4112SN/A
4122SN/Avoid
4133187SN/AMemTest::doRetry()
4142SN/A{
4153187SN/A    if (cachePort.sendTiming(retryPkt)) {
4167544SN/A        DPRINTF(MemTest, "accessRetry setting to false\n");
4173187SN/A        accessRetry = false;
4183187SN/A        retryPkt = NULL;
4193187SN/A    }
4202SN/A}
4212SN/A
4225314SN/A
4235314SN/Avoid
4245314SN/AMemTest::printAddr(Addr a)
4255314SN/A{
4265314SN/A    cachePort.printAddr(a);
4275314SN/A}
4285315SN/A
4295315SN/A
4305315SN/AMemTest *
4315315SN/AMemTestParams::create()
4325315SN/A{
4335315SN/A    return new MemTest(this);
4345315SN/A}
435