2 * Copyright (c) 2002-2004 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.
29 // FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
37 #include "base/misc.hh"
38 #include "base/statistics.hh"
39 #include "cpu/exec_context.hh"
40 #include "cpu/memtest/memtest.hh"
41 #include "mem/cache/base_cache.hh"
42 #include "mem/functional_mem/main_memory.hh"
43 #include "sim/builder.hh"
44 #include "sim/sim_events.hh"
45 #include "sim/stats.hh"
49 int TESTER_ALLOCATOR
=0;
51 MemTest::MemTest(const string
&name
,
52 MemInterface
*_cache_interface
,
53 FunctionalMemory
*main_mem
,
54 FunctionalMemory
*check_mem
,
56 unsigned _percentReads
,
57 unsigned _percentCopies
,
58 unsigned _percentUncacheable
,
59 unsigned _progressInterval
,
60 unsigned _percentSourceUnaligned
,
61 unsigned _percentDestUnaligned
,
66 cacheInterface(_cache_interface
),
70 percentReads(_percentReads
),
71 percentCopies(_percentCopies
),
72 percentUncacheable(_percentUncacheable
),
73 progressInterval(_progressInterval
),
74 nextProgressMessage(_progressInterval
),
75 percentSourceUnaligned(_percentSourceUnaligned
),
76 percentDestUnaligned(percentDestUnaligned
),
80 cmd
.push_back("/bin/ls");
81 vector
<string
> null_vec
;
82 xc
= new ExecContext(NULL
, 0, mainMem
, 0);
84 blockSize
= cacheInterface
->getBlockSize();
85 blockAddrMask
= blockSize
- 1;
86 traceBlockAddr
= blockAddr(_traceAddr
);
88 //setup data storage with interesting values
89 uint8_t *data1
= new uint8_t[size
];
90 uint8_t *data2
= new uint8_t[size
];
91 uint8_t *data3
= new uint8_t[size
];
92 memset(data1
, 1, size
);
93 memset(data2
, 2, size
);
94 memset(data3
, 3, size
);
99 uncacheAddr
= 0x800000;
101 // set up intial memory contents here
102 mainMem
->prot_write(baseAddr1
, data1
, size
);
103 checkMem
->prot_write(baseAddr1
, data1
, size
);
104 mainMem
->prot_write(baseAddr2
, data2
, size
);
105 checkMem
->prot_write(baseAddr2
, data2
, size
);
106 mainMem
->prot_write(uncacheAddr
, data3
, size
);
107 checkMem
->prot_write(uncacheAddr
, data3
, size
);
114 noResponseCycles
= 0;
116 tickEvent
.schedule(0);
118 id
= TESTER_ALLOCATOR
++;
122 printData(ostream
&os
, uint8_t *data
, int nbytes
)
124 os
<< hex
<< setfill('0');
125 // assume little-endian: print bytes from highest address to lowest
126 for (uint8_t *dp
= data
+ nbytes
- 1; dp
>= data
; --dp
) {
127 os
<< setw(2) << (unsigned)*dp
;
133 MemTest::completeRequest(MemReqPtr
&req
, uint8_t *data
)
135 //Remove the address from the list of outstanding
136 std::set
<unsigned>::iterator removeAddr
= outstandingAddrs
.find(req
->paddr
);
137 assert(removeAddr
!= outstandingAddrs
.end());
138 outstandingAddrs
.erase(removeAddr
);
142 if (memcmp(req
->data
, data
, req
->size
) != 0) {
143 cerr
<< name() << ": on read of 0x" << hex
<< req
->paddr
144 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
145 << "@ cycle " << dec
<< curTick
146 << ", cache returns 0x";
147 printData(cerr
, req
->data
, req
->size
);
148 cerr
<< ", expected 0x";
149 printData(cerr
, data
, req
->size
);
157 if (numReads
== nextProgressMessage
) {
158 ccprintf(cerr
, "%s: completed %d read accesses @%d\n",
159 name(), numReads
, curTick
);
160 nextProgressMessage
+= progressInterval
;
163 if (numReads
>= maxLoads
)
164 SimExit(curTick
, "Maximum number of loads reached!");
172 //Also remove dest from outstanding list
173 removeAddr
= outstandingAddrs
.find(req
->dest
);
174 assert(removeAddr
!= outstandingAddrs
.end());
175 outstandingAddrs
.erase(removeAddr
);
180 panic("invalid command");
183 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
184 cerr
<< name() << ": completed "
185 << (req
->cmd
.isWrite() ? "write" : "read")
187 << dec
<< req
->size
<< " bytes at address 0x"
189 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
191 printData(cerr
, req
->data
, req
->size
);
192 cerr
<< " @ cycle " << dec
<< curTick
;
197 noResponseCycles
= 0;
205 using namespace Stats
;
209 .name(name() + ".num_reads")
210 .desc("number of read accesses completed")
214 .name(name() + ".num_writes")
215 .desc("number of write accesses completed")
219 .name(name() + ".num_copies")
220 .desc("number of copy accesses completed")
227 if (!tickEvent
.scheduled())
228 tickEvent
.schedule(curTick
+ 1);
230 if (++noResponseCycles
>= 500000) {
231 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
235 if (cacheInterface
->isBlocked()) {
240 unsigned cmd
= rand() % 100;
241 unsigned offset1
= random() % size
;
242 unsigned offset2
= random() % size
;
243 unsigned base
= random() % 2;
244 uint64_t data
= random();
245 unsigned access_size
= random() % 4;
246 unsigned cacheable
= rand() % 100;
247 unsigned source_align
= rand() % 100;
248 unsigned dest_align
= rand() % 100;
250 //If we aren't doing copies, use id as offset, and do a false sharing
252 if (percentCopies
== 0) {
253 //We can eliminate the lower bits of the offset, and then use the id
254 //to offset within the blks
255 offset1
&= ~63; //Not the low order bits
260 MemReqPtr req
= new MemReq();
262 if (cacheable
< percentUncacheable
) {
263 req
->flags
|= UNCACHEABLE
;
264 req
->paddr
= uncacheAddr
+ offset1
;
266 req
->paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
268 bool probe
= (rand() % 2 == 1) && !req
->isUncacheable();
271 req
->size
= 1 << access_size
;
272 req
->data
= new uint8_t[req
->size
];
273 req
->paddr
&= ~(req
->size
- 1);
277 if (cmd
< percentReads
) {
280 //For now we only allow one outstanding request per addreess per tester
281 //This means we assume CPU does write forwarding to reads that alias something
282 //in the cpu store buffer.
283 if (outstandingAddrs
.find(req
->paddr
) != outstandingAddrs
.end()) return;
284 else outstandingAddrs
.insert(req
->paddr
);
287 uint8_t *result
= new uint8_t[8];
288 checkMem
->access(Read
, req
->paddr
, result
, req
->size
);
289 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
291 << ": initiating read "
292 << ((probe
)?"probe of ":"access of ")
293 << dec
<< req
->size
<< " bytes from addr 0x"
295 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
297 << dec
<< curTick
<< endl
;
300 cacheInterface
->probeAndUpdate(req
);
301 completeRequest(req
, result
);
303 req
->completionEvent
= new MemCompleteEvent(req
, result
, this);
304 cacheInterface
->access(req
);
306 } else if (cmd
< (100 - percentCopies
)){
309 //For now we only allow one outstanding request per addreess per tester
310 //This means we assume CPU does write forwarding to reads that alias something
311 //in the cpu store buffer.
312 if (outstandingAddrs
.find(req
->paddr
) != outstandingAddrs
.end()) return;
313 else outstandingAddrs
.insert(req
->paddr
);
316 memcpy(req
->data
, &data
, req
->size
);
317 checkMem
->access(Write
, req
->paddr
, req
->data
, req
->size
);
318 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
319 cerr
<< name() << ": initiating write "
320 << ((probe
)?"probe of ":"access of ")
321 << dec
<< req
->size
<< " bytes (value = 0x";
322 printData(cerr
, req
->data
, req
->size
);
323 cerr
<< ") to addr 0x"
325 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
327 << dec
<< curTick
<< endl
;
330 cacheInterface
->probeAndUpdate(req
);
331 completeRequest(req
, NULL
);
333 req
->completionEvent
= new MemCompleteEvent(req
, NULL
, this);
334 cacheInterface
->access(req
);
338 Addr source
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
339 Addr dest
= ((base
) ? baseAddr2
: baseAddr1
) + offset2
;
340 if (outstandingAddrs
.find(source
) != outstandingAddrs
.end()) return;
341 else outstandingAddrs
.insert(source
);
342 if (outstandingAddrs
.find(dest
) != outstandingAddrs
.end()) return;
343 else outstandingAddrs
.insert(dest
);
345 if (source_align
>= percentSourceUnaligned
) {
346 source
= blockAddr(source
);
348 if (dest_align
>= percentDestUnaligned
) {
349 dest
= blockAddr(dest
);
352 req
->flags
&= ~UNCACHEABLE
;
356 req
->data
= new uint8_t[blockSize
];
357 req
->size
= blockSize
;
358 if (source
== traceBlockAddr
|| dest
== traceBlockAddr
) {
360 << ": initiating copy of "
361 << dec
<< req
->size
<< " bytes from addr 0x"
363 << " (0x" << hex
<< blockAddr(source
) << ")"
366 << " (0x" << hex
<< blockAddr(dest
) << ")"
368 << dec
<< curTick
<< endl
;
370 cacheInterface
->access(req
);
371 uint8_t result
[blockSize
];
372 checkMem
->access(Read
, source
, &result
, blockSize
);
373 checkMem
->access(Write
, dest
, &result
, blockSize
);
379 MemCompleteEvent::process()
381 tester
->completeRequest(req
, data
);
387 MemCompleteEvent::description()
389 return "memory access completion";
393 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
395 SimObjectParam
<BaseCache
*> cache
;
396 SimObjectParam
<FunctionalMemory
*> main_mem
;
397 SimObjectParam
<FunctionalMemory
*> check_mem
;
398 Param
<unsigned> memory_size
;
399 Param
<unsigned> percent_reads
;
400 Param
<unsigned> percent_copies
;
401 Param
<unsigned> percent_uncacheable
;
402 Param
<unsigned> progress_interval
;
403 Param
<unsigned> percent_source_unaligned
;
404 Param
<unsigned> percent_dest_unaligned
;
405 Param
<Addr
> trace_addr
;
406 Param
<Counter
> max_loads
;
408 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
411 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
413 INIT_PARAM(cache
, "L1 cache"),
414 INIT_PARAM(main_mem
, "hierarchical memory"),
415 INIT_PARAM(check_mem
, "check memory"),
416 INIT_PARAM(memory_size
, "memory size"),
417 INIT_PARAM(percent_reads
, "target read percentage"),
418 INIT_PARAM(percent_copies
, "target copy percentage"),
419 INIT_PARAM(percent_uncacheable
, "target uncacheable percentage"),
420 INIT_PARAM(progress_interval
, "progress report interval (in accesses)"),
421 INIT_PARAM(percent_source_unaligned
,
422 "percent of copy source address that are unaligned"),
423 INIT_PARAM(percent_dest_unaligned
,
424 "percent of copy dest address that are unaligned"),
425 INIT_PARAM(trace_addr
, "address to trace"),
426 INIT_PARAM(max_loads
, "terminate when we have reached this load count")
428 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
431 CREATE_SIM_OBJECT(MemTest
)
433 return new MemTest(getInstanceName(), cache
->getInterface(), main_mem
,
434 check_mem
, memory_size
, percent_reads
, percent_copies
,
435 percent_uncacheable
, progress_interval
,
436 percent_source_unaligned
, percent_dest_unaligned
,
437 trace_addr
, max_loads
);
440 REGISTER_SIM_OBJECT("MemTest", MemTest
)