memtest.cc revision 10713
12SN/A/* 210688Sandreas.hansson@arm.com * Copyright (c) 2015 ARM Limited 310688Sandreas.hansson@arm.com * All rights reserved 410688Sandreas.hansson@arm.com * 510688Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 610688Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 710688Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 810688Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 910688Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 1010688Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 1110688Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 1210688Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 1310688Sandreas.hansson@arm.com * 141762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 152SN/A * All rights reserved. 162SN/A * 172SN/A * Redistribution and use in source and binary forms, with or without 182SN/A * modification, are permitted provided that the following conditions are 192SN/A * met: redistributions of source code must retain the above copyright 202SN/A * notice, this list of conditions and the following disclaimer; 212SN/A * redistributions in binary form must reproduce the above copyright 222SN/A * notice, this list of conditions and the following disclaimer in the 232SN/A * documentation and/or other materials provided with the distribution; 242SN/A * neither the name of the copyright holders nor the names of its 252SN/A * contributors may be used to endorse or promote products derived from 262SN/A * this software without specific prior written permission. 272SN/A * 282SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665SN/A * 402665SN/A * Authors: Erik Hallnor 412665SN/A * Steve Reinhardt 4210688Sandreas.hansson@arm.com * Andreas Hansson 432SN/A */ 442SN/A 4510348Sandreas.hansson@arm.com#include "base/random.hh" 46146SN/A#include "base/statistics.hh" 477632SBrad.Beckmann@amd.com#include "cpu/testers/memtest/memtest.hh" 488232Snate@binkert.org#include "debug/MemTest.hh" 493348SN/A#include "mem/mem_object.hh" 5010688Sandreas.hansson@arm.com#include "sim/sim_exit.hh" 51695SN/A#include "sim/stats.hh" 528832SAli.Saidi@ARM.com#include "sim/system.hh" 532SN/A 542SN/Ausing namespace std; 552SN/A 5610688Sandreas.hansson@arm.comunsigned int TESTER_ALLOCATOR = 0; 571298SN/A 583187SN/Abool 598975Sandreas.hansson@arm.comMemTest::CpuPort::recvTimingResp(PacketPtr pkt) 603187SN/A{ 6110688Sandreas.hansson@arm.com memtest.completeRequest(pkt); 623187SN/A return true; 633187SN/A} 643187SN/A 653187SN/Avoid 6610713Sandreas.hansson@arm.comMemTest::CpuPort::recvReqRetry() 673187SN/A{ 6810688Sandreas.hansson@arm.com memtest.recvRetry(); 693187SN/A} 703187SN/A 7110688Sandreas.hansson@arm.combool 723349SN/AMemTest::sendPkt(PacketPtr pkt) { 733262SN/A if (atomic) { 7410688Sandreas.hansson@arm.com port.sendAtomic(pkt); 753262SN/A completeRequest(pkt); 767544SN/A } else { 7710688Sandreas.hansson@arm.com if (!port.sendTimingReq(pkt)) { 7810688Sandreas.hansson@arm.com retryPkt = pkt; 7910688Sandreas.hansson@arm.com return false; 807544SN/A } 813262SN/A } 8210688Sandreas.hansson@arm.com return true; 833262SN/A} 843262SN/A 855034SN/AMemTest::MemTest(const Params *p) 865034SN/A : MemObject(p), 872SN/A tickEvent(this), 8810688Sandreas.hansson@arm.com noRequestEvent(this), 8910688Sandreas.hansson@arm.com noResponseEvent(this), 9010688Sandreas.hansson@arm.com port("port", *this), 9110688Sandreas.hansson@arm.com retryPkt(nullptr), 9210688Sandreas.hansson@arm.com size(p->size), 9310688Sandreas.hansson@arm.com interval(p->interval), 945034SN/A percentReads(p->percent_reads), 955034SN/A percentFunctional(p->percent_functional), 965034SN/A percentUncacheable(p->percent_uncacheable), 9710688Sandreas.hansson@arm.com masterId(p->system->getMasterId(name())), 9810688Sandreas.hansson@arm.com blockSize(p->system->cacheLineSize()), 9910688Sandreas.hansson@arm.com blockAddrMask(blockSize - 1), 1005034SN/A progressInterval(p->progress_interval), 10110688Sandreas.hansson@arm.com progressCheck(p->progress_check), 1025034SN/A nextProgressMessage(p->progress_interval), 1035034SN/A maxLoads(p->max_loads), 10410688Sandreas.hansson@arm.com atomic(p->system->isAtomicMode()), 10510688Sandreas.hansson@arm.com suppressFuncWarnings(p->suppress_func_warnings) 1062SN/A{ 1077544SN/A id = TESTER_ALLOCATOR++; 10810688Sandreas.hansson@arm.com fatal_if(id >= blockSize, "Too many testers, only %d allowed\n", 10910688Sandreas.hansson@arm.com blockSize - 1); 1107544SN/A 1112SN/A baseAddr1 = 0x100000; 1122SN/A baseAddr2 = 0x400000; 1132SN/A uncacheAddr = 0x800000; 1142SN/A 1152SN/A // set up counters 1162SN/A numReads = 0; 1178436SBrad.Beckmann@amd.com numWrites = 0; 1181298SN/A 11910688Sandreas.hansson@arm.com // kick things into action 12010688Sandreas.hansson@arm.com schedule(tickEvent, curTick()); 12110688Sandreas.hansson@arm.com schedule(noRequestEvent, clockEdge(progressCheck)); 12210688Sandreas.hansson@arm.com schedule(noResponseEvent, clockEdge(progressCheck)); 1233187SN/A} 1243187SN/A 1259294Sandreas.hansson@arm.comBaseMasterPort & 1269294Sandreas.hansson@arm.comMemTest::getMasterPort(const std::string &if_name, PortID idx) 1273187SN/A{ 12810688Sandreas.hansson@arm.com if (if_name == "port") 12910688Sandreas.hansson@arm.com return port; 1303187SN/A else 1318922Swilliam.wang@arm.com return MemObject::getMasterPort(if_name, idx); 1323187SN/A} 1333187SN/A 1343187SN/Avoid 13510688Sandreas.hansson@arm.comMemTest::completeRequest(PacketPtr pkt, bool functional) 1362SN/A{ 1374628SN/A Request *req = pkt->req; 13810688Sandreas.hansson@arm.com assert(req->getSize() == 1); 1394628SN/A 14010688Sandreas.hansson@arm.com // this address is no longer outstanding 14110688Sandreas.hansson@arm.com auto remove_addr = outstandingAddrs.find(req->getPaddr()); 14210688Sandreas.hansson@arm.com assert(remove_addr != outstandingAddrs.end()); 14310688Sandreas.hansson@arm.com outstandingAddrs.erase(remove_addr); 1447544SN/A 14510688Sandreas.hansson@arm.com DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n", 1464628SN/A pkt->isWrite() ? "write" : "read", 14710688Sandreas.hansson@arm.com req->getPaddr(), blockAlign(req->getPaddr()), 1488436SBrad.Beckmann@amd.com pkt->isError() ? "error" : "success"); 1494628SN/A 15010688Sandreas.hansson@arm.com const uint8_t *pkt_data = pkt->getConstPtr<uint8_t>(); 1511298SN/A 1528436SBrad.Beckmann@amd.com if (pkt->isError()) { 15310688Sandreas.hansson@arm.com if (!functional || !suppressFuncWarnings) { 15410688Sandreas.hansson@arm.com warn("%s access failed at %#x\n", 15510688Sandreas.hansson@arm.com pkt->isWrite() ? "Write" : "Read", req->getPaddr()); 1562SN/A } 1578436SBrad.Beckmann@amd.com } else { 1588436SBrad.Beckmann@amd.com if (pkt->isRead()) { 15910688Sandreas.hansson@arm.com uint8_t ref_data = referenceData[req->getPaddr()]; 16010688Sandreas.hansson@arm.com if (pkt_data[0] != ref_data) { 1618436SBrad.Beckmann@amd.com panic("%s: read of %x (blk %x) @ cycle %d " 1628436SBrad.Beckmann@amd.com "returns %x, expected %x\n", name(), 16310688Sandreas.hansson@arm.com req->getPaddr(), blockAlign(req->getPaddr()), curTick(), 16410688Sandreas.hansson@arm.com pkt_data[0], ref_data); 1658436SBrad.Beckmann@amd.com } 1662SN/A 1678436SBrad.Beckmann@amd.com numReads++; 1688436SBrad.Beckmann@amd.com numReadsStat++; 1692SN/A 1708436SBrad.Beckmann@amd.com if (numReads == (uint64_t)nextProgressMessage) { 1718436SBrad.Beckmann@amd.com ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n", 1728436SBrad.Beckmann@amd.com name(), numReads, numWrites, curTick()); 1738436SBrad.Beckmann@amd.com nextProgressMessage += progressInterval; 1748436SBrad.Beckmann@amd.com } 1758436SBrad.Beckmann@amd.com 1768436SBrad.Beckmann@amd.com if (maxLoads != 0 && numReads >= maxLoads) 1778436SBrad.Beckmann@amd.com exitSimLoop("maximum number of loads reached"); 1788436SBrad.Beckmann@amd.com } else { 1798436SBrad.Beckmann@amd.com assert(pkt->isWrite()); 18010688Sandreas.hansson@arm.com 18110688Sandreas.hansson@arm.com // update the reference data 18210688Sandreas.hansson@arm.com referenceData[req->getPaddr()] = pkt_data[0]; 1838436SBrad.Beckmann@amd.com numWrites++; 1848436SBrad.Beckmann@amd.com numWritesStat++; 1852SN/A } 1862SN/A } 1872SN/A 1883187SN/A delete pkt->req; 18910688Sandreas.hansson@arm.com 19010688Sandreas.hansson@arm.com // the packet will delete the data 1913187SN/A delete pkt; 19210688Sandreas.hansson@arm.com 19310688Sandreas.hansson@arm.com // finally shift the response timeout forward 19410688Sandreas.hansson@arm.com reschedule(noResponseEvent, clockEdge(progressCheck), true); 1952SN/A} 1962SN/A 1972SN/Avoid 1982SN/AMemTest::regStats() 1992SN/A{ 200729SN/A using namespace Stats; 2012SN/A 202695SN/A numReadsStat 2032SN/A .name(name() + ".num_reads") 2042SN/A .desc("number of read accesses completed") 2052SN/A ; 2062SN/A 207695SN/A numWritesStat 2082SN/A .name(name() + ".num_writes") 2092SN/A .desc("number of write accesses completed") 2102SN/A ; 2112SN/A} 2122SN/A 2132SN/Avoid 2142SN/AMemTest::tick() 2152SN/A{ 21610688Sandreas.hansson@arm.com // we should never tick if we are waiting for a retry 21710688Sandreas.hansson@arm.com assert(!retryPkt); 2182SN/A 21910688Sandreas.hansson@arm.com // create a new request 22010348Sandreas.hansson@arm.com unsigned cmd = random_mt.random(0, 100); 22110688Sandreas.hansson@arm.com uint8_t data = random_mt.random<uint8_t>(); 22210688Sandreas.hansson@arm.com bool uncacheable = random_mt.random(0, 100) < percentUncacheable; 22310348Sandreas.hansson@arm.com unsigned base = random_mt.random(0, 1); 2245736SN/A Request::Flags flags; 2253187SN/A Addr paddr; 2262SN/A 22710688Sandreas.hansson@arm.com // generate a unique address 22810688Sandreas.hansson@arm.com do { 22910688Sandreas.hansson@arm.com unsigned offset = random_mt.random<unsigned>(0, size - 1); 2309301Snilay@cs.wisc.edu 23110688Sandreas.hansson@arm.com // use the tester id as offset within the block for false sharing 23210688Sandreas.hansson@arm.com offset = blockAlign(offset); 23310688Sandreas.hansson@arm.com offset += id; 23410688Sandreas.hansson@arm.com 23510688Sandreas.hansson@arm.com if (uncacheable) { 23610688Sandreas.hansson@arm.com flags.set(Request::UNCACHEABLE); 23710688Sandreas.hansson@arm.com paddr = uncacheAddr + offset; 23810688Sandreas.hansson@arm.com } else { 23910688Sandreas.hansson@arm.com paddr = ((base) ? baseAddr1 : baseAddr2) + offset; 24010688Sandreas.hansson@arm.com } 24110688Sandreas.hansson@arm.com } while (outstandingAddrs.find(paddr) != outstandingAddrs.end()); 2429301Snilay@cs.wisc.edu 24310348Sandreas.hansson@arm.com bool do_functional = (random_mt.random(0, 100) < percentFunctional) && 24410348Sandreas.hansson@arm.com !uncacheable; 24510688Sandreas.hansson@arm.com Request *req = new Request(paddr, 1, flags, masterId); 24610688Sandreas.hansson@arm.com req->setThreadContext(id, 0); 2472SN/A 24810688Sandreas.hansson@arm.com outstandingAddrs.insert(paddr); 24910688Sandreas.hansson@arm.com 25010688Sandreas.hansson@arm.com // sanity check 25110688Sandreas.hansson@arm.com panic_if(outstandingAddrs.size() > 100, 25210688Sandreas.hansson@arm.com "Tester %s has more than 100 outstanding requests\n", name()); 25310688Sandreas.hansson@arm.com 25410688Sandreas.hansson@arm.com PacketPtr pkt = nullptr; 25510688Sandreas.hansson@arm.com uint8_t *pkt_data = new uint8_t[1]; 2563187SN/A 2572SN/A if (cmd < percentReads) { 25810688Sandreas.hansson@arm.com // start by ensuring there is a reference value if we have not 25910688Sandreas.hansson@arm.com // seen this address before 26010688Sandreas.hansson@arm.com uint8_t M5_VAR_USED ref_data = 0; 26110688Sandreas.hansson@arm.com auto ref = referenceData.find(req->getPaddr()); 26210688Sandreas.hansson@arm.com if (ref == referenceData.end()) { 26310688Sandreas.hansson@arm.com referenceData[req->getPaddr()] = 0; 26410688Sandreas.hansson@arm.com } else { 26510688Sandreas.hansson@arm.com ref_data = ref->second; 26610688Sandreas.hansson@arm.com } 2673187SN/A 2684628SN/A DPRINTF(MemTest, 26910688Sandreas.hansson@arm.com "Initiating %sread at addr %x (blk %x) expecting %x\n", 27010688Sandreas.hansson@arm.com do_functional ? "functional " : "", req->getPaddr(), 27110688Sandreas.hansson@arm.com blockAlign(req->getPaddr()), ref_data); 2723187SN/A 27310688Sandreas.hansson@arm.com pkt = new Packet(req, MemCmd::ReadReq); 27410688Sandreas.hansson@arm.com pkt->dataDynamic(pkt_data); 27510688Sandreas.hansson@arm.com } else { 27610688Sandreas.hansson@arm.com DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n", 27710688Sandreas.hansson@arm.com do_functional ? "functional " : "", req->getPaddr(), 27810688Sandreas.hansson@arm.com blockAlign(req->getPaddr()), data); 2793187SN/A 28010688Sandreas.hansson@arm.com pkt = new Packet(req, MemCmd::WriteReq); 28110688Sandreas.hansson@arm.com pkt->dataDynamic(pkt_data); 28210688Sandreas.hansson@arm.com pkt_data[0] = data; 28310688Sandreas.hansson@arm.com } 28410688Sandreas.hansson@arm.com 28510688Sandreas.hansson@arm.com // there is no point in ticking if we are waiting for a retry 28610688Sandreas.hansson@arm.com bool keep_ticking = true; 28710688Sandreas.hansson@arm.com if (do_functional) { 28810688Sandreas.hansson@arm.com pkt->setSuppressFuncError(); 28910688Sandreas.hansson@arm.com port.sendFunctional(pkt); 29010688Sandreas.hansson@arm.com completeRequest(pkt, true); 2913187SN/A } else { 29210688Sandreas.hansson@arm.com keep_ticking = sendPkt(pkt); 29310688Sandreas.hansson@arm.com } 2941298SN/A 29510688Sandreas.hansson@arm.com if (keep_ticking) { 29610688Sandreas.hansson@arm.com // schedule the next tick 29710688Sandreas.hansson@arm.com schedule(tickEvent, clockEdge(interval)); 2984628SN/A 29910688Sandreas.hansson@arm.com // finally shift the timeout for sending of requests forwards 30010688Sandreas.hansson@arm.com // as we have successfully sent a packet 30110688Sandreas.hansson@arm.com reschedule(noRequestEvent, clockEdge(progressCheck), true); 30210688Sandreas.hansson@arm.com } else { 30310688Sandreas.hansson@arm.com DPRINTF(MemTest, "Waiting for retry\n"); 3043187SN/A } 3052SN/A} 3062SN/A 3072SN/Avoid 30810688Sandreas.hansson@arm.comMemTest::noRequest() 3092SN/A{ 31010688Sandreas.hansson@arm.com panic("%s did not send a request for %d cycles", name(), progressCheck); 31110688Sandreas.hansson@arm.com} 31210688Sandreas.hansson@arm.com 31310688Sandreas.hansson@arm.comvoid 31410688Sandreas.hansson@arm.comMemTest::noResponse() 31510688Sandreas.hansson@arm.com{ 31610688Sandreas.hansson@arm.com panic("%s did not see a response for %d cycles", name(), progressCheck); 31710688Sandreas.hansson@arm.com} 31810688Sandreas.hansson@arm.com 31910688Sandreas.hansson@arm.comvoid 32010688Sandreas.hansson@arm.comMemTest::recvRetry() 32110688Sandreas.hansson@arm.com{ 32210688Sandreas.hansson@arm.com assert(retryPkt); 32310688Sandreas.hansson@arm.com if (port.sendTimingReq(retryPkt)) { 32410688Sandreas.hansson@arm.com DPRINTF(MemTest, "Proceeding after successful retry\n"); 32510688Sandreas.hansson@arm.com 32610688Sandreas.hansson@arm.com retryPkt = nullptr; 32710688Sandreas.hansson@arm.com // kick things into action again 32810688Sandreas.hansson@arm.com schedule(tickEvent, clockEdge(interval)); 3293187SN/A } 3302SN/A} 3312SN/A 3325315SN/AMemTest * 3335315SN/AMemTestParams::create() 3345315SN/A{ 3355315SN/A return new MemTest(this); 3365315SN/A} 337