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/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;
112 tickEvent
.schedule(0);
116 printData(ostream
&os
, uint8_t *data
, int nbytes
)
118 os
<< hex
<< setfill('0');
119 // assume little-endian: print bytes from highest address to lowest
120 for (uint8_t *dp
= data
+ nbytes
- 1; dp
>= data
; --dp
) {
121 os
<< setw(2) << (unsigned)*dp
;
127 MemTest::completeRequest(MemReqPtr
&req
, uint8_t *data
)
131 if (memcmp(req
->data
, data
, req
->size
) != 0) {
132 cerr
<< name() << ": on read of 0x" << hex
<< req
->paddr
133 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
134 << "@ cycle " << dec
<< curTick
135 << ", cache returns 0x";
136 printData(cerr
, req
->data
, req
->size
);
137 cerr
<< ", expected 0x";
138 printData(cerr
, data
, req
->size
);
146 if (numReads
== nextProgressMessage
) {
147 ccprintf(cerr
, "%s: completed %d read accesses @%d\n",
148 name(), numReads
, curTick
);
149 nextProgressMessage
+= progressInterval
;
152 comLoadEventQueue
[0]->serviceEvents(numReads
);
164 panic("invalid command");
167 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
168 cerr
<< name() << ": completed "
169 << (req
->cmd
.isWrite() ? "write" : "read")
171 << dec
<< req
->size
<< " bytes at address 0x"
173 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
175 printData(cerr
, req
->data
, req
->size
);
176 cerr
<< " @ cycle " << dec
<< curTick
;
181 noResponseCycles
= 0;
189 using namespace Statistics
;
193 .name(name() + ".num_reads")
194 .desc("number of read accesses completed")
198 .name(name() + ".num_writes")
199 .desc("number of write accesses completed")
203 .name(name() + ".num_copies")
204 .desc("number of copy accesses completed")
211 if (!tickEvent
.scheduled())
212 tickEvent
.schedule(curTick
+ 1);
214 if (++noResponseCycles
>= 5000) {
215 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
219 if (cacheInterface
->isBlocked()) {
224 unsigned cmd
= rand() % 100;
225 unsigned offset1
= random() % size
;
226 unsigned offset2
= random() % size
;
227 unsigned base
= random() % 2;
228 uint64_t data
= random();
229 unsigned access_size
= random() % 4;
230 unsigned cacheable
= rand() % 100;
231 unsigned source_align
= rand() % 100;
232 unsigned dest_align
= rand() % 100;
234 MemReqPtr req
= new MemReq();
236 if (cacheable
< percentUncacheable
) {
237 req
->flags
|= UNCACHEABLE
;
238 req
->paddr
= uncacheAddr
+ offset1
;
240 req
->paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
242 bool probe
= (rand() % 2 == 1) && !req
->isUncacheable();
245 req
->size
= 1 << access_size
;
246 req
->data
= new uint8_t[req
->size
];
247 req
->paddr
&= ~(req
->size
- 1);
251 if (cmd
< percentReads
) {
254 uint8_t *result
= new uint8_t[8];
255 checkMem
->access(Read
, req
->paddr
, result
, req
->size
);
256 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
258 << ": initiating read "
259 << ((probe
)?"probe of ":"access of ")
260 << dec
<< req
->size
<< " bytes from addr 0x"
262 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
264 << dec
<< curTick
<< endl
;
267 cacheInterface
->probeAndUpdate(req
);
268 completeRequest(req
, result
);
270 req
->completionEvent
= new MemCompleteEvent(req
, result
, this);
271 cacheInterface
->access(req
);
273 } else if (cmd
< (100 - percentCopies
)){
276 memcpy(req
->data
, &data
, req
->size
);
277 checkMem
->access(Write
, req
->paddr
, req
->data
, req
->size
);
278 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
279 cerr
<< name() << ": initiating write "
280 << ((probe
)?"probe of ":"access of ")
281 << dec
<< req
->size
<< " bytes (value = 0x";
282 printData(cerr
, req
->data
, req
->size
);
283 cerr
<< ") to addr 0x"
285 << " (0x" << hex
<< blockAddr(req
->paddr
) << ")"
287 << dec
<< curTick
<< endl
;
290 cacheInterface
->probeAndUpdate(req
);
291 completeRequest(req
, NULL
);
293 req
->completionEvent
= new MemCompleteEvent(req
, NULL
, this);
294 cacheInterface
->access(req
);
298 Addr source
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
299 Addr dest
= ((base
) ? baseAddr2
: baseAddr1
) + offset2
;
300 if (source_align
>= percentSourceUnaligned
) {
301 source
= blockAddr(source
);
303 if (dest_align
>= percentDestUnaligned
) {
304 dest
= blockAddr(dest
);
307 req
->flags
&= ~UNCACHEABLE
;
311 req
->data
= new uint8_t[blockSize
];
312 req
->size
= blockSize
;
313 if (source
== traceBlockAddr
|| dest
== traceBlockAddr
) {
315 << ": initiating copy of "
316 << dec
<< req
->size
<< " bytes from addr 0x"
318 << " (0x" << hex
<< blockAddr(source
) << ")"
321 << " (0x" << hex
<< blockAddr(dest
) << ")"
323 << dec
<< curTick
<< endl
;
325 cacheInterface
->access(req
);
326 uint8_t result
[blockSize
];
327 checkMem
->access(Read
, source
, &result
, blockSize
);
328 checkMem
->access(Write
, dest
, &result
, blockSize
);
334 MemCompleteEvent::process()
336 tester
->completeRequest(req
, data
);
342 MemCompleteEvent::description()
344 return "memory access completion";
348 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
350 SimObjectParam
<BaseCache
*> cache
;
351 SimObjectParam
<FunctionalMemory
*> main_mem
;
352 SimObjectParam
<FunctionalMemory
*> check_mem
;
353 Param
<unsigned> memory_size
;
354 Param
<unsigned> percent_reads
;
355 Param
<unsigned> percent_copies
;
356 Param
<unsigned> percent_uncacheable
;
357 Param
<unsigned> progress_interval
;
358 Param
<unsigned> percent_source_unaligned
;
359 Param
<unsigned> percent_dest_unaligned
;
360 Param
<Addr
> trace_addr
;
361 Param
<Counter
> max_loads_any_thread
;
362 Param
<Counter
> max_loads_all_threads
;
364 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
367 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
369 INIT_PARAM(cache
, "L1 cache"),
370 INIT_PARAM(main_mem
, "hierarchical memory"),
371 INIT_PARAM(check_mem
, "check memory"),
372 INIT_PARAM_DFLT(memory_size
, "memory size", 65536),
373 INIT_PARAM_DFLT(percent_reads
, "target read percentage", 65),
374 INIT_PARAM_DFLT(percent_copies
, "target copy percentage", 0),
375 INIT_PARAM_DFLT(percent_uncacheable
, "target uncacheable percentage", 10),
376 INIT_PARAM_DFLT(progress_interval
,
377 "progress report interval (in accesses)", 1000000),
378 INIT_PARAM_DFLT(percent_source_unaligned
, "percent of copy source address "
379 "that are unaligned", 50),
380 INIT_PARAM_DFLT(percent_dest_unaligned
, "percent of copy dest address "
381 "that are unaligned", 50),
382 INIT_PARAM_DFLT(trace_addr
, "address to trace", 0),
383 INIT_PARAM_DFLT(max_loads_any_thread
,
384 "terminate when any thread reaches this load count",
386 INIT_PARAM_DFLT(max_loads_all_threads
,
387 "terminate when all threads have reached this load count",
390 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
393 CREATE_SIM_OBJECT(MemTest
)
395 return new MemTest(getInstanceName(), cache
->getInterface(), main_mem
,
396 check_mem
, memory_size
, percent_reads
, percent_copies
,
397 percent_uncacheable
, progress_interval
,
398 percent_source_unaligned
, percent_dest_unaligned
,
399 trace_addr
, max_loads_any_thread
,
400 max_loads_all_threads
);
403 REGISTER_SIM_OBJECT("MemTest", MemTest
)