memtest.cc revision 7632
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" 423348SN/A#include "mem/mem_object.hh" 433348SN/A#include "mem/port.hh" 443348SN/A#include "mem/packet.hh" 453348SN/A#include "mem/request.hh" 4656SN/A#include "sim/sim_events.hh" 47695SN/A#include "sim/stats.hh" 482SN/A 492SN/Ausing namespace std; 502SN/A 511298SN/Aint TESTER_ALLOCATOR=0; 521298SN/A 533187SN/Abool 543349SN/AMemTest::CpuPort::recvTiming(PacketPtr pkt) 553187SN/A{ 564898SN/A if (pkt->isResponse()) { 574898SN/A memtest->completeRequest(pkt); 584898SN/A } else { 594898SN/A // must be snoop upcall 604898SN/A assert(pkt->isRequest()); 614898SN/A assert(pkt->getDest() == Packet::Broadcast); 624898SN/A } 633187SN/A return true; 643187SN/A} 653187SN/A 663187SN/ATick 673349SN/AMemTest::CpuPort::recvAtomic(PacketPtr pkt) 683187SN/A{ 694895SN/A // must be snoop upcall 704895SN/A assert(pkt->isRequest()); 714895SN/A assert(pkt->getDest() == Packet::Broadcast); 723187SN/A return curTick; 733187SN/A} 743187SN/A 753187SN/Avoid 763349SN/AMemTest::CpuPort::recvFunctional(PacketPtr pkt) 773187SN/A{ 783204SN/A //Do nothing if we see one come through 793340SN/A// if (curTick != 0)//Supress warning durring initialization 803340SN/A// warn("Functional Writes not implemented in MemTester\n"); 813262SN/A //Need to find any response values that intersect and update 823204SN/A return; 833187SN/A} 843187SN/A 853187SN/Avoid 863187SN/AMemTest::CpuPort::recvStatusChange(Status status) 873187SN/A{ 883647SN/A if (status == RangeChange) { 893647SN/A if (!snoopRangeSent) { 903647SN/A snoopRangeSent = true; 913647SN/A sendStatusChange(Port::RangeChange); 923647SN/A } 933187SN/A return; 943647SN/A } 953187SN/A 963187SN/A panic("MemTest doesn't expect recvStatusChange callback!"); 973187SN/A} 983187SN/A 993187SN/Avoid 1003187SN/AMemTest::CpuPort::recvRetry() 1013187SN/A{ 1023187SN/A memtest->doRetry(); 1033187SN/A} 1043187SN/A 1053262SN/Avoid 1063349SN/AMemTest::sendPkt(PacketPtr pkt) { 1073262SN/A if (atomic) { 1083262SN/A cachePort.sendAtomic(pkt); 1093262SN/A completeRequest(pkt); 1103262SN/A } 1113262SN/A else if (!cachePort.sendTiming(pkt)) { 1127544SN/A DPRINTF(MemTest, "accessRetry setting to true\n"); 1137544SN/A 1147544SN/A // 1157544SN/A // dma requests should never be retried 1167544SN/A // 1177544SN/A if (issueDmas) { 1187544SN/A panic("Nacked DMA requests are not supported\n"); 1197544SN/A } 1203262SN/A accessRetry = true; 1213262SN/A retryPkt = pkt; 1227544SN/A } else { 1237544SN/A if (issueDmas) { 1247544SN/A dmaOutstanding = true; 1257544SN/A } 1263262SN/A } 1273262SN/A 1283262SN/A} 1293262SN/A 1305034SN/AMemTest::MemTest(const Params *p) 1315034SN/A : MemObject(p), 1322SN/A tickEvent(this), 1333187SN/A cachePort("test", this), 1343187SN/A funcPort("functional", this), 1353187SN/A retryPkt(NULL), 1363187SN/A// mainMem(main_mem), 1373187SN/A// checkMem(check_mem), 1385034SN/A size(p->memory_size), 1395034SN/A percentReads(p->percent_reads), 1405034SN/A percentFunctional(p->percent_functional), 1415034SN/A percentUncacheable(p->percent_uncacheable), 1427544SN/A issueDmas(p->issue_dmas), 1435034SN/A progressInterval(p->progress_interval), 1445034SN/A nextProgressMessage(p->progress_interval), 1455034SN/A percentSourceUnaligned(p->percent_source_unaligned), 1465034SN/A percentDestUnaligned(p->percent_dest_unaligned), 1475034SN/A maxLoads(p->max_loads), 1485034SN/A atomic(p->atomic) 1492SN/A{ 1507544SN/A 1512SN/A vector<string> cmd; 1522SN/A cmd.push_back("/bin/ls"); 1532SN/A vector<string> null_vec; 1543187SN/A // thread = new SimpleThread(NULL, 0, NULL, 0, mainMem); 1552SN/A curTick = 0; 1562SN/A 1573647SN/A cachePort.snoopRangeSent = false; 1583647SN/A funcPort.snoopRangeSent = true; 1593647SN/A 1607544SN/A id = TESTER_ALLOCATOR++; 1617544SN/A 1623187SN/A // Needs to be masked off once we know the block size. 1635034SN/A traceBlockAddr = p->trace_addr; 1642SN/A baseAddr1 = 0x100000; 1652SN/A baseAddr2 = 0x400000; 1662SN/A uncacheAddr = 0x800000; 1672SN/A 1682SN/A // set up counters 1692SN/A noResponseCycles = 0; 1702SN/A numReads = 0; 1715606SN/A schedule(tickEvent, 0); 1721298SN/A 1733187SN/A accessRetry = false; 1747544SN/A dmaOutstanding = false; 1753187SN/A} 1763187SN/A 1773187SN/APort * 1783187SN/AMemTest::getPort(const std::string &if_name, int idx) 1793187SN/A{ 1803187SN/A if (if_name == "functional") 1813187SN/A return &funcPort; 1823187SN/A else if (if_name == "test") 1833187SN/A return &cachePort; 1843187SN/A else 1853187SN/A panic("No Such Port\n"); 1863187SN/A} 1873187SN/A 1883187SN/Avoid 1893187SN/AMemTest::init() 1903187SN/A{ 1913187SN/A // By the time init() is called, the ports should be hooked up. 1923187SN/A blockSize = cachePort.peerBlockSize(); 1933187SN/A blockAddrMask = blockSize - 1; 1943187SN/A traceBlockAddr = blockAddr(traceBlockAddr); 1953187SN/A 1964579SN/A // initial memory contents for both physical memory and functional 1974579SN/A // memory should be 0; no need to initialize them. 1982SN/A} 1992SN/A 2002SN/A 2012SN/Avoid 2023349SN/AMemTest::completeRequest(PacketPtr pkt) 2032SN/A{ 2044628SN/A Request *req = pkt->req; 2054628SN/A 2067544SN/A if (issueDmas) { 2077544SN/A dmaOutstanding = false; 2087544SN/A } 2097544SN/A 2104628SN/A DPRINTF(MemTest, "completing %s at address %x (blk %x)\n", 2114628SN/A pkt->isWrite() ? "write" : "read", 2124628SN/A req->getPaddr(), blockAddr(req->getPaddr())); 2134628SN/A 2143187SN/A MemTestSenderState *state = 2153187SN/A dynamic_cast<MemTestSenderState *>(pkt->senderState); 2163187SN/A 2173187SN/A uint8_t *data = state->data; 2183187SN/A uint8_t *pkt_data = pkt->getPtr<uint8_t>(); 2193187SN/A 2201298SN/A //Remove the address from the list of outstanding 2214628SN/A std::set<unsigned>::iterator removeAddr = 2224628SN/A outstandingAddrs.find(req->getPaddr()); 2231298SN/A assert(removeAddr != outstandingAddrs.end()); 2241298SN/A outstandingAddrs.erase(removeAddr); 2251298SN/A 2265319SN/A assert(pkt->isResponse()); 2273187SN/A 2285319SN/A if (pkt->isRead()) { 2293187SN/A if (memcmp(pkt_data, data, pkt->getSize()) != 0) { 2304626SN/A panic("%s: read of %x (blk %x) @ cycle %d " 2314626SN/A "returns %x, expected %x\n", name(), 2324626SN/A req->getPaddr(), blockAddr(req->getPaddr()), curTick, 2334626SN/A *pkt_data, *data); 2342SN/A } 2352SN/A 2362SN/A numReads++; 237695SN/A numReadsStat++; 2382SN/A 2396227SN/A if (numReads == (uint64_t)nextProgressMessage) { 240695SN/A ccprintf(cerr, "%s: completed %d read accesses @%d\n", 241695SN/A name(), numReads, curTick); 2422SN/A nextProgressMessage += progressInterval; 2432SN/A } 2442SN/A 2454893SN/A if (maxLoads != 0 && numReads >= maxLoads) 2464628SN/A exitSimLoop("maximum number of loads reached"); 2475319SN/A } else { 2485319SN/A assert(pkt->isWrite()); 249695SN/A numWritesStat++; 2502SN/A } 2512SN/A 2522SN/A noResponseCycles = 0; 2533187SN/A delete state; 2542SN/A delete [] data; 2553187SN/A delete pkt->req; 2563187SN/A delete pkt; 2572SN/A} 2582SN/A 2592SN/Avoid 2602SN/AMemTest::regStats() 2612SN/A{ 262729SN/A using namespace Stats; 2632SN/A 264695SN/A numReadsStat 2652SN/A .name(name() + ".num_reads") 2662SN/A .desc("number of read accesses completed") 2672SN/A ; 2682SN/A 269695SN/A numWritesStat 2702SN/A .name(name() + ".num_writes") 2712SN/A .desc("number of write accesses completed") 2722SN/A ; 2732SN/A 274695SN/A numCopiesStat 2752SN/A .name(name() + ".num_copies") 2762SN/A .desc("number of copy accesses completed") 2772SN/A ; 2782SN/A} 2792SN/A 2802SN/Avoid 2812SN/AMemTest::tick() 2822SN/A{ 2832SN/A if (!tickEvent.scheduled()) 2845606SN/A schedule(tickEvent, curTick + ticks(1)); 2852SN/A 2861298SN/A if (++noResponseCycles >= 500000) { 2877544SN/A if (issueDmas) { 2887544SN/A cerr << "DMA tester "; 2897544SN/A } 2902SN/A cerr << name() << ": deadlocked at cycle " << curTick << endl; 2912SN/A fatal(""); 2922SN/A } 2932SN/A 2947544SN/A if (accessRetry || (issueDmas && dmaOutstanding)) { 2957544SN/A DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n"); 2962SN/A return; 2972SN/A } 2982SN/A 2992SN/A //make new request 3001899SN/A unsigned cmd = random() % 100; 3011899SN/A unsigned offset = random() % size; 3022SN/A unsigned base = random() % 2; 3032SN/A uint64_t data = random(); 3042SN/A unsigned access_size = random() % 4; 3055736SN/A bool uncacheable = (random() % 100) < percentUncacheable; 3062SN/A 3077544SN/A unsigned dma_access_size = random() % 4; 3087544SN/A 3091298SN/A //If we aren't doing copies, use id as offset, and do a false sharing 3101298SN/A //mem tester 3113187SN/A //We can eliminate the lower bits of the offset, and then use the id 3123187SN/A //to offset within the blks 3134628SN/A offset = blockAddr(offset); 3143187SN/A offset += id; 3153187SN/A access_size = 0; 3167544SN/A dma_access_size = 0; 3171298SN/A 3183187SN/A Request *req = new Request(); 3195736SN/A Request::Flags flags; 3203187SN/A Addr paddr; 3212SN/A 3225736SN/A if (uncacheable) { 3235736SN/A flags.set(Request::UNCACHEABLE); 3243187SN/A paddr = uncacheAddr + offset; 3257544SN/A } else { 3263187SN/A paddr = ((base) ? baseAddr1 : baseAddr2) + offset; 3272SN/A } 3285736SN/A bool probe = (random() % 100 < percentFunctional) && !uncacheable; 3292SN/A 3307544SN/A if (issueDmas) { 3317544SN/A paddr &= ~((1 << dma_access_size) - 1); 3327544SN/A req->setPhys(paddr, 1 << dma_access_size, flags); 3337544SN/A req->setThreadContext(id,0); 3347544SN/A } else { 3357544SN/A paddr &= ~((1 << access_size) - 1); 3367544SN/A req->setPhys(paddr, 1 << access_size, flags); 3377544SN/A req->setThreadContext(id,0); 3387544SN/A } 3397544SN/A assert(req->getSize() == 1); 3403187SN/A 3413187SN/A uint8_t *result = new uint8_t[8]; 3422SN/A 3432SN/A if (cmd < percentReads) { 3442SN/A // read 3451298SN/A 3464628SN/A // For now we only allow one outstanding request per address 3474628SN/A // per tester This means we assume CPU does write forwarding 3484628SN/A // to reads that alias something in the cpu store buffer. 3493282SN/A if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) { 3504203SN/A delete [] result; 3513282SN/A delete req; 3523282SN/A return; 3533282SN/A } 3544628SN/A 3554628SN/A outstandingAddrs.insert(paddr); 3561298SN/A 3573187SN/A // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin 3583187SN/A funcPort.readBlob(req->getPaddr(), result, req->getSize()); 3593187SN/A 3604628SN/A DPRINTF(MemTest, 3617544SN/A "id %d initiating read at address %x (blk %x) expecting %x\n", 3627544SN/A id, req->getPaddr(), blockAddr(req->getPaddr()), *result); 3633187SN/A 3644022SN/A PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 3654660SN/A pkt->setSrc(0); 3663187SN/A pkt->dataDynamicArray(new uint8_t[req->getSize()]); 3673187SN/A MemTestSenderState *state = new MemTestSenderState(result); 3683187SN/A pkt->senderState = state; 3693187SN/A 370145SN/A if (probe) { 3713187SN/A cachePort.sendFunctional(pkt); 3723204SN/A completeRequest(pkt); 373145SN/A } else { 3743262SN/A sendPkt(pkt); 375145SN/A } 3763187SN/A } else { 3772SN/A // write 3781298SN/A 3794628SN/A // For now we only allow one outstanding request per addreess 3804628SN/A // per tester. This means we assume CPU does write forwarding 3814628SN/A // to reads that alias something in the cpu store buffer. 3823282SN/A if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) { 3833283SN/A delete [] result; 3843282SN/A delete req; 3853282SN/A return; 3863282SN/A } 3873282SN/A 3884628SN/A outstandingAddrs.insert(paddr); 3891298SN/A 3904628SN/A DPRINTF(MemTest, "initiating write at address %x (blk %x) value %x\n", 3914628SN/A req->getPaddr(), blockAddr(req->getPaddr()), data & 0xff); 3924628SN/A 3934022SN/A PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 3944660SN/A pkt->setSrc(0); 3953187SN/A uint8_t *pkt_data = new uint8_t[req->getSize()]; 3963187SN/A pkt->dataDynamicArray(pkt_data); 3973187SN/A memcpy(pkt_data, &data, req->getSize()); 3983187SN/A MemTestSenderState *state = new MemTestSenderState(result); 3993187SN/A pkt->senderState = state; 4003187SN/A 4013187SN/A funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize()); 4023187SN/A 403145SN/A if (probe) { 4043187SN/A cachePort.sendFunctional(pkt); 4053262SN/A completeRequest(pkt); 406145SN/A } else { 4073262SN/A sendPkt(pkt); 408145SN/A } 4093187SN/A } 4102SN/A} 4112SN/A 4122SN/Avoid 4133187SN/AMemTest::doRetry() 4142SN/A{ 4153187SN/A if (cachePort.sendTiming(retryPkt)) { 4167544SN/A DPRINTF(MemTest, "accessRetry setting to false\n"); 4173187SN/A accessRetry = false; 4183187SN/A retryPkt = NULL; 4193187SN/A } 4202SN/A} 4212SN/A 4225314SN/A 4235314SN/Avoid 4245314SN/AMemTest::printAddr(Addr a) 4255314SN/A{ 4265314SN/A cachePort.printAddr(a); 4275314SN/A} 4285315SN/A 4295315SN/A 4305315SN/AMemTest * 4315315SN/AMemTestParams::create() 4325315SN/A{ 4335315SN/A return new MemTest(this); 4345315SN/A} 435