12SN/A/* 214027Stiago.muck@arm.com * Copyright (c) 2015, 2019 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 4511793Sbrandon.potter@amd.com#include "cpu/testers/memtest/memtest.hh" 4611793Sbrandon.potter@amd.com 4710348Sandreas.hansson@arm.com#include "base/random.hh" 48146SN/A#include "base/statistics.hh" 4911800Sbrandon.potter@amd.com#include "base/trace.hh" 508232Snate@binkert.org#include "debug/MemTest.hh" 5110688Sandreas.hansson@arm.com#include "sim/sim_exit.hh" 52695SN/A#include "sim/stats.hh" 538832SAli.Saidi@ARM.com#include "sim/system.hh" 542SN/A 552SN/Ausing namespace std; 562SN/A 5710688Sandreas.hansson@arm.comunsigned int TESTER_ALLOCATOR = 0; 581298SN/A 593187SN/Abool 608975Sandreas.hansson@arm.comMemTest::CpuPort::recvTimingResp(PacketPtr pkt) 613187SN/A{ 6210688Sandreas.hansson@arm.com memtest.completeRequest(pkt); 633187SN/A return true; 643187SN/A} 653187SN/A 663187SN/Avoid 6710713Sandreas.hansson@arm.comMemTest::CpuPort::recvReqRetry() 683187SN/A{ 6910688Sandreas.hansson@arm.com memtest.recvRetry(); 703187SN/A} 713187SN/A 7210688Sandreas.hansson@arm.combool 733349SN/AMemTest::sendPkt(PacketPtr pkt) { 743262SN/A if (atomic) { 7510688Sandreas.hansson@arm.com port.sendAtomic(pkt); 763262SN/A completeRequest(pkt); 777544SN/A } else { 7810688Sandreas.hansson@arm.com if (!port.sendTimingReq(pkt)) { 7910688Sandreas.hansson@arm.com retryPkt = pkt; 8010688Sandreas.hansson@arm.com return false; 817544SN/A } 823262SN/A } 8310688Sandreas.hansson@arm.com return true; 843262SN/A} 853262SN/A 865034SN/AMemTest::MemTest(const Params *p) 8713892Sgabeblack@google.com : ClockedObject(p), 8812085Sspwilson2@wisc.edu tickEvent([this]{ tick(); }, name()), 8912085Sspwilson2@wisc.edu noRequestEvent([this]{ noRequest(); }, name()), 9012085Sspwilson2@wisc.edu noResponseEvent([this]{ noResponse(); }, name()), 9110688Sandreas.hansson@arm.com port("port", *this), 9210688Sandreas.hansson@arm.com retryPkt(nullptr), 9310688Sandreas.hansson@arm.com size(p->size), 9410688Sandreas.hansson@arm.com interval(p->interval), 955034SN/A percentReads(p->percent_reads), 965034SN/A percentFunctional(p->percent_functional), 975034SN/A percentUncacheable(p->percent_uncacheable), 9812680Sgiacomo.travaglini@arm.com masterId(p->system->getMasterId(this)), 9910688Sandreas.hansson@arm.com blockSize(p->system->cacheLineSize()), 10010688Sandreas.hansson@arm.com blockAddrMask(blockSize - 1), 1015034SN/A progressInterval(p->progress_interval), 10210688Sandreas.hansson@arm.com progressCheck(p->progress_check), 1035034SN/A nextProgressMessage(p->progress_interval), 1045034SN/A maxLoads(p->max_loads), 10510688Sandreas.hansson@arm.com atomic(p->system->isAtomicMode()), 10610688Sandreas.hansson@arm.com suppressFuncWarnings(p->suppress_func_warnings) 1072SN/A{ 1087544SN/A id = TESTER_ALLOCATOR++; 10910688Sandreas.hansson@arm.com fatal_if(id >= blockSize, "Too many testers, only %d allowed\n", 11010688Sandreas.hansson@arm.com blockSize - 1); 1117544SN/A 1122SN/A baseAddr1 = 0x100000; 1132SN/A baseAddr2 = 0x400000; 1142SN/A uncacheAddr = 0x800000; 1152SN/A 1162SN/A // set up counters 1172SN/A numReads = 0; 1188436SBrad.Beckmann@amd.com numWrites = 0; 1191298SN/A 12010688Sandreas.hansson@arm.com // kick things into action 12110688Sandreas.hansson@arm.com schedule(tickEvent, curTick()); 12210688Sandreas.hansson@arm.com schedule(noRequestEvent, clockEdge(progressCheck)); 1233187SN/A} 1243187SN/A 12513784Sgabeblack@google.comPort & 12613784Sgabeblack@google.comMemTest::getPort(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 13113892Sgabeblack@google.com return ClockedObject::getPort(if_name, idx); 1323187SN/A} 1333187SN/A 1343187SN/Avoid 13510688Sandreas.hansson@arm.comMemTest::completeRequest(PacketPtr pkt, bool functional) 1362SN/A{ 13712749Sgiacomo.travaglini@arm.com const RequestPtr &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 18810688Sandreas.hansson@arm.com // the packet will delete the data 1893187SN/A delete pkt; 19010688Sandreas.hansson@arm.com 19114027Stiago.muck@arm.com // finally shift the response timeout forward if we are still 19214027Stiago.muck@arm.com // expecting responses; deschedule it otherwise 19314027Stiago.muck@arm.com if (outstandingAddrs.size() != 0) 19414027Stiago.muck@arm.com reschedule(noResponseEvent, clockEdge(progressCheck)); 19514027Stiago.muck@arm.com else if (noResponseEvent.scheduled()) 19614027Stiago.muck@arm.com deschedule(noResponseEvent); 1972SN/A} 1982SN/A 1992SN/Avoid 2002SN/AMemTest::regStats() 2012SN/A{ 20213892Sgabeblack@google.com ClockedObject::regStats(); 20311523Sdavid.guillen@arm.com 204729SN/A using namespace Stats; 2052SN/A 206695SN/A numReadsStat 2072SN/A .name(name() + ".num_reads") 2082SN/A .desc("number of read accesses completed") 2092SN/A ; 2102SN/A 211695SN/A numWritesStat 2122SN/A .name(name() + ".num_writes") 2132SN/A .desc("number of write accesses completed") 2142SN/A ; 2152SN/A} 2162SN/A 2172SN/Avoid 2182SN/AMemTest::tick() 2192SN/A{ 22010688Sandreas.hansson@arm.com // we should never tick if we are waiting for a retry 22110688Sandreas.hansson@arm.com assert(!retryPkt); 2222SN/A 22310688Sandreas.hansson@arm.com // create a new request 22410348Sandreas.hansson@arm.com unsigned cmd = random_mt.random(0, 100); 22510688Sandreas.hansson@arm.com uint8_t data = random_mt.random<uint8_t>(); 22610688Sandreas.hansson@arm.com bool uncacheable = random_mt.random(0, 100) < percentUncacheable; 22710348Sandreas.hansson@arm.com unsigned base = random_mt.random(0, 1); 2285736SN/A Request::Flags flags; 2293187SN/A Addr paddr; 2302SN/A 23110688Sandreas.hansson@arm.com // generate a unique address 23210688Sandreas.hansson@arm.com do { 23310688Sandreas.hansson@arm.com unsigned offset = random_mt.random<unsigned>(0, size - 1); 2349301Snilay@cs.wisc.edu 23510688Sandreas.hansson@arm.com // use the tester id as offset within the block for false sharing 23610688Sandreas.hansson@arm.com offset = blockAlign(offset); 23710688Sandreas.hansson@arm.com offset += id; 23810688Sandreas.hansson@arm.com 23910688Sandreas.hansson@arm.com if (uncacheable) { 24010688Sandreas.hansson@arm.com flags.set(Request::UNCACHEABLE); 24110688Sandreas.hansson@arm.com paddr = uncacheAddr + offset; 24210688Sandreas.hansson@arm.com } else { 24310688Sandreas.hansson@arm.com paddr = ((base) ? baseAddr1 : baseAddr2) + offset; 24410688Sandreas.hansson@arm.com } 24510688Sandreas.hansson@arm.com } while (outstandingAddrs.find(paddr) != outstandingAddrs.end()); 2469301Snilay@cs.wisc.edu 24710348Sandreas.hansson@arm.com bool do_functional = (random_mt.random(0, 100) < percentFunctional) && 24810348Sandreas.hansson@arm.com !uncacheable; 24912749Sgiacomo.travaglini@arm.com RequestPtr req = std::make_shared<Request>(paddr, 1, flags, masterId); 25011435Smitch.hayenga@arm.com req->setContext(id); 2512SN/A 25210688Sandreas.hansson@arm.com outstandingAddrs.insert(paddr); 25310688Sandreas.hansson@arm.com 25410688Sandreas.hansson@arm.com // sanity check 25510688Sandreas.hansson@arm.com panic_if(outstandingAddrs.size() > 100, 25610688Sandreas.hansson@arm.com "Tester %s has more than 100 outstanding requests\n", name()); 25710688Sandreas.hansson@arm.com 25810688Sandreas.hansson@arm.com PacketPtr pkt = nullptr; 25910688Sandreas.hansson@arm.com uint8_t *pkt_data = new uint8_t[1]; 2603187SN/A 2612SN/A if (cmd < percentReads) { 26210688Sandreas.hansson@arm.com // start by ensuring there is a reference value if we have not 26310688Sandreas.hansson@arm.com // seen this address before 26410688Sandreas.hansson@arm.com uint8_t M5_VAR_USED ref_data = 0; 26510688Sandreas.hansson@arm.com auto ref = referenceData.find(req->getPaddr()); 26610688Sandreas.hansson@arm.com if (ref == referenceData.end()) { 26710688Sandreas.hansson@arm.com referenceData[req->getPaddr()] = 0; 26810688Sandreas.hansson@arm.com } else { 26910688Sandreas.hansson@arm.com ref_data = ref->second; 27010688Sandreas.hansson@arm.com } 2713187SN/A 2724628SN/A DPRINTF(MemTest, 27310688Sandreas.hansson@arm.com "Initiating %sread at addr %x (blk %x) expecting %x\n", 27410688Sandreas.hansson@arm.com do_functional ? "functional " : "", req->getPaddr(), 27510688Sandreas.hansson@arm.com blockAlign(req->getPaddr()), ref_data); 2763187SN/A 27710688Sandreas.hansson@arm.com pkt = new Packet(req, MemCmd::ReadReq); 27810688Sandreas.hansson@arm.com pkt->dataDynamic(pkt_data); 27910688Sandreas.hansson@arm.com } else { 28010688Sandreas.hansson@arm.com DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n", 28110688Sandreas.hansson@arm.com do_functional ? "functional " : "", req->getPaddr(), 28210688Sandreas.hansson@arm.com blockAlign(req->getPaddr()), data); 2833187SN/A 28410688Sandreas.hansson@arm.com pkt = new Packet(req, MemCmd::WriteReq); 28510688Sandreas.hansson@arm.com pkt->dataDynamic(pkt_data); 28610688Sandreas.hansson@arm.com pkt_data[0] = data; 28710688Sandreas.hansson@arm.com } 28810688Sandreas.hansson@arm.com 28910688Sandreas.hansson@arm.com // there is no point in ticking if we are waiting for a retry 29010688Sandreas.hansson@arm.com bool keep_ticking = true; 29110688Sandreas.hansson@arm.com if (do_functional) { 29210688Sandreas.hansson@arm.com pkt->setSuppressFuncError(); 29310688Sandreas.hansson@arm.com port.sendFunctional(pkt); 29410688Sandreas.hansson@arm.com completeRequest(pkt, true); 2953187SN/A } else { 29610688Sandreas.hansson@arm.com keep_ticking = sendPkt(pkt); 29710688Sandreas.hansson@arm.com } 2981298SN/A 29910688Sandreas.hansson@arm.com if (keep_ticking) { 30010688Sandreas.hansson@arm.com // schedule the next tick 30110688Sandreas.hansson@arm.com schedule(tickEvent, clockEdge(interval)); 3024628SN/A 30310688Sandreas.hansson@arm.com // finally shift the timeout for sending of requests forwards 30410688Sandreas.hansson@arm.com // as we have successfully sent a packet 30510688Sandreas.hansson@arm.com reschedule(noRequestEvent, clockEdge(progressCheck), true); 30610688Sandreas.hansson@arm.com } else { 30710688Sandreas.hansson@arm.com DPRINTF(MemTest, "Waiting for retry\n"); 3083187SN/A } 30914027Stiago.muck@arm.com 31014027Stiago.muck@arm.com // Schedule noResponseEvent now if we are expecting a response 31114027Stiago.muck@arm.com if (!noResponseEvent.scheduled() && (outstandingAddrs.size() != 0)) 31214027Stiago.muck@arm.com schedule(noResponseEvent, clockEdge(progressCheck)); 3132SN/A} 3142SN/A 3152SN/Avoid 31610688Sandreas.hansson@arm.comMemTest::noRequest() 3172SN/A{ 31810688Sandreas.hansson@arm.com panic("%s did not send a request for %d cycles", name(), progressCheck); 31910688Sandreas.hansson@arm.com} 32010688Sandreas.hansson@arm.com 32110688Sandreas.hansson@arm.comvoid 32210688Sandreas.hansson@arm.comMemTest::noResponse() 32310688Sandreas.hansson@arm.com{ 32410688Sandreas.hansson@arm.com panic("%s did not see a response for %d cycles", name(), progressCheck); 32510688Sandreas.hansson@arm.com} 32610688Sandreas.hansson@arm.com 32710688Sandreas.hansson@arm.comvoid 32810688Sandreas.hansson@arm.comMemTest::recvRetry() 32910688Sandreas.hansson@arm.com{ 33010688Sandreas.hansson@arm.com assert(retryPkt); 33110688Sandreas.hansson@arm.com if (port.sendTimingReq(retryPkt)) { 33210688Sandreas.hansson@arm.com DPRINTF(MemTest, "Proceeding after successful retry\n"); 33310688Sandreas.hansson@arm.com 33410688Sandreas.hansson@arm.com retryPkt = nullptr; 33510688Sandreas.hansson@arm.com // kick things into action again 33610688Sandreas.hansson@arm.com schedule(tickEvent, clockEdge(interval)); 33714027Stiago.muck@arm.com reschedule(noRequestEvent, clockEdge(progressCheck), true); 3383187SN/A } 3392SN/A} 3402SN/A 3415315SN/AMemTest * 3425315SN/AMemTestParams::create() 3435315SN/A{ 3445315SN/A return new MemTest(this); 3455315SN/A} 346