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