memtest.cc revision 13784:1941dc118243
16757SAli.Saidi@ARM.com/* 212495Sgiacomo.travaglini@arm.com * Copyright (c) 2015 ARM Limited 36757SAli.Saidi@ARM.com * All rights reserved 46757SAli.Saidi@ARM.com * 57111Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67111Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77111Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87111Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97111Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107111Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117111Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127111Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137111Sgblack@eecs.umich.edu * 146757SAli.Saidi@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 156757SAli.Saidi@ARM.com * All rights reserved. 166757SAli.Saidi@ARM.com * 176757SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 186757SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 196757SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 206757SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 216757SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 226757SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 236757SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 246757SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 256757SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 266757SAli.Saidi@ARM.com * this software without specific prior written permission. 276757SAli.Saidi@ARM.com * 286757SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 296757SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 306757SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 316757SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 326757SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 336757SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346757SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 356757SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 366757SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 376757SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386757SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 396735Sgblack@eecs.umich.edu * 4011793Sbrandon.potter@amd.com * Authors: Erik Hallnor 4111793Sbrandon.potter@amd.com * Steve Reinhardt 4210474Sandreas.hansson@arm.com * Andreas Hansson 436757SAli.Saidi@ARM.com */ 446757SAli.Saidi@ARM.com 457707Sgblack@eecs.umich.edu#include "cpu/testers/memtest/memtest.hh" 4610037SARM gem5 Developers 478782Sgblack@eecs.umich.edu#include "base/random.hh" 488782Sgblack@eecs.umich.edu#include "base/statistics.hh" 4911793Sbrandon.potter@amd.com#include "base/trace.hh" 508887Sgeoffrey.blake@arm.com#include "debug/MemTest.hh" 516757SAli.Saidi@ARM.com#include "mem/mem_object.hh" 528706Sandreas.hansson@arm.com#include "sim/sim_exit.hh" 538782Sgblack@eecs.umich.edu#include "sim/stats.hh" 547749SAli.Saidi@ARM.com#include "sim/system.hh" 556735Sgblack@eecs.umich.edu 566735Sgblack@eecs.umich.eduusing namespace std; 576735Sgblack@eecs.umich.edu 586735Sgblack@eecs.umich.eduunsigned int TESTER_ALLOCATOR = 0; 596735Sgblack@eecs.umich.edu 606735Sgblack@eecs.umich.edubool 619058Satgutier@umich.eduMemTest::CpuPort::recvTimingResp(PacketPtr pkt) 626735Sgblack@eecs.umich.edu{ 638886SAli.Saidi@ARM.com memtest.completeRequest(pkt); 6410474Sandreas.hansson@arm.com return true; 658286SAli.Saidi@ARM.com} 666735Sgblack@eecs.umich.edu 676735Sgblack@eecs.umich.eduvoid 687707Sgblack@eecs.umich.eduMemTest::CpuPort::recvReqRetry() 697707Sgblack@eecs.umich.edu{ 707707Sgblack@eecs.umich.edu memtest.recvRetry(); 718806Sgblack@eecs.umich.edu} 728806Sgblack@eecs.umich.edu 738806Sgblack@eecs.umich.edubool 748806Sgblack@eecs.umich.eduMemTest::sendPkt(PacketPtr pkt) { 758706Sandreas.hansson@arm.com if (atomic) { 767693SAli.Saidi@ARM.com port.sendAtomic(pkt); 777693SAli.Saidi@ARM.com completeRequest(pkt); 787693SAli.Saidi@ARM.com } else { 7910037SARM gem5 Developers if (!port.sendTimingReq(pkt)) { 8010037SARM gem5 Developers retryPkt = pkt; 8110037SARM gem5 Developers return false; 8210037SARM gem5 Developers } 8310037SARM gem5 Developers } 8410037SARM gem5 Developers return true; 857693SAli.Saidi@ARM.com} 8610037SARM gem5 Developers 877693SAli.Saidi@ARM.comMemTest::MemTest(const Params *p) 887693SAli.Saidi@ARM.com : MemObject(p), 8910037SARM gem5 Developers tickEvent([this]{ tick(); }, name()), 9010318Sandreas.hansson@arm.com noRequestEvent([this]{ noRequest(); }, name()), 9110037SARM gem5 Developers noResponseEvent([this]{ noResponse(); }, name()), 9210037SARM gem5 Developers port("port", *this), 9310037SARM gem5 Developers retryPkt(nullptr), 9410037SARM gem5 Developers size(p->size), 9510037SARM gem5 Developers interval(p->interval), 9610037SARM gem5 Developers percentReads(p->percent_reads), 9710037SARM gem5 Developers percentFunctional(p->percent_functional), 9810037SARM gem5 Developers percentUncacheable(p->percent_uncacheable), 9910037SARM gem5 Developers masterId(p->system->getMasterId(this)), 10010037SARM gem5 Developers blockSize(p->system->cacheLineSize()), 10110037SARM gem5 Developers blockAddrMask(blockSize - 1), 10210037SARM gem5 Developers progressInterval(p->progress_interval), 10310037SARM gem5 Developers progressCheck(p->progress_check), 10410037SARM gem5 Developers nextProgressMessage(p->progress_interval), 10510037SARM gem5 Developers maxLoads(p->max_loads), 10610037SARM gem5 Developers atomic(p->system->isAtomicMode()), 10710037SARM gem5 Developers suppressFuncWarnings(p->suppress_func_warnings) 10810037SARM gem5 Developers{ 10910037SARM gem5 Developers id = TESTER_ALLOCATOR++; 11010037SARM gem5 Developers fatal_if(id >= blockSize, "Too many testers, only %d allowed\n", 11110037SARM gem5 Developers blockSize - 1); 11210037SARM gem5 Developers 11310037SARM gem5 Developers baseAddr1 = 0x100000; 11410037SARM gem5 Developers baseAddr2 = 0x400000; 11510037SARM gem5 Developers uncacheAddr = 0x800000; 11610037SARM gem5 Developers 11710037SARM gem5 Developers // set up counters 11810037SARM gem5 Developers numReads = 0; 1197693SAli.Saidi@ARM.com numWrites = 0; 12010037SARM gem5 Developers 12110037SARM gem5 Developers // kick things into action 12210037SARM gem5 Developers schedule(tickEvent, curTick()); 12310037SARM gem5 Developers schedule(noRequestEvent, clockEdge(progressCheck)); 12410037SARM gem5 Developers schedule(noResponseEvent, clockEdge(progressCheck)); 1257693SAli.Saidi@ARM.com} 1267650SAli.Saidi@ARM.com 12710037SARM gem5 DevelopersPort & 1286757SAli.Saidi@ARM.comMemTest::getPort(const std::string &if_name, PortID idx) 1296757SAli.Saidi@ARM.com{ 1307693SAli.Saidi@ARM.com if (if_name == "port") 1317693SAli.Saidi@ARM.com return port; 1327693SAli.Saidi@ARM.com else 1339920Syasuko.eckert@amd.com return MemObject::getPort(if_name, idx); 13410037SARM gem5 Developers} 13510037SARM gem5 Developers 13610037SARM gem5 Developersvoid 13710037SARM gem5 DevelopersMemTest::completeRequest(PacketPtr pkt, bool functional) 13810037SARM gem5 Developers{ 1398887Sgeoffrey.blake@arm.com const RequestPtr &req = pkt->req; 1408887Sgeoffrey.blake@arm.com assert(req->getSize() == 1); 1418887Sgeoffrey.blake@arm.com 1428887Sgeoffrey.blake@arm.com // this address is no longer outstanding 1438887Sgeoffrey.blake@arm.com auto remove_addr = outstandingAddrs.find(req->getPaddr()); 1448887Sgeoffrey.blake@arm.com assert(remove_addr != outstandingAddrs.end()); 1458887Sgeoffrey.blake@arm.com outstandingAddrs.erase(remove_addr); 1467693SAli.Saidi@ARM.com 1477693SAli.Saidi@ARM.com DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n", 1487748SAli.Saidi@ARM.com pkt->isWrite() ? "write" : "read", 1497748SAli.Saidi@ARM.com req->getPaddr(), blockAlign(req->getPaddr()), 1507748SAli.Saidi@ARM.com pkt->isError() ? "error" : "success"); 1519920Syasuko.eckert@amd.com 1529431SAndreas.Sandberg@ARM.com const uint8_t *pkt_data = pkt->getConstPtr<uint8_t>(); 1538208SAli.Saidi@ARM.com 1549920Syasuko.eckert@amd.com if (pkt->isError()) { 15513500Sgabeblack@google.com if (!functional || !suppressFuncWarnings) { 1568208SAli.Saidi@ARM.com warn("%s access failed at %#x\n", 15712109SRekai.GonzalezAlberquilla@arm.com pkt->isWrite() ? "Write" : "Read", req->getPaddr()); 15812109SRekai.GonzalezAlberquilla@arm.com } 15912109SRekai.GonzalezAlberquilla@arm.com } else { 16010338SCurtis.Dunham@arm.com if (pkt->isRead()) { 16110338SCurtis.Dunham@arm.com uint8_t ref_data = referenceData[req->getPaddr()]; 1629920Syasuko.eckert@amd.com if (pkt_data[0] != ref_data) { 1639920Syasuko.eckert@amd.com panic("%s: read of %x (blk %x) @ cycle %d " 1647748SAli.Saidi@ARM.com "returns %x, expected %x\n", name(), 1656759SAli.Saidi@ARM.com req->getPaddr(), blockAlign(req->getPaddr()), curTick(), 1667748SAli.Saidi@ARM.com pkt_data[0], ref_data); 1677748SAli.Saidi@ARM.com } 1687748SAli.Saidi@ARM.com 1697748SAli.Saidi@ARM.com numReads++; 1707749SAli.Saidi@ARM.com numReadsStat++; 1717748SAli.Saidi@ARM.com 1727749SAli.Saidi@ARM.com if (numReads == (uint64_t)nextProgressMessage) { 1737749SAli.Saidi@ARM.com ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n", 17412406Sgabeblack@google.com name(), numReads, numWrites, curTick()); 17512406Sgabeblack@google.com nextProgressMessage += progressInterval; 1766759SAli.Saidi@ARM.com } 1777752SWilliam.Wang@arm.com 17810037SARM gem5 Developers if (maxLoads != 0 && numReads >= maxLoads) 17910037SARM gem5 Developers exitSimLoop("maximum number of loads reached"); 18010037SARM gem5 Developers } else { 18110037SARM gem5 Developers assert(pkt->isWrite()); 18210037SARM gem5 Developers 18310037SARM gem5 Developers // update the reference data 18410037SARM gem5 Developers referenceData[req->getPaddr()] = pkt_data[0]; 18510037SARM gem5 Developers numWrites++; 18610037SARM gem5 Developers numWritesStat++; 18712495Sgiacomo.travaglini@arm.com } 18812495Sgiacomo.travaglini@arm.com } 18912495Sgiacomo.travaglini@arm.com 19012495Sgiacomo.travaglini@arm.com // the packet will delete the data 19112495Sgiacomo.travaglini@arm.com delete pkt; 19212495Sgiacomo.travaglini@arm.com 19312495Sgiacomo.travaglini@arm.com // finally shift the response timeout forward 19410037SARM gem5 Developers reschedule(noResponseEvent, clockEdge(progressCheck), true); 19510037SARM gem5 Developers} 19610037SARM gem5 Developers 19710037SARM gem5 Developersvoid 19810037SARM gem5 DevelopersMemTest::regStats() 19910037SARM gem5 Developers{ 20010037SARM gem5 Developers MemObject::regStats(); 20110037SARM gem5 Developers 20210037SARM gem5 Developers using namespace Stats; 20310037SARM gem5 Developers 20410037SARM gem5 Developers numReadsStat 20510037SARM gem5 Developers .name(name() + ".num_reads") 20610037SARM gem5 Developers .desc("number of read accesses completed") 20710037SARM gem5 Developers ; 20813550Sgiacomo.travaglini@arm.com 20913550Sgiacomo.travaglini@arm.com numWritesStat 21013550Sgiacomo.travaglini@arm.com .name(name() + ".num_writes") 21113550Sgiacomo.travaglini@arm.com .desc("number of write accesses completed") 21213550Sgiacomo.travaglini@arm.com ; 21313550Sgiacomo.travaglini@arm.com} 21413550Sgiacomo.travaglini@arm.com 21513550Sgiacomo.travaglini@arm.comvoid 21613550Sgiacomo.travaglini@arm.comMemTest::tick() 21713550Sgiacomo.travaglini@arm.com{ 21813550Sgiacomo.travaglini@arm.com // we should never tick if we are waiting for a retry 21913550Sgiacomo.travaglini@arm.com assert(!retryPkt); 22013550Sgiacomo.travaglini@arm.com 22113550Sgiacomo.travaglini@arm.com // create a new request 22213550Sgiacomo.travaglini@arm.com unsigned cmd = random_mt.random(0, 100); 22313550Sgiacomo.travaglini@arm.com uint8_t data = random_mt.random<uint8_t>(); 22413550Sgiacomo.travaglini@arm.com bool uncacheable = random_mt.random(0, 100) < percentUncacheable; 22513550Sgiacomo.travaglini@arm.com unsigned base = random_mt.random(0, 1); 22613550Sgiacomo.travaglini@arm.com Request::Flags flags; 22713550Sgiacomo.travaglini@arm.com Addr paddr; 22813550Sgiacomo.travaglini@arm.com 22913550Sgiacomo.travaglini@arm.com // generate a unique address 23013550Sgiacomo.travaglini@arm.com do { 23113550Sgiacomo.travaglini@arm.com unsigned offset = random_mt.random<unsigned>(0, size - 1); 23213550Sgiacomo.travaglini@arm.com 23313550Sgiacomo.travaglini@arm.com // use the tester id as offset within the block for false sharing 23413550Sgiacomo.travaglini@arm.com offset = blockAlign(offset); 23513550Sgiacomo.travaglini@arm.com offset += id; 23613550Sgiacomo.travaglini@arm.com 23713550Sgiacomo.travaglini@arm.com if (uncacheable) { 23813550Sgiacomo.travaglini@arm.com flags.set(Request::UNCACHEABLE); 23910037SARM gem5 Developers paddr = uncacheAddr + offset; 24010037SARM gem5 Developers } else { 24110190Sakash.bagdia@arm.com paddr = ((base) ? baseAddr1 : baseAddr2) + offset; 24210190Sakash.bagdia@arm.com } 24310190Sakash.bagdia@arm.com } while (outstandingAddrs.find(paddr) != outstandingAddrs.end()); 24410190Sakash.bagdia@arm.com 24510190Sakash.bagdia@arm.com bool do_functional = (random_mt.random(0, 100) < percentFunctional) && 24610190Sakash.bagdia@arm.com !uncacheable; 24710190Sakash.bagdia@arm.com RequestPtr req = std::make_shared<Request>(paddr, 1, flags, masterId); 24810190Sakash.bagdia@arm.com req->setContext(id); 24910190Sakash.bagdia@arm.com 25010190Sakash.bagdia@arm.com outstandingAddrs.insert(paddr); 25110190Sakash.bagdia@arm.com 25210190Sakash.bagdia@arm.com // sanity check 25311294Sandreas.hansson@arm.com panic_if(outstandingAddrs.size() > 100, 25411149Smitch.hayenga@arm.com "Tester %s has more than 100 outstanding requests\n", name()); 25511149Smitch.hayenga@arm.com 25612712Sgiacomo.travaglini@arm.com PacketPtr pkt = nullptr; 25711149Smitch.hayenga@arm.com uint8_t *pkt_data = new uint8_t[1]; 25811149Smitch.hayenga@arm.com 25910037SARM gem5 Developers if (cmd < percentReads) { 26010190Sakash.bagdia@arm.com // start by ensuring there is a reference value if we have not 26110037SARM gem5 Developers // seen this address before 26210037SARM gem5 Developers uint8_t M5_VAR_USED ref_data = 0; 26310037SARM gem5 Developers auto ref = referenceData.find(req->getPaddr()); 26410190Sakash.bagdia@arm.com if (ref == referenceData.end()) { 26510037SARM gem5 Developers referenceData[req->getPaddr()] = 0; 26610037SARM gem5 Developers } else { 26710037SARM gem5 Developers ref_data = ref->second; 26810037SARM gem5 Developers } 26910037SARM gem5 Developers 27010037SARM gem5 Developers DPRINTF(MemTest, 27112494Schuan.zhu@arm.com "Initiating %sread at addr %x (blk %x) expecting %x\n", 27212494Schuan.zhu@arm.com do_functional ? "functional " : "", req->getPaddr(), 27310037SARM gem5 Developers blockAlign(req->getPaddr()), ref_data); 27412494Schuan.zhu@arm.com 27512494Schuan.zhu@arm.com pkt = new Packet(req, MemCmd::ReadReq); 27612494Schuan.zhu@arm.com pkt->dataDynamic(pkt_data); 27712496Sgiacomo.travaglini@arm.com } else { 27812496Sgiacomo.travaglini@arm.com DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n", 27912496Sgiacomo.travaglini@arm.com do_functional ? "functional " : "", req->getPaddr(), 28012496Sgiacomo.travaglini@arm.com blockAlign(req->getPaddr()), data); 28112496Sgiacomo.travaglini@arm.com 28212496Sgiacomo.travaglini@arm.com pkt = new Packet(req, MemCmd::WriteReq); 28312496Sgiacomo.travaglini@arm.com pkt->dataDynamic(pkt_data); 28412496Sgiacomo.travaglini@arm.com pkt_data[0] = data; 28512496Sgiacomo.travaglini@arm.com } 28612494Schuan.zhu@arm.com 28712494Schuan.zhu@arm.com // there is no point in ticking if we are waiting for a retry 28812494Schuan.zhu@arm.com bool keep_ticking = true; 28912494Schuan.zhu@arm.com if (do_functional) { 29012494Schuan.zhu@arm.com pkt->setSuppressFuncError(); 29112494Schuan.zhu@arm.com port.sendFunctional(pkt); 29212494Schuan.zhu@arm.com completeRequest(pkt, true); 29312496Sgiacomo.travaglini@arm.com } else { 29412496Sgiacomo.travaglini@arm.com keep_ticking = sendPkt(pkt); 29512496Sgiacomo.travaglini@arm.com } 29612496Sgiacomo.travaglini@arm.com 29712496Sgiacomo.travaglini@arm.com if (keep_ticking) { 29812496Sgiacomo.travaglini@arm.com // schedule the next tick 29912494Schuan.zhu@arm.com schedule(tickEvent, clockEdge(interval)); 30012496Sgiacomo.travaglini@arm.com 30112496Sgiacomo.travaglini@arm.com // finally shift the timeout for sending of requests forwards 30212494Schuan.zhu@arm.com // as we have successfully sent a packet 30312494Schuan.zhu@arm.com reschedule(noRequestEvent, clockEdge(progressCheck), true); 30412494Schuan.zhu@arm.com } else { 30512494Schuan.zhu@arm.com DPRINTF(MemTest, "Waiting for retry\n"); 30612494Schuan.zhu@arm.com } 30712494Schuan.zhu@arm.com} 30812495Sgiacomo.travaglini@arm.com 30912495Sgiacomo.travaglini@arm.comvoid 31012494Schuan.zhu@arm.comMemTest::noRequest() 31112494Schuan.zhu@arm.com{ 31212494Schuan.zhu@arm.com panic("%s did not send a request for %d cycles", name(), progressCheck); 31312496Sgiacomo.travaglini@arm.com} 31412494Schuan.zhu@arm.com 31512496Sgiacomo.travaglini@arm.comvoid 31612496Sgiacomo.travaglini@arm.comMemTest::noResponse() 31712496Sgiacomo.travaglini@arm.com{ 31812494Schuan.zhu@arm.com panic("%s did not see a response for %d cycles", name(), progressCheck); 31912496Sgiacomo.travaglini@arm.com} 32012496Sgiacomo.travaglini@arm.com 32112496Sgiacomo.travaglini@arm.comvoid 32210037SARM gem5 DevelopersMemTest::recvRetry() 32310037SARM gem5 Developers{ 32412496Sgiacomo.travaglini@arm.com assert(retryPkt); 32512496Sgiacomo.travaglini@arm.com if (port.sendTimingReq(retryPkt)) { 32610037SARM gem5 Developers DPRINTF(MemTest, "Proceeding after successful retry\n"); 32710037SARM gem5 Developers 32810037SARM gem5 Developers retryPkt = nullptr; 32910037SARM gem5 Developers // kick things into action again 33010037SARM gem5 Developers schedule(tickEvent, clockEdge(interval)); 33110037SARM gem5 Developers } 33210037SARM gem5 Developers} 33310037SARM gem5 Developers 33410037SARM gem5 DevelopersMemTest * 33510037SARM gem5 DevelopersMemTestParams::create() 33610037SARM gem5 Developers{ 33710037SARM gem5 Developers return new MemTest(this); 33810037SARM gem5 Developers} 33910037SARM gem5 Developers