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/scoreboard.cc
|
||||||
o3/store_set.cc
|
o3/store_set.cc
|
||||||
''')
|
''')
|
||||||
|
sources += Split('memtest/memtest.cc')
|
||||||
if env['USE_CHECKER']:
|
if env['USE_CHECKER']:
|
||||||
sources += Split('o3/checker_builder.cc')
|
sources += Split('o3/checker_builder.cc')
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -38,39 +38,80 @@
|
||||||
|
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
#include "cpu/simple_thread.hh"
|
//#include "cpu/simple_thread.hh"
|
||||||
#include "cpu/memtest/memtest.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/builder.hh"
|
||||||
#include "sim/sim_events.hh"
|
#include "sim/sim_events.hh"
|
||||||
#include "sim/stats.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 std;
|
||||||
using namespace TheISA;
|
|
||||||
|
|
||||||
int TESTER_ALLOCATOR=0;
|
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,
|
MemTest::MemTest(const string &name,
|
||||||
MemInterface *_cache_interface,
|
// MemInterface *_cache_interface,
|
||||||
FunctionalMemory *main_mem,
|
// PhysicalMemory *main_mem,
|
||||||
FunctionalMemory *check_mem,
|
// PhysicalMemory *check_mem,
|
||||||
unsigned _memorySize,
|
unsigned _memorySize,
|
||||||
unsigned _percentReads,
|
unsigned _percentReads,
|
||||||
unsigned _percentCopies,
|
// unsigned _percentCopies,
|
||||||
unsigned _percentUncacheable,
|
unsigned _percentUncacheable,
|
||||||
unsigned _progressInterval,
|
unsigned _progressInterval,
|
||||||
unsigned _percentSourceUnaligned,
|
unsigned _percentSourceUnaligned,
|
||||||
unsigned _percentDestUnaligned,
|
unsigned _percentDestUnaligned,
|
||||||
Addr _traceAddr,
|
Addr _traceAddr,
|
||||||
Counter _max_loads)
|
Counter _max_loads)
|
||||||
: SimObject(name),
|
: MemObject(name),
|
||||||
tickEvent(this),
|
tickEvent(this),
|
||||||
cacheInterface(_cache_interface),
|
cachePort("test", this),
|
||||||
mainMem(main_mem),
|
funcPort("functional", this),
|
||||||
checkMem(check_mem),
|
retryPkt(NULL),
|
||||||
|
// mainMem(main_mem),
|
||||||
|
// checkMem(check_mem),
|
||||||
size(_memorySize),
|
size(_memorySize),
|
||||||
percentReads(_percentReads),
|
percentReads(_percentReads),
|
||||||
percentCopies(_percentCopies),
|
// percentCopies(_percentCopies),
|
||||||
percentUncacheable(_percentUncacheable),
|
percentUncacheable(_percentUncacheable),
|
||||||
progressInterval(_progressInterval),
|
progressInterval(_progressInterval),
|
||||||
nextProgressMessage(_progressInterval),
|
nextProgressMessage(_progressInterval),
|
||||||
|
@ -81,43 +122,52 @@ MemTest::MemTest(const string &name,
|
||||||
vector<string> cmd;
|
vector<string> cmd;
|
||||||
cmd.push_back("/bin/ls");
|
cmd.push_back("/bin/ls");
|
||||||
vector<string> null_vec;
|
vector<string> null_vec;
|
||||||
thread = new SimpleThread(NULL, 0, mainMem, 0);
|
// thread = new SimpleThread(NULL, 0, NULL, 0, mainMem);
|
||||||
|
|
||||||
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;
|
curTick = 0;
|
||||||
|
|
||||||
|
// Needs to be masked off once we know the block size.
|
||||||
|
traceBlockAddr = _traceAddr;
|
||||||
baseAddr1 = 0x100000;
|
baseAddr1 = 0x100000;
|
||||||
baseAddr2 = 0x400000;
|
baseAddr2 = 0x400000;
|
||||||
uncacheAddr = 0x800000;
|
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
|
// set up counters
|
||||||
noResponseCycles = 0;
|
noResponseCycles = 0;
|
||||||
numReads = 0;
|
numReads = 0;
|
||||||
tickEvent.schedule(0);
|
tickEvent.schedule(0);
|
||||||
|
|
||||||
id = TESTER_ALLOCATOR++;
|
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
|
static void
|
||||||
|
@ -132,23 +182,31 @@ printData(ostream &os, uint8_t *data, int nbytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
//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());
|
assert(removeAddr != outstandingAddrs.end());
|
||||||
outstandingAddrs.erase(removeAddr);
|
outstandingAddrs.erase(removeAddr);
|
||||||
|
|
||||||
switch (req->cmd) {
|
switch (pkt->cmd) {
|
||||||
case Read:
|
case Packet::ReadResp:
|
||||||
if (memcmp(req->data, data, req->size) != 0) {
|
|
||||||
cerr << name() << ": on read of 0x" << hex << req->paddr
|
if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
|
||||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
cerr << name() << ": on read of 0x" << hex << req->getPaddr()
|
||||||
|
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
||||||
<< "@ cycle " << dec << curTick
|
<< "@ cycle " << dec << curTick
|
||||||
<< ", cache returns 0x";
|
<< ", cache returns 0x";
|
||||||
printData(cerr, req->data, req->size);
|
printData(cerr, pkt_data, pkt->getSize());
|
||||||
cerr << ", expected 0x";
|
cerr << ", expected 0x";
|
||||||
printData(cerr, data, req->size);
|
printData(cerr, data, pkt->getSize());
|
||||||
cerr << endl;
|
cerr << endl;
|
||||||
fatal("");
|
fatal("");
|
||||||
}
|
}
|
||||||
|
@ -163,13 +221,13 @@ MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numReads >= maxLoads)
|
if (numReads >= maxLoads)
|
||||||
SimExit(curTick, "Maximum number of loads reached!");
|
exitSimLoop("Maximum number of loads reached!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Write:
|
case Packet::WriteResp:
|
||||||
numWritesStat++;
|
numWritesStat++;
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
case Copy:
|
case Copy:
|
||||||
//Also remove dest from outstanding list
|
//Also remove dest from outstanding list
|
||||||
removeAddr = outstandingAddrs.find(req->dest);
|
removeAddr = outstandingAddrs.find(req->dest);
|
||||||
|
@ -177,36 +235,37 @@ MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
|
||||||
outstandingAddrs.erase(removeAddr);
|
outstandingAddrs.erase(removeAddr);
|
||||||
numCopiesStat++;
|
numCopiesStat++;
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
panic("invalid command");
|
panic("invalid command");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockAddr(req->paddr) == traceBlockAddr) {
|
if (blockAddr(req->getPaddr()) == traceBlockAddr) {
|
||||||
cerr << name() << ": completed "
|
cerr << name() << ": completed "
|
||||||
<< (req->cmd.isWrite() ? "write" : "read")
|
<< (pkt->isWrite() ? "write" : "read")
|
||||||
<< " access of "
|
<< " access of "
|
||||||
<< dec << req->size << " bytes at address 0x"
|
<< dec << pkt->getSize() << " bytes at address 0x"
|
||||||
<< hex << req->paddr
|
<< hex << req->getPaddr()
|
||||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
||||||
<< ", value = 0x";
|
<< ", value = 0x";
|
||||||
printData(cerr, req->data, req->size);
|
printData(cerr, pkt_data, pkt->getSize());
|
||||||
cerr << " @ cycle " << dec << curTick;
|
cerr << " @ cycle " << dec << curTick;
|
||||||
|
|
||||||
cerr << endl;
|
cerr << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
noResponseCycles = 0;
|
noResponseCycles = 0;
|
||||||
|
delete state;
|
||||||
delete [] data;
|
delete [] data;
|
||||||
|
delete pkt->req;
|
||||||
|
delete pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MemTest::regStats()
|
MemTest::regStats()
|
||||||
{
|
{
|
||||||
using namespace Stats;
|
using namespace Stats;
|
||||||
|
|
||||||
|
|
||||||
numReadsStat
|
numReadsStat
|
||||||
.name(name() + ".num_reads")
|
.name(name() + ".num_reads")
|
||||||
.desc("number of read accesses completed")
|
.desc("number of read accesses completed")
|
||||||
|
@ -234,7 +293,7 @@ MemTest::tick()
|
||||||
fatal("");
|
fatal("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cacheInterface->isBlocked()) {
|
if (accessRetry) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,30 +307,30 @@ MemTest::tick()
|
||||||
|
|
||||||
//If we aren't doing copies, use id as offset, and do a false sharing
|
//If we aren't doing copies, use id as offset, and do a false sharing
|
||||||
//mem tester
|
//mem tester
|
||||||
if (percentCopies == 0) {
|
|
||||||
//We can eliminate the lower bits of the offset, and then use the id
|
//We can eliminate the lower bits of the offset, and then use the id
|
||||||
//to offset within the blks
|
//to offset within the blks
|
||||||
offset &= ~63; //Not the low order bits
|
offset &= ~63; //Not the low order bits
|
||||||
offset += id;
|
offset += id;
|
||||||
access_size = 0;
|
access_size = 0;
|
||||||
}
|
|
||||||
|
|
||||||
MemReqPtr req = new MemReq();
|
Request *req = new Request();
|
||||||
|
uint32_t flags = 0;
|
||||||
|
Addr paddr;
|
||||||
|
|
||||||
if (cacheable < percentUncacheable) {
|
if (cacheable < percentUncacheable) {
|
||||||
req->flags |= UNCACHEABLE;
|
flags |= UNCACHEABLE;
|
||||||
req->paddr = uncacheAddr + offset;
|
paddr = uncacheAddr + offset;
|
||||||
} else {
|
} else {
|
||||||
req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
|
paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
|
||||||
}
|
}
|
||||||
// bool probe = (random() % 2 == 1) && !req->isUncacheable();
|
// bool probe = (random() % 2 == 1) && !req->isUncacheable();
|
||||||
bool probe = false;
|
bool probe = false;
|
||||||
|
|
||||||
req->size = 1 << access_size;
|
paddr &= ~((1 << access_size) - 1);
|
||||||
req->data = new uint8_t[req->size];
|
req->setPhys(paddr, 1 << access_size, flags);
|
||||||
req->paddr &= ~(req->size - 1);
|
req->setThreadContext(id,0);
|
||||||
req->time = curTick;
|
|
||||||
req->xc = thread->getProxy();
|
uint8_t *result = new uint8_t[8];
|
||||||
|
|
||||||
if (cmd < percentReads) {
|
if (cmd < percentReads) {
|
||||||
// read
|
// read
|
||||||
|
@ -279,60 +338,81 @@ MemTest::tick()
|
||||||
//For now we only allow one outstanding request per addreess per tester
|
//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
|
//This means we assume CPU does write forwarding to reads that alias something
|
||||||
//in the cpu store buffer.
|
//in the cpu store buffer.
|
||||||
if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return;
|
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) return;
|
||||||
else outstandingAddrs.insert(req->paddr);
|
else outstandingAddrs.insert(paddr);
|
||||||
|
|
||||||
req->cmd = Read;
|
// ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
|
||||||
uint8_t *result = new uint8_t[8];
|
funcPort.readBlob(req->getPaddr(), result, req->getSize());
|
||||||
checkMem->access(Read, req->paddr, result, req->size);
|
|
||||||
if (blockAddr(req->paddr) == traceBlockAddr) {
|
if (blockAddr(paddr) == traceBlockAddr) {
|
||||||
cerr << name()
|
cerr << name()
|
||||||
<< ": initiating read "
|
<< ": initiating read "
|
||||||
<< ((probe) ? "probe of " : "access of ")
|
<< ((probe) ? "probe of " : "access of ")
|
||||||
<< dec << req->size << " bytes from addr 0x"
|
<< dec << req->getSize() << " bytes from addr 0x"
|
||||||
<< hex << req->paddr
|
<< hex << paddr
|
||||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
<< " (0x" << hex << blockAddr(paddr) << ")"
|
||||||
<< " at cycle "
|
<< " at cycle "
|
||||||
<< dec << curTick << endl;
|
<< 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) {
|
if (probe) {
|
||||||
cacheInterface->probeAndUpdate(req);
|
cachePort.sendFunctional(pkt);
|
||||||
completeRequest(req, result);
|
// completeRequest(pkt, result);
|
||||||
} else {
|
} else {
|
||||||
req->completionEvent = new MemCompleteEvent(req, result, this);
|
// req->completionEvent = new MemCompleteEvent(req, result, this);
|
||||||
cacheInterface->access(req);
|
if (!cachePort.sendTiming(pkt)) {
|
||||||
|
accessRetry = true;
|
||||||
|
retryPkt = pkt;
|
||||||
}
|
}
|
||||||
} else if (cmd < (100 - percentCopies)){
|
}
|
||||||
|
} else {
|
||||||
// write
|
// write
|
||||||
|
|
||||||
//For now we only allow one outstanding request per addreess per tester
|
//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
|
//This means we assume CPU does write forwarding to reads that alias something
|
||||||
//in the cpu store buffer.
|
//in the cpu store buffer.
|
||||||
if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return;
|
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) return;
|
||||||
else outstandingAddrs.insert(req->paddr);
|
else outstandingAddrs.insert(paddr);
|
||||||
|
|
||||||
req->cmd = Write;
|
/*
|
||||||
memcpy(req->data, &data, req->size);
|
if (blockAddr(req->getPaddr()) == traceBlockAddr) {
|
||||||
checkMem->access(Write, req->paddr, req->data, req->size);
|
|
||||||
if (blockAddr(req->paddr) == traceBlockAddr) {
|
|
||||||
cerr << name() << ": initiating write "
|
cerr << name() << ": initiating write "
|
||||||
<< ((probe)?"probe of ":"access of ")
|
<< ((probe)?"probe of ":"access of ")
|
||||||
<< dec << req->size << " bytes (value = 0x";
|
<< dec << req->getSize() << " bytes (value = 0x";
|
||||||
printData(cerr, req->data, req->size);
|
printData(cerr, data_pkt->getPtr(), req->getSize());
|
||||||
cerr << ") to addr 0x"
|
cerr << ") to addr 0x"
|
||||||
<< hex << req->paddr
|
<< hex << req->getPaddr()
|
||||||
<< " (0x" << hex << blockAddr(req->paddr) << ")"
|
<< " (0x" << hex << blockAddr(req->getPaddr()) << ")"
|
||||||
<< " at cycle "
|
<< " at cycle "
|
||||||
<< dec << curTick << endl;
|
<< 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) {
|
if (probe) {
|
||||||
cacheInterface->probeAndUpdate(req);
|
cachePort.sendFunctional(pkt);
|
||||||
completeRequest(req, NULL);
|
// completeRequest(req, NULL);
|
||||||
} else {
|
} else {
|
||||||
req->completionEvent = new MemCompleteEvent(req, NULL, this);
|
// req->completionEvent = new MemCompleteEvent(req, NULL, this);
|
||||||
cacheInterface->access(req);
|
if (!cachePort.sendTiming(pkt)) {
|
||||||
|
accessRetry = true;
|
||||||
|
retryPkt = pkt;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
/* else {
|
||||||
// copy
|
// copy
|
||||||
unsigned source_align = random() % 100;
|
unsigned source_align = random() % 100;
|
||||||
unsigned dest_align = random() % 100;
|
unsigned dest_align = random() % 100;
|
||||||
|
@ -369,38 +449,32 @@ MemTest::tick()
|
||||||
<< " (0x" << hex << blockAddr(dest) << ")"
|
<< " (0x" << hex << blockAddr(dest) << ")"
|
||||||
<< " at cycle "
|
<< " at cycle "
|
||||||
<< dec << curTick << endl;
|
<< dec << curTick << endl;
|
||||||
}
|
}*
|
||||||
cacheInterface->access(req);
|
cacheInterface->access(req);
|
||||||
uint8_t result[blockSize];
|
uint8_t result[blockSize];
|
||||||
checkMem->access(Read, source, &result, blockSize);
|
checkMem->access(Read, source, &result, blockSize);
|
||||||
checkMem->access(Write, dest, &result, blockSize);
|
checkMem->access(Write, dest, &result, blockSize);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MemCompleteEvent::process()
|
MemTest::doRetry()
|
||||||
{
|
{
|
||||||
tester->completeRequest(req, data);
|
if (cachePort.sendTiming(retryPkt)) {
|
||||||
delete this;
|
accessRetry = false;
|
||||||
|
retryPkt = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
|
||||||
MemCompleteEvent::description()
|
|
||||||
{
|
|
||||||
return "memory access completion";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
|
BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
|
||||||
|
|
||||||
SimObjectParam<BaseCache *> cache;
|
// SimObjectParam<BaseCache *> cache;
|
||||||
SimObjectParam<FunctionalMemory *> main_mem;
|
// SimObjectParam<PhysicalMemory *> main_mem;
|
||||||
SimObjectParam<FunctionalMemory *> check_mem;
|
// SimObjectParam<PhysicalMemory *> check_mem;
|
||||||
Param<unsigned> memory_size;
|
Param<unsigned> memory_size;
|
||||||
Param<unsigned> percent_reads;
|
Param<unsigned> percent_reads;
|
||||||
Param<unsigned> percent_copies;
|
// Param<unsigned> percent_copies;
|
||||||
Param<unsigned> percent_uncacheable;
|
Param<unsigned> percent_uncacheable;
|
||||||
Param<unsigned> progress_interval;
|
Param<unsigned> progress_interval;
|
||||||
Param<unsigned> percent_source_unaligned;
|
Param<unsigned> percent_source_unaligned;
|
||||||
|
@ -413,12 +487,12 @@ END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
|
||||||
|
|
||||||
BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
|
BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
|
||||||
|
|
||||||
INIT_PARAM(cache, "L1 cache"),
|
// INIT_PARAM(cache, "L1 cache"),
|
||||||
INIT_PARAM(main_mem, "hierarchical memory"),
|
// INIT_PARAM(main_mem, "hierarchical memory"),
|
||||||
INIT_PARAM(check_mem, "check memory"),
|
// INIT_PARAM(check_mem, "check memory"),
|
||||||
INIT_PARAM(memory_size, "memory size"),
|
INIT_PARAM(memory_size, "memory size"),
|
||||||
INIT_PARAM(percent_reads, "target read percentage"),
|
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(percent_uncacheable, "target uncacheable percentage"),
|
||||||
INIT_PARAM(progress_interval, "progress report interval (in accesses)"),
|
INIT_PARAM(progress_interval, "progress report interval (in accesses)"),
|
||||||
INIT_PARAM(percent_source_unaligned,
|
INIT_PARAM(percent_source_unaligned,
|
||||||
|
@ -433,8 +507,8 @@ END_INIT_SIM_OBJECT_PARAMS(MemTest)
|
||||||
|
|
||||||
CREATE_SIM_OBJECT(MemTest)
|
CREATE_SIM_OBJECT(MemTest)
|
||||||
{
|
{
|
||||||
return new MemTest(getInstanceName(), cache->getInterface(), main_mem,
|
return new MemTest(getInstanceName(), /*cache->getInterface(),*/ /*main_mem,*/
|
||||||
check_mem, memory_size, percent_reads, percent_copies,
|
/*check_mem,*/ memory_size, percent_reads, /*percent_copies,*/
|
||||||
percent_uncacheable, progress_interval,
|
percent_uncacheable, progress_interval,
|
||||||
percent_source_unaligned, percent_dest_unaligned,
|
percent_source_unaligned, percent_dest_unaligned,
|
||||||
trace_addr, max_loads);
|
trace_addr, max_loads);
|
||||||
|
|
|
@ -35,25 +35,27 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
#include "mem/functional/functional.hh"
|
//#include "mem/functional/functional.hh"
|
||||||
#include "mem/mem_interface.hh"
|
//#include "mem/mem_interface.hh"
|
||||||
#include "sim/eventq.hh"
|
#include "sim/eventq.hh"
|
||||||
#include "sim/sim_exit.hh"
|
#include "sim/sim_exit.hh"
|
||||||
#include "sim/sim_object.hh"
|
#include "sim/sim_object.hh"
|
||||||
#include "sim/stats.hh"
|
#include "sim/stats.hh"
|
||||||
|
#include "mem/mem_object.hh"
|
||||||
|
#include "mem/port.hh"
|
||||||
|
|
||||||
class ThreadContext;
|
class Packet;
|
||||||
class MemTest : public SimObject
|
class MemTest : public MemObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MemTest(const std::string &name,
|
MemTest(const std::string &name,
|
||||||
MemInterface *_cache_interface,
|
// MemInterface *_cache_interface,
|
||||||
FunctionalMemory *main_mem,
|
// PhysicalMemory *main_mem,
|
||||||
FunctionalMemory *check_mem,
|
// PhysicalMemory *check_mem,
|
||||||
unsigned _memorySize,
|
unsigned _memorySize,
|
||||||
unsigned _percentReads,
|
unsigned _percentReads,
|
||||||
unsigned _percentCopies,
|
// unsigned _percentCopies,
|
||||||
unsigned _percentUncacheable,
|
unsigned _percentUncacheable,
|
||||||
unsigned _progressInterval,
|
unsigned _progressInterval,
|
||||||
unsigned _percentSourceUnaligned,
|
unsigned _percentSourceUnaligned,
|
||||||
|
@ -61,6 +63,8 @@ class MemTest : public SimObject
|
||||||
Addr _traceAddr,
|
Addr _traceAddr,
|
||||||
Counter _max_loads);
|
Counter _max_loads);
|
||||||
|
|
||||||
|
virtual void init();
|
||||||
|
|
||||||
// register statistics
|
// register statistics
|
||||||
virtual void regStats();
|
virtual void regStats();
|
||||||
|
|
||||||
|
@ -69,6 +73,8 @@ class MemTest : public SimObject
|
||||||
// main simulation loop (one cycle)
|
// main simulation loop (one cycle)
|
||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
|
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class TickEvent : public Event
|
class TickEvent : public Event
|
||||||
{
|
{
|
||||||
|
@ -82,16 +88,62 @@ class MemTest : public SimObject
|
||||||
};
|
};
|
||||||
|
|
||||||
TickEvent tickEvent;
|
TickEvent tickEvent;
|
||||||
|
class CpuPort : public Port
|
||||||
|
{
|
||||||
|
|
||||||
MemInterface *cacheInterface;
|
MemTest *memtest;
|
||||||
FunctionalMemory *mainMem;
|
|
||||||
FunctionalMemory *checkMem;
|
public:
|
||||||
SimpleThread *thread;
|
|
||||||
|
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 size; // size of testing memory region
|
||||||
|
|
||||||
unsigned percentReads; // target percentage of read accesses
|
unsigned percentReads; // target percentage of read accesses
|
||||||
unsigned percentCopies; // target percentage of copy accesses
|
// unsigned percentCopies; // target percentage of copy accesses
|
||||||
unsigned percentUncacheable;
|
unsigned percentUncacheable;
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
|
@ -128,31 +180,13 @@ class MemTest : public SimObject
|
||||||
Stats::Scalar<> numCopiesStat;
|
Stats::Scalar<> numCopiesStat;
|
||||||
|
|
||||||
// called by MemCompleteEvent::process()
|
// called by MemCompleteEvent::process()
|
||||||
void completeRequest(MemReqPtr &req, uint8_t *data);
|
void completeRequest(Packet *pkt);
|
||||||
|
|
||||||
|
void doRetry();
|
||||||
|
|
||||||
friend class MemCompleteEvent;
|
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__
|
#endif // __CPU_MEMTEST_MEMTEST_HH__
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
from m5.SimObject import SimObject
|
from m5.SimObject import SimObject
|
||||||
from m5.params import *
|
from m5.params import *
|
||||||
|
from m5.proxy import *
|
||||||
|
from m5 import build_env
|
||||||
|
|
||||||
class MemTest(SimObject):
|
class MemTest(SimObject):
|
||||||
type = 'MemTest'
|
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")
|
max_loads = Param.Counter("number of loads to execute")
|
||||||
memory_size = Param.Int(65536, "memory size")
|
memory_size = Param.Int(65536, "memory size")
|
||||||
percent_copies = Param.Percent(0, "target copy percentage")
|
|
||||||
percent_dest_unaligned = Param.Percent(50,
|
percent_dest_unaligned = Param.Percent(50,
|
||||||
"percent of copy dest address that are unaligned")
|
"percent of copy dest address that are unaligned")
|
||||||
percent_reads = Param.Percent(65, "target read percentage")
|
percent_reads = Param.Percent(65, "target read percentage")
|
||||||
|
@ -18,3 +17,6 @@ class MemTest(SimObject):
|
||||||
progress_interval = Param.Counter(1000000,
|
progress_interval = Param.Counter(1000000,
|
||||||
"progress report interval (in accesses)")
|
"progress report interval (in accesses)")
|
||||||
trace_addr = Param.Addr(0, "address to trace")
|
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