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 _percentUncacheable
,
54 unsigned _progressInterval
,
56 Counter max_loads_any_thread
,
57 Counter max_loads_all_threads
)
58 : BaseCPU(name
, 1, 0, 0, max_loads_any_thread
, max_loads_all_threads
),
60 cacheInterface(_cache_interface
),
64 percentReads(_percentReads
),
65 percentUncacheable(_percentUncacheable
),
66 progressInterval(_progressInterval
),
67 nextProgressMessage(_progressInterval
)
70 cmd
.push_back("/bin/ls");
71 vector
<string
> null_vec
;
72 xc
= new ExecContext(this ,0,mainMem
,0);
74 blockSize
= cacheInterface
->getBlockSize();
75 blockAddrMask
= blockSize
- 1;
76 traceBlockAddr
= blockAddr(_traceAddr
);
78 //setup data storage with interesting values
79 uint8_t *data1
= new uint8_t[size
];
80 uint8_t *data2
= new uint8_t[size
];
81 uint8_t *data3
= new uint8_t[size
];
82 memset(data1
, 1, size
);
83 memset(data2
, 2, size
);
84 memset(data3
, 3, size
);
89 uncacheAddr
= 0x800000;
91 // set up intial memory contents here
92 mainMem
->prot_write(baseAddr1
, data1
, size
);
93 checkMem
->prot_write(baseAddr1
, data1
, size
);
94 mainMem
->prot_write(baseAddr2
, data2
, size
);
95 checkMem
->prot_write(baseAddr2
, data2
, size
);
96 mainMem
->prot_write(uncacheAddr
, data3
, size
);
97 checkMem
->prot_write(uncacheAddr
, data3
, size
);
104 noResponseCycles
= 0;
107 tickEvent
.schedule(0);
111 printData(ostream
&os
, uint8_t *data
, int nbytes
)
113 os
<< hex
<< setfill('0');
114 // assume little-endian: print bytes from highest address to lowest
115 for (uint8_t *dp
= data
+ nbytes
- 1; dp
>= data
; --dp
) {
116 os
<< setw(2) << (unsigned)*dp
;
122 MemTest::completeRequest(MemReqPtr
&req
, uint8_t *data
)
126 if (memcmp(req
->data
, data
, req
->size
) != 0) {
127 cerr
<< name() << ": on read of 0x" << hex
<< req
->paddr
128 << " @ cycle " << dec
<< curTick
129 << ", cache returns 0x";
130 printData(cerr
, req
->data
, req
->size
);
131 cerr
<< ", expected 0x";
132 printData(cerr
, data
, req
->size
);
139 if (numReads
.value() == nextProgressMessage
) {
140 cerr
<< name() << ": completed " << numReads
.value()
141 << " read accesses @ " << curTick
<< endl
;
142 nextProgressMessage
+= progressInterval
;
145 comLoadEventQueue
[0]->serviceEvents(numReads
.value());
154 panic("invalid command");
157 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
158 cerr
<< name() << ": completed "
159 << (req
->cmd
.isWrite() ? "write" : "read") << " access of "
160 << req
->size
<< " bytes at address 0x"
161 << hex
<< req
->paddr
<< ", value = 0x";
162 printData(cerr
, req
->data
, req
->size
);
163 cerr
<< " @ cycle " << dec
<< curTick
;
168 noResponseCycles
= 0;
176 using namespace Statistics
;
179 .name(name() + ".num_reads")
180 .desc("number of read accesses completed")
184 .name(name() + ".num_writes")
185 .desc("number of write accesses completed")
189 .name(name() + ".num_copies")
190 .desc("number of copy accesses completed")
197 if (!tickEvent
.scheduled())
198 tickEvent
.schedule(curTick
+ 1);
200 if (++noResponseCycles
>= 5000) {
201 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
205 if (cacheInterface
->isBlocked()) {
210 unsigned cmd
= rand() % 100;
211 unsigned offset1
= random() % size
;
212 unsigned base
= random() % 2;
213 uint64_t data
= random();
214 unsigned access_size
= random() % 4;
215 unsigned cacheable
= rand() % 100;
217 MemReqPtr req
= new MemReq();
219 if (cacheable
< percentUncacheable
) {
220 req
->flags
|= UNCACHEABLE
;
221 req
->paddr
= uncacheAddr
+ offset1
;
223 req
->paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
225 bool probe
= (rand() % 2 == 1) && !req
->isUncacheable();
228 req
->size
= 1 << access_size
;
229 req
->data
= new uint8_t[req
->size
];
230 req
->paddr
&= ~(req
->size
- 1);
234 if (cmd
< percentReads
) {
237 uint8_t *result
= new uint8_t[8];
238 checkMem
->access(Read
, req
->paddr
, result
, req
->size
);
239 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
240 cerr
<< name() << ": initiating read "
241 << ((probe
)?"probe of ":"access of ")
242 << req
->size
<< " bytes from addr 0x"
243 << hex
<< req
->paddr
<< " at cycle "
244 << dec
<< curTick
<< endl
;
247 cacheInterface
->probeAndUpdate(req
);
248 completeRequest(req
, result
);
250 req
->completionEvent
= new MemCompleteEvent(req
, result
, this);
251 cacheInterface
->access(req
);
256 memcpy(req
->data
, &data
, req
->size
);
257 checkMem
->access(Write
, req
->paddr
, req
->data
, req
->size
);
258 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
259 cerr
<< name() << ": initiating write "
260 << ((probe
)?"probe of ":"access of ")
261 << req
->size
<< " bytes (value = 0x";
262 printData(cerr
, req
->data
, req
->size
);
263 cerr
<< ") to addr 0x"
264 << hex
<< req
->paddr
<< " at cycle "
265 << dec
<< curTick
<< endl
;
268 cacheInterface
->probeAndUpdate(req
);
269 completeRequest(req
, NULL
);
271 req
->completionEvent
= new MemCompleteEvent(req
, NULL
, this);
272 cacheInterface
->access(req
);
279 MemCompleteEvent::process()
281 tester
->completeRequest(req
, data
);
287 MemCompleteEvent::description()
289 return "memory access completion";
293 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
295 SimObjectParam
<BaseCache
*> cache
;
296 SimObjectParam
<FunctionalMemory
*> main_mem
;
297 SimObjectParam
<FunctionalMemory
*> check_mem
;
298 Param
<unsigned> memory_size
;
299 Param
<unsigned> percent_reads
;
300 Param
<unsigned> percent_uncacheable
;
301 Param
<unsigned> progress_interval
;
302 Param
<Addr
> trace_addr
;
303 Param
<Counter
> max_loads_any_thread
;
304 Param
<Counter
> max_loads_all_threads
;
306 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
309 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
311 INIT_PARAM(cache
, "L1 cache"),
312 INIT_PARAM(main_mem
, "hierarchical memory"),
313 INIT_PARAM(check_mem
, "check memory"),
314 INIT_PARAM_DFLT(memory_size
, "memory size", 65536),
315 INIT_PARAM_DFLT(percent_reads
, "target read percentage", 65),
316 INIT_PARAM_DFLT(percent_uncacheable
, "target uncacheable percentage", 10),
317 INIT_PARAM_DFLT(progress_interval
,
318 "progress report interval (in accesses)", 1000000),
319 INIT_PARAM_DFLT(trace_addr
, "address to trace", 0),
320 INIT_PARAM_DFLT(max_loads_any_thread
,
321 "terminate when any thread reaches this load count",
323 INIT_PARAM_DFLT(max_loads_all_threads
,
324 "terminate when all threads have reached this load count",
327 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
330 CREATE_SIM_OBJECT(MemTest
)
332 return new MemTest(getInstanceName(), cache
->getInterface(), main_mem
,
333 check_mem
, memory_size
, percent_reads
,
334 percent_uncacheable
, progress_interval
,
335 trace_addr
, max_loads_any_thread
,
336 max_loads_all_threads
);
339 REGISTER_SIM_OBJECT("MemTest", MemTest
)