b72fdca4a3f150b3e0cb80ef3d0e1b8ac58e6f52
[gem5.git] / src / sim / pseudo_inst.cc
1 /*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2011 Advanced Micro Devices, Inc.
15 * Copyright (c) 2003-2006 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Nathan Binkert
42 */
43
44 #include <fcntl.h>
45 #include <unistd.h>
46
47 #include <cerrno>
48 #include <fstream>
49 #include <string>
50
51 #include "arch/kernel_stats.hh"
52 #include "arch/vtophys.hh"
53 #include "base/debug.hh"
54 #include "config/the_isa.hh"
55 #include "cpu/base.hh"
56 #include "cpu/quiesce_event.hh"
57 #include "cpu/thread_context.hh"
58 #include "debug/Loader.hh"
59 #include "debug/Quiesce.hh"
60 #include "debug/WorkItems.hh"
61 #include "params/BaseCPU.hh"
62 #include "sim/full_system.hh"
63 #include "sim/pseudo_inst.hh"
64 #include "sim/serialize.hh"
65 #include "sim/sim_events.hh"
66 #include "sim/sim_exit.hh"
67 #include "sim/stat_control.hh"
68 #include "sim/stats.hh"
69 #include "sim/system.hh"
70 #include "sim/vptr.hh"
71
72 using namespace std;
73
74 using namespace Stats;
75 using namespace TheISA;
76
77 namespace PseudoInst {
78
79 static inline void
80 panicFsOnlyPseudoInst(const char *name)
81 {
82 panic("Pseudo inst \"%s\" is only available in Full System mode.");
83 }
84
85 void
86 arm(ThreadContext *tc)
87 {
88 if (!FullSystem)
89 panicFsOnlyPseudoInst("arm");
90
91 if (tc->getKernelStats())
92 tc->getKernelStats()->arm();
93 }
94
95 void
96 quiesce(ThreadContext *tc)
97 {
98 if (!FullSystem)
99 panicFsOnlyPseudoInst("quiesce");
100
101 if (!tc->getCpuPtr()->params()->do_quiesce)
102 return;
103
104 DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name());
105
106 tc->suspend();
107 if (tc->getKernelStats())
108 tc->getKernelStats()->quiesce();
109 }
110
111 void
112 quiesceSkip(ThreadContext *tc)
113 {
114 if (!FullSystem)
115 panicFsOnlyPseudoInst("quiesceSkip");
116
117 BaseCPU *cpu = tc->getCpuPtr();
118
119 if (!cpu->params()->do_quiesce)
120 return;
121
122 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
123
124 Tick resume = curTick() + 1;
125
126 cpu->reschedule(quiesceEvent, resume, true);
127
128 DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n",
129 cpu->name(), resume);
130
131 tc->suspend();
132 if (tc->getKernelStats())
133 tc->getKernelStats()->quiesce();
134 }
135
136 void
137 quiesceNs(ThreadContext *tc, uint64_t ns)
138 {
139 if (!FullSystem)
140 panicFsOnlyPseudoInst("quiesceNs");
141
142 BaseCPU *cpu = tc->getCpuPtr();
143
144 if (!cpu->params()->do_quiesce || ns == 0)
145 return;
146
147 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
148
149 Tick resume = curTick() + SimClock::Int::ns * ns;
150
151 cpu->reschedule(quiesceEvent, resume, true);
152
153 DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n",
154 cpu->name(), ns, resume);
155
156 tc->suspend();
157 if (tc->getKernelStats())
158 tc->getKernelStats()->quiesce();
159 }
160
161 void
162 quiesceCycles(ThreadContext *tc, uint64_t cycles)
163 {
164 if (!FullSystem)
165 panicFsOnlyPseudoInst("quiesceCycles");
166
167 BaseCPU *cpu = tc->getCpuPtr();
168
169 if (!cpu->params()->do_quiesce || cycles == 0)
170 return;
171
172 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
173
174 Tick resume = curTick() + cpu->ticks(cycles);
175
176 cpu->reschedule(quiesceEvent, resume, true);
177
178 DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n",
179 cpu->name(), cycles, resume);
180
181 tc->suspend();
182 if (tc->getKernelStats())
183 tc->getKernelStats()->quiesce();
184 }
185
186 uint64_t
187 quiesceTime(ThreadContext *tc)
188 {
189 if (!FullSystem) {
190 panicFsOnlyPseudoInst("quiesceTime");
191 return 0;
192 }
193
194 return (tc->readLastActivate() - tc->readLastSuspend()) /
195 SimClock::Int::ns;
196 }
197
198 uint64_t
199 rpns(ThreadContext *tc)
200 {
201 return curTick() / SimClock::Int::ns;
202 }
203
204 void
205 wakeCPU(ThreadContext *tc, uint64_t cpuid)
206 {
207 System *sys = tc->getSystemPtr();
208 ThreadContext *other_tc = sys->threadContexts[cpuid];
209 if (other_tc->status() == ThreadContext::Suspended)
210 other_tc->activate();
211 }
212
213 void
214 m5exit(ThreadContext *tc, Tick delay)
215 {
216 Tick when = curTick() + delay * SimClock::Int::ns;
217 exitSimLoop("m5_exit instruction encountered", 0, when);
218 }
219
220 void
221 loadsymbol(ThreadContext *tc)
222 {
223 if (!FullSystem)
224 panicFsOnlyPseudoInst("loadsymbol");
225
226 const string &filename = tc->getCpuPtr()->system->params()->symbolfile;
227 if (filename.empty()) {
228 return;
229 }
230
231 std::string buffer;
232 ifstream file(filename.c_str());
233
234 if (!file)
235 fatal("file error: Can't open symbol table file %s\n", filename);
236
237 while (!file.eof()) {
238 getline(file, buffer);
239
240 if (buffer.empty())
241 continue;
242
243 string::size_type idx = buffer.find(' ');
244 if (idx == string::npos)
245 continue;
246
247 string address = "0x" + buffer.substr(0, idx);
248 eat_white(address);
249 if (address.empty())
250 continue;
251
252 // Skip over letter and space
253 string symbol = buffer.substr(idx + 3);
254 eat_white(symbol);
255 if (symbol.empty())
256 continue;
257
258 Addr addr;
259 if (!to_number(address, addr))
260 continue;
261
262 if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
263 continue;
264
265
266 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
267 }
268 file.close();
269 }
270
271 void
272 addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
273 {
274 if (!FullSystem)
275 panicFsOnlyPseudoInst("addSymbol");
276
277 char symb[100];
278 CopyStringOut(tc, symb, symbolAddr, 100);
279 std::string symbol(symb);
280
281 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
282
283 tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
284 debugSymbolTable->insert(addr,symbol);
285 }
286
287 uint64_t
288 initParam(ThreadContext *tc)
289 {
290 if (!FullSystem) {
291 panicFsOnlyPseudoInst("initParam");
292 return 0;
293 }
294
295 return tc->getCpuPtr()->system->init_param;
296 }
297
298
299 void
300 resetstats(ThreadContext *tc, Tick delay, Tick period)
301 {
302 if (!tc->getCpuPtr()->params()->do_statistics_insts)
303 return;
304
305
306 Tick when = curTick() + delay * SimClock::Int::ns;
307 Tick repeat = period * SimClock::Int::ns;
308
309 Stats::schedStatEvent(false, true, when, repeat);
310 }
311
312 void
313 dumpstats(ThreadContext *tc, Tick delay, Tick period)
314 {
315 if (!tc->getCpuPtr()->params()->do_statistics_insts)
316 return;
317
318
319 Tick when = curTick() + delay * SimClock::Int::ns;
320 Tick repeat = period * SimClock::Int::ns;
321
322 Stats::schedStatEvent(true, false, when, repeat);
323 }
324
325 void
326 dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
327 {
328 if (!tc->getCpuPtr()->params()->do_statistics_insts)
329 return;
330
331
332 Tick when = curTick() + delay * SimClock::Int::ns;
333 Tick repeat = period * SimClock::Int::ns;
334
335 Stats::schedStatEvent(true, true, when, repeat);
336 }
337
338 void
339 m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
340 {
341 if (!tc->getCpuPtr()->params()->do_checkpoint_insts)
342 return;
343
344 Tick when = curTick() + delay * SimClock::Int::ns;
345 Tick repeat = period * SimClock::Int::ns;
346
347 exitSimLoop("checkpoint", 0, when, repeat);
348 }
349
350 uint64_t
351 readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
352 {
353 if (!FullSystem) {
354 panicFsOnlyPseudoInst("readfile");
355 return 0;
356 }
357
358 const string &file = tc->getSystemPtr()->params()->readfile;
359 if (file.empty()) {
360 return ULL(0);
361 }
362
363 uint64_t result = 0;
364
365 int fd = ::open(file.c_str(), O_RDONLY, 0);
366 if (fd < 0)
367 panic("could not open file %s\n", file);
368
369 if (::lseek(fd, offset, SEEK_SET) < 0)
370 panic("could not seek: %s", strerror(errno));
371
372 char *buf = new char[len];
373 char *p = buf;
374 while (len > 0) {
375 int bytes = ::read(fd, p, len);
376 if (bytes <= 0)
377 break;
378
379 p += bytes;
380 result += bytes;
381 len -= bytes;
382 }
383
384 close(fd);
385 CopyIn(tc, vaddr, buf, result);
386 delete [] buf;
387 return result;
388 }
389
390 void
391 debugbreak(ThreadContext *tc)
392 {
393 Debug::breakpoint();
394 }
395
396 void
397 switchcpu(ThreadContext *tc)
398 {
399 exitSimLoop("switchcpu");
400 }
401
402 //
403 // This function is executed when annotated work items begin. Depending on
404 // what the user specified at the command line, the simulation may exit and/or
405 // take a checkpoint when a certain work item begins.
406 //
407 void
408 workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid)
409 {
410 tc->getCpuPtr()->workItemBegin();
411 System *sys = tc->getSystemPtr();
412 const System::Params *params = sys->params();
413 sys->workItemBegin(threadid, workid);
414
415 DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid,
416 threadid);
417
418 //
419 // If specified, determine if this is the specific work item the user
420 // identified
421 //
422 if (params->work_item_id == -1 || params->work_item_id == workid) {
423
424 uint64_t systemWorkBeginCount = sys->incWorkItemsBegin();
425 int cpuId = tc->getCpuPtr()->cpuId();
426
427 if (params->work_cpus_ckpt_count != 0 &&
428 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) {
429 //
430 // If active cpus equals checkpoint count, create checkpoint
431 //
432 exitSimLoop("checkpoint");
433 }
434
435 if (systemWorkBeginCount == params->work_begin_ckpt_count) {
436 //
437 // Note: the string specified as the cause of the exit event must
438 // exactly equal "checkpoint" inorder to create a checkpoint
439 //
440 exitSimLoop("checkpoint");
441 }
442
443 if (systemWorkBeginCount == params->work_begin_exit_count) {
444 //
445 // If a certain number of work items started, exit simulation
446 //
447 exitSimLoop("work started count reach");
448 }
449
450 if (cpuId == params->work_begin_cpu_id_exit) {
451 //
452 // If work started on the cpu id specified, exit simulation
453 //
454 exitSimLoop("work started on specific cpu");
455 }
456 }
457 }
458
459 //
460 // This function is executed when annotated work items end. Depending on
461 // what the user specified at the command line, the simulation may exit and/or
462 // take a checkpoint when a certain work item ends.
463 //
464 void
465 workend(ThreadContext *tc, uint64_t workid, uint64_t threadid)
466 {
467 tc->getCpuPtr()->workItemEnd();
468 System *sys = tc->getSystemPtr();
469 const System::Params *params = sys->params();
470 sys->workItemEnd(threadid, workid);
471
472 DPRINTF(WorkItems, "Work End workid: %d, threadid %d\n", workid, threadid);
473
474 //
475 // If specified, determine if this is the specific work item the user
476 // identified
477 //
478 if (params->work_item_id == -1 || params->work_item_id == workid) {
479
480 uint64_t systemWorkEndCount = sys->incWorkItemsEnd();
481 int cpuId = tc->getCpuPtr()->cpuId();
482
483 if (params->work_cpus_ckpt_count != 0 &&
484 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) {
485 //
486 // If active cpus equals checkpoint count, create checkpoint
487 //
488 exitSimLoop("checkpoint");
489 }
490
491 if (params->work_end_ckpt_count != 0 &&
492 systemWorkEndCount == params->work_end_ckpt_count) {
493 //
494 // If total work items completed equals checkpoint count, create
495 // checkpoint
496 //
497 exitSimLoop("checkpoint");
498 }
499
500 if (params->work_end_exit_count != 0 &&
501 systemWorkEndCount == params->work_end_exit_count) {
502 //
503 // If total work items completed equals exit count, exit simulation
504 //
505 exitSimLoop("work items exit count reached");
506 }
507 }
508 }
509
510 } // namespace PseudoInst