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