Update the Memtester, commit a config file/test for it.
src/cpu/SConscript: Add memtester to the compilation environment. Someone who knows this better should make the MemTest a cpu model parameter. For now attached with the build of o3 cpu. src/cpu/memtest/memtest.cc: src/cpu/memtest/memtest.hh: Update Memtest for new mem system src/python/m5/objects/MemTest.py: Update memtest python description --HG-- extra : convert_revision : d6a63e08fda0975a7abfb23814a86a0caf53e482
This commit is contained in:
parent
0a3e4d56e5
commit
6c7ab02682
6 changed files with 392 additions and 165 deletions
|
@ -158,6 +158,7 @@ if 'O3CPU' in env['CPU_MODELS']:
|
|||
o3/scoreboard.cc
|
||||
o3/store_set.cc
|
||||
''')
|
||||
sources += Split('memtest/memtest.cc')
|
||||
if env['USE_CHECKER']:
|
||||
sources += Split('o3/checker_builder.cc')
|
||||
else:
|
||||
|
|
|
@ -38,39 +38,80 @@
|
|||
|
||||
#include "base/misc.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
//#include "cpu/simple_thread.hh"
|
||||
#include "cpu/memtest/memtest.hh"
|
||||
#include "mem/cache/base_cache.hh"
|
||||
//#include "mem/cache/base_cache.hh"
|
||||
//#include "mem/physical.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/sim_events.hh"
|
||||
#include "sim/stats.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
int TESTER_ALLOCATOR=0;
|
||||
|
||||
bool
|
||||
MemTest::CpuPort::recvTiming(Packet *pkt)
|
||||
{
|
||||
memtest->completeRequest(pkt);
|
||||
return true;
|
||||
}
|
||||
|
||||
Tick
|
||||
MemTest::CpuPort::recvAtomic(Packet *pkt)
|
||||
{
|
||||
panic("MemTest doesn't expect recvAtomic callback!");
|
||||
return curTick;
|
||||
}
|
||||
|
||||
void
|
||||
MemTest::CpuPort::recvFunctional(Packet *pkt)
|
||||
{
|
||||
memtest->completeRequest(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
MemTest::CpuPort::recvStatusChange(Status status)
|
||||
{
|
||||
if (status == RangeChange)
|
||||
return;
|
||||
|
||||
panic("MemTest doesn't expect recvStatusChange callback!");
|
||||
}
|
||||
|
||||
void
|
||||
MemTest::CpuPort::recvRetry()
|
||||
{
|
||||
memtest->doRetry();
|
||||
}
|
||||
|
||||
MemTest::MemTest(const string &name,
|
||||
MemInterface *_cache_interface,
|
||||
FunctionalMemory *main_mem,
|
||||
FunctionalMemory *check_mem,
|
||||
// MemInterface *_cache_interface,
|
||||
// PhysicalMemory *main_mem,
|
||||
// PhysicalMemory *check_mem,
|
||||
unsigned _memorySize,
|
||||
unsigned _percentReads,
|
||||
unsigned _percentCopies,
|
||||
// unsigned _percentCopies,
|
||||
unsigned _percentUncacheable,
|
||||
unsigned _progressInterval,
|
||||
unsigned _percentSourceUnaligned,
|
||||
unsigned _percentDestUnaligned,
|
||||
Addr _traceAddr,
|
||||
Counter _max_loads)
|
||||
: SimObject(name),
|
||||
: MemObject(name),
|
||||
tickEvent(this),
|
||||
cacheInterface(_cache_interface),
|
||||
mainMem(main_mem),
|
||||
checkMem(check_mem),
|
||||
cachePort("test", this),
|
||||
funcPort("functional", this),
|
||||
retryPkt(NULL),
|
||||
// mainMem(main_mem),
|
||||
// checkMem(check_mem),
|
||||
size(_memorySize),
|
||||
percentReads(_percentReads),
|
||||
percentCopies(_percentCopies),
|
||||
// percentCopies(_percentCopies),
|
||||
percentUncacheable(_percentUncacheable),
|
||||
progressInterval(_progressInterval),
|
||||
nextProgressMessage(_progressInterval),
|
||||
|
@ -81,43 +122,52 @@ MemTest::MemTest(const string &name,
|
|||
vector<string> cmd;
|
||||
cmd.push_back("/bin/ls");
|
||||
vector<string> null_vec;
|
||||
thread = new SimpleThread(NULL, 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);
|
||||
// thread = new SimpleThread(NULL, 0, NULL, 0, mainMem);
|
||||
curTick = 0;
|
||||
|
||||
// Needs to be masked off once we know the block size.
|
||||
traceBlockAddr = _traceAddr;
|
||||
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;
|
||||
tickEvent.schedule(0);
|
||||
|
||||
id = TESTER_ALLOCATOR++;
|
||||
|
||||
accessRetry = false;
|
||||
}
|
||||
|
||||
Port *
|
||||
MemTest::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "functional")
|
||||
return &funcPort;
|
||||
else if (if_name == "test")
|
||||
return &cachePort;
|
||||
else
|
||||
panic("No Such Port\n");
|
||||
}
|
||||
|
||||
void
|
||||
MemTest::init()
|
||||
{
|
||||
// By the time init() is called, the ports should be hooked up.
|
||||
blockSize = cachePort.peerBlockSize();
|
||||
blockAddrMask = blockSize - 1;
|
||||
traceBlockAddr = blockAddr(traceBlockAddr);
|
||||
|
||||
// set up intial memory contents here
|
||||
|
||||
cachePort.memsetBlob(baseAddr1, 1, size);
|
||||
funcPort.memsetBlob(baseAddr1, 1, size);
|
||||
cachePort.memsetBlob(baseAddr2, 2, size);
|
||||
funcPort.memsetBlob(baseAddr2, 2, size);
|
||||
cachePort.memsetBlob(uncacheAddr, 3, size);
|
||||
funcPort.memsetBlob(uncacheAddr, 3, size);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -132,23 +182,31 @@ printData(ostream &os, uint8_t *data, int nbytes)
|
|||
}
|
||||
|
||||
void
|
||||
MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
|
||||
MemTest::completeRequest(Packet *pkt)
|
||||
{
|
||||
MemTestSenderState *state =
|
||||
dynamic_cast<MemTestSenderState *>(pkt->senderState);
|
||||
|
||||
uint8_t *data = state->data;
|
||||
uint8_t *pkt_data = pkt->getPtr<uint8_t>();
|
||||
Request *req = pkt->req;
|
||||
|
||||
//Remove the address from the list of outstanding
|
||||
std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr);
|
||||
std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->getPaddr());
|
||||
assert(removeAddr != outstandingAddrs.end());
|
||||
outstandingAddrs.erase(removeAddr);
|
||||
|
||||
switch (req->cmd) {
|
||||
case Read:
|
||||
if (memcmp(req->data, data, req->size) != 0) {
|
||||
cerr << name() << ": on read of 0x" << hex << req->paddr
|
||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
||||
switch (pkt->cmd) {
|
||||
case Packet::ReadResp:
|
||||
|
||||
if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
|
||||
cerr << name() << ": on read of 0x" << hex << req->getPaddr()
|
||||
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
||||
<< "@ cycle " << dec << curTick
|
||||
<< ", cache returns 0x";
|
||||
printData(cerr, req->data, req->size);
|
||||
printData(cerr, pkt_data, pkt->getSize());
|
||||
cerr << ", expected 0x";
|
||||
printData(cerr, data, req->size);
|
||||
printData(cerr, data, pkt->getSize());
|
||||
cerr << endl;
|
||||
fatal("");
|
||||
}
|
||||
|
@ -163,13 +221,13 @@ MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
|
|||
}
|
||||
|
||||
if (numReads >= maxLoads)
|
||||
SimExit(curTick, "Maximum number of loads reached!");
|
||||
exitSimLoop("Maximum number of loads reached!");
|
||||
break;
|
||||
|
||||
case Write:
|
||||
case Packet::WriteResp:
|
||||
numWritesStat++;
|
||||
break;
|
||||
|
||||
/*
|
||||
case Copy:
|
||||
//Also remove dest from outstanding list
|
||||
removeAddr = outstandingAddrs.find(req->dest);
|
||||
|
@ -177,36 +235,37 @@ MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
|
|||
outstandingAddrs.erase(removeAddr);
|
||||
numCopiesStat++;
|
||||
break;
|
||||
|
||||
*/
|
||||
default:
|
||||
panic("invalid command");
|
||||
}
|
||||
|
||||
if (blockAddr(req->paddr) == traceBlockAddr) {
|
||||
if (blockAddr(req->getPaddr()) == traceBlockAddr) {
|
||||
cerr << name() << ": completed "
|
||||
<< (req->cmd.isWrite() ? "write" : "read")
|
||||
<< (pkt->isWrite() ? "write" : "read")
|
||||
<< " access of "
|
||||
<< dec << req->size << " bytes at address 0x"
|
||||
<< hex << req->paddr
|
||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
||||
<< dec << pkt->getSize() << " bytes at address 0x"
|
||||
<< hex << req->getPaddr()
|
||||
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
||||
<< ", value = 0x";
|
||||
printData(cerr, req->data, req->size);
|
||||
printData(cerr, pkt_data, pkt->getSize());
|
||||
cerr << " @ cycle " << dec << curTick;
|
||||
|
||||
cerr << endl;
|
||||
}
|
||||
|
||||
noResponseCycles = 0;
|
||||
delete state;
|
||||
delete [] data;
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemTest::regStats()
|
||||
{
|
||||
using namespace Stats;
|
||||
|
||||
|
||||
numReadsStat
|
||||
.name(name() + ".num_reads")
|
||||
.desc("number of read accesses completed")
|
||||
|
@ -234,7 +293,7 @@ MemTest::tick()
|
|||
fatal("");
|
||||
}
|
||||
|
||||
if (cacheInterface->isBlocked()) {
|
||||
if (accessRetry) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -248,30 +307,30 @@ MemTest::tick()
|
|||
|
||||
//If we aren't doing copies, use id as offset, and do a false sharing
|
||||
//mem tester
|
||||
if (percentCopies == 0) {
|
||||
//We can eliminate the lower bits of the offset, and then use the id
|
||||
//to offset within the blks
|
||||
offset &= ~63; //Not the low order bits
|
||||
offset += id;
|
||||
access_size = 0;
|
||||
}
|
||||
//We can eliminate the lower bits of the offset, and then use the id
|
||||
//to offset within the blks
|
||||
offset &= ~63; //Not the low order bits
|
||||
offset += id;
|
||||
access_size = 0;
|
||||
|
||||
MemReqPtr req = new MemReq();
|
||||
Request *req = new Request();
|
||||
uint32_t flags = 0;
|
||||
Addr paddr;
|
||||
|
||||
if (cacheable < percentUncacheable) {
|
||||
req->flags |= UNCACHEABLE;
|
||||
req->paddr = uncacheAddr + offset;
|
||||
flags |= UNCACHEABLE;
|
||||
paddr = uncacheAddr + offset;
|
||||
} else {
|
||||
req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
|
||||
paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
|
||||
}
|
||||
// bool probe = (random() % 2 == 1) && !req->isUncacheable();
|
||||
bool probe = false;
|
||||
|
||||
req->size = 1 << access_size;
|
||||
req->data = new uint8_t[req->size];
|
||||
req->paddr &= ~(req->size - 1);
|
||||
req->time = curTick;
|
||||
req->xc = thread->getProxy();
|
||||
paddr &= ~((1 << access_size) - 1);
|
||||
req->setPhys(paddr, 1 << access_size, flags);
|
||||
req->setThreadContext(id,0);
|
||||
|
||||
uint8_t *result = new uint8_t[8];
|
||||
|
||||
if (cmd < percentReads) {
|
||||
// read
|
||||
|
@ -279,60 +338,81 @@ MemTest::tick()
|
|||
//For now we only allow one outstanding request per addreess per tester
|
||||
//This means we assume CPU does write forwarding to reads that alias something
|
||||
//in the cpu store buffer.
|
||||
if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return;
|
||||
else outstandingAddrs.insert(req->paddr);
|
||||
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) return;
|
||||
else outstandingAddrs.insert(paddr);
|
||||
|
||||
req->cmd = Read;
|
||||
uint8_t *result = new uint8_t[8];
|
||||
checkMem->access(Read, req->paddr, result, req->size);
|
||||
if (blockAddr(req->paddr) == traceBlockAddr) {
|
||||
// ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
|
||||
funcPort.readBlob(req->getPaddr(), result, req->getSize());
|
||||
|
||||
if (blockAddr(paddr) == traceBlockAddr) {
|
||||
cerr << name()
|
||||
<< ": initiating read "
|
||||
<< ((probe) ? "probe of " : "access of ")
|
||||
<< dec << req->size << " bytes from addr 0x"
|
||||
<< hex << req->paddr
|
||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
||||
<< dec << req->getSize() << " bytes from addr 0x"
|
||||
<< hex << paddr
|
||||
<< " (0x" << hex << blockAddr(paddr) << ")"
|
||||
<< " at cycle "
|
||||
<< dec << curTick << endl;
|
||||
}
|
||||
|
||||
Packet *pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast);
|
||||
pkt->dataDynamicArray(new uint8_t[req->getSize()]);
|
||||
MemTestSenderState *state = new MemTestSenderState(result);
|
||||
pkt->senderState = state;
|
||||
|
||||
if (probe) {
|
||||
cacheInterface->probeAndUpdate(req);
|
||||
completeRequest(req, result);
|
||||
cachePort.sendFunctional(pkt);
|
||||
// completeRequest(pkt, result);
|
||||
} else {
|
||||
req->completionEvent = new MemCompleteEvent(req, result, this);
|
||||
cacheInterface->access(req);
|
||||
// req->completionEvent = new MemCompleteEvent(req, result, this);
|
||||
if (!cachePort.sendTiming(pkt)) {
|
||||
accessRetry = true;
|
||||
retryPkt = pkt;
|
||||
}
|
||||
}
|
||||
} else if (cmd < (100 - percentCopies)){
|
||||
} else {
|
||||
// write
|
||||
|
||||
//For now we only allow one outstanding request per addreess per tester
|
||||
//This means we assume CPU does write forwarding to reads that alias something
|
||||
//in the cpu store buffer.
|
||||
if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return;
|
||||
else outstandingAddrs.insert(req->paddr);
|
||||
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) return;
|
||||
else outstandingAddrs.insert(paddr);
|
||||
|
||||
req->cmd = Write;
|
||||
memcpy(req->data, &data, req->size);
|
||||
checkMem->access(Write, req->paddr, req->data, req->size);
|
||||
if (blockAddr(req->paddr) == traceBlockAddr) {
|
||||
/*
|
||||
if (blockAddr(req->getPaddr()) == traceBlockAddr) {
|
||||
cerr << name() << ": initiating write "
|
||||
<< ((probe)?"probe of ":"access of ")
|
||||
<< dec << req->size << " bytes (value = 0x";
|
||||
printData(cerr, req->data, req->size);
|
||||
<< dec << req->getSize() << " bytes (value = 0x";
|
||||
printData(cerr, data_pkt->getPtr(), req->getSize());
|
||||
cerr << ") to addr 0x"
|
||||
<< hex << req->paddr
|
||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
||||
<< hex << req->getPaddr()
|
||||
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
||||
<< " at cycle "
|
||||
<< dec << curTick << endl;
|
||||
}
|
||||
*/
|
||||
Packet *pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
|
||||
uint8_t *pkt_data = new uint8_t[req->getSize()];
|
||||
pkt->dataDynamicArray(pkt_data);
|
||||
memcpy(pkt_data, &data, req->getSize());
|
||||
MemTestSenderState *state = new MemTestSenderState(result);
|
||||
pkt->senderState = state;
|
||||
|
||||
funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());
|
||||
|
||||
if (probe) {
|
||||
cacheInterface->probeAndUpdate(req);
|
||||
completeRequest(req, NULL);
|
||||
cachePort.sendFunctional(pkt);
|
||||
// completeRequest(req, NULL);
|
||||
} else {
|
||||
req->completionEvent = new MemCompleteEvent(req, NULL, this);
|
||||
cacheInterface->access(req);
|
||||
// req->completionEvent = new MemCompleteEvent(req, NULL, this);
|
||||
if (!cachePort.sendTiming(pkt)) {
|
||||
accessRetry = true;
|
||||
retryPkt = pkt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
/* else {
|
||||
// copy
|
||||
unsigned source_align = random() % 100;
|
||||
unsigned dest_align = random() % 100;
|
||||
|
@ -369,38 +449,32 @@ MemTest::tick()
|
|||
<< " (0x" << hex << blockAddr(dest) << ")"
|
||||
<< " at cycle "
|
||||
<< dec << curTick << endl;
|
||||
}
|
||||
}*
|
||||
cacheInterface->access(req);
|
||||
uint8_t result[blockSize];
|
||||
checkMem->access(Read, source, &result, blockSize);
|
||||
checkMem->access(Write, dest, &result, blockSize);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemCompleteEvent::process()
|
||||
MemTest::doRetry()
|
||||
{
|
||||
tester->completeRequest(req, data);
|
||||
delete this;
|
||||
if (cachePort.sendTiming(retryPkt)) {
|
||||
accessRetry = false;
|
||||
retryPkt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
// SimObjectParam<BaseCache *> cache;
|
||||
// SimObjectParam<PhysicalMemory *> main_mem;
|
||||
// SimObjectParam<PhysicalMemory *> check_mem;
|
||||
Param<unsigned> memory_size;
|
||||
Param<unsigned> percent_reads;
|
||||
Param<unsigned> percent_copies;
|
||||
// Param<unsigned> percent_copies;
|
||||
Param<unsigned> percent_uncacheable;
|
||||
Param<unsigned> progress_interval;
|
||||
Param<unsigned> percent_source_unaligned;
|
||||
|
@ -413,12 +487,12 @@ 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(cache, "L1 cache"),
|
||||
// INIT_PARAM(main_mem, "hierarchical memory"),
|
||||
// INIT_PARAM(check_mem, "check memory"),
|
||||
INIT_PARAM(memory_size, "memory size"),
|
||||
INIT_PARAM(percent_reads, "target read percentage"),
|
||||
INIT_PARAM(percent_copies, "target copy percentage"),
|
||||
// INIT_PARAM(percent_copies, "target copy percentage"),
|
||||
INIT_PARAM(percent_uncacheable, "target uncacheable percentage"),
|
||||
INIT_PARAM(progress_interval, "progress report interval (in accesses)"),
|
||||
INIT_PARAM(percent_source_unaligned,
|
||||
|
@ -433,8 +507,8 @@ 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_copies,
|
||||
return new MemTest(getInstanceName(), /*cache->getInterface(),*/ /*main_mem,*/
|
||||
/*check_mem,*/ memory_size, percent_reads, /*percent_copies,*/
|
||||
percent_uncacheable, progress_interval,
|
||||
percent_source_unaligned, percent_dest_unaligned,
|
||||
trace_addr, max_loads);
|
||||
|
|
|
@ -35,25 +35,27 @@
|
|||
#include <set>
|
||||
|
||||
#include "base/statistics.hh"
|
||||
#include "mem/functional/functional.hh"
|
||||
#include "mem/mem_interface.hh"
|
||||
//#include "mem/functional/functional.hh"
|
||||
//#include "mem/mem_interface.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/stats.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/port.hh"
|
||||
|
||||
class ThreadContext;
|
||||
class MemTest : public SimObject
|
||||
class Packet;
|
||||
class MemTest : public MemObject
|
||||
{
|
||||
public:
|
||||
|
||||
MemTest(const std::string &name,
|
||||
MemInterface *_cache_interface,
|
||||
FunctionalMemory *main_mem,
|
||||
FunctionalMemory *check_mem,
|
||||
// MemInterface *_cache_interface,
|
||||
// PhysicalMemory *main_mem,
|
||||
// PhysicalMemory *check_mem,
|
||||
unsigned _memorySize,
|
||||
unsigned _percentReads,
|
||||
unsigned _percentCopies,
|
||||
// unsigned _percentCopies,
|
||||
unsigned _percentUncacheable,
|
||||
unsigned _progressInterval,
|
||||
unsigned _percentSourceUnaligned,
|
||||
|
@ -61,6 +63,8 @@ class MemTest : public SimObject
|
|||
Addr _traceAddr,
|
||||
Counter _max_loads);
|
||||
|
||||
virtual void init();
|
||||
|
||||
// register statistics
|
||||
virtual void regStats();
|
||||
|
||||
|
@ -69,6 +73,8 @@ class MemTest : public SimObject
|
|||
// main simulation loop (one cycle)
|
||||
void tick();
|
||||
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
protected:
|
||||
class TickEvent : public Event
|
||||
{
|
||||
|
@ -82,16 +88,62 @@ class MemTest : public SimObject
|
|||
};
|
||||
|
||||
TickEvent tickEvent;
|
||||
class CpuPort : public Port
|
||||
{
|
||||
|
||||
MemInterface *cacheInterface;
|
||||
FunctionalMemory *mainMem;
|
||||
FunctionalMemory *checkMem;
|
||||
SimpleThread *thread;
|
||||
MemTest *memtest;
|
||||
|
||||
public:
|
||||
|
||||
CpuPort(const std::string &_name, MemTest *_memtest)
|
||||
: Port(_name), memtest(_memtest)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool recvTiming(Packet *pkt);
|
||||
|
||||
virtual Tick recvAtomic(Packet *pkt);
|
||||
|
||||
virtual void recvFunctional(Packet *pkt);
|
||||
|
||||
virtual void recvStatusChange(Status status);
|
||||
|
||||
virtual void recvRetry();
|
||||
|
||||
virtual void getDeviceAddressRanges(AddrRangeList &resp,
|
||||
AddrRangeList &snoop)
|
||||
{ resp.clear(); snoop.clear(); }
|
||||
};
|
||||
|
||||
CpuPort cachePort;
|
||||
CpuPort funcPort;
|
||||
|
||||
class MemTestSenderState : public Packet::SenderState
|
||||
{
|
||||
public:
|
||||
/** Constructor. */
|
||||
MemTestSenderState(uint8_t *_data)
|
||||
: data(_data)
|
||||
{ }
|
||||
|
||||
// Hold onto data pointer
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
// Request *dataReq;
|
||||
Packet *retryPkt;
|
||||
// MemInterface *cacheInterface;
|
||||
// PhysicalMemory *mainMem;
|
||||
// PhysicalMemory *checkMem;
|
||||
// SimpleThread *thread;
|
||||
|
||||
bool accessRetry;
|
||||
|
||||
unsigned size; // size of testing memory region
|
||||
|
||||
unsigned percentReads; // target percentage of read accesses
|
||||
unsigned percentCopies; // target percentage of copy accesses
|
||||
// unsigned percentCopies; // target percentage of copy accesses
|
||||
unsigned percentUncacheable;
|
||||
|
||||
int id;
|
||||
|
@ -128,31 +180,13 @@ class MemTest : public SimObject
|
|||
Stats::Scalar<> numCopiesStat;
|
||||
|
||||
// called by MemCompleteEvent::process()
|
||||
void completeRequest(MemReqPtr &req, uint8_t *data);
|
||||
void completeRequest(Packet *pkt);
|
||||
|
||||
void doRetry();
|
||||
|
||||
friend class MemCompleteEvent;
|
||||
};
|
||||
|
||||
|
||||
class MemCompleteEvent : public Event
|
||||
{
|
||||
MemReqPtr req;
|
||||
uint8_t *data;
|
||||
MemTest *tester;
|
||||
|
||||
public:
|
||||
|
||||
MemCompleteEvent(MemReqPtr &_req, uint8_t *_data, MemTest *_tester)
|
||||
: Event(&mainEventQueue),
|
||||
req(_req), data(_data), tester(_tester)
|
||||
{
|
||||
}
|
||||
|
||||
void process();
|
||||
|
||||
virtual const char *description();
|
||||
};
|
||||
|
||||
#endif // __CPU_MEMTEST_MEMTEST_HH__
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
from m5 import build_env
|
||||
|
||||
class MemTest(SimObject):
|
||||
type = 'MemTest'
|
||||
cache = Param.BaseCache("L1 cache")
|
||||
check_mem = Param.FunctionalMemory("check memory")
|
||||
main_mem = Param.FunctionalMemory("hierarchical memory")
|
||||
max_loads = Param.Counter("number of loads to execute")
|
||||
memory_size = Param.Int(65536, "memory size")
|
||||
percent_copies = Param.Percent(0, "target copy percentage")
|
||||
percent_dest_unaligned = Param.Percent(50,
|
||||
"percent of copy dest address that are unaligned")
|
||||
percent_reads = Param.Percent(65, "target read percentage")
|
||||
|
@ -18,3 +17,6 @@ class MemTest(SimObject):
|
|||
progress_interval = Param.Counter(1000000,
|
||||
"progress report interval (in accesses)")
|
||||
trace_addr = Param.Addr(0, "address to trace")
|
||||
|
||||
test = Port("Port to the memory system to test")
|
||||
functional = Port("Port to the functional memory used for verification")
|
||||
|
|
88
tests/configs/memtest.py
Normal file
88
tests/configs/memtest.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
# Copyright (c) 2006 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.
|
||||
#
|
||||
# Authors: Ron Dreslinski
|
||||
|
||||
import m5
|
||||
from m5.objects import *
|
||||
|
||||
# --------------------
|
||||
# Base L1 Cache
|
||||
# ====================
|
||||
|
||||
class L1(BaseCache):
|
||||
latency = 1
|
||||
block_size = 64
|
||||
mshrs = 4
|
||||
tgts_per_mshr = 8
|
||||
protocol = CoherenceProtocol(protocol='moesi')
|
||||
|
||||
# ----------------------
|
||||
# Base L2 Cache
|
||||
# ----------------------
|
||||
|
||||
class L2(BaseCache):
|
||||
block_size = 64
|
||||
latency = 100
|
||||
mshrs = 92
|
||||
tgts_per_mshr = 16
|
||||
write_buffers = 8
|
||||
|
||||
nb_cores = 1
|
||||
cpus = [ MemTest(max_loads=1e12) for i in xrange(nb_cores) ]
|
||||
|
||||
# system simulated
|
||||
system = System(cpu = cpus, funcmem = PhysicalMemory(),
|
||||
physmem = PhysicalMemory(), membus = Bus())
|
||||
|
||||
# l2cache & bus
|
||||
system.toL2Bus = Bus()
|
||||
system.l2c = L2(size='4MB', assoc=8)
|
||||
system.l2c.cpu_side = system.toL2Bus.port
|
||||
|
||||
# connect l2c to membus
|
||||
system.l2c.mem_side = system.membus.port
|
||||
|
||||
# add L1 caches
|
||||
for cpu in cpus:
|
||||
cpu.l1c = L1(size = '32kB', assoc = 4)
|
||||
cpu.l1c.cpu_side = cpu.test
|
||||
cpu.l1c.mem_side = system.toL2Bus.port
|
||||
system.funcmem.port = cpu.functional
|
||||
|
||||
|
||||
# connect memory to membus
|
||||
system.physmem.port = system.membus.port
|
||||
|
||||
|
||||
# -----------------------
|
||||
# run simulation
|
||||
# -----------------------
|
||||
|
||||
root = Root( system = system )
|
||||
root.system.mem_mode = 'timing'
|
||||
#root.trace.flags="InstExec"
|
||||
root.trace.flags="Bus"
|
28
tests/quick/50.memtest/test.py
Normal file
28
tests/quick/50.memtest/test.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2006 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.
|
||||
#
|
||||
# Authors: Ron Dreslinski
|
||||
|
Loading…
Reference in a new issue