diff --git a/src/SConscript b/src/SConscript index 9f88bbeea..e75a36ab5 100644 --- a/src/SConscript +++ b/src/SConscript @@ -285,6 +285,7 @@ turbolaser_sources = Split(''' # Syscall emulation (non-full-system) sources syscall_emulation_sources = Split(''' + cpu/memtest/memtest.cc mem/translating_port.cc mem/page_table.cc sim/process.cc diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc index 7ea9eaefc..e3a47f10a 100644 --- a/src/cpu/memtest/memtest.cc +++ b/src/cpu/memtest/memtest.cc @@ -40,7 +40,8 @@ #include "base/statistics.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" @@ -50,27 +51,64 @@ 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), + cachePort("dcache", this), + retryPkt(NULL), mainMem(main_mem), checkMem(check_mem), size(_memorySize), percentReads(_percentReads), - percentCopies(_percentCopies), +// percentCopies(_percentCopies), percentUncacheable(_percentUncacheable), progressInterval(_progressInterval), nextProgressMessage(_progressInterval), @@ -81,11 +119,43 @@ MemTest::MemTest(const string &name, vector cmd; cmd.push_back("/bin/ls"); vector null_vec; - thread = new SimpleThread(NULL, 0, mainMem, 0); + thread = new SimpleThread(NULL, 0, NULL, 0, mainMem); + curTick = 0; - blockSize = cacheInterface->getBlockSize(); + // Needs to be masked off once we know the block size. + traceBlockAddr = _traceAddr; + baseAddr1 = 0x100000; + baseAddr2 = 0x400000; + uncacheAddr = 0x800000; + + // set up counters + noResponseCycles = 0; + numReads = 0; + tickEvent.schedule(0); + + id = TESTER_ALLOCATOR++; +} + +Port * +MemTest::getPort(const std::string &if_name, int idx) +{ + // ***** NOTE TO RON: I'm not sure what it should do if these get ports + // are called on it. + if (if_name == "dcache_port") + return &cachePort; + else if (if_name == "icache_port") + 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(_traceAddr); + traceBlockAddr = blockAddr(traceBlockAddr); //setup data storage with interesting values uint8_t *data1 = new uint8_t[size]; @@ -94,30 +164,22 @@ MemTest::MemTest(const string &name, 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 + // ***** NOTE FOR RON: I'm not sure how to setup initial memory + // contents. - Kevin +/* 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++; } static void @@ -132,23 +194,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(pkt->senderState); + + uint8_t *data = state->data; + uint8_t *pkt_data = pkt->getPtr(); + Request *req = pkt->req; + //Remove the address from the list of outstanding - std::set::iterator removeAddr = outstandingAddrs.find(req->paddr); + std::set::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::ReadReq: + + 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 +233,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::WriteReq: numWritesStat++; break; - +/* case Copy: //Also remove dest from outstanding list removeAddr = outstandingAddrs.find(req->dest); @@ -177,36 +247,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 +305,7 @@ MemTest::tick() fatal(""); } - if (cacheInterface->isBlocked()) { + if (accessRetry) { return; } @@ -248,6 +319,9 @@ MemTest::tick() //If we aren't doing copies, use id as offset, and do a false sharing //mem tester + // ***** NOTE FOR RON: We're not doing copies, but I'm not sure if this + // code should be used. +/* if (percentCopies == 0) { //We can eliminate the lower bits of the offset, and then use the id //to offset within the blks @@ -255,23 +329,25 @@ MemTest::tick() offset += id; access_size = 0; } +*/ - MemReqPtr req = new MemReq(); + Request *req = new Request(); + uint32_t flags = req->getFlags(); + 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); + + uint8_t *result = new uint8_t[8]; if (cmd < percentReads) { // read @@ -279,60 +355,84 @@ 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 +// checkMem->access(Read, req->getPaddr(), result, req->size); + 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); + // ***** NOTE FOR RON: Send functional access? It used to + // be a probeAndUpdate access. - Kevin + 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) { + // ***** NOTE FOR RON: Not sure how to access memory. +// checkMem->access(Write, req->paddr, req->data, req->size); +/* + 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; + if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, NULL); + // ***** NOTE FOR RON: Send functional access? It used to + // be a probe access. - Kevin + 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 +469,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 cache; - SimObjectParam main_mem; - SimObjectParam check_mem; +// SimObjectParam cache; + SimObjectParam main_mem; + SimObjectParam check_mem; Param memory_size; Param percent_reads; - Param percent_copies; +// Param percent_copies; Param percent_uncacheable; Param progress_interval; Param percent_source_unaligned; @@ -413,12 +507,12 @@ END_DECLARE_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(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 +527,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); diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index 42fb235db..a0e58126b 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -35,25 +35,26 @@ #include #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" +class PhysicalMemory; class ThreadContext; -class MemTest : public SimObject +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 +62,8 @@ class MemTest : public SimObject Addr _traceAddr, Counter _max_loads); + virtual void init(); + // register statistics virtual void regStats(); @@ -69,6 +72,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 +87,61 @@ class MemTest : public SimObject }; TickEvent tickEvent; + class CpuPort : public Port + { - MemInterface *cacheInterface; - FunctionalMemory *mainMem; - FunctionalMemory *checkMem; + 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; + + 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 +178,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__