pseudo_inst.cc (11320:42ecb523c64a) pseudo_inst.cc (11359:b0b976a1ceda)
1/*
2 * Copyright (c) 2010-2012, 2015 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#include <vector>
51
52#include "arch/kernel_stats.hh"
53#include "arch/utility.hh"
54#include "arch/vtophys.hh"
55#include "arch/pseudo_inst.hh"
56#include "base/debug.hh"
57#include "base/output.hh"
58#include "config/the_isa.hh"
59#include "cpu/base.hh"
60#include "cpu/quiesce_event.hh"
61#include "cpu/thread_context.hh"
62#include "debug/Loader.hh"
63#include "debug/PseudoInst.hh"
64#include "debug/Quiesce.hh"
65#include "debug/WorkItems.hh"
66#include "dev/net/dist_iface.hh"
67#include "params/BaseCPU.hh"
68#include "sim/full_system.hh"
69#include "sim/initparam_keys.hh"
70#include "sim/process.hh"
71#include "sim/pseudo_inst.hh"
72#include "sim/serialize.hh"
73#include "sim/sim_events.hh"
74#include "sim/sim_exit.hh"
75#include "sim/stat_control.hh"
76#include "sim/stats.hh"
77#include "sim/system.hh"
78#include "sim/vptr.hh"
79
80using namespace std;
81
82using namespace Stats;
83using namespace TheISA;
84
85namespace PseudoInst {
86
87static inline void
88panicFsOnlyPseudoInst(const char *name)
89{
90 panic("Pseudo inst \"%s\" is only available in Full System mode.");
91}
92
93uint64_t
94pseudoInst(ThreadContext *tc, uint8_t func, uint8_t subfunc)
95{
96 uint64_t args[4];
97
98 DPRINTF(PseudoInst, "PseudoInst::pseudoInst(%i, %i)\n", func, subfunc);
99
100 // We need to do this in a slightly convoluted way since
101 // getArgument() might have side-effects on arg_num. We could have
102 // used the Argument class, but due to the possible side effects
103 // from getArgument, it'd most likely break.
104 int arg_num(0);
105 for (int i = 0; i < sizeof(args) / sizeof(*args); ++i) {
106 args[arg_num] = getArgument(tc, arg_num, sizeof(uint64_t), false);
107 ++arg_num;
108 }
109
110 switch (func) {
111 case 0x00: // arm_func
112 arm(tc);
113 break;
114
115 case 0x01: // quiesce_func
116 quiesce(tc);
117 break;
118
119 case 0x02: // quiescens_func
120 quiesceSkip(tc);
121 break;
122
123 case 0x03: // quiescecycle_func
124 quiesceNs(tc, args[0]);
125 break;
126
127 case 0x04: // quiescetime_func
128 return quiesceTime(tc);
129
130 case 0x07: // rpns_func
131 return rpns(tc);
132
133 case 0x09: // wakecpu_func
134 wakeCPU(tc, args[0]);
135 break;
136
137 case 0x21: // exit_func
138 m5exit(tc, args[0]);
139 break;
140
141 case 0x22:
142 m5fail(tc, args[0], args[1]);
143 break;
144
145 case 0x30: // initparam_func
146 return initParam(tc, args[0], args[1]);
147
148 case 0x31: // loadsymbol_func
149 loadsymbol(tc);
150 break;
151
152 case 0x40: // resetstats_func
153 resetstats(tc, args[0], args[1]);
154 break;
155
156 case 0x41: // dumpstats_func
157 dumpstats(tc, args[0], args[1]);
158 break;
159
160 case 0x42: // dumprststats_func
161 dumpresetstats(tc, args[0], args[1]);
162 break;
163
164 case 0x43: // ckpt_func
165 m5checkpoint(tc, args[0], args[1]);
166 break;
167
168 case 0x4f: // writefile_func
169 return writefile(tc, args[0], args[1], args[2], args[3]);
170
171 case 0x50: // readfile_func
172 return readfile(tc, args[0], args[1], args[2]);
173
174 case 0x51: // debugbreak_func
175 debugbreak(tc);
176 break;
177
178 case 0x52: // switchcpu_func
179 switchcpu(tc);
180 break;
181
182 case 0x53: // addsymbol_func
183 addsymbol(tc, args[0], args[1]);
184 break;
185
186 case 0x54: // panic_func
187 panic("M5 panic instruction called at %s\n", tc->pcState());
188
189 case 0x5a: // work_begin_func
190 workbegin(tc, args[0], args[1]);
191 break;
192
193 case 0x5b: // work_end_func
194 workend(tc, args[0], args[1]);
195 break;
196
197 case 0x55: // annotate_func
198 case 0x56: // reserved2_func
199 case 0x57: // reserved3_func
200 case 0x58: // reserved4_func
201 case 0x59: // reserved5_func
202 warn("Unimplemented m5 op (0x%x)\n", func);
203 break;
204
205 /* SE mode functions */
206 case 0x60: // syscall_func
207 m5Syscall(tc);
208 break;
209
210 case 0x61: // pagefault_func
211 m5PageFault(tc);
212 break;
213
214 default:
215 warn("Unhandled m5 op: 0x%x\n", func);
216 break;
217 }
218
219 return 0;
220}
221
222void
223arm(ThreadContext *tc)
224{
225 DPRINTF(PseudoInst, "PseudoInst::arm()\n");
226 if (!FullSystem)
227 panicFsOnlyPseudoInst("arm");
228
229 if (tc->getKernelStats())
230 tc->getKernelStats()->arm();
231}
232
233void
234quiesce(ThreadContext *tc)
235{
236 DPRINTF(PseudoInst, "PseudoInst::quiesce()\n");
237 if (!FullSystem)
238 panicFsOnlyPseudoInst("quiesce");
239
240 if (!tc->getCpuPtr()->params()->do_quiesce)
241 return;
242
243 DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name());
244
245 tc->suspend();
246 if (tc->getKernelStats())
247 tc->getKernelStats()->quiesce();
248}
249
250void
251quiesceSkip(ThreadContext *tc)
252{
253 DPRINTF(PseudoInst, "PseudoInst::quiesceSkip()\n");
254 if (!FullSystem)
255 panicFsOnlyPseudoInst("quiesceSkip");
256
257 BaseCPU *cpu = tc->getCpuPtr();
258
259 if (!cpu->params()->do_quiesce)
260 return;
261
262 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
263
264 Tick resume = curTick() + 1;
265
266 cpu->reschedule(quiesceEvent, resume, true);
267
268 DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n",
269 cpu->name(), resume);
270
271 tc->suspend();
272 if (tc->getKernelStats())
273 tc->getKernelStats()->quiesce();
274}
275
276void
277quiesceNs(ThreadContext *tc, uint64_t ns)
278{
279 DPRINTF(PseudoInst, "PseudoInst::quiesceNs(%i)\n", ns);
280 if (!FullSystem)
281 panicFsOnlyPseudoInst("quiesceNs");
282
283 BaseCPU *cpu = tc->getCpuPtr();
284
285 if (!cpu->params()->do_quiesce)
286 return;
287
288 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
289
290 Tick resume = curTick() + SimClock::Int::ns * ns;
291
292 cpu->reschedule(quiesceEvent, resume, true);
293
294 DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n",
295 cpu->name(), ns, resume);
296
297 tc->suspend();
298 if (tc->getKernelStats())
299 tc->getKernelStats()->quiesce();
300}
301
302void
303quiesceCycles(ThreadContext *tc, uint64_t cycles)
304{
305 DPRINTF(PseudoInst, "PseudoInst::quiesceCycles(%i)\n", cycles);
306 if (!FullSystem)
307 panicFsOnlyPseudoInst("quiesceCycles");
308
309 BaseCPU *cpu = tc->getCpuPtr();
310
311 if (!cpu->params()->do_quiesce)
312 return;
313
314 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
315
316 Tick resume = cpu->clockEdge(Cycles(cycles));
317
318 cpu->reschedule(quiesceEvent, resume, true);
319
320 DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n",
321 cpu->name(), cycles, resume);
322
323 tc->suspend();
324 if (tc->getKernelStats())
325 tc->getKernelStats()->quiesce();
326}
327
328uint64_t
329quiesceTime(ThreadContext *tc)
330{
331 DPRINTF(PseudoInst, "PseudoInst::quiesceTime()\n");
332 if (!FullSystem) {
333 panicFsOnlyPseudoInst("quiesceTime");
334 return 0;
335 }
336
337 return (tc->readLastActivate() - tc->readLastSuspend()) /
338 SimClock::Int::ns;
339}
340
341uint64_t
342rpns(ThreadContext *tc)
343{
344 DPRINTF(PseudoInst, "PseudoInst::rpns()\n");
345 return curTick() / SimClock::Int::ns;
346}
347
348void
349wakeCPU(ThreadContext *tc, uint64_t cpuid)
350{
351 DPRINTF(PseudoInst, "PseudoInst::wakeCPU(%i)\n", cpuid);
352 System *sys = tc->getSystemPtr();
353 ThreadContext *other_tc = sys->threadContexts[cpuid];
354 if (other_tc->status() == ThreadContext::Suspended)
355 other_tc->activate();
356}
357
358void
359m5exit(ThreadContext *tc, Tick delay)
360{
361 DPRINTF(PseudoInst, "PseudoInst::m5exit(%i)\n", delay);
362 if (DistIface::readyToExit(delay)) {
363 Tick when = curTick() + delay * SimClock::Int::ns;
364 exitSimLoop("m5_exit instruction encountered", 0, when, 0, true);
365 }
366}
367
368void
369m5fail(ThreadContext *tc, Tick delay, uint64_t code)
370{
371 DPRINTF(PseudoInst, "PseudoInst::m5fail(%i, %i)\n", delay, code);
372 Tick when = curTick() + delay * SimClock::Int::ns;
373 exitSimLoop("m5_fail instruction encountered", code, when, 0, true);
374}
375
376void
377loadsymbol(ThreadContext *tc)
378{
379 DPRINTF(PseudoInst, "PseudoInst::loadsymbol()\n");
380 if (!FullSystem)
381 panicFsOnlyPseudoInst("loadsymbol");
382
383 const string &filename = tc->getCpuPtr()->system->params()->symbolfile;
384 if (filename.empty()) {
385 return;
386 }
387
388 std::string buffer;
389 ifstream file(filename.c_str());
390
391 if (!file)
392 fatal("file error: Can't open symbol table file %s\n", filename);
393
394 while (!file.eof()) {
395 getline(file, buffer);
396
397 if (buffer.empty())
398 continue;
399
400 string::size_type idx = buffer.find(' ');
401 if (idx == string::npos)
402 continue;
403
404 string address = "0x" + buffer.substr(0, idx);
405 eat_white(address);
406 if (address.empty())
407 continue;
408
409 // Skip over letter and space
410 string symbol = buffer.substr(idx + 3);
411 eat_white(symbol);
412 if (symbol.empty())
413 continue;
414
415 Addr addr;
416 if (!to_number(address, addr))
417 continue;
418
419 if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
420 continue;
421
422
423 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
424 }
425 file.close();
426}
427
428void
429addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
430{
431 DPRINTF(PseudoInst, "PseudoInst::addsymbol(0x%x, 0x%x)\n",
432 addr, symbolAddr);
433 if (!FullSystem)
434 panicFsOnlyPseudoInst("addSymbol");
435
436 char symb[100];
437 CopyStringOut(tc, symb, symbolAddr, 100);
438 std::string symbol(symb);
439
440 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
441
442 tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
443 debugSymbolTable->insert(addr,symbol);
444}
445
446uint64_t
447initParam(ThreadContext *tc, uint64_t key_str1, uint64_t key_str2)
448{
449 DPRINTF(PseudoInst, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1,
450 (char *)&key_str2);
451 if (!FullSystem) {
452 panicFsOnlyPseudoInst("initParam");
453 return 0;
454 }
455
456 // The key parameter string is passed in via two 64-bit registers. We copy
457 // out the characters from the 64-bit integer variables here and concatenate
458 // them in the key_str character buffer
459 const int len = 2 * sizeof(uint64_t) + 1;
460 char key_str[len];
461 memset(key_str, '\0', len);
462 if (key_str1 == 0) {
463 assert(key_str2 == 0);
464 } else {
465 strncpy(key_str, (char *)&key_str1, sizeof(uint64_t));
466 }
467
468 if (strlen(key_str) == sizeof(uint64_t)) {
469 strncpy(key_str + sizeof(uint64_t), (char *)&key_str2,
470 sizeof(uint64_t));
471 } else {
472 assert(key_str2 == 0);
473 }
474
475 // Compare the key parameter with the known values to select the return
476 // value
477 uint64_t val;
478 if (strcmp(key_str, InitParamKey::DEFAULT) == 0) {
479 val = tc->getCpuPtr()->system->init_param;
480 } else if (strcmp(key_str, InitParamKey::DIST_RANK) == 0) {
481 val = DistIface::rankParam();
482 } else if (strcmp(key_str, InitParamKey::DIST_SIZE) == 0) {
483 val = DistIface::sizeParam();
484 } else {
485 panic("Unknown key for initparam pseudo instruction:\"%s\"", key_str);
486 }
487 return val;
488}
489
490
491void
492resetstats(ThreadContext *tc, Tick delay, Tick period)
493{
494 DPRINTF(PseudoInst, "PseudoInst::resetstats(%i, %i)\n", delay, period);
495 if (!tc->getCpuPtr()->params()->do_statistics_insts)
496 return;
497
498
499 Tick when = curTick() + delay * SimClock::Int::ns;
500 Tick repeat = period * SimClock::Int::ns;
501
502 Stats::schedStatEvent(false, true, when, repeat);
503}
504
505void
506dumpstats(ThreadContext *tc, Tick delay, Tick period)
507{
508 DPRINTF(PseudoInst, "PseudoInst::dumpstats(%i, %i)\n", delay, period);
509 if (!tc->getCpuPtr()->params()->do_statistics_insts)
510 return;
511
512
513 Tick when = curTick() + delay * SimClock::Int::ns;
514 Tick repeat = period * SimClock::Int::ns;
515
516 Stats::schedStatEvent(true, false, when, repeat);
517}
518
519void
520dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
521{
522 DPRINTF(PseudoInst, "PseudoInst::dumpresetstats(%i, %i)\n", delay, period);
523 if (!tc->getCpuPtr()->params()->do_statistics_insts)
524 return;
525
526
527 Tick when = curTick() + delay * SimClock::Int::ns;
528 Tick repeat = period * SimClock::Int::ns;
529
530 Stats::schedStatEvent(true, true, when, repeat);
531}
532
533void
534m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
535{
536 DPRINTF(PseudoInst, "PseudoInst::m5checkpoint(%i, %i)\n", delay, period);
537 if (!tc->getCpuPtr()->params()->do_checkpoint_insts)
538 return;
539
540 if (DistIface::readyToCkpt(delay, period)) {
541 Tick when = curTick() + delay * SimClock::Int::ns;
542 Tick repeat = period * SimClock::Int::ns;
543 exitSimLoop("checkpoint", 0, when, repeat);
544 }
545}
546
547uint64_t
548readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
549{
550 DPRINTF(PseudoInst, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n",
551 vaddr, len, offset);
552 if (!FullSystem) {
553 panicFsOnlyPseudoInst("readfile");
554 return 0;
555 }
556
557 const string &file = tc->getSystemPtr()->params()->readfile;
558 if (file.empty()) {
559 return ULL(0);
560 }
561
562 uint64_t result = 0;
563
564 int fd = ::open(file.c_str(), O_RDONLY, 0);
565 if (fd < 0)
566 panic("could not open file %s\n", file);
567
568 if (::lseek(fd, offset, SEEK_SET) < 0)
569 panic("could not seek: %s", strerror(errno));
570
571 char *buf = new char[len];
572 char *p = buf;
573 while (len > 0) {
574 int bytes = ::read(fd, p, len);
575 if (bytes <= 0)
576 break;
577
578 p += bytes;
579 result += bytes;
580 len -= bytes;
581 }
582
583 close(fd);
584 CopyIn(tc, vaddr, buf, result);
585 delete [] buf;
586 return result;
587}
588
589uint64_t
590writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset,
591 Addr filename_addr)
592{
593 DPRINTF(PseudoInst, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n",
594 vaddr, len, offset, filename_addr);
1/*
2 * Copyright (c) 2010-2012, 2015 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#include <vector>
51
52#include "arch/kernel_stats.hh"
53#include "arch/utility.hh"
54#include "arch/vtophys.hh"
55#include "arch/pseudo_inst.hh"
56#include "base/debug.hh"
57#include "base/output.hh"
58#include "config/the_isa.hh"
59#include "cpu/base.hh"
60#include "cpu/quiesce_event.hh"
61#include "cpu/thread_context.hh"
62#include "debug/Loader.hh"
63#include "debug/PseudoInst.hh"
64#include "debug/Quiesce.hh"
65#include "debug/WorkItems.hh"
66#include "dev/net/dist_iface.hh"
67#include "params/BaseCPU.hh"
68#include "sim/full_system.hh"
69#include "sim/initparam_keys.hh"
70#include "sim/process.hh"
71#include "sim/pseudo_inst.hh"
72#include "sim/serialize.hh"
73#include "sim/sim_events.hh"
74#include "sim/sim_exit.hh"
75#include "sim/stat_control.hh"
76#include "sim/stats.hh"
77#include "sim/system.hh"
78#include "sim/vptr.hh"
79
80using namespace std;
81
82using namespace Stats;
83using namespace TheISA;
84
85namespace PseudoInst {
86
87static inline void
88panicFsOnlyPseudoInst(const char *name)
89{
90 panic("Pseudo inst \"%s\" is only available in Full System mode.");
91}
92
93uint64_t
94pseudoInst(ThreadContext *tc, uint8_t func, uint8_t subfunc)
95{
96 uint64_t args[4];
97
98 DPRINTF(PseudoInst, "PseudoInst::pseudoInst(%i, %i)\n", func, subfunc);
99
100 // We need to do this in a slightly convoluted way since
101 // getArgument() might have side-effects on arg_num. We could have
102 // used the Argument class, but due to the possible side effects
103 // from getArgument, it'd most likely break.
104 int arg_num(0);
105 for (int i = 0; i < sizeof(args) / sizeof(*args); ++i) {
106 args[arg_num] = getArgument(tc, arg_num, sizeof(uint64_t), false);
107 ++arg_num;
108 }
109
110 switch (func) {
111 case 0x00: // arm_func
112 arm(tc);
113 break;
114
115 case 0x01: // quiesce_func
116 quiesce(tc);
117 break;
118
119 case 0x02: // quiescens_func
120 quiesceSkip(tc);
121 break;
122
123 case 0x03: // quiescecycle_func
124 quiesceNs(tc, args[0]);
125 break;
126
127 case 0x04: // quiescetime_func
128 return quiesceTime(tc);
129
130 case 0x07: // rpns_func
131 return rpns(tc);
132
133 case 0x09: // wakecpu_func
134 wakeCPU(tc, args[0]);
135 break;
136
137 case 0x21: // exit_func
138 m5exit(tc, args[0]);
139 break;
140
141 case 0x22:
142 m5fail(tc, args[0], args[1]);
143 break;
144
145 case 0x30: // initparam_func
146 return initParam(tc, args[0], args[1]);
147
148 case 0x31: // loadsymbol_func
149 loadsymbol(tc);
150 break;
151
152 case 0x40: // resetstats_func
153 resetstats(tc, args[0], args[1]);
154 break;
155
156 case 0x41: // dumpstats_func
157 dumpstats(tc, args[0], args[1]);
158 break;
159
160 case 0x42: // dumprststats_func
161 dumpresetstats(tc, args[0], args[1]);
162 break;
163
164 case 0x43: // ckpt_func
165 m5checkpoint(tc, args[0], args[1]);
166 break;
167
168 case 0x4f: // writefile_func
169 return writefile(tc, args[0], args[1], args[2], args[3]);
170
171 case 0x50: // readfile_func
172 return readfile(tc, args[0], args[1], args[2]);
173
174 case 0x51: // debugbreak_func
175 debugbreak(tc);
176 break;
177
178 case 0x52: // switchcpu_func
179 switchcpu(tc);
180 break;
181
182 case 0x53: // addsymbol_func
183 addsymbol(tc, args[0], args[1]);
184 break;
185
186 case 0x54: // panic_func
187 panic("M5 panic instruction called at %s\n", tc->pcState());
188
189 case 0x5a: // work_begin_func
190 workbegin(tc, args[0], args[1]);
191 break;
192
193 case 0x5b: // work_end_func
194 workend(tc, args[0], args[1]);
195 break;
196
197 case 0x55: // annotate_func
198 case 0x56: // reserved2_func
199 case 0x57: // reserved3_func
200 case 0x58: // reserved4_func
201 case 0x59: // reserved5_func
202 warn("Unimplemented m5 op (0x%x)\n", func);
203 break;
204
205 /* SE mode functions */
206 case 0x60: // syscall_func
207 m5Syscall(tc);
208 break;
209
210 case 0x61: // pagefault_func
211 m5PageFault(tc);
212 break;
213
214 default:
215 warn("Unhandled m5 op: 0x%x\n", func);
216 break;
217 }
218
219 return 0;
220}
221
222void
223arm(ThreadContext *tc)
224{
225 DPRINTF(PseudoInst, "PseudoInst::arm()\n");
226 if (!FullSystem)
227 panicFsOnlyPseudoInst("arm");
228
229 if (tc->getKernelStats())
230 tc->getKernelStats()->arm();
231}
232
233void
234quiesce(ThreadContext *tc)
235{
236 DPRINTF(PseudoInst, "PseudoInst::quiesce()\n");
237 if (!FullSystem)
238 panicFsOnlyPseudoInst("quiesce");
239
240 if (!tc->getCpuPtr()->params()->do_quiesce)
241 return;
242
243 DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name());
244
245 tc->suspend();
246 if (tc->getKernelStats())
247 tc->getKernelStats()->quiesce();
248}
249
250void
251quiesceSkip(ThreadContext *tc)
252{
253 DPRINTF(PseudoInst, "PseudoInst::quiesceSkip()\n");
254 if (!FullSystem)
255 panicFsOnlyPseudoInst("quiesceSkip");
256
257 BaseCPU *cpu = tc->getCpuPtr();
258
259 if (!cpu->params()->do_quiesce)
260 return;
261
262 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
263
264 Tick resume = curTick() + 1;
265
266 cpu->reschedule(quiesceEvent, resume, true);
267
268 DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n",
269 cpu->name(), resume);
270
271 tc->suspend();
272 if (tc->getKernelStats())
273 tc->getKernelStats()->quiesce();
274}
275
276void
277quiesceNs(ThreadContext *tc, uint64_t ns)
278{
279 DPRINTF(PseudoInst, "PseudoInst::quiesceNs(%i)\n", ns);
280 if (!FullSystem)
281 panicFsOnlyPseudoInst("quiesceNs");
282
283 BaseCPU *cpu = tc->getCpuPtr();
284
285 if (!cpu->params()->do_quiesce)
286 return;
287
288 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
289
290 Tick resume = curTick() + SimClock::Int::ns * ns;
291
292 cpu->reschedule(quiesceEvent, resume, true);
293
294 DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n",
295 cpu->name(), ns, resume);
296
297 tc->suspend();
298 if (tc->getKernelStats())
299 tc->getKernelStats()->quiesce();
300}
301
302void
303quiesceCycles(ThreadContext *tc, uint64_t cycles)
304{
305 DPRINTF(PseudoInst, "PseudoInst::quiesceCycles(%i)\n", cycles);
306 if (!FullSystem)
307 panicFsOnlyPseudoInst("quiesceCycles");
308
309 BaseCPU *cpu = tc->getCpuPtr();
310
311 if (!cpu->params()->do_quiesce)
312 return;
313
314 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
315
316 Tick resume = cpu->clockEdge(Cycles(cycles));
317
318 cpu->reschedule(quiesceEvent, resume, true);
319
320 DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n",
321 cpu->name(), cycles, resume);
322
323 tc->suspend();
324 if (tc->getKernelStats())
325 tc->getKernelStats()->quiesce();
326}
327
328uint64_t
329quiesceTime(ThreadContext *tc)
330{
331 DPRINTF(PseudoInst, "PseudoInst::quiesceTime()\n");
332 if (!FullSystem) {
333 panicFsOnlyPseudoInst("quiesceTime");
334 return 0;
335 }
336
337 return (tc->readLastActivate() - tc->readLastSuspend()) /
338 SimClock::Int::ns;
339}
340
341uint64_t
342rpns(ThreadContext *tc)
343{
344 DPRINTF(PseudoInst, "PseudoInst::rpns()\n");
345 return curTick() / SimClock::Int::ns;
346}
347
348void
349wakeCPU(ThreadContext *tc, uint64_t cpuid)
350{
351 DPRINTF(PseudoInst, "PseudoInst::wakeCPU(%i)\n", cpuid);
352 System *sys = tc->getSystemPtr();
353 ThreadContext *other_tc = sys->threadContexts[cpuid];
354 if (other_tc->status() == ThreadContext::Suspended)
355 other_tc->activate();
356}
357
358void
359m5exit(ThreadContext *tc, Tick delay)
360{
361 DPRINTF(PseudoInst, "PseudoInst::m5exit(%i)\n", delay);
362 if (DistIface::readyToExit(delay)) {
363 Tick when = curTick() + delay * SimClock::Int::ns;
364 exitSimLoop("m5_exit instruction encountered", 0, when, 0, true);
365 }
366}
367
368void
369m5fail(ThreadContext *tc, Tick delay, uint64_t code)
370{
371 DPRINTF(PseudoInst, "PseudoInst::m5fail(%i, %i)\n", delay, code);
372 Tick when = curTick() + delay * SimClock::Int::ns;
373 exitSimLoop("m5_fail instruction encountered", code, when, 0, true);
374}
375
376void
377loadsymbol(ThreadContext *tc)
378{
379 DPRINTF(PseudoInst, "PseudoInst::loadsymbol()\n");
380 if (!FullSystem)
381 panicFsOnlyPseudoInst("loadsymbol");
382
383 const string &filename = tc->getCpuPtr()->system->params()->symbolfile;
384 if (filename.empty()) {
385 return;
386 }
387
388 std::string buffer;
389 ifstream file(filename.c_str());
390
391 if (!file)
392 fatal("file error: Can't open symbol table file %s\n", filename);
393
394 while (!file.eof()) {
395 getline(file, buffer);
396
397 if (buffer.empty())
398 continue;
399
400 string::size_type idx = buffer.find(' ');
401 if (idx == string::npos)
402 continue;
403
404 string address = "0x" + buffer.substr(0, idx);
405 eat_white(address);
406 if (address.empty())
407 continue;
408
409 // Skip over letter and space
410 string symbol = buffer.substr(idx + 3);
411 eat_white(symbol);
412 if (symbol.empty())
413 continue;
414
415 Addr addr;
416 if (!to_number(address, addr))
417 continue;
418
419 if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
420 continue;
421
422
423 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
424 }
425 file.close();
426}
427
428void
429addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
430{
431 DPRINTF(PseudoInst, "PseudoInst::addsymbol(0x%x, 0x%x)\n",
432 addr, symbolAddr);
433 if (!FullSystem)
434 panicFsOnlyPseudoInst("addSymbol");
435
436 char symb[100];
437 CopyStringOut(tc, symb, symbolAddr, 100);
438 std::string symbol(symb);
439
440 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
441
442 tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
443 debugSymbolTable->insert(addr,symbol);
444}
445
446uint64_t
447initParam(ThreadContext *tc, uint64_t key_str1, uint64_t key_str2)
448{
449 DPRINTF(PseudoInst, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1,
450 (char *)&key_str2);
451 if (!FullSystem) {
452 panicFsOnlyPseudoInst("initParam");
453 return 0;
454 }
455
456 // The key parameter string is passed in via two 64-bit registers. We copy
457 // out the characters from the 64-bit integer variables here and concatenate
458 // them in the key_str character buffer
459 const int len = 2 * sizeof(uint64_t) + 1;
460 char key_str[len];
461 memset(key_str, '\0', len);
462 if (key_str1 == 0) {
463 assert(key_str2 == 0);
464 } else {
465 strncpy(key_str, (char *)&key_str1, sizeof(uint64_t));
466 }
467
468 if (strlen(key_str) == sizeof(uint64_t)) {
469 strncpy(key_str + sizeof(uint64_t), (char *)&key_str2,
470 sizeof(uint64_t));
471 } else {
472 assert(key_str2 == 0);
473 }
474
475 // Compare the key parameter with the known values to select the return
476 // value
477 uint64_t val;
478 if (strcmp(key_str, InitParamKey::DEFAULT) == 0) {
479 val = tc->getCpuPtr()->system->init_param;
480 } else if (strcmp(key_str, InitParamKey::DIST_RANK) == 0) {
481 val = DistIface::rankParam();
482 } else if (strcmp(key_str, InitParamKey::DIST_SIZE) == 0) {
483 val = DistIface::sizeParam();
484 } else {
485 panic("Unknown key for initparam pseudo instruction:\"%s\"", key_str);
486 }
487 return val;
488}
489
490
491void
492resetstats(ThreadContext *tc, Tick delay, Tick period)
493{
494 DPRINTF(PseudoInst, "PseudoInst::resetstats(%i, %i)\n", delay, period);
495 if (!tc->getCpuPtr()->params()->do_statistics_insts)
496 return;
497
498
499 Tick when = curTick() + delay * SimClock::Int::ns;
500 Tick repeat = period * SimClock::Int::ns;
501
502 Stats::schedStatEvent(false, true, when, repeat);
503}
504
505void
506dumpstats(ThreadContext *tc, Tick delay, Tick period)
507{
508 DPRINTF(PseudoInst, "PseudoInst::dumpstats(%i, %i)\n", delay, period);
509 if (!tc->getCpuPtr()->params()->do_statistics_insts)
510 return;
511
512
513 Tick when = curTick() + delay * SimClock::Int::ns;
514 Tick repeat = period * SimClock::Int::ns;
515
516 Stats::schedStatEvent(true, false, when, repeat);
517}
518
519void
520dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
521{
522 DPRINTF(PseudoInst, "PseudoInst::dumpresetstats(%i, %i)\n", delay, period);
523 if (!tc->getCpuPtr()->params()->do_statistics_insts)
524 return;
525
526
527 Tick when = curTick() + delay * SimClock::Int::ns;
528 Tick repeat = period * SimClock::Int::ns;
529
530 Stats::schedStatEvent(true, true, when, repeat);
531}
532
533void
534m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
535{
536 DPRINTF(PseudoInst, "PseudoInst::m5checkpoint(%i, %i)\n", delay, period);
537 if (!tc->getCpuPtr()->params()->do_checkpoint_insts)
538 return;
539
540 if (DistIface::readyToCkpt(delay, period)) {
541 Tick when = curTick() + delay * SimClock::Int::ns;
542 Tick repeat = period * SimClock::Int::ns;
543 exitSimLoop("checkpoint", 0, when, repeat);
544 }
545}
546
547uint64_t
548readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
549{
550 DPRINTF(PseudoInst, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n",
551 vaddr, len, offset);
552 if (!FullSystem) {
553 panicFsOnlyPseudoInst("readfile");
554 return 0;
555 }
556
557 const string &file = tc->getSystemPtr()->params()->readfile;
558 if (file.empty()) {
559 return ULL(0);
560 }
561
562 uint64_t result = 0;
563
564 int fd = ::open(file.c_str(), O_RDONLY, 0);
565 if (fd < 0)
566 panic("could not open file %s\n", file);
567
568 if (::lseek(fd, offset, SEEK_SET) < 0)
569 panic("could not seek: %s", strerror(errno));
570
571 char *buf = new char[len];
572 char *p = buf;
573 while (len > 0) {
574 int bytes = ::read(fd, p, len);
575 if (bytes <= 0)
576 break;
577
578 p += bytes;
579 result += bytes;
580 len -= bytes;
581 }
582
583 close(fd);
584 CopyIn(tc, vaddr, buf, result);
585 delete [] buf;
586 return result;
587}
588
589uint64_t
590writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset,
591 Addr filename_addr)
592{
593 DPRINTF(PseudoInst, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n",
594 vaddr, len, offset, filename_addr);
595 ostream *os;
596
597 // copy out target filename
598 char fn[100];
599 std::string filename;
600 CopyStringOut(tc, fn, filename_addr, 100);
601 filename = std::string(fn);
602
595
596 // copy out target filename
597 char fn[100];
598 std::string filename;
599 CopyStringOut(tc, fn, filename_addr, 100);
600 filename = std::string(fn);
601
602 OutputStream *out;
603 if (offset == 0) {
604 // create a new file (truncate)
603 if (offset == 0) {
604 // create a new file (truncate)
605 os = simout.create(filename, true, true);
605 out = simout.create(filename, true, true);
606 } else {
607 // do not truncate file if offset is non-zero
608 // (ios::in flag is required as well to keep the existing data
609 // intact, otherwise existing data will be zeroed out.)
606 } else {
607 // do not truncate file if offset is non-zero
608 // (ios::in flag is required as well to keep the existing data
609 // intact, otherwise existing data will be zeroed out.)
610 os = simout.openFile(simout.directory() + filename,
611 ios::in | ios::out | ios::binary, true);
610 out = simout.open(filename, ios::in | ios::out | ios::binary, true);
612 }
611 }
612
613 ostream *os(out->stream());
613 if (!os)
614 panic("could not open file %s\n", filename);
615
616 // seek to offset
617 os->seekp(offset);
618
619 // copy out data and write to file
620 char *buf = new char[len];
621 CopyOut(tc, buf, vaddr, len);
622 os->write(buf, len);
623 if (os->fail() || os->bad())
624 panic("Error while doing writefile!\n");
625
614 if (!os)
615 panic("could not open file %s\n", filename);
616
617 // seek to offset
618 os->seekp(offset);
619
620 // copy out data and write to file
621 char *buf = new char[len];
622 CopyOut(tc, buf, vaddr, len);
623 os->write(buf, len);
624 if (os->fail() || os->bad())
625 panic("Error while doing writefile!\n");
626
626 simout.close(os);
627 simout.close(out);
627
628 delete [] buf;
629
630 return len;
631}
632
633void
634debugbreak(ThreadContext *tc)
635{
636 DPRINTF(PseudoInst, "PseudoInst::debugbreak()\n");
637 Debug::breakpoint();
638}
639
640void
641switchcpu(ThreadContext *tc)
642{
643 DPRINTF(PseudoInst, "PseudoInst::switchcpu()\n");
644 exitSimLoop("switchcpu");
645}
646
647//
648// This function is executed when annotated work items begin. Depending on
649// what the user specified at the command line, the simulation may exit and/or
650// take a checkpoint when a certain work item begins.
651//
652void
653workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid)
654{
655 DPRINTF(PseudoInst, "PseudoInst::workbegin(%i, %i)\n", workid, threadid);
656 System *sys = tc->getSystemPtr();
657 const System::Params *params = sys->params();
658
659 if (params->exit_on_work_items) {
660 exitSimLoop("workbegin", static_cast<int>(workid));
661 return;
662 }
663
664 DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid,
665 threadid);
666 tc->getCpuPtr()->workItemBegin();
667 sys->workItemBegin(threadid, workid);
668
669 //
670 // If specified, determine if this is the specific work item the user
671 // identified
672 //
673 if (params->work_item_id == -1 || params->work_item_id == workid) {
674
675 uint64_t systemWorkBeginCount = sys->incWorkItemsBegin();
676 int cpuId = tc->getCpuPtr()->cpuId();
677
678 if (params->work_cpus_ckpt_count != 0 &&
679 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) {
680 //
681 // If active cpus equals checkpoint count, create checkpoint
682 //
683 exitSimLoop("checkpoint");
684 }
685
686 if (systemWorkBeginCount == params->work_begin_ckpt_count) {
687 //
688 // Note: the string specified as the cause of the exit event must
689 // exactly equal "checkpoint" inorder to create a checkpoint
690 //
691 exitSimLoop("checkpoint");
692 }
693
694 if (systemWorkBeginCount == params->work_begin_exit_count) {
695 //
696 // If a certain number of work items started, exit simulation
697 //
698 exitSimLoop("work started count reach");
699 }
700
701 if (cpuId == params->work_begin_cpu_id_exit) {
702 //
703 // If work started on the cpu id specified, exit simulation
704 //
705 exitSimLoop("work started on specific cpu");
706 }
707 }
708}
709
710//
711// This function is executed when annotated work items end. Depending on
712// what the user specified at the command line, the simulation may exit and/or
713// take a checkpoint when a certain work item ends.
714//
715void
716workend(ThreadContext *tc, uint64_t workid, uint64_t threadid)
717{
718 DPRINTF(PseudoInst, "PseudoInst::workend(%i, %i)\n", workid, threadid);
719 System *sys = tc->getSystemPtr();
720 const System::Params *params = sys->params();
721
722 if (params->exit_on_work_items) {
723 exitSimLoop("workend", static_cast<int>(workid));
724 return;
725 }
726
727 DPRINTF(WorkItems, "Work End workid: %d, threadid %d\n", workid, threadid);
728 tc->getCpuPtr()->workItemEnd();
729 sys->workItemEnd(threadid, workid);
730
731 //
732 // If specified, determine if this is the specific work item the user
733 // identified
734 //
735 if (params->work_item_id == -1 || params->work_item_id == workid) {
736
737 uint64_t systemWorkEndCount = sys->incWorkItemsEnd();
738 int cpuId = tc->getCpuPtr()->cpuId();
739
740 if (params->work_cpus_ckpt_count != 0 &&
741 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) {
742 //
743 // If active cpus equals checkpoint count, create checkpoint
744 //
745 exitSimLoop("checkpoint");
746 }
747
748 if (params->work_end_ckpt_count != 0 &&
749 systemWorkEndCount == params->work_end_ckpt_count) {
750 //
751 // If total work items completed equals checkpoint count, create
752 // checkpoint
753 //
754 exitSimLoop("checkpoint");
755 }
756
757 if (params->work_end_exit_count != 0 &&
758 systemWorkEndCount == params->work_end_exit_count) {
759 //
760 // If total work items completed equals exit count, exit simulation
761 //
762 exitSimLoop("work items exit count reached");
763 }
764 }
765}
766
767} // namespace PseudoInst
628
629 delete [] buf;
630
631 return len;
632}
633
634void
635debugbreak(ThreadContext *tc)
636{
637 DPRINTF(PseudoInst, "PseudoInst::debugbreak()\n");
638 Debug::breakpoint();
639}
640
641void
642switchcpu(ThreadContext *tc)
643{
644 DPRINTF(PseudoInst, "PseudoInst::switchcpu()\n");
645 exitSimLoop("switchcpu");
646}
647
648//
649// This function is executed when annotated work items begin. Depending on
650// what the user specified at the command line, the simulation may exit and/or
651// take a checkpoint when a certain work item begins.
652//
653void
654workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid)
655{
656 DPRINTF(PseudoInst, "PseudoInst::workbegin(%i, %i)\n", workid, threadid);
657 System *sys = tc->getSystemPtr();
658 const System::Params *params = sys->params();
659
660 if (params->exit_on_work_items) {
661 exitSimLoop("workbegin", static_cast<int>(workid));
662 return;
663 }
664
665 DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid,
666 threadid);
667 tc->getCpuPtr()->workItemBegin();
668 sys->workItemBegin(threadid, workid);
669
670 //
671 // If specified, determine if this is the specific work item the user
672 // identified
673 //
674 if (params->work_item_id == -1 || params->work_item_id == workid) {
675
676 uint64_t systemWorkBeginCount = sys->incWorkItemsBegin();
677 int cpuId = tc->getCpuPtr()->cpuId();
678
679 if (params->work_cpus_ckpt_count != 0 &&
680 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) {
681 //
682 // If active cpus equals checkpoint count, create checkpoint
683 //
684 exitSimLoop("checkpoint");
685 }
686
687 if (systemWorkBeginCount == params->work_begin_ckpt_count) {
688 //
689 // Note: the string specified as the cause of the exit event must
690 // exactly equal "checkpoint" inorder to create a checkpoint
691 //
692 exitSimLoop("checkpoint");
693 }
694
695 if (systemWorkBeginCount == params->work_begin_exit_count) {
696 //
697 // If a certain number of work items started, exit simulation
698 //
699 exitSimLoop("work started count reach");
700 }
701
702 if (cpuId == params->work_begin_cpu_id_exit) {
703 //
704 // If work started on the cpu id specified, exit simulation
705 //
706 exitSimLoop("work started on specific cpu");
707 }
708 }
709}
710
711//
712// This function is executed when annotated work items end. Depending on
713// what the user specified at the command line, the simulation may exit and/or
714// take a checkpoint when a certain work item ends.
715//
716void
717workend(ThreadContext *tc, uint64_t workid, uint64_t threadid)
718{
719 DPRINTF(PseudoInst, "PseudoInst::workend(%i, %i)\n", workid, threadid);
720 System *sys = tc->getSystemPtr();
721 const System::Params *params = sys->params();
722
723 if (params->exit_on_work_items) {
724 exitSimLoop("workend", static_cast<int>(workid));
725 return;
726 }
727
728 DPRINTF(WorkItems, "Work End workid: %d, threadid %d\n", workid, threadid);
729 tc->getCpuPtr()->workItemEnd();
730 sys->workItemEnd(threadid, workid);
731
732 //
733 // If specified, determine if this is the specific work item the user
734 // identified
735 //
736 if (params->work_item_id == -1 || params->work_item_id == workid) {
737
738 uint64_t systemWorkEndCount = sys->incWorkItemsEnd();
739 int cpuId = tc->getCpuPtr()->cpuId();
740
741 if (params->work_cpus_ckpt_count != 0 &&
742 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) {
743 //
744 // If active cpus equals checkpoint count, create checkpoint
745 //
746 exitSimLoop("checkpoint");
747 }
748
749 if (params->work_end_ckpt_count != 0 &&
750 systemWorkEndCount == params->work_end_ckpt_count) {
751 //
752 // If total work items completed equals checkpoint count, create
753 // checkpoint
754 //
755 exitSimLoop("checkpoint");
756 }
757
758 if (params->work_end_exit_count != 0 &&
759 systemWorkEndCount == params->work_end_exit_count) {
760 //
761 // If total work items completed equals exit count, exit simulation
762 //
763 exitSimLoop("work items exit count reached");
764 }
765 }
766}
767
768} // namespace PseudoInst