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 "sim/builder.hh"
43 #include "sim/sim_events.hh"
44 #include "sim/stats.hh"
48 int TESTER_ALLOCATOR
=0;
50 MemTest::MemTest(const string
&name
,
51 MemInterface
*_cache_interface
,
52 FunctionalMemory
*main_mem
,
53 FunctionalMemory
*check_mem
,
55 unsigned _percentReads
,
56 unsigned _percentCopies
,
57 unsigned _percentUncacheable
,
58 unsigned _progressInterval
,
59 unsigned _percentSourceUnaligned
,
60 unsigned _percentDestUnaligned
,
65 cacheInterface(_cache_interface
),
69 percentReads(_percentReads
),
70 percentCopies(_percentCopies
),
71 percentUncacheable(_percentUncacheable
),
72 progressInterval(_progressInterval
),
73 nextProgressMessage(_progressInterval
),
74 percentSourceUnaligned(_percentSourceUnaligned
),
75 percentDestUnaligned(percentDestUnaligned
),
79 cmd
.push_back("/bin/ls");
80 vector
<string
> null_vec
;
81 xc
= new ExecContext(NULL
, 0, mainMem
, 0);
83 blockSize
= cacheInterface
->getBlockSize();
84 blockAddrMask
= blockSize
- 1;
85 traceBlockAddr
= blockAddr(_traceAddr
);
87 //setup data storage with interesting values
88 uint8_t *data1
= new uint8_t[size
];
89 uint8_t *data2
= new uint8_t[size
];
90 uint8_t *data3
= new uint8_t[size
];
91 memset(data1
, 1, size
);
92 memset(data2
, 2, size
);
93 memset(data3
, 3, size
);
98 uncacheAddr
= 0x800000;
100 // set up intial memory contents here
101 mainMem
->prot_write(baseAddr1
, data1
, size
);
102 checkMem
->prot_write(baseAddr1
, data1
, size
);
103 mainMem
->prot_write(baseAddr2
, data2
, size
);
104 checkMem
->prot_write(baseAddr2
, data2
, size
);
105 mainMem
->prot_write(uncacheAddr
, data3
, size
);
106 checkMem
->prot_write(uncacheAddr
, data3
, size
);
113 noResponseCycles
= 0;
115 tickEvent
.schedule(0);
117 id
= TESTER_ALLOCATOR
++;
121 printData(ostream
&os
, uint8_t *data
, int nbytes
)
123 os
<< hex
<< setfill('0');
124 // assume little-endian: print bytes from highest address to lowest
125 for (uint8_t *dp
= data
+ nbytes
- 1; dp
>= data
; --dp
) {
126 os
<< setw(2) << (unsigned)*dp
;
132 MemTest::completeRequest(MemReqPtr
&req
, uint8_t *data
)
134 //Remove the address from the list of outstanding
135 std::set
<unsigned>::iterator removeAddr
= outstandingAddrs
.find(req
->paddr
);
136 assert(removeAddr
!= outstandingAddrs
.end());
137 outstandingAddrs
.erase(removeAddr
);
141 if (memcmp(req
->data
, data
, req
->size
) != 0) {
142 cerr
<< name() << ": on read of 0x" << hex
<< req
->paddr
143 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
144 << "@ cycle " << dec
<< curTick
145 << ", cache returns 0x";
146 printData(cerr
, req
->data
, req
->size
);
147 cerr
<< ", expected 0x";
148 printData(cerr
, data
, req
->size
);
156 if (numReads
== nextProgressMessage
) {
157 ccprintf(cerr
, "%s: completed %d read accesses @%d\n",
158 name(), numReads
, curTick
);
159 nextProgressMessage
+= progressInterval
;
162 if (numReads
>= maxLoads
)
163 SimExit(curTick
, "Maximum number of loads reached!");
171 //Also remove dest from outstanding list
172 removeAddr
= outstandingAddrs
.find(req
->dest
);
173 assert(removeAddr
!= outstandingAddrs
.end());
174 outstandingAddrs
.erase(removeAddr
);
179 panic("invalid command");
182 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
183 cerr
<< name() << ": completed "
184 << (req
->cmd
.isWrite() ? "write" : "read")
186 << dec
<< req
->size
<< " bytes at address 0x"
188 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
190 printData(cerr
, req
->data
, req
->size
);
191 cerr
<< " @ cycle " << dec
<< curTick
;
196 noResponseCycles
= 0;
204 using namespace Stats
;
208 .name(name() + ".num_reads")
209 .desc("number of read accesses completed")
213 .name(name() + ".num_writes")
214 .desc("number of write accesses completed")
218 .name(name() + ".num_copies")
219 .desc("number of copy accesses completed")
226 if (!tickEvent
.scheduled())
227 tickEvent
.schedule(curTick
+ cycles(1));
229 if (++noResponseCycles
>= 500000) {
230 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
234 if (cacheInterface
->isBlocked()) {
239 unsigned cmd
= rand() % 100;
240 unsigned offset1
= random() % size
;
241 unsigned offset2
= random() % size
;
242 unsigned base
= random() % 2;
243 uint64_t data
= random();
244 unsigned access_size
= random() % 4;
245 unsigned cacheable
= rand() % 100;
246 unsigned source_align
= rand() % 100;
247 unsigned dest_align
= rand() % 100;
249 //If we aren't doing copies, use id as offset, and do a false sharing
251 if (percentCopies
== 0) {
252 //We can eliminate the lower bits of the offset, and then use the id
253 //to offset within the blks
254 offset1
&= ~63; //Not the low order bits
259 MemReqPtr req
= new MemReq();
261 if (cacheable
< percentUncacheable
) {
262 req
->flags
|= UNCACHEABLE
;
263 req
->paddr
= uncacheAddr
+ offset1
;
265 req
->paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
267 bool probe
= (rand() % 2 == 1) && !req
->isUncacheable();
270 req
->size
= 1 << access_size
;
271 req
->data
= new uint8_t[req
->size
];
272 req
->paddr
&= ~(req
->size
- 1);
276 if (cmd
< percentReads
) {
279 //For now we only allow one outstanding request per addreess per tester
280 //This means we assume CPU does write forwarding to reads that alias something
281 //in the cpu store buffer.
282 if (outstandingAddrs
.find(req
->paddr
) != outstandingAddrs
.end()) return;
283 else outstandingAddrs
.insert(req
->paddr
);
286 uint8_t *result
= new uint8_t[8];
287 checkMem
->access(Read
, req
->paddr
, result
, req
->size
);
288 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
290 << ": initiating read "
291 << ((probe
)?"probe of ":"access of ")
292 << dec
<< req
->size
<< " bytes from addr 0x"
294 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
296 << dec
<< curTick
<< endl
;
299 cacheInterface
->probeAndUpdate(req
);
300 completeRequest(req
, result
);
302 req
->completionEvent
= new MemCompleteEvent(req
, result
, this);
303 cacheInterface
->access(req
);
305 } else if (cmd
< (100 - percentCopies
)){
308 //For now we only allow one outstanding request per addreess per tester
309 //This means we assume CPU does write forwarding to reads that alias something
310 //in the cpu store buffer.
311 if (outstandingAddrs
.find(req
->paddr
) != outstandingAddrs
.end()) return;
312 else outstandingAddrs
.insert(req
->paddr
);
315 memcpy(req
->data
, &data
, req
->size
);
316 checkMem
->access(Write
, req
->paddr
, req
->data
, req
->size
);
317 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
318 cerr
<< name() << ": initiating write "
319 << ((probe
)?"probe of ":"access of ")
320 << dec
<< req
->size
<< " bytes (value = 0x";
321 printData(cerr
, req
->data
, req
->size
);
322 cerr
<< ") to addr 0x"
324 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
326 << dec
<< curTick
<< endl
;
329 cacheInterface
->probeAndUpdate(req
);
330 completeRequest(req
, NULL
);
332 req
->completionEvent
= new MemCompleteEvent(req
, NULL
, this);
333 cacheInterface
->access(req
);
337 Addr source
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
338 Addr dest
= ((base
) ? baseAddr2
: baseAddr1
) + offset2
;
339 if (outstandingAddrs
.find(source
) != outstandingAddrs
.end()) return;
340 else outstandingAddrs
.insert(source
);
341 if (outstandingAddrs
.find(dest
) != outstandingAddrs
.end()) return;
342 else outstandingAddrs
.insert(dest
);
344 if (source_align
>= percentSourceUnaligned
) {
345 source
= blockAddr(source
);
347 if (dest_align
>= percentDestUnaligned
) {
348 dest
= blockAddr(dest
);
351 req
->flags
&= ~UNCACHEABLE
;
355 req
->data
= new uint8_t[blockSize
];
356 req
->size
= blockSize
;
357 if (source
== traceBlockAddr
|| dest
== traceBlockAddr
) {
359 << ": initiating copy of "
360 << dec
<< req
->size
<< " bytes from addr 0x"
362 << " (0x" << hex
<< blockAddr(source
) << ")"
365 << " (0x" << hex
<< blockAddr(dest
) << ")"
367 << dec
<< curTick
<< endl
;
369 cacheInterface
->access(req
);
370 uint8_t result
[blockSize
];
371 checkMem
->access(Read
, source
, &result
, blockSize
);
372 checkMem
->access(Write
, dest
, &result
, blockSize
);
378 MemCompleteEvent::process()
380 tester
->completeRequest(req
, data
);
386 MemCompleteEvent::description()
388 return "memory access completion";
392 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
394 SimObjectParam
<BaseCache
*> cache
;
395 SimObjectParam
<FunctionalMemory
*> main_mem
;
396 SimObjectParam
<FunctionalMemory
*> check_mem
;
397 Param
<unsigned> memory_size
;
398 Param
<unsigned> percent_reads
;
399 Param
<unsigned> percent_copies
;
400 Param
<unsigned> percent_uncacheable
;
401 Param
<unsigned> progress_interval
;
402 Param
<unsigned> percent_source_unaligned
;
403 Param
<unsigned> percent_dest_unaligned
;
404 Param
<Addr
> trace_addr
;
405 Param
<Counter
> max_loads
;
407 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
410 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
412 INIT_PARAM(cache
, "L1 cache"),
413 INIT_PARAM(main_mem
, "hierarchical memory"),
414 INIT_PARAM(check_mem
, "check memory"),
415 INIT_PARAM(memory_size
, "memory size"),
416 INIT_PARAM(percent_reads
, "target read percentage"),
417 INIT_PARAM(percent_copies
, "target copy percentage"),
418 INIT_PARAM(percent_uncacheable
, "target uncacheable percentage"),
419 INIT_PARAM(progress_interval
, "progress report interval (in accesses)"),
420 INIT_PARAM(percent_source_unaligned
,
421 "percent of copy source address that are unaligned"),
422 INIT_PARAM(percent_dest_unaligned
,
423 "percent of copy dest address that are unaligned"),
424 INIT_PARAM(trace_addr
, "address to trace"),
425 INIT_PARAM(max_loads
, "terminate when we have reached this load count")
427 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
430 CREATE_SIM_OBJECT(MemTest
)
432 return new MemTest(getInstanceName(), cache
->getInterface(), main_mem
,
433 check_mem
, memory_size
, percent_reads
, percent_copies
,
434 percent_uncacheable
, progress_interval
,
435 percent_source_unaligned
, percent_dest_unaligned
,
436 trace_addr
, max_loads
);
439 REGISTER_SIM_OBJECT("MemTest", MemTest
)