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
38 #include "sim_events.hh"
39 #include "main_memory.hh"
40 #include "base_cache.hh"
42 #include "statistics.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 _percentUncacheable
,
55 unsigned _progressInterval
,
59 cacheInterface(_cache_interface
),
63 percentReads(_percentReads
),
64 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
.val() == nextProgressMessage
) {
140 cerr
<< name() << ": completed " << numReads
.val()
141 << " read accesses @ " << curTick
<< endl
;
142 nextProgressMessage
+= progressInterval
;
145 if (numReads
.val() == maxReads
) {
147 stream
<< name() << " reached max read count (" << maxReads
150 new SimExitEvent(stream
.str());
160 panic("invalid command");
163 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
164 cerr
<< name() << ": completed "
165 << (req
->cmd
.isWrite() ? "write" : "read") << " access of "
166 << req
->size
<< " bytes at address 0x"
167 << hex
<< req
->paddr
<< ", value = 0x";
168 printData(cerr
, req
->data
, req
->size
);
172 noResponseCycles
= 0;
180 using namespace Statistics
;
183 .name(name() + ".num_reads")
184 .desc("number of read accesses completed")
188 .name(name() + ".num_writes")
189 .desc("number of write accesses completed")
193 .name(name() + ".num_copies")
194 .desc("number of copy accesses completed")
201 if (!tickEvent
.scheduled())
202 tickEvent
.schedule(curTick
+ 1);
204 if (++noResponseCycles
>= 5000) {
205 cerr
<< name() << ": deadlocked at cycle " << curTick
<< endl
;
209 if (cacheInterface
->isBlocked()) {
214 unsigned cmd
= rand() % 100;
215 unsigned offset1
= random() % size
;
216 unsigned base
= random() % 2;
217 uint64_t data
= random();
218 unsigned access_size
= random() % 4;
219 unsigned cacheable
= rand() % 100;
221 MemReqPtr req
= new MemReq();
223 if (cacheable
< percentUncacheable
) {
224 req
->flags
|= UNCACHEABLE
;
225 req
->paddr
= uncacheAddr
+ offset1
;
227 req
->paddr
= ((base
) ? baseAddr1
: baseAddr2
) + offset1
;
230 req
->size
= 1 << access_size
;
231 req
->data
= new uint8_t[req
->size
];
232 req
->paddr
&= ~(req
->size
- 1);
236 if (cmd
< percentReads
) {
239 uint8_t *result
= new uint8_t[8];
240 checkMem
->access(Read
, req
->paddr
, result
, req
->size
);
241 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
242 cerr
<< name() << ": initiating read of "
243 << req
->size
<< " bytes from addr 0x"
244 << hex
<< req
->paddr
<< " at cycle "
245 << dec
<< curTick
<< endl
;
248 req
->completionEvent
= new MemCompleteEvent(req
, result
, this);
249 cacheInterface
->access(req
);
253 memcpy(req
->data
, &data
, req
->size
);
254 checkMem
->access(Write
, req
->paddr
, req
->data
, req
->size
);
255 if (blockAddr(req
->paddr
) == traceBlockAddr
) {
256 cerr
<< name() << ": initiating write of "
257 << req
->size
<< " bytes (value = 0x";
258 printData(cerr
, req
->data
, req
->size
);
259 cerr
<< ") to addr 0x"
260 << hex
<< req
->paddr
<< " at cycle "
261 << dec
<< curTick
<< endl
;
263 req
->completionEvent
= new MemCompleteEvent(req
, NULL
, this);
264 cacheInterface
->access(req
);
270 MemCompleteEvent::process()
272 tester
->completeRequest(req
, data
);
278 MemCompleteEvent::description()
280 return "memory access completion";
284 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
286 SimObjectParam
<BaseCache
*> cache
;
287 SimObjectParam
<FunctionalMemory
*> main_mem
;
288 SimObjectParam
<FunctionalMemory
*> check_mem
;
289 Param
<unsigned> memory_size
;
290 Param
<unsigned> percent_reads
;
291 Param
<unsigned> percent_uncacheable
;
292 Param
<unsigned> max_reads
;
293 Param
<unsigned> progress_interval
;
294 Param
<Addr
> trace_addr
;
296 END_DECLARE_SIM_OBJECT_PARAMS(MemTest
)
299 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest
)
301 INIT_PARAM(cache
, "L1 cache"),
302 INIT_PARAM(main_mem
, "hierarchical memory"),
303 INIT_PARAM(check_mem
, "check memory"),
304 INIT_PARAM_DFLT(memory_size
, "memory size", 65536),
305 INIT_PARAM_DFLT(percent_reads
, "target read percentage", 65),
306 INIT_PARAM_DFLT(percent_uncacheable
, "target uncacheable percentage", 10),
307 INIT_PARAM_DFLT(max_reads
, "number of reads to simulate", 0),
308 INIT_PARAM_DFLT(progress_interval
,
309 "progress report interval (in accesses)", 1000000),
310 INIT_PARAM_DFLT(trace_addr
, "address to trace", 0)
312 END_INIT_SIM_OBJECT_PARAMS(MemTest
)
315 CREATE_SIM_OBJECT(MemTest
)
317 return new MemTest(getInstanceName(), cache
->getInterface(), main_mem
,
319 memory_size
, percent_reads
,
320 percent_uncacheable
, max_reads
, progress_interval
,
324 REGISTER_SIM_OBJECT("MemTest", MemTest
)