Merge ehallnor@zizzer:/bk/m5 into zazzer.eecs.umich.edu:/z/ehallnor/m5
[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 _percentUncacheable,
54 unsigned _progressInterval,
55 Addr _traceAddr,
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),
59 tickEvent(this),
60 cacheInterface(_cache_interface),
61 mainMem(main_mem),
62 checkMem(check_mem),
63 size(_memorySize),
64 percentReads(_percentReads),
65 percentUncacheable(_percentUncacheable),
66 progressInterval(_progressInterval),
67 nextProgressMessage(_progressInterval)
68 {
69 vector<string> cmd;
70 cmd.push_back("/bin/ls");
71 vector<string> null_vec;
72 xc = new ExecContext(this ,0,mainMem,0);
73
74 blockSize = cacheInterface->getBlockSize();
75 blockAddrMask = blockSize - 1;
76 traceBlockAddr = blockAddr(_traceAddr);
77
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);
85 curTick = 0;
86
87 baseAddr1 = 0x100000;
88 baseAddr2 = 0x400000;
89 uncacheAddr = 0x800000;
90
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);
98
99 delete [] data1;
100 delete [] data2;
101 delete [] data3;
102
103 // set up counters
104 noResponseCycles = 0;
105 numReads = 0;
106 numWrites = 0;
107 tickEvent.schedule(0);
108 }
109
110 static void
111 printData(ostream &os, uint8_t *data, int nbytes)
112 {
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;
117 }
118 os << dec;
119 }
120
121 void
122 MemTest::completeRequest(MemReqPtr req, uint8_t *data)
123 {
124 switch (req->cmd) {
125 case Read:
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);
133 cerr << endl;
134 fatal("");
135 }
136
137 numReads++;
138
139 if (numReads.value() == nextProgressMessage) {
140 cerr << name() << ": completed " << numReads.value()
141 << " read accesses @ " << curTick << endl;
142 nextProgressMessage += progressInterval;
143 }
144
145 comLoadEventQueue[0]->serviceEvents(numReads.value());
146 break;
147
148 case Write:
149 numWrites++;
150 break;
151
152
153 default:
154 panic("invalid command");
155 }
156
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;
164
165 cerr << endl;
166 }
167
168 noResponseCycles = 0;
169 delete [] data;
170 }
171
172
173 void
174 MemTest::regStats()
175 {
176 using namespace Statistics;
177
178 numReads
179 .name(name() + ".num_reads")
180 .desc("number of read accesses completed")
181 ;
182
183 numWrites
184 .name(name() + ".num_writes")
185 .desc("number of write accesses completed")
186 ;
187
188 numCopies
189 .name(name() + ".num_copies")
190 .desc("number of copy accesses completed")
191 ;
192 }
193
194 void
195 MemTest::tick()
196 {
197 if (!tickEvent.scheduled())
198 tickEvent.schedule(curTick + 1);
199
200 if (++noResponseCycles >= 5000) {
201 cerr << name() << ": deadlocked at cycle " << curTick << endl;
202 fatal("");
203 }
204
205 if (cacheInterface->isBlocked()) {
206 return;
207 }
208
209 //make new request
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;
216 unsigned probe = rand() % 2;
217
218 MemReqPtr req = new MemReq();
219
220 if (cacheable < percentUncacheable) {
221 req->flags |= UNCACHEABLE;
222 req->paddr = uncacheAddr + offset1;
223 } else {
224 req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1;
225 }
226
227 req->size = 1 << access_size;
228 req->data = new uint8_t[req->size];
229 req->paddr &= ~(req->size - 1);
230 req->time = curTick;
231 req->xc = xc;
232
233 if (cmd < percentReads) {
234 // read
235 req->cmd = Read;
236 uint8_t *result = new uint8_t[8];
237 checkMem->access(Read, req->paddr, result, req->size);
238 if (blockAddr(req->paddr) == traceBlockAddr) {
239 cerr << name() << ": initiating read "
240 << ((probe)?"probe of ":"access of ")
241 << req->size << " bytes from addr 0x"
242 << hex << req->paddr << " at cycle "
243 << dec << curTick << endl;
244 }
245 if (probe) {
246 cacheInterface->probeAndUpdate(req);
247 completeRequest(req, result);
248 } else {
249 req->completionEvent = new MemCompleteEvent(req, result, this);
250 cacheInterface->access(req);
251 }
252 } else {
253 // write
254 req->cmd = Write;
255 memcpy(req->data, &data, req->size);
256 checkMem->access(Write, req->paddr, req->data, req->size);
257 if (blockAddr(req->paddr) == traceBlockAddr) {
258 cerr << name() << ": initiating write "
259 << ((probe)?"probe of ":"access of ")
260 << req->size << " bytes (value = 0x";
261 printData(cerr, req->data, req->size);
262 cerr << ") to addr 0x"
263 << hex << req->paddr << " at cycle "
264 << dec << curTick << endl;
265 }
266 if (probe) {
267 cacheInterface->probeAndUpdate(req);
268 completeRequest(req, NULL);
269 } else {
270 req->completionEvent = new MemCompleteEvent(req, NULL, this);
271 cacheInterface->access(req);
272 }
273 }
274 }
275
276
277 void
278 MemCompleteEvent::process()
279 {
280 tester->completeRequest(req, data);
281 delete this;
282 }
283
284
285 const char *
286 MemCompleteEvent::description()
287 {
288 return "memory access completion";
289 }
290
291
292 BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
293
294 SimObjectParam<BaseCache *> cache;
295 SimObjectParam<FunctionalMemory *> main_mem;
296 SimObjectParam<FunctionalMemory *> check_mem;
297 Param<unsigned> memory_size;
298 Param<unsigned> percent_reads;
299 Param<unsigned> percent_uncacheable;
300 Param<unsigned> progress_interval;
301 Param<Addr> trace_addr;
302 Param<Counter> max_loads_any_thread;
303 Param<Counter> max_loads_all_threads;
304
305 END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
306
307
308 BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
309
310 INIT_PARAM(cache, "L1 cache"),
311 INIT_PARAM(main_mem, "hierarchical memory"),
312 INIT_PARAM(check_mem, "check memory"),
313 INIT_PARAM_DFLT(memory_size, "memory size", 65536),
314 INIT_PARAM_DFLT(percent_reads, "target read percentage", 65),
315 INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10),
316 INIT_PARAM_DFLT(progress_interval,
317 "progress report interval (in accesses)", 1000000),
318 INIT_PARAM_DFLT(trace_addr, "address to trace", 0),
319 INIT_PARAM_DFLT(max_loads_any_thread,
320 "terminate when any thread reaches this load count",
321 0),
322 INIT_PARAM_DFLT(max_loads_all_threads,
323 "terminate when all threads have reached this load count",
324 0)
325
326 END_INIT_SIM_OBJECT_PARAMS(MemTest)
327
328
329 CREATE_SIM_OBJECT(MemTest)
330 {
331 return new MemTest(getInstanceName(), cache->getInterface(), main_mem,
332 check_mem, memory_size, percent_reads,
333 percent_uncacheable, progress_interval,
334 trace_addr, max_loads_any_thread,
335 max_loads_all_threads);
336 }
337
338 REGISTER_SIM_OBJECT("MemTest", MemTest)