memtest.cc revision 8711
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" 492SN/A 502SN/Ausing namespace std; 512SN/A 521298SN/Aint TESTER_ALLOCATOR=0; 531298SN/A 543187SN/Abool 553349SN/AMemTest::CpuPort::recvTiming(PacketPtr pkt) 563187SN/A{ 574898SN/A if (pkt->isResponse()) { 584898SN/A memtest->completeRequest(pkt); 594898SN/A } else { 604898SN/A // must be snoop upcall 614898SN/A assert(pkt->isRequest()); 624898SN/A assert(pkt->getDest() == Packet::Broadcast); 634898SN/A } 643187SN/A return true; 653187SN/A} 663187SN/A 673187SN/ATick 683349SN/AMemTest::CpuPort::recvAtomic(PacketPtr pkt) 693187SN/A{ 704895SN/A // must be snoop upcall 714895SN/A assert(pkt->isRequest()); 724895SN/A assert(pkt->getDest() == Packet::Broadcast); 737823Ssteve.reinhardt@amd.com return curTick(); 743187SN/A} 753187SN/A 763187SN/Avoid 773349SN/AMemTest::CpuPort::recvFunctional(PacketPtr pkt) 783187SN/A{ 793204SN/A //Do nothing if we see one come through 807823Ssteve.reinhardt@amd.com// if (curTick() != 0)//Supress warning durring initialization 813340SN/A// warn("Functional Writes not implemented in MemTester\n"); 823262SN/A //Need to find any response values that intersect and update 833204SN/A return; 843187SN/A} 853187SN/A 863187SN/Avoid 878711Sandreas.hansson@arm.comMemTest::CpuPort::recvRangeChange() 883187SN/A{ 893187SN/A} 903187SN/A 913187SN/Avoid 923187SN/AMemTest::CpuPort::recvRetry() 933187SN/A{ 943187SN/A memtest->doRetry(); 953187SN/A} 963187SN/A 973262SN/Avoid 983349SN/AMemTest::sendPkt(PacketPtr pkt) { 993262SN/A if (atomic) { 1003262SN/A cachePort.sendAtomic(pkt); 1013262SN/A completeRequest(pkt); 1023262SN/A } 1033262SN/A else if (!cachePort.sendTiming(pkt)) { 1047544SN/A DPRINTF(MemTest, "accessRetry setting to true\n"); 1057544SN/A 1067544SN/A // 1077544SN/A // dma requests should never be retried 1087544SN/A // 1097544SN/A if (issueDmas) { 1107544SN/A panic("Nacked DMA requests are not supported\n"); 1117544SN/A } 1123262SN/A accessRetry = true; 1133262SN/A retryPkt = pkt; 1147544SN/A } else { 1157544SN/A if (issueDmas) { 1167544SN/A dmaOutstanding = true; 1177544SN/A } 1183262SN/A } 1193262SN/A 1203262SN/A} 1213262SN/A 1225034SN/AMemTest::MemTest(const Params *p) 1235034SN/A : MemObject(p), 1242SN/A tickEvent(this), 1253187SN/A cachePort("test", this), 1263187SN/A funcPort("functional", this), 1273187SN/A retryPkt(NULL), 1283187SN/A// mainMem(main_mem), 1293187SN/A// checkMem(check_mem), 1305034SN/A size(p->memory_size), 1315034SN/A percentReads(p->percent_reads), 1325034SN/A percentFunctional(p->percent_functional), 1335034SN/A percentUncacheable(p->percent_uncacheable), 1347544SN/A issueDmas(p->issue_dmas), 1355034SN/A progressInterval(p->progress_interval), 1365034SN/A nextProgressMessage(p->progress_interval), 1375034SN/A percentSourceUnaligned(p->percent_source_unaligned), 1385034SN/A percentDestUnaligned(p->percent_dest_unaligned), 1395034SN/A maxLoads(p->max_loads), 1408436SBrad.Beckmann@amd.com atomic(p->atomic), 1418436SBrad.Beckmann@amd.com suppress_func_warnings(p->suppress_func_warnings) 1422SN/A{ 1437544SN/A id = TESTER_ALLOCATOR++; 1447544SN/A 1453187SN/A // Needs to be masked off once we know the block size. 1465034SN/A traceBlockAddr = p->trace_addr; 1472SN/A baseAddr1 = 0x100000; 1482SN/A baseAddr2 = 0x400000; 1492SN/A uncacheAddr = 0x800000; 1502SN/A 1512SN/A // set up counters 1522SN/A noResponseCycles = 0; 1532SN/A numReads = 0; 1548436SBrad.Beckmann@amd.com numWrites = 0; 1555606SN/A schedule(tickEvent, 0); 1561298SN/A 1573187SN/A accessRetry = false; 1587544SN/A dmaOutstanding = false; 1593187SN/A} 1603187SN/A 1613187SN/APort * 1623187SN/AMemTest::getPort(const std::string &if_name, int idx) 1633187SN/A{ 1643187SN/A if (if_name == "functional") 1653187SN/A return &funcPort; 1663187SN/A else if (if_name == "test") 1673187SN/A return &cachePort; 1683187SN/A else 1693187SN/A panic("No Such Port\n"); 1703187SN/A} 1713187SN/A 1723187SN/Avoid 1733187SN/AMemTest::init() 1743187SN/A{ 1753187SN/A // By the time init() is called, the ports should be hooked up. 1763187SN/A blockSize = cachePort.peerBlockSize(); 1773187SN/A blockAddrMask = blockSize - 1; 1783187SN/A traceBlockAddr = blockAddr(traceBlockAddr); 1793187SN/A 1804579SN/A // initial memory contents for both physical memory and functional 1814579SN/A // memory should be 0; no need to initialize them. 1822SN/A} 1832SN/A 1842SN/A 1852SN/Avoid 1863349SN/AMemTest::completeRequest(PacketPtr pkt) 1872SN/A{ 1884628SN/A Request *req = pkt->req; 1894628SN/A 1907544SN/A if (issueDmas) { 1917544SN/A dmaOutstanding = false; 1927544SN/A } 1937544SN/A 1948436SBrad.Beckmann@amd.com DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n", 1954628SN/A pkt->isWrite() ? "write" : "read", 1968436SBrad.Beckmann@amd.com req->getPaddr(), blockAddr(req->getPaddr()), 1978436SBrad.Beckmann@amd.com pkt->isError() ? "error" : "success"); 1984628SN/A 1993187SN/A MemTestSenderState *state = 2003187SN/A dynamic_cast<MemTestSenderState *>(pkt->senderState); 2013187SN/A 2023187SN/A uint8_t *data = state->data; 2033187SN/A uint8_t *pkt_data = pkt->getPtr<uint8_t>(); 2043187SN/A 2051298SN/A //Remove the address from the list of outstanding 2064628SN/A std::set<unsigned>::iterator removeAddr = 2074628SN/A outstandingAddrs.find(req->getPaddr()); 2081298SN/A assert(removeAddr != outstandingAddrs.end()); 2091298SN/A outstandingAddrs.erase(removeAddr); 2101298SN/A 2118436SBrad.Beckmann@amd.com if (pkt->isError()) { 2128436SBrad.Beckmann@amd.com if (!suppress_func_warnings) { 2138436SBrad.Beckmann@amd.com warn("Functional Access failed for %x at %x\n", 2148436SBrad.Beckmann@amd.com pkt->isWrite() ? "write" : "read", req->getPaddr()); 2152SN/A } 2168436SBrad.Beckmann@amd.com } else { 2178436SBrad.Beckmann@amd.com if (pkt->isRead()) { 2188436SBrad.Beckmann@amd.com if (memcmp(pkt_data, data, pkt->getSize()) != 0) { 2198436SBrad.Beckmann@amd.com panic("%s: read of %x (blk %x) @ cycle %d " 2208436SBrad.Beckmann@amd.com "returns %x, expected %x\n", name(), 2218436SBrad.Beckmann@amd.com req->getPaddr(), blockAddr(req->getPaddr()), curTick(), 2228436SBrad.Beckmann@amd.com *pkt_data, *data); 2238436SBrad.Beckmann@amd.com } 2242SN/A 2258436SBrad.Beckmann@amd.com numReads++; 2268436SBrad.Beckmann@amd.com numReadsStat++; 2272SN/A 2288436SBrad.Beckmann@amd.com if (numReads == (uint64_t)nextProgressMessage) { 2298436SBrad.Beckmann@amd.com ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n", 2308436SBrad.Beckmann@amd.com name(), numReads, numWrites, curTick()); 2318436SBrad.Beckmann@amd.com nextProgressMessage += progressInterval; 2328436SBrad.Beckmann@amd.com } 2338436SBrad.Beckmann@amd.com 2348436SBrad.Beckmann@amd.com if (maxLoads != 0 && numReads >= maxLoads) 2358436SBrad.Beckmann@amd.com exitSimLoop("maximum number of loads reached"); 2368436SBrad.Beckmann@amd.com } else { 2378436SBrad.Beckmann@amd.com assert(pkt->isWrite()); 2388436SBrad.Beckmann@amd.com funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize()); 2398436SBrad.Beckmann@amd.com numWrites++; 2408436SBrad.Beckmann@amd.com numWritesStat++; 2412SN/A } 2422SN/A } 2432SN/A 2442SN/A noResponseCycles = 0; 2453187SN/A delete state; 2462SN/A delete [] data; 2473187SN/A delete pkt->req; 2483187SN/A delete pkt; 2492SN/A} 2502SN/A 2512SN/Avoid 2522SN/AMemTest::regStats() 2532SN/A{ 254729SN/A using namespace Stats; 2552SN/A 256695SN/A numReadsStat 2572SN/A .name(name() + ".num_reads") 2582SN/A .desc("number of read accesses completed") 2592SN/A ; 2602SN/A 261695SN/A numWritesStat 2622SN/A .name(name() + ".num_writes") 2632SN/A .desc("number of write accesses completed") 2642SN/A ; 2652SN/A 266695SN/A numCopiesStat 2672SN/A .name(name() + ".num_copies") 2682SN/A .desc("number of copy accesses completed") 2692SN/A ; 2702SN/A} 2712SN/A 2722SN/Avoid 2732SN/AMemTest::tick() 2742SN/A{ 2752SN/A if (!tickEvent.scheduled()) 2767823Ssteve.reinhardt@amd.com schedule(tickEvent, curTick() + ticks(1)); 2772SN/A 2781298SN/A if (++noResponseCycles >= 500000) { 2797544SN/A if (issueDmas) { 2807544SN/A cerr << "DMA tester "; 2817544SN/A } 2827823Ssteve.reinhardt@amd.com cerr << name() << ": deadlocked at cycle " << curTick() << endl; 2832SN/A fatal(""); 2842SN/A } 2852SN/A 2867544SN/A if (accessRetry || (issueDmas && dmaOutstanding)) { 2877544SN/A DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n"); 2882SN/A return; 2892SN/A } 2902SN/A 2912SN/A //make new request 2921899SN/A unsigned cmd = random() % 100; 2931899SN/A unsigned offset = random() % size; 2942SN/A unsigned base = random() % 2; 2952SN/A uint64_t data = random(); 2962SN/A unsigned access_size = random() % 4; 2975736SN/A bool uncacheable = (random() % 100) < percentUncacheable; 2982SN/A 2997544SN/A unsigned dma_access_size = random() % 4; 3007544SN/A 3011298SN/A //If we aren't doing copies, use id as offset, and do a false sharing 3021298SN/A //mem tester 3033187SN/A //We can eliminate the lower bits of the offset, and then use the id 3043187SN/A //to offset within the blks 3054628SN/A offset = blockAddr(offset); 3063187SN/A offset += id; 3073187SN/A access_size = 0; 3087544SN/A dma_access_size = 0; 3091298SN/A 3103187SN/A Request *req = new Request(); 3115736SN/A Request::Flags flags; 3123187SN/A Addr paddr; 3132SN/A 3145736SN/A if (uncacheable) { 3155736SN/A flags.set(Request::UNCACHEABLE); 3163187SN/A paddr = uncacheAddr + offset; 3177544SN/A } else { 3183187SN/A paddr = ((base) ? baseAddr1 : baseAddr2) + offset; 3192SN/A } 3207657Ssteve.reinhardt@amd.com bool do_functional = (random() % 100 < percentFunctional) && !uncacheable; 3212SN/A 3227544SN/A if (issueDmas) { 3237544SN/A paddr &= ~((1 << dma_access_size) - 1); 3247544SN/A req->setPhys(paddr, 1 << dma_access_size, flags); 3257544SN/A req->setThreadContext(id,0); 3267544SN/A } else { 3277544SN/A paddr &= ~((1 << access_size) - 1); 3287544SN/A req->setPhys(paddr, 1 << access_size, flags); 3297544SN/A req->setThreadContext(id,0); 3307544SN/A } 3317544SN/A assert(req->getSize() == 1); 3323187SN/A 3333187SN/A uint8_t *result = new uint8_t[8]; 3342SN/A 3352SN/A if (cmd < percentReads) { 3362SN/A // read 3371298SN/A 3384628SN/A // For now we only allow one outstanding request per address 3394628SN/A // per tester This means we assume CPU does write forwarding 3404628SN/A // to reads that alias something in the cpu store buffer. 3413282SN/A if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) { 3424203SN/A delete [] result; 3433282SN/A delete req; 3443282SN/A return; 3453282SN/A } 3464628SN/A 3474628SN/A outstandingAddrs.insert(paddr); 3481298SN/A 3493187SN/A // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin 3503187SN/A funcPort.readBlob(req->getPaddr(), result, req->getSize()); 3513187SN/A 3524628SN/A DPRINTF(MemTest, 3537657Ssteve.reinhardt@amd.com "id %d initiating %sread at addr %x (blk %x) expecting %x\n", 3547657Ssteve.reinhardt@amd.com id, do_functional ? "functional " : "", req->getPaddr(), 3557657Ssteve.reinhardt@amd.com blockAddr(req->getPaddr()), *result); 3563187SN/A 3574022SN/A PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 3584660SN/A pkt->setSrc(0); 3593187SN/A pkt->dataDynamicArray(new uint8_t[req->getSize()]); 3603187SN/A MemTestSenderState *state = new MemTestSenderState(result); 3613187SN/A pkt->senderState = state; 3623187SN/A 3637657Ssteve.reinhardt@amd.com if (do_functional) { 3648436SBrad.Beckmann@amd.com assert(pkt->needsResponse()); 3658436SBrad.Beckmann@amd.com pkt->setSuppressFuncError(); 3663187SN/A cachePort.sendFunctional(pkt); 3673204SN/A completeRequest(pkt); 368145SN/A } else { 3693262SN/A sendPkt(pkt); 370145SN/A } 3713187SN/A } else { 3722SN/A // write 3731298SN/A 3744628SN/A // For now we only allow one outstanding request per addreess 3754628SN/A // per tester. This means we assume CPU does write forwarding 3764628SN/A // to reads that alias something in the cpu store buffer. 3773282SN/A if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) { 3783283SN/A delete [] result; 3793282SN/A delete req; 3803282SN/A return; 3813282SN/A } 3823282SN/A 3834628SN/A outstandingAddrs.insert(paddr); 3841298SN/A 3857657Ssteve.reinhardt@amd.com DPRINTF(MemTest, "initiating %swrite at addr %x (blk %x) value %x\n", 3867657Ssteve.reinhardt@amd.com do_functional ? "functional " : "", req->getPaddr(), 3877657Ssteve.reinhardt@amd.com blockAddr(req->getPaddr()), data & 0xff); 3884628SN/A 3894022SN/A PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 3904660SN/A pkt->setSrc(0); 3913187SN/A uint8_t *pkt_data = new uint8_t[req->getSize()]; 3923187SN/A pkt->dataDynamicArray(pkt_data); 3933187SN/A memcpy(pkt_data, &data, req->getSize()); 3943187SN/A MemTestSenderState *state = new MemTestSenderState(result); 3953187SN/A pkt->senderState = state; 3963187SN/A 3977657Ssteve.reinhardt@amd.com if (do_functional) { 3988436SBrad.Beckmann@amd.com pkt->setSuppressFuncError(); 3993187SN/A cachePort.sendFunctional(pkt); 4003262SN/A completeRequest(pkt); 401145SN/A } else { 4023262SN/A sendPkt(pkt); 403145SN/A } 4043187SN/A } 4052SN/A} 4062SN/A 4072SN/Avoid 4083187SN/AMemTest::doRetry() 4092SN/A{ 4103187SN/A if (cachePort.sendTiming(retryPkt)) { 4117544SN/A DPRINTF(MemTest, "accessRetry setting to false\n"); 4123187SN/A accessRetry = false; 4133187SN/A retryPkt = NULL; 4143187SN/A } 4152SN/A} 4162SN/A 4175314SN/A 4185314SN/Avoid 4195314SN/AMemTest::printAddr(Addr a) 4205314SN/A{ 4215314SN/A cachePort.printAddr(a); 4225314SN/A} 4235315SN/A 4245315SN/A 4255315SN/AMemTest * 4265315SN/AMemTestParams::create() 4275315SN/A{ 4285315SN/A return new MemTest(this); 4295315SN/A} 430