2 * Copyright (c) 2003 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
36 #include "base/misc.hh"
37 #include "base/statistics.hh"
38 #include "cpu/memtest/memtest.hh"
39 #include "mem/cache/base_cache.hh"
40 #include "mem/functional_mem/main_memory.hh"
41 #include "sim/builder.hh"
42 #include "sim/sim_events.hh"
43 #include "sim/sim_stats.hh"
47 MemTest::MemTest(const string
&name
,
48 MemInterface
*_cache_interface
,
49 FunctionalMemory
*main_mem
,
50 FunctionalMemory
*check_mem
,
52 unsigned _percentReads
,
53 unsigned _percentCopies
,
54 unsigned _percentUncacheable
,
55 unsigned _progressInterval
,
56 unsigned _percentSourceUnaligned
,
57 unsigned _percentDestUnaligned
,
59 Counter max_loads_any_thread
,
60 Counter max_loads_all_threads
)
61 : BaseCPU(name
, 1, 0, 0, max_loads_any_thread
, max_loads_all_threads
),
63 cacheInterface(_cache_interface
),
67 percentReads(_percentReads
),
68 percentCopies(_percentCopies
),
69 percentUncacheable(_percentUncacheable
),
70 progressInterval(_progressInterval
),
71 nextProgressMessage(_progressInterval
),
72 percentSourceUnaligned(_percentSourceUnaligned
),
73 percentDestUnaligned(percentDestUnaligned
)
76 cmd
.push_back("/bin/ls");
77 vector
<string
> null_vec
;
78 xc
= new ExecContext(this ,0,mainMem
,0);
80 blockSize
= cacheInterface
->getBlockSize();
81 blockAddrMask
= blockSize
- 1;
82 traceBlockAddr
= blockAddr(_traceAddr
);
84 //setup data storage with interesting values
85 uint8_t *data1
= new uint8_t[size
];
86 uint8_t *data2
= new uint8_t[size
];
87 uint8_t *data3
= new uint8_t[size
];
88 memset(data1
, 1, size
);
89 memset(data2
, 2, size
);
90 memset(data3
, 3, size
);
95 uncacheAddr
= 0x800000;
97 // set up intial memory contents here
98 mainMem
->prot_write(baseAddr1
, data1
, size
);
99 checkMem
->prot_write(baseAddr1
, data1
, size
);
100 mainMem
->prot_write(baseAddr2
, data2
, size
);
101 checkMem
->prot_write(baseAddr2
, data2
, size
);
102 mainMem
->prot_write(uncacheAddr
, data3
, size
);
103 checkMem
->prot_write(uncacheAddr
, data3
, size
);
110 noResponseCycles
= 0;
113 tickEvent
.schedule(0);
117 printData(ostream
&os
, uint8_t *data
, int nbytes
)
119 os
<< hex
<< setfill('0');
120 // assume little-endian: print bytes from highest address to lowest
121 for (uint8_t *dp
= data
+ nbytes
- 1; dp
>= data
; --dp
) {
122 os
<< setw(2) << (unsigned)*dp
;
128 MemTest::completeRequest(MemReqPtr
&req
, uint8_t *data
)
132 if (memcmp(req
->data
, data
, req
->size
) != 0) {
133 cerr
<< name() << ": on read of 0x" << hex
<< req
->paddr
134 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
135 << "@ cycle " << dec
<< curTick
136 << ", cache returns 0x";
137 printData(cerr
, req
->data
, req
->size
);
138 cerr
<< ", expected 0x";
139 printData(cerr
, data
, req
->size
);
146 if (numReads
.value() == nextProgressMessage
) {
147 cerr
<< name() << ": completed " << numReads
.value()
148 << " read accesses @ " << curTick
<< endl
;
149 nextProgressMessage
+= progressInterval
;
152 comLoadEventQueue
[0]->serviceEvents(numReads
.value());
163 panic("invalid command");
166 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
167 cerr
<< name() << ": completed "
168 << (req
->cmd
.isWrite() ? "write" : "read")
170 << dec
<< req
->size
<< " bytes at address 0x"
172 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
174 printData(cerr
, req
->data
, req
->size
);
175 cerr
<< " @ cycle " << dec
<< curTick
;
180 noResponseCycles
= 0;
188 using namespace Statistics
;
191 .name(name() + ".num_reads")
192 .desc("number of read accesses completed")
196 .name(name() + ".num_writes")
197 .desc("number of write accesses completed")
201 .name(name() + ".num_copies")
202 .desc("number of copy accesses completed")
209 if (!tickEvent
.scheduled())
210 tickEvent
.schedule(curTick
+ 1);
212 if (++noResponseCycles
>= 5000) {
213 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
217 if (cacheInterface
->isBlocked()) {
222 unsigned cmd
= rand() % 100;
223 unsigned offset1
= random() % size
;
224 unsigned offset2
= random() % size
;
225 unsigned base
= random() % 2;
226 uint64_t data
= random();
227 unsigned access_size
= random() % 4;
228 unsigned cacheable
= rand() % 100;
229 unsigned source_align
= rand() % 100;
230 unsigned dest_align
= rand() % 100;
232 MemReqPtr req
= new MemReq();
234 if (cacheable
< percentUncacheable
) {
235 req
->flags
|= UNCACHEABLE
;
236 req
->paddr
= uncacheAddr
+ offset1
;
238 req
->paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
240 bool probe
= (rand() % 2 == 1) && !req
->isUncacheable();
243 req
->size
= 1 << access_size
;
244 req
->data
= new uint8_t[req
->size
];
245 req
->paddr
&= ~(req
->size
- 1);
249 if (cmd
< percentReads
) {
252 uint8_t *result
= new uint8_t[8];
253 checkMem
->access(Read
, req
->paddr
, result
, req
->size
);
254 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
256 << ": initiating read "
257 << ((probe
)?"probe of ":"access of ")
258 << dec
<< req
->size
<< " bytes from addr 0x"
260 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
262 << dec
<< curTick
<< endl
;
265 cacheInterface
->probeAndUpdate(req
);
266 completeRequest(req
, result
);
268 req
->completionEvent
= new MemCompleteEvent(req
, result
, this);
269 cacheInterface
->access(req
);
271 } else if (cmd
< (100 - percentCopies
)){
274 memcpy(req
->data
, &data
, req
->size
);
275 checkMem
->access(Write
, req
->paddr
, req
->data
, req
->size
);
276 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
277 cerr
<< name() << ": initiating write "
278 << ((probe
)?"probe of ":"access of ")
279 << dec
<< req
->size
<< " bytes (value = 0x";
280 printData(cerr
, req
->data
, req
->size
);
281 cerr
<< ") to addr 0x"
283 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
285 << dec
<< curTick
<< endl
;
288 cacheInterface
->probeAndUpdate(req
);
289 completeRequest(req
, NULL
);
291 req
->completionEvent
= new MemCompleteEvent(req
, NULL
, this);
292 cacheInterface
->access(req
);
296 Addr source
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
297 Addr dest
= ((base
) ? baseAddr2
: baseAddr1
) + offset2
;
298 if (source_align
>= percentSourceUnaligned
) {
299 source
= blockAddr(source
);
301 if (dest_align
>= percentDestUnaligned
) {
302 dest
= blockAddr(dest
);
305 req
->flags
&= ~UNCACHEABLE
;
309 req
->data
= new uint8_t[blockSize
];
310 req
->size
= blockSize
;
311 if (source
== traceBlockAddr
|| dest
== traceBlockAddr
) {
313 << ": initiating copy of "
314 << dec
<< req
->size
<< " bytes from addr 0x"
316 << " (0x" << hex
<< blockAddr(source
) << ")"
319 << " (0x" << hex
<< blockAddr(dest
) << ")"
321 << dec
<< curTick
<< endl
;
323 cacheInterface
->access(req
);
324 uint8_t result
[blockSize
];
325 checkMem
->access(Read
, source
, &result
, blockSize
);
326 checkMem
->access(Write
, dest
, &result
, blockSize
);
332 MemCompleteEvent::process()
334 tester
->completeRequest(req
, data
);
340 MemCompleteEvent::description()
342 return "memory access completion";
346 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
348 SimObjectParam
<BaseCache
*> cache
;
349 SimObjectParam
<FunctionalMemory
*> main_mem
;
350 SimObjectParam
<FunctionalMemory
*> check_mem
;
351 Param
<unsigned> memory_size
;
352 Param
<unsigned> percent_reads
;
353 Param
<unsigned> percent_copies
;
354 Param
<unsigned> percent_uncacheable
;
355 Param
<unsigned> progress_interval
;
356 Param
<unsigned> percent_source_unaligned
;
357 Param
<unsigned> percent_dest_unaligned
;
358 Param
<Addr
> trace_addr
;
359 Param
<Counter
> max_loads_any_thread
;
360 Param
<Counter
> max_loads_all_threads
;
362 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
365 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
367 INIT_PARAM(cache
, "L1 cache"),
368 INIT_PARAM(main_mem
, "hierarchical memory"),
369 INIT_PARAM(check_mem
, "check memory"),
370 INIT_PARAM_DFLT(memory_size
, "memory size", 65536),
371 INIT_PARAM_DFLT(percent_reads
, "target read percentage", 65),
372 INIT_PARAM_DFLT(percent_copies
, "target copy percentage", 0),
373 INIT_PARAM_DFLT(percent_uncacheable
, "target uncacheable percentage", 10),
374 INIT_PARAM_DFLT(progress_interval
,
375 "progress report interval (in accesses)", 1000000),
376 INIT_PARAM_DFLT(percent_source_unaligned
, "percent of copy source address "
377 "that are unaligned", 50),
378 INIT_PARAM_DFLT(percent_dest_unaligned
, "percent of copy dest address "
379 "that are unaligned", 50),
380 INIT_PARAM_DFLT(trace_addr
, "address to trace", 0),
381 INIT_PARAM_DFLT(max_loads_any_thread
,
382 "terminate when any thread reaches this load count",
384 INIT_PARAM_DFLT(max_loads_all_threads
,
385 "terminate when all threads have reached this load count",
388 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
391 CREATE_SIM_OBJECT(MemTest
)
393 return new MemTest(getInstanceName(), cache
->getInterface(), main_mem
,
394 check_mem
, memory_size
, percent_reads
, percent_copies
,
395 percent_uncacheable
, progress_interval
,
396 percent_source_unaligned
, percent_dest_unaligned
,
397 trace_addr
, max_loads_any_thread
,
398 max_loads_all_threads
);
401 REGISTER_SIM_OBJECT("MemTest", MemTest
)