1a2,13
> * 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.
> *
29a42
> * Andreas Hansson
32,39d44
< // FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
<
< #include <iomanip>
< #include <set>
< #include <string>
< #include <vector>
<
< #include "base/misc.hh"
45,48c50
< #include "mem/packet.hh"
< #include "mem/port.hh"
< #include "mem/request.hh"
< #include "sim/sim_events.hh"
---
> #include "sim/sim_exit.hh"
54c56
< int TESTER_ALLOCATOR=0;
---
> unsigned int TESTER_ALLOCATOR = 0;
59c61
< memtest->completeRequest(pkt);
---
> memtest.completeRequest(pkt);
66c68
< memtest->doRetry();
---
> memtest.recvRetry();
69c71
< void
---
> bool
72c74
< cachePort.sendAtomic(pkt);
---
> port.sendAtomic(pkt);
74,85d75
< }
< 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;
87,88c77,79
< if (issueDmas) {
< dmaOutstanding = true;
---
> if (!port.sendTimingReq(pkt)) {
> retryPkt = pkt;
> return false;
91c82
<
---
> return true;
97,103c88,93
< 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),
107,109c97,99
< 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),
110a101
> progressCheck(p->progress_check),
112,113d102
< percentSourceUnaligned(p->percent_source_unaligned),
< percentDestUnaligned(p->percent_dest_unaligned),
115,116c104,105
< atomic(p->atomic),
< suppress_func_warnings(p->suppress_func_warnings)
---
> atomic(p->system->isAtomicMode()),
> suppressFuncWarnings(p->suppress_func_warnings)
118a108,109
> fatal_if(id >= blockSize, "Too many testers, only %d allowed\n",
> blockSize - 1);
120,121d110
< // Needs to be masked off once we know the block size.
< traceBlockAddr = p->trace_addr;
126,128d114
< blockAddrMask = blockSize - 1;
< traceBlockAddr = blockAddr(traceBlockAddr);
<
130d115
< noResponseCycles = 0;
133d117
< schedule(tickEvent, 0);
135,136c119,122
< accessRetry = false;
< dmaOutstanding = false;
---
> // kick things into action
> schedule(tickEvent, curTick());
> schedule(noRequestEvent, clockEdge(progressCheck));
> schedule(noResponseEvent, clockEdge(progressCheck));
142,145c128,129
< if (if_name == "functional")
< return funcPort;
< else if (if_name == "test")
< return cachePort;
---
> if (if_name == "port")
> return port;
151c135
< MemTest::init()
---
> MemTest::completeRequest(PacketPtr pkt, bool functional)
153,160d136
< // initial memory contents for both physical memory and functional
< // memory should be 0; no need to initialize them.
< }
<
<
< void
< MemTest::completeRequest(PacketPtr pkt)
< {
161a138
> assert(req->getSize() == 1);
163,165c140,143
< 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);
167c145
< DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n",
---
> DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n",
169c147
< req->getPaddr(), blockAddr(req->getPaddr()),
---
> req->getPaddr(), blockAlign(req->getPaddr()),
172,173c150
< MemTestSenderState *state =
< safe_cast<MemTestSenderState *>(pkt->senderState);
---
> const uint8_t *pkt_data = pkt->getConstPtr<uint8_t>();
175,184d151
< 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);
<
186,188c153,155
< 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());
192c159,160
< if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
---
> uint8_t ref_data = referenceData[req->getPaddr()];
> if (pkt_data[0] != ref_data) {
195,196c163,164
< req->getPaddr(), blockAddr(req->getPaddr()), curTick(),
< *pkt_data, *data);
---
> req->getPaddr(), blockAlign(req->getPaddr()), curTick(),
> pkt_data[0], ref_data);
212c180,182
< funcProxy.writeBlob(req->getPaddr(), pkt_data, req->getSize());
---
>
> // update the reference data
> referenceData[req->getPaddr()] = pkt_data[0];
218,220d187
< noResponseCycles = 0;
< delete state;
< delete [] data;
221a189,190
>
> // the packet will delete the data
222a192,194
>
> // finally shift the response timeout forward
> reschedule(noResponseEvent, clockEdge(progressCheck), true);
239,243d210
<
< numCopiesStat
< .name(name() + ".num_copies")
< .desc("number of copy accesses completed")
< ;
249,250c216,217
< if (!tickEvent.scheduled())
< schedule(tickEvent, clockEdge(Cycles(1)));
---
> // we should never tick if we are waiting for a retry
> assert(!retryPkt);
252,265c219
< 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
267,270c221
< 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>();
272,283c223
<
< 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);
287,292c227,229
< 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);
294,299c231,233
< // 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;
300a235,242
> if (uncacheable) {
> flags.set(Request::UNCACHEABLE);
> paddr = uncacheAddr + offset;
> } else {
> paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
> }
> } while (outstandingAddrs.find(paddr) != outstandingAddrs.end());
>
303,304c245,246
< Request *req = nullptr;
< uint8_t *result = new uint8_t[8];
---
> Request *req = new Request(paddr, 1, flags, masterId);
> req->setThreadContext(id, 0);
306,315c248
< 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);
317,319c250,252
< if (cmd < percentReads) {
< // read
< outstandingAddrs.insert(paddr);
---
> // sanity check
> panic_if(outstandingAddrs.size() > 100,
> "Tester %s has more than 100 outstanding requests\n", name());
321,322c254,255
< // ***** 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];
324,338c257,263
< 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;
340c265
< sendPkt(pkt);
---
> ref_data = ref->second;
342,344d266
< } else {
< // write
< outstandingAddrs.insert(paddr);
346c268,269
< DPRINTF(MemTest, "initiating %swrite at addr %x (blk %x) value %x\n",
---
> DPRINTF(MemTest,
> "Initiating %sread at addr %x (blk %x) expecting %x\n",
348c271
< blockAddr(req->getPaddr()), data & 0xff);
---
> blockAlign(req->getPaddr()), ref_data);
350,351c273
< PacketPtr pkt = new Packet(req, MemCmd::WriteReq);
< uint8_t *pkt_data = new uint8_t[req->getSize()];
---
> pkt = new Packet(req, MemCmd::ReadReq);
353,355c275,278
< memcpy(pkt_data, &data, req->getSize());
< MemTestSenderState *state = new MemTestSenderState(result);
< pkt->senderState = state;
---
> } else {
> DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n",
> do_functional ? "functional " : "", req->getPaddr(),
> blockAlign(req->getPaddr()), data);
357,363c280,282
< if (do_functional) {
< pkt->setSuppressFuncError();
< cachePort.sendFunctional(pkt);
< completeRequest(pkt);
< } else {
< sendPkt(pkt);
< }
---
> pkt = new Packet(req, MemCmd::WriteReq);
> pkt->dataDynamic(pkt_data);
> pkt_data[0] = data;
364a284,304
>
> // 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");
> }
368c308
< MemTest::doRetry()
---
> MemTest::noRequest()
370,374c310
< 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);
377d312
<
379c314
< MemTest::printAddr(Addr a)
---
> MemTest::noResponse()
381c316
< cachePort.printAddr(a);
---
> panic("%s did not see a response for %d cycles", name(), progressCheck);
383a319,324
> void
> MemTest::recvRetry()
> {
> assert(retryPkt);
> if (port.sendTimingReq(retryPkt)) {
> DPRINTF(MemTest, "Proceeding after successful retry\n");
384a326,331
> retryPkt = nullptr;
> // kick things into action again
> schedule(tickEvent, clockEdge(interval));
> }
> }
>