summaryrefslogtreecommitdiff
path: root/src/cpu/testers/memtest/memtest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/testers/memtest/memtest.cc')
-rw-r--r--src/cpu/testers/memtest/memtest.cc355
1 files changed, 151 insertions, 204 deletions
diff --git a/src/cpu/testers/memtest/memtest.cc b/src/cpu/testers/memtest/memtest.cc
index a94f6950d..1d2554852 100644
--- a/src/cpu/testers/memtest/memtest.cc
+++ b/src/cpu/testers/memtest/memtest.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -27,173 +39,129 @@
*
* Authors: Erik Hallnor
* Steve Reinhardt
+ * Andreas Hansson
*/
-// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
-
-#include <iomanip>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/misc.hh"
#include "base/random.hh"
#include "base/statistics.hh"
#include "cpu/testers/memtest/memtest.hh"
#include "debug/MemTest.hh"
#include "mem/mem_object.hh"
-#include "mem/packet.hh"
-#include "mem/port.hh"
-#include "mem/request.hh"
-#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
#include "sim/stats.hh"
#include "sim/system.hh"
using namespace std;
-int TESTER_ALLOCATOR=0;
+unsigned int TESTER_ALLOCATOR = 0;
bool
MemTest::CpuPort::recvTimingResp(PacketPtr pkt)
{
- memtest->completeRequest(pkt);
+ memtest.completeRequest(pkt);
return true;
}
void
MemTest::CpuPort::recvRetry()
{
- memtest->doRetry();
+ memtest.recvRetry();
}
-void
+bool
MemTest::sendPkt(PacketPtr pkt) {
if (atomic) {
- cachePort.sendAtomic(pkt);
+ port.sendAtomic(pkt);
completeRequest(pkt);
- }
- else if (!cachePort.sendTimingReq(pkt)) {
- DPRINTF(MemTest, "accessRetry setting to true\n");
-
- //
- // dma requests should never be retried
- //
- if (issueDmas) {
- panic("Nacked DMA requests are not supported\n");
- }
- accessRetry = true;
- retryPkt = pkt;
} else {
- if (issueDmas) {
- dmaOutstanding = true;
+ if (!port.sendTimingReq(pkt)) {
+ retryPkt = pkt;
+ return false;
}
}
-
+ return true;
}
MemTest::MemTest(const Params *p)
: MemObject(p),
tickEvent(this),
- cachePort("test", this),
- funcPort("functional", this),
- funcProxy(funcPort, p->sys->cacheLineSize()),
- retryPkt(NULL),
-// mainMem(main_mem),
-// checkMem(check_mem),
- size(p->memory_size),
+ noRequestEvent(this),
+ noResponseEvent(this),
+ port("port", *this),
+ retryPkt(nullptr),
+ size(p->size),
+ interval(p->interval),
percentReads(p->percent_reads),
percentFunctional(p->percent_functional),
percentUncacheable(p->percent_uncacheable),
- issueDmas(p->issue_dmas),
- masterId(p->sys->getMasterId(name())),
- blockSize(p->sys->cacheLineSize()),
+ masterId(p->system->getMasterId(name())),
+ blockSize(p->system->cacheLineSize()),
+ blockAddrMask(blockSize - 1),
progressInterval(p->progress_interval),
+ progressCheck(p->progress_check),
nextProgressMessage(p->progress_interval),
- percentSourceUnaligned(p->percent_source_unaligned),
- percentDestUnaligned(p->percent_dest_unaligned),
maxLoads(p->max_loads),
- atomic(p->atomic),
- suppress_func_warnings(p->suppress_func_warnings)
+ atomic(p->system->isAtomicMode()),
+ suppressFuncWarnings(p->suppress_func_warnings)
{
id = TESTER_ALLOCATOR++;
+ fatal_if(id >= blockSize, "Too many testers, only %d allowed\n",
+ blockSize - 1);
- // Needs to be masked off once we know the block size.
- traceBlockAddr = p->trace_addr;
baseAddr1 = 0x100000;
baseAddr2 = 0x400000;
uncacheAddr = 0x800000;
- blockAddrMask = blockSize - 1;
- traceBlockAddr = blockAddr(traceBlockAddr);
-
// set up counters
- noResponseCycles = 0;
numReads = 0;
numWrites = 0;
- schedule(tickEvent, 0);
- accessRetry = false;
- dmaOutstanding = false;
+ // kick things into action
+ schedule(tickEvent, curTick());
+ schedule(noRequestEvent, clockEdge(progressCheck));
+ schedule(noResponseEvent, clockEdge(progressCheck));
}
BaseMasterPort &
MemTest::getMasterPort(const std::string &if_name, PortID idx)
{
- if (if_name == "functional")
- return funcPort;
- else if (if_name == "test")
- return cachePort;
+ if (if_name == "port")
+ return port;
else
return MemObject::getMasterPort(if_name, idx);
}
void
-MemTest::init()
-{
- // initial memory contents for both physical memory and functional
- // memory should be 0; no need to initialize them.
-}
-
-
-void
-MemTest::completeRequest(PacketPtr pkt)
+MemTest::completeRequest(PacketPtr pkt, bool functional)
{
Request *req = pkt->req;
+ assert(req->getSize() == 1);
- if (issueDmas) {
- dmaOutstanding = false;
- }
+ // this address is no longer outstanding
+ auto remove_addr = outstandingAddrs.find(req->getPaddr());
+ assert(remove_addr != outstandingAddrs.end());
+ outstandingAddrs.erase(remove_addr);
- DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n",
+ DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n",
pkt->isWrite() ? "write" : "read",
- req->getPaddr(), blockAddr(req->getPaddr()),
+ req->getPaddr(), blockAlign(req->getPaddr()),
pkt->isError() ? "error" : "success");
- MemTestSenderState *state =
- safe_cast<MemTestSenderState *>(pkt->senderState);
-
- uint8_t *data = state->data;
- // @todo: This should really be a const pointer
- uint8_t *pkt_data = pkt->getPtr<uint8_t>();
-
- //Remove the address from the list of outstanding
- std::set<unsigned>::iterator removeAddr =
- outstandingAddrs.find(req->getPaddr());
- assert(removeAddr != outstandingAddrs.end());
- outstandingAddrs.erase(removeAddr);
+ const uint8_t *pkt_data = pkt->getConstPtr<uint8_t>();
if (pkt->isError()) {
- if (!suppress_func_warnings) {
- warn("Functional %s access failed at %#x\n",
- pkt->isWrite() ? "write" : "read", req->getPaddr());
+ if (!functional || !suppressFuncWarnings) {
+ warn("%s access failed at %#x\n",
+ pkt->isWrite() ? "Write" : "Read", req->getPaddr());
}
} else {
if (pkt->isRead()) {
- if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
+ uint8_t ref_data = referenceData[req->getPaddr()];
+ if (pkt_data[0] != ref_data) {
panic("%s: read of %x (blk %x) @ cycle %d "
"returns %x, expected %x\n", name(),
- req->getPaddr(), blockAddr(req->getPaddr()), curTick(),
- *pkt_data, *data);
+ req->getPaddr(), blockAlign(req->getPaddr()), curTick(),
+ pkt_data[0], ref_data);
}
numReads++;
@@ -209,17 +177,21 @@ MemTest::completeRequest(PacketPtr pkt)
exitSimLoop("maximum number of loads reached");
} else {
assert(pkt->isWrite());
- funcProxy.writeBlob(req->getPaddr(), pkt_data, req->getSize());
+
+ // update the reference data
+ referenceData[req->getPaddr()] = pkt_data[0];
numWrites++;
numWritesStat++;
}
}
- noResponseCycles = 0;
- delete state;
- delete [] data;
delete pkt->req;
+
+ // the packet will delete the data
delete pkt;
+
+ // finally shift the response timeout forward
+ reschedule(noResponseEvent, clockEdge(progressCheck), true);
}
void
@@ -236,151 +208,126 @@ MemTest::regStats()
.name(name() + ".num_writes")
.desc("number of write accesses completed")
;
-
- numCopiesStat
- .name(name() + ".num_copies")
- .desc("number of copy accesses completed")
- ;
}
void
MemTest::tick()
{
- if (!tickEvent.scheduled())
- schedule(tickEvent, clockEdge(Cycles(1)));
+ // we should never tick if we are waiting for a retry
+ assert(!retryPkt);
- if (++noResponseCycles >= 500000) {
- if (issueDmas) {
- cerr << "DMA tester ";
- }
- cerr << name() << ": deadlocked at cycle " << curTick() << endl;
- fatal("");
- }
-
- if (accessRetry || (issueDmas && dmaOutstanding)) {
- DPRINTF(MemTest, "MemTester waiting on accessRetry or DMA response\n");
- return;
- }
-
- //make new request
+ // create a new request
unsigned cmd = random_mt.random(0, 100);
- unsigned offset = random_mt.random<unsigned>(0, size - 1);
- unsigned base = random_mt.random(0, 1);
- uint64_t data = random_mt.random<uint64_t>();
- unsigned access_size = random_mt.random(0, 3);
+ uint8_t data = random_mt.random<uint8_t>();
bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
-
- unsigned dma_access_size = random_mt.random(0, 3);
-
- //If we aren't doing copies, use id as offset, and do a false sharing
- //mem tester
- //We can eliminate the lower bits of the offset, and then use the id
- //to offset within the blks
- offset = blockAddr(offset);
- offset += id;
- access_size = 0;
- dma_access_size = 0;
-
+ unsigned base = random_mt.random(0, 1);
Request::Flags flags;
Addr paddr;
- if (uncacheable) {
- flags.set(Request::UNCACHEABLE);
- paddr = uncacheAddr + offset;
- } else {
- paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
- }
+ // generate a unique address
+ do {
+ unsigned offset = random_mt.random<unsigned>(0, size - 1);
- // For now we only allow one outstanding request per address
- // per tester This means we assume CPU does write forwarding
- // to reads that alias something in the cpu store buffer.
- if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
- return;
- }
+ // use the tester id as offset within the block for false sharing
+ offset = blockAlign(offset);
+ offset += id;
+
+ if (uncacheable) {
+ flags.set(Request::UNCACHEABLE);
+ paddr = uncacheAddr + offset;
+ } else {
+ paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
+ }
+ } while (outstandingAddrs.find(paddr) != outstandingAddrs.end());
bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
!uncacheable;
- Request *req = nullptr;
- uint8_t *result = new uint8_t[8];
+ Request *req = new Request(paddr, 1, flags, masterId);
+ req->setThreadContext(id, 0);
- if (issueDmas) {
- paddr &= ~((1 << dma_access_size) - 1);
- req = new Request(paddr, 1 << dma_access_size, flags, masterId);
- req->setThreadContext(id,0);
- } else {
- paddr &= ~((1 << access_size) - 1);
- req = new Request(paddr, 1 << access_size, flags, masterId);
- req->setThreadContext(id,0);
- }
- assert(req->getSize() == 1);
+ outstandingAddrs.insert(paddr);
- if (cmd < percentReads) {
- // read
- outstandingAddrs.insert(paddr);
+ // sanity check
+ panic_if(outstandingAddrs.size() > 100,
+ "Tester %s has more than 100 outstanding requests\n", name());
- // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
- funcProxy.readBlob(req->getPaddr(), result, req->getSize());
+ PacketPtr pkt = nullptr;
+ uint8_t *pkt_data = new uint8_t[1];
- DPRINTF(MemTest,
- "id %d initiating %sread at addr %x (blk %x) expecting %x\n",
- id, do_functional ? "functional " : "", req->getPaddr(),
- blockAddr(req->getPaddr()), *result);
-
- PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
- pkt->dataDynamic(new uint8_t[req->getSize()]);
- MemTestSenderState *state = new MemTestSenderState(result);
- pkt->senderState = state;
-
- if (do_functional) {
- assert(pkt->needsResponse());
- pkt->setSuppressFuncError();
- cachePort.sendFunctional(pkt);
- completeRequest(pkt);
+ if (cmd < percentReads) {
+ // start by ensuring there is a reference value if we have not
+ // seen this address before
+ uint8_t M5_VAR_USED ref_data = 0;
+ auto ref = referenceData.find(req->getPaddr());
+ if (ref == referenceData.end()) {
+ referenceData[req->getPaddr()] = 0;
} else {
- sendPkt(pkt);
+ ref_data = ref->second;
}
- } else {
- // write
- outstandingAddrs.insert(paddr);
- DPRINTF(MemTest, "initiating %swrite at addr %x (blk %x) value %x\n",
+ DPRINTF(MemTest,
+ "Initiating %sread at addr %x (blk %x) expecting %x\n",
do_functional ? "functional " : "", req->getPaddr(),
- blockAddr(req->getPaddr()), data & 0xff);
+ blockAlign(req->getPaddr()), ref_data);
- PacketPtr pkt = new Packet(req, MemCmd::WriteReq);
- uint8_t *pkt_data = new uint8_t[req->getSize()];
+ pkt = new Packet(req, MemCmd::ReadReq);
pkt->dataDynamic(pkt_data);
- memcpy(pkt_data, &data, req->getSize());
- MemTestSenderState *state = new MemTestSenderState(result);
- pkt->senderState = state;
-
- if (do_functional) {
- pkt->setSuppressFuncError();
- cachePort.sendFunctional(pkt);
- completeRequest(pkt);
- } else {
- sendPkt(pkt);
- }
+ } else {
+ DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n",
+ do_functional ? "functional " : "", req->getPaddr(),
+ blockAlign(req->getPaddr()), data);
+
+ pkt = new Packet(req, MemCmd::WriteReq);
+ pkt->dataDynamic(pkt_data);
+ pkt_data[0] = data;
+ }
+
+ // there is no point in ticking if we are waiting for a retry
+ bool keep_ticking = true;
+ if (do_functional) {
+ pkt->setSuppressFuncError();
+ port.sendFunctional(pkt);
+ completeRequest(pkt, true);
+ } else {
+ keep_ticking = sendPkt(pkt);
+ }
+
+ if (keep_ticking) {
+ // schedule the next tick
+ schedule(tickEvent, clockEdge(interval));
+
+ // finally shift the timeout for sending of requests forwards
+ // as we have successfully sent a packet
+ reschedule(noRequestEvent, clockEdge(progressCheck), true);
+ } else {
+ DPRINTF(MemTest, "Waiting for retry\n");
}
}
void
-MemTest::doRetry()
+MemTest::noRequest()
{
- if (cachePort.sendTimingReq(retryPkt)) {
- DPRINTF(MemTest, "accessRetry setting to false\n");
- accessRetry = false;
- retryPkt = NULL;
- }
+ panic("%s did not send a request for %d cycles", name(), progressCheck);
}
-
void
-MemTest::printAddr(Addr a)
+MemTest::noResponse()
{
- cachePort.printAddr(a);
+ panic("%s did not see a response for %d cycles", name(), progressCheck);
}
+void
+MemTest::recvRetry()
+{
+ assert(retryPkt);
+ if (port.sendTimingReq(retryPkt)) {
+ DPRINTF(MemTest, "Proceeding after successful retry\n");
+
+ retryPkt = nullptr;
+ // kick things into action again
+ schedule(tickEvent, clockEdge(interval));
+ }
+}
MemTest *
MemTestParams::create()