6e8c5d0bf0d1655b63ac935b92046fd7fb132e96
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Authors: Erik Hallnor
32 // FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
39 #include "base/misc.hh"
40 #include "base/statistics.hh"
41 #include "cpu/memtest/memtest.hh"
42 //#include "cpu/simple_thread.hh"
43 //#include "mem/cache/base_cache.hh"
44 #include "mem/mem_object.hh"
45 #include "mem/port.hh"
46 #include "mem/packet.hh"
47 //#include "mem/physical.hh"
48 #include "mem/request.hh"
49 #include "sim/builder.hh"
50 #include "sim/sim_events.hh"
51 #include "sim/stats.hh"
55 int TESTER_ALLOCATOR
=0;
58 MemTest::CpuPort::recvTiming(PacketPtr pkt
)
60 memtest
->completeRequest(pkt
);
65 MemTest::CpuPort::recvAtomic(PacketPtr pkt
)
67 panic("MemTest doesn't expect recvAtomic callback!");
72 MemTest::CpuPort::recvFunctional(PacketPtr pkt
)
74 //Do nothing if we see one come through
75 // if (curTick != 0)//Supress warning durring initialization
76 // warn("Functional Writes not implemented in MemTester\n");
77 //Need to find any response values that intersect and update
82 MemTest::CpuPort::recvStatusChange(Status status
)
84 if (status
== RangeChange
) {
85 if (!snoopRangeSent
) {
86 snoopRangeSent
= true;
87 sendStatusChange(Port::RangeChange
);
92 panic("MemTest doesn't expect recvStatusChange callback!");
96 MemTest::CpuPort::recvRetry()
102 MemTest::sendPkt(PacketPtr pkt
) {
104 cachePort
.sendAtomic(pkt
);
105 completeRequest(pkt
);
107 else if (!cachePort
.sendTiming(pkt
)) {
114 MemTest::MemTest(const string
&name
,
115 // MemInterface *_cache_interface,
116 // PhysicalMemory *main_mem,
117 // PhysicalMemory *check_mem,
118 unsigned _memorySize
,
119 unsigned _percentReads
,
120 unsigned _percentFunctional
,
121 unsigned _percentUncacheable
,
122 unsigned _progressInterval
,
123 unsigned _percentSourceUnaligned
,
124 unsigned _percentDestUnaligned
,
130 cachePort("test", this),
131 funcPort("functional", this),
133 // mainMem(main_mem),
134 // checkMem(check_mem),
136 percentReads(_percentReads
),
137 percentFunctional(_percentFunctional
),
138 percentUncacheable(_percentUncacheable
),
139 progressInterval(_progressInterval
),
140 nextProgressMessage(_progressInterval
),
141 percentSourceUnaligned(_percentSourceUnaligned
),
142 percentDestUnaligned(percentDestUnaligned
),
143 maxLoads(_max_loads
),
147 cmd
.push_back("/bin/ls");
148 vector
<string
> null_vec
;
149 // thread = new SimpleThread(NULL, 0, NULL, 0, mainMem);
152 cachePort
.snoopRangeSent
= false;
153 funcPort
.snoopRangeSent
= true;
155 // Needs to be masked off once we know the block size.
156 traceBlockAddr
= _traceAddr
;
157 baseAddr1
= 0x100000;
158 baseAddr2
= 0x400000;
159 uncacheAddr
= 0x800000;
162 noResponseCycles
= 0;
164 tickEvent
.schedule(0);
166 id
= TESTER_ALLOCATOR
++;
172 MemTest::getPort(const std::string
&if_name
, int idx
)
174 if (if_name
== "functional")
176 else if (if_name
== "test")
179 panic("No Such Port\n");
185 // By the time init() is called, the ports should be hooked up.
186 blockSize
= cachePort
.peerBlockSize();
187 blockAddrMask
= blockSize
- 1;
188 traceBlockAddr
= blockAddr(traceBlockAddr
);
190 // initial memory contents for both physical memory and functional
191 // memory should be 0; no need to initialize them.
196 MemTest::completeRequest(PacketPtr pkt
)
198 Request
*req
= pkt
->req
;
200 DPRINTF(MemTest
, "completing %s at address %x (blk %x)\n",
201 pkt
->isWrite() ? "write" : "read",
202 req
->getPaddr(), blockAddr(req
->getPaddr()));
204 MemTestSenderState
*state
=
205 dynamic_cast<MemTestSenderState
*>(pkt
->senderState
);
207 uint8_t *data
= state
->data
;
208 uint8_t *pkt_data
= pkt
->getPtr
<uint8_t>();
210 //Remove the address from the list of outstanding
211 std::set
<unsigned>::iterator removeAddr
=
212 outstandingAddrs
.find(req
->getPaddr());
213 assert(removeAddr
!= outstandingAddrs
.end());
214 outstandingAddrs
.erase(removeAddr
);
216 switch (pkt
->cmd
.toInt()) {
217 case MemCmd::ReadResp
:
219 if (memcmp(pkt_data
, data
, pkt
->getSize()) != 0) {
220 panic("%s: read of %x (blk %x) @ cycle %d "
221 "returns %x, expected %x\n", name(),
222 req
->getPaddr(), blockAddr(req
->getPaddr()), curTick
,
229 if (numReads
== nextProgressMessage
) {
230 ccprintf(cerr
, "%s: completed %d read accesses @%d\n",
231 name(), numReads
, curTick
);
232 nextProgressMessage
+= progressInterval
;
235 if (numReads
>= maxLoads
)
236 exitSimLoop("maximum number of loads reached");
239 case MemCmd::WriteResp
:
244 panic("invalid command %s (%d)", pkt
->cmdString(), pkt
->cmd
.toInt());
247 noResponseCycles
= 0;
257 using namespace Stats
;
260 .name(name() + ".num_reads")
261 .desc("number of read accesses completed")
265 .name(name() + ".num_writes")
266 .desc("number of write accesses completed")
270 .name(name() + ".num_copies")
271 .desc("number of copy accesses completed")
278 if (!tickEvent
.scheduled())
279 tickEvent
.schedule(curTick
+ cycles(1));
281 if (++noResponseCycles
>= 500000) {
282 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
291 unsigned cmd
= random() % 100;
292 unsigned offset
= random() % size
;
293 unsigned base
= random() % 2;
294 uint64_t data
= random();
295 unsigned access_size
= random() % 4;
296 unsigned cacheable
= random() % 100;
298 //If we aren't doing copies, use id as offset, and do a false sharing
300 //We can eliminate the lower bits of the offset, and then use the id
301 //to offset within the blks
302 offset
= blockAddr(offset
);
306 Request
*req
= new Request();
310 if (cacheable
< percentUncacheable
) {
311 flags
|= UNCACHEABLE
;
312 paddr
= uncacheAddr
+ offset
;
314 paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset
;
316 bool probe
= (random() % 100 < percentFunctional
) && !(flags
& UNCACHEABLE
);
317 //bool probe = false;
319 paddr
&= ~((1 << access_size
) - 1);
320 req
->setPhys(paddr
, 1 << access_size
, flags
);
321 req
->setThreadContext(id
,0);
323 uint8_t *result
= new uint8_t[8];
325 if (cmd
< percentReads
) {
328 // For now we only allow one outstanding request per address
329 // per tester This means we assume CPU does write forwarding
330 // to reads that alias something in the cpu store buffer.
331 if (outstandingAddrs
.find(paddr
) != outstandingAddrs
.end()) {
337 outstandingAddrs
.insert(paddr
);
339 // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
340 funcPort
.readBlob(req
->getPaddr(), result
, req
->getSize());
343 "initiating read at address %x (blk %x) expecting %x\n",
344 req
->getPaddr(), blockAddr(req
->getPaddr()), *result
);
346 PacketPtr pkt
= new Packet(req
, MemCmd::ReadReq
, Packet::Broadcast
);
347 pkt
->dataDynamicArray(new uint8_t[req
->getSize()]);
348 MemTestSenderState
*state
= new MemTestSenderState(result
);
349 pkt
->senderState
= state
;
352 cachePort
.sendFunctional(pkt
);
353 pkt
->makeAtomicResponse();
354 completeRequest(pkt
);
361 // For now we only allow one outstanding request per addreess
362 // per tester. This means we assume CPU does write forwarding
363 // to reads that alias something in the cpu store buffer.
364 if (outstandingAddrs
.find(paddr
) != outstandingAddrs
.end()) {
370 outstandingAddrs
.insert(paddr
);
372 DPRINTF(MemTest
, "initiating write at address %x (blk %x) value %x\n",
373 req
->getPaddr(), blockAddr(req
->getPaddr()), data
& 0xff);
375 PacketPtr pkt
= new Packet(req
, MemCmd::WriteReq
, Packet::Broadcast
);
376 uint8_t *pkt_data
= new uint8_t[req
->getSize()];
377 pkt
->dataDynamicArray(pkt_data
);
378 memcpy(pkt_data
, &data
, req
->getSize());
379 MemTestSenderState
*state
= new MemTestSenderState(result
);
380 pkt
->senderState
= state
;
382 funcPort
.writeBlob(req
->getPaddr(), pkt_data
, req
->getSize());
385 cachePort
.sendFunctional(pkt
);
386 pkt
->makeAtomicResponse();
387 completeRequest(pkt
);
397 if (cachePort
.sendTiming(retryPkt
)) {
403 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
405 // SimObjectParam<BaseCache *> cache;
406 // SimObjectParam<PhysicalMemory *> main_mem;
407 // SimObjectParam<PhysicalMemory *> check_mem;
408 Param
<unsigned> memory_size
;
409 Param
<unsigned> percent_reads
;
410 Param
<unsigned> percent_functional
;
411 Param
<unsigned> percent_uncacheable
;
412 Param
<unsigned> progress_interval
;
413 Param
<unsigned> percent_source_unaligned
;
414 Param
<unsigned> percent_dest_unaligned
;
415 Param
<Addr
> trace_addr
;
416 Param
<Counter
> max_loads
;
419 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
422 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
424 // INIT_PARAM(cache, "L1 cache"),
425 // INIT_PARAM(main_mem, "hierarchical memory"),
426 // INIT_PARAM(check_mem, "check memory"),
427 INIT_PARAM(memory_size
, "memory size"),
428 INIT_PARAM(percent_reads
, "target read percentage"),
429 INIT_PARAM(percent_functional
, "percentage of access that are functional"),
430 INIT_PARAM(percent_uncacheable
, "target uncacheable percentage"),
431 INIT_PARAM(progress_interval
, "progress report interval (in accesses)"),
432 INIT_PARAM(percent_source_unaligned
,
433 "percent of copy source address that are unaligned"),
434 INIT_PARAM(percent_dest_unaligned
,
435 "percent of copy dest address that are unaligned"),
436 INIT_PARAM(trace_addr
, "address to trace"),
437 INIT_PARAM(max_loads
, "terminate when we have reached this load count"),
438 INIT_PARAM(atomic
, "Is the tester testing atomic mode (or timing)")
440 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
443 CREATE_SIM_OBJECT(MemTest
)
445 return new MemTest(getInstanceName(), /*cache->getInterface(),*/ /*main_mem,*/
446 /*check_mem,*/ memory_size
, percent_reads
, percent_functional
,
447 percent_uncacheable
, progress_interval
,
448 percent_source_unaligned
, percent_dest_unaligned
,
449 trace_addr
, max_loads
, atomic
);
452 REGISTER_SIM_OBJECT("MemTest", MemTest
)