diff options
Diffstat (limited to 'sim/memtest.cc')
-rw-r--r-- | sim/memtest.cc | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/sim/memtest.cc b/sim/memtest.cc new file mode 100644 index 000000000..70b6fbf13 --- /dev/null +++ b/sim/memtest.cc @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded + +#include <string> +#include <sstream> +#include <iomanip> +#include <vector> + +#include "memtest.hh" +#include "misc.hh" +#include "sim_events.hh" +#include "main_memory.hh" +#include "base_cache.hh" + +#include "statistics.hh" +#include "sim_stats.hh" + +using namespace std; + +MemTest::MemTest(const string &name, + MemInterface *_cache_interface, + FunctionalMemory *main_mem, + FunctionalMemory *check_mem, + unsigned _memorySize, + unsigned _percentReads, + unsigned _percentUncacheable, + unsigned _maxReads, + unsigned _progressInterval, + Addr _traceAddr) + : BaseCPU(name, 1), + tickEvent(this), + cacheInterface(_cache_interface), + mainMem(main_mem), + checkMem(check_mem), + size(_memorySize), + percentReads(_percentReads), + percentUncacheable(_percentUncacheable), + maxReads(_maxReads), + progressInterval(_progressInterval), + nextProgressMessage(_progressInterval) +{ + vector<string> cmd; + cmd.push_back("/bin/ls"); + vector<string> null_vec; + xc = new ExecContext(this ,0,mainMem,0); + + blockSize = cacheInterface->getBlockSize(); + blockAddrMask = blockSize - 1; + traceBlockAddr = blockAddr(_traceAddr); + + //setup data storage with interesting values + uint8_t *data1 = new uint8_t[size]; + uint8_t *data2 = new uint8_t[size]; + uint8_t *data3 = new uint8_t[size]; + memset(data1, 1, size); + memset(data2, 2, size); + memset(data3, 3, size); + curTick = 0; + + baseAddr1 = 0x100000; + baseAddr2 = 0x400000; + uncacheAddr = 0x800000; + + // set up intial memory contents here + mainMem->prot_write(baseAddr1, data1, size); + checkMem->prot_write(baseAddr1, data1, size); + mainMem->prot_write(baseAddr2, data2, size); + checkMem->prot_write(baseAddr2, data2, size); + mainMem->prot_write(uncacheAddr, data3, size); + checkMem->prot_write(uncacheAddr, data3, size); + + delete [] data1; + delete [] data2; + delete [] data3; + + // set up counters + noResponseCycles = 0; + numReads = 0; + numWrites = 0; + tickEvent.schedule(0); +} + +static void +printData(ostream &os, uint8_t *data, int nbytes) +{ + os << hex << setfill('0'); + // assume little-endian: print bytes from highest address to lowest + for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { + os << setw(2) << (unsigned)*dp; + } + os << dec; +} + +void +MemTest::completeRequest(MemReqPtr req, uint8_t *data) +{ + switch (req->cmd) { + case Read: + if (memcmp(req->data, data, req->size) != 0) { + cerr << name() << ": on read of 0x" << hex << req->paddr + << " @ cycle " << dec << curTick + << ", cache returns 0x"; + printData(cerr, req->data, req->size); + cerr << ", expected 0x"; + printData(cerr, data, req->size); + cerr << endl; + fatal(""); + } + + numReads++; + + if (numReads.val() == nextProgressMessage) { + cerr << name() << ": completed " << numReads.val() + << " read accesses @ " << curTick << endl; + nextProgressMessage += progressInterval; + } + + if (numReads.val() == maxReads) { + stringstream stream; + stream << name() << " reached max read count (" << maxReads + << ")" << endl; + + new SimExitEvent(stream.str()); + } + break; + + case Write: + numWrites++; + break; + + + default: + panic("invalid command"); + } + + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": completed " + << (req->cmd.isWrite() ? "write" : "read") << " access of " + << req->size << " bytes at address 0x" + << hex << req->paddr << ", value = 0x"; + printData(cerr, req->data, req->size); + cerr << endl; + } + + noResponseCycles = 0; + delete [] data; +} + + +void +MemTest::regStats() +{ + using namespace Statistics; + + numReads + .name(name() + ".num_reads") + .desc("number of read accesses completed") + ; + + numWrites + .name(name() + ".num_writes") + .desc("number of write accesses completed") + ; + + numCopies + .name(name() + ".num_copies") + .desc("number of copy accesses completed") + ; +} + +void +MemTest::tick() +{ + if (!tickEvent.scheduled()) + tickEvent.schedule(curTick + 1); + + if (++noResponseCycles >= 5000) { + cerr << name() << ": deadlocked at cycle " << curTick << endl; + fatal(""); + } + + if (cacheInterface->isBlocked()) { + return; + } + + //make new request + unsigned cmd = rand() % 100; + unsigned offset1 = random() % size; + unsigned base = random() % 2; + uint64_t data = random(); + unsigned access_size = random() % 4; + unsigned cacheable = rand() % 100; + + MemReqPtr req = new MemReq(); + + if (cacheable < percentUncacheable) { + req->flags |= UNCACHEABLE; + req->paddr = uncacheAddr + offset1; + } else { + req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1; + } + + req->size = 1 << access_size; + req->data = new uint8_t[req->size]; + req->paddr &= ~(req->size - 1); + req->time = curTick; + req->xc = xc; + + if (cmd < percentReads) { + // read + req->cmd = Read; + uint8_t *result = new uint8_t[8]; + checkMem->access(Read, req->paddr, result, req->size); + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": initiating read of " + << req->size << " bytes from addr 0x" + << hex << req->paddr << " at cycle " + << dec << curTick << endl; + } + + req->completionEvent = new MemCompleteEvent(req, result, this); + cacheInterface->access(req); + } else { + // write + req->cmd = Write; + memcpy(req->data, &data, req->size); + checkMem->access(Write, req->paddr, req->data, req->size); + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": initiating write of " + << req->size << " bytes (value = 0x"; + printData(cerr, req->data, req->size); + cerr << ") to addr 0x" + << hex << req->paddr << " at cycle " + << dec << curTick << endl; + } + req->completionEvent = new MemCompleteEvent(req, NULL, this); + cacheInterface->access(req); + } +} + + +void +MemCompleteEvent::process() +{ + tester->completeRequest(req, data); + delete this; +} + + +const char * +MemCompleteEvent::description() +{ + return "memory access completion"; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) + + SimObjectParam<BaseCache *> cache; + SimObjectParam<FunctionalMemory *> main_mem; + SimObjectParam<FunctionalMemory *> check_mem; + Param<unsigned> memory_size; + Param<unsigned> percent_reads; + Param<unsigned> percent_uncacheable; + Param<unsigned> max_reads; + Param<unsigned> progress_interval; + Param<Addr> trace_addr; + +END_DECLARE_SIM_OBJECT_PARAMS(MemTest) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) + + INIT_PARAM(cache, "L1 cache"), + INIT_PARAM(main_mem, "hierarchical memory"), + INIT_PARAM(check_mem, "check memory"), + INIT_PARAM_DFLT(memory_size, "memory size", 65536), + INIT_PARAM_DFLT(percent_reads, "target read percentage", 65), + INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10), + INIT_PARAM_DFLT(max_reads, "number of reads to simulate", 0), + INIT_PARAM_DFLT(progress_interval, + "progress report interval (in accesses)", 1000000), + INIT_PARAM_DFLT(trace_addr, "address to trace", 0) + +END_INIT_SIM_OBJECT_PARAMS(MemTest) + + +CREATE_SIM_OBJECT(MemTest) +{ + return new MemTest(getInstanceName(), cache->getInterface(), main_mem, + check_mem, + memory_size, percent_reads, + percent_uncacheable, max_reads, progress_interval, + trace_addr); +} + +REGISTER_SIM_OBJECT("MemTest", MemTest) |