merge etherpkt and makefile
[gem5.git] / cpu / memtest / memtest.cc
1 /*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
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.
15 *
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.
27 */
28
29 // FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
30
31 #include <string>
32 #include <sstream>
33 #include <iomanip>
34 #include <vector>
35
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"
44
45 using namespace std;
46
47 MemTest::MemTest(const string &name,
48 MemInterface *_cache_interface,
49 FunctionalMemory *main_mem,
50 FunctionalMemory *check_mem,
51 unsigned _memorySize,
52 unsigned _percentReads,
53 unsigned _percentCopies,
54 unsigned _percentUncacheable,
55 unsigned _progressInterval,
56 unsigned _percentSourceUnaligned,
57 unsigned _percentDestUnaligned,
58 Addr _traceAddr,
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),
62 tickEvent(this),
63 cacheInterface(_cache_interface),
64 mainMem(main_mem),
65 checkMem(check_mem),
66 size(_memorySize),
67 percentReads(_percentReads),
68 percentCopies(_percentCopies),
69 percentUncacheable(_percentUncacheable),
70 progressInterval(_progressInterval),
71 nextProgressMessage(_progressInterval),
72 percentSourceUnaligned(_percentSourceUnaligned),
73 percentDestUnaligned(percentDestUnaligned)
74 {
75 vector<string> cmd;
76 cmd.push_back("/bin/ls");
77 vector<string> null_vec;
78 xc = new ExecContext(this ,0,mainMem,0);
79
80 blockSize = cacheInterface->getBlockSize();
81 blockAddrMask = blockSize - 1;
82 traceBlockAddr = blockAddr(_traceAddr);
83
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);
91 curTick = 0;
92
93 baseAddr1 = 0x100000;
94 baseAddr2 = 0x400000;
95 uncacheAddr = 0x800000;
96
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);
104
105 delete [] data1;
106 delete [] data2;
107 delete [] data3;
108
109 // set up counters
110 noResponseCycles = 0;
111 numReads = 0;
112 numWrites = 0;
113 tickEvent.schedule(0);
114 }
115
116 static void
117 printData(ostream &os, uint8_t *data, int nbytes)
118 {
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;
123 }
124 os << dec;
125 }
126
127 void
128 MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
129 {
130 switch (req->cmd) {
131 case Read:
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);
140 cerr << endl;
141 fatal("");
142 }
143
144 numReads++;
145
146 if (numReads.value() == nextProgressMessage) {
147 cerr << name() << ": completed " << numReads.value()
148 << " read accesses @ " << curTick << endl;
149 nextProgressMessage += progressInterval;
150 }
151
152 comLoadEventQueue[0]->serviceEvents(numReads.value());
153 break;
154
155 case Write:
156 numWrites++;
157 break;
158
159 case Copy:
160 break;
161
162 default:
163 panic("invalid command");
164 }
165
166 if (blockAddr(req->paddr) == traceBlockAddr) {
167 cerr << name() << ": completed "
168 << (req->cmd.isWrite() ? "write" : "read")
169 << " access of "
170 << dec << req->size << " bytes at address 0x"
171 << hex << req->paddr
172 << " (0x" << hex << blockAddr(req->paddr) << ")"
173 << ", value = 0x";
174 printData(cerr, req->data, req->size);
175 cerr << " @ cycle " << dec << curTick;
176
177 cerr << endl;
178 }
179
180 noResponseCycles = 0;
181 delete [] data;
182 }
183
184
185 void
186 MemTest::regStats()
187 {
188 using namespace Statistics;
189
190 numReads
191 .name(name() + ".num_reads")
192 .desc("number of read accesses completed")
193 ;
194
195 numWrites
196 .name(name() + ".num_writes")
197 .desc("number of write accesses completed")
198 ;
199
200 numCopies
201 .name(name() + ".num_copies")
202 .desc("number of copy accesses completed")
203 ;
204 }
205
206 void
207 MemTest::tick()
208 {
209 if (!tickEvent.scheduled())
210 tickEvent.schedule(curTick + 1);
211
212 if (++noResponseCycles >= 5000) {
213 cerr << name() << ": deadlocked at cycle " << curTick << endl;
214 fatal("");
215 }
216
217 if (cacheInterface->isBlocked()) {
218 return;
219 }
220
221 //make new request
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;
231
232 MemReqPtr req = new MemReq();
233
234 if (cacheable < percentUncacheable) {
235 req->flags |= UNCACHEABLE;
236 req->paddr = uncacheAddr + offset1;
237 } else {
238 req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1;
239 }
240 bool probe = (rand() % 2 == 1) && !req->isUncacheable();
241 probe = false;
242
243 req->size = 1 << access_size;
244 req->data = new uint8_t[req->size];
245 req->paddr &= ~(req->size - 1);
246 req->time = curTick;
247 req->xc = xc;
248
249 if (cmd < percentReads) {
250 // read
251 req->cmd = Read;
252 uint8_t *result = new uint8_t[8];
253 checkMem->access(Read, req->paddr, result, req->size);
254 if (blockAddr(req->paddr) == traceBlockAddr) {
255 cerr << name()
256 << ": initiating read "
257 << ((probe)?"probe of ":"access of ")
258 << dec << req->size << " bytes from addr 0x"
259 << hex << req->paddr
260 << " (0x" << hex << blockAddr(req->paddr) << ")"
261 << " at cycle "
262 << dec << curTick << endl;
263 }
264 if (probe) {
265 cacheInterface->probeAndUpdate(req);
266 completeRequest(req, result);
267 } else {
268 req->completionEvent = new MemCompleteEvent(req, result, this);
269 cacheInterface->access(req);
270 }
271 } else if (cmd < (100 - percentCopies)){
272 // write
273 req->cmd = Write;
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"
282 << hex << req->paddr
283 << " (0x" << hex << blockAddr(req->paddr) << ")"
284 << " at cycle "
285 << dec << curTick << endl;
286 }
287 if (probe) {
288 cacheInterface->probeAndUpdate(req);
289 completeRequest(req, NULL);
290 } else {
291 req->completionEvent = new MemCompleteEvent(req, NULL, this);
292 cacheInterface->access(req);
293 }
294 } else {
295 // copy
296 Addr source = ((base) ? baseAddr1 : baseAddr2) + offset1;
297 Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2;
298 if (source_align >= percentSourceUnaligned) {
299 source = blockAddr(source);
300 }
301 if (dest_align >= percentDestUnaligned) {
302 dest = blockAddr(dest);
303 }
304 req->cmd = Copy;
305 req->flags &= ~UNCACHEABLE;
306 req->paddr = source;
307 req->dest = dest;
308 delete [] req->data;
309 req->data = new uint8_t[blockSize];
310 req->size = blockSize;
311 if (source == traceBlockAddr || dest == traceBlockAddr) {
312 cerr << name()
313 << ": initiating copy of "
314 << dec << req->size << " bytes from addr 0x"
315 << hex << source
316 << " (0x" << hex << blockAddr(source) << ")"
317 << " to addr 0x"
318 << hex << dest
319 << " (0x" << hex << blockAddr(dest) << ")"
320 << " at cycle "
321 << dec << curTick << endl;
322 }
323 cacheInterface->access(req);
324 uint8_t result[blockSize];
325 checkMem->access(Read, source, &result, blockSize);
326 checkMem->access(Write, dest, &result, blockSize);
327 }
328 }
329
330
331 void
332 MemCompleteEvent::process()
333 {
334 tester->completeRequest(req, data);
335 delete this;
336 }
337
338
339 const char *
340 MemCompleteEvent::description()
341 {
342 return "memory access completion";
343 }
344
345
346 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
347
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;
361
362 END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
363
364
365 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
366
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",
383 0),
384 INIT_PARAM_DFLT(max_loads_all_threads,
385 "terminate when all threads have reached this load count",
386 0)
387
388 END_INIT_SIM_OBJECT_PARAMS(MemTest)
389
390
391 CREATE_SIM_OBJECT(MemTest)
392 {
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);
399 }
400
401 REGISTER_SIM_OBJECT("MemTest", MemTest)