2 * Copyright (c) 2010-2012, 2015, 2017 ARM Limited
3 * Copyright (c) 2020 Barkhausen Institut
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
15 * Copyright (c) 2011 Advanced Micro Devices, Inc.
16 * Copyright (c) 2003-2006 The Regents of The University of Michigan
17 * All rights reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met: redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer;
23 * redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution;
26 * neither the name of the copyright holders nor the names of its
27 * contributors may be used to endorse or promote products derived from
28 * this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #include "sim/pseudo_inst.hh"
54 #include "base/debug.hh"
55 #include "base/output.hh"
56 #include "config/the_isa.hh"
57 #include "cpu/base.hh"
58 #include "cpu/thread_context.hh"
59 #include "debug/Loader.hh"
60 #include "debug/Quiesce.hh"
61 #include "debug/WorkItems.hh"
62 #include "dev/net/dist_iface.hh"
63 #include "params/BaseCPU.hh"
64 #include "sim/full_system.hh"
65 #include "sim/process.hh"
66 #include "sim/serialize.hh"
67 #include "sim/sim_events.hh"
68 #include "sim/sim_exit.hh"
69 #include "sim/stat_control.hh"
70 #include "sim/stats.hh"
71 #include "sim/system.hh"
74 using namespace Stats
;
80 * Unique keys to retrieve various params by the initParam pseudo inst.
82 * @note Each key may be at most 16 characters (because we use
83 * two 64-bit registers to pass in the key to the initparam function).
85 namespace InitParamKey
89 * The default key (empty string)
91 const std::string DEFAULT
= "";
93 * Unique key for "rank" param (distributed gem5 runs)
95 const std::string DIST_RANK
= "dist-rank";
97 * Unique key for "size" param (distributed gem5 runs)
99 const std::string DIST_SIZE
= "dist-size";
101 } // namespace InitParamKey
104 panicFsOnlyPseudoInst(const char *name
)
106 panic("Pseudo inst \"%s\" is only available in Full System mode.", name
);
110 arm(ThreadContext
*tc
)
112 DPRINTF(PseudoInst
, "PseudoInst::arm()\n");
114 panicFsOnlyPseudoInst("arm");
116 auto *workload
= tc
->getSystemPtr()->workload
;
118 workload
->recordArm();
122 quiesce(ThreadContext
*tc
)
124 DPRINTF(PseudoInst
, "PseudoInst::quiesce()\n");
129 quiesceSkip(ThreadContext
*tc
)
131 DPRINTF(PseudoInst
, "PseudoInst::quiesceSkip()\n");
132 tc
->quiesceTick(tc
->getCpuPtr()->nextCycle() + 1);
136 quiesceNs(ThreadContext
*tc
, uint64_t ns
)
138 DPRINTF(PseudoInst
, "PseudoInst::quiesceNs(%i)\n", ns
);
139 tc
->quiesceTick(curTick() + SimClock::Int::ns
* ns
);
143 quiesceCycles(ThreadContext
*tc
, uint64_t cycles
)
145 DPRINTF(PseudoInst
, "PseudoInst::quiesceCycles(%i)\n", cycles
);
146 tc
->quiesceTick(tc
->getCpuPtr()->clockEdge(Cycles(cycles
)));
150 quiesceTime(ThreadContext
*tc
)
152 DPRINTF(PseudoInst
, "PseudoInst::quiesceTime()\n");
154 return (tc
->readLastActivate() - tc
->readLastSuspend()) /
159 rpns(ThreadContext
*tc
)
161 DPRINTF(PseudoInst
, "PseudoInst::rpns()\n");
162 return curTick() / SimClock::Int::ns
;
166 wakeCPU(ThreadContext
*tc
, uint64_t cpuid
)
168 DPRINTF(PseudoInst
, "PseudoInst::wakeCPU(%i)\n", cpuid
);
169 System
*sys
= tc
->getSystemPtr();
171 if (sys
->threads
.size() <= cpuid
) {
172 warn("PseudoInst::wakeCPU(%i), cpuid greater than number of contexts"
173 "(%i)\n", cpuid
, sys
->threads
.size());
177 ThreadContext
*other_tc
= sys
->threads
[cpuid
];
178 if (other_tc
->status() == ThreadContext::Suspended
)
179 other_tc
->activate();
183 m5exit(ThreadContext
*tc
, Tick delay
)
185 DPRINTF(PseudoInst
, "PseudoInst::m5exit(%i)\n", delay
);
186 if (DistIface::readyToExit(delay
)) {
187 Tick when
= curTick() + delay
* SimClock::Int::ns
;
188 exitSimLoop("m5_exit instruction encountered", 0, when
, 0, true);
192 // m5sum is for sanity checking the gem5 op interface.
194 m5sum(ThreadContext
*tc
, uint64_t a
, uint64_t b
, uint64_t c
,
195 uint64_t d
, uint64_t e
, uint64_t f
)
197 DPRINTF(PseudoInst
, "PseudoInst::m5sum(%#x, %#x, %#x, %#x, %#x, %#x)\n",
199 return a
+ b
+ c
+ d
+ e
+ f
;
203 m5fail(ThreadContext
*tc
, Tick delay
, uint64_t code
)
205 DPRINTF(PseudoInst
, "PseudoInst::m5fail(%i, %i)\n", delay
, code
);
206 Tick when
= curTick() + delay
* SimClock::Int::ns
;
207 exitSimLoop("m5_fail instruction encountered", code
, when
, 0, true);
211 loadsymbol(ThreadContext
*tc
)
213 DPRINTF(PseudoInst
, "PseudoInst::loadsymbol()\n");
215 panicFsOnlyPseudoInst("loadsymbol");
217 const string
&filename
= tc
->getCpuPtr()->system
->params().symbolfile
;
218 if (filename
.empty()) {
223 ifstream
file(filename
.c_str());
226 fatal("file error: Can't open symbol table file %s\n", filename
);
228 while (!file
.eof()) {
229 getline(file
, buffer
);
234 string::size_type idx
= buffer
.find(' ');
235 if (idx
== string::npos
)
238 string address
= "0x" + buffer
.substr(0, idx
);
243 // Skip over letter and space
244 string symbol
= buffer
.substr(idx
+ 3);
250 if (!to_number(address
, addr
))
253 if (!tc
->getSystemPtr()->workload
->insertSymbol(
254 { Loader::Symbol::Binding::Global
, symbol
, addr
})) {
259 DPRINTF(Loader
, "Loaded symbol: %s @ %#llx\n", symbol
, addr
);
265 addsymbol(ThreadContext
*tc
, Addr addr
, Addr symbolAddr
)
267 DPRINTF(PseudoInst
, "PseudoInst::addsymbol(0x%x, 0x%x)\n",
270 panicFsOnlyPseudoInst("addSymbol");
273 tc
->getVirtProxy().readString(symbol
, symbolAddr
);
275 DPRINTF(Loader
, "Loaded symbol: %s @ %#llx\n", symbol
, addr
);
277 tc
->getSystemPtr()->workload
->insertSymbol(
278 { Loader::Symbol::Binding::Global
, symbol
, addr
});
279 Loader::debugSymbolTable
.insert(
280 { Loader::Symbol::Binding::Global
, symbol
, addr
});
284 initParam(ThreadContext
*tc
, uint64_t key_str1
, uint64_t key_str2
)
286 DPRINTF(PseudoInst
, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1
,
289 panicFsOnlyPseudoInst("initParam");
293 // The key parameter string is passed in via two 64-bit registers. We copy
294 // out the characters from the 64-bit integer variables here, and
295 // concatenate them in the key character buffer
296 const int len
= 2 * sizeof(uint64_t) + 1;
298 memset(key
, '\0', len
);
300 std::array
<uint64_t, 2> key_regs
= {{ key_str1
, key_str2
}};
301 key_regs
= letoh(key_regs
);
302 memcpy(key
, key_regs
.data(), sizeof(key_regs
));
304 // Check key parameter to figure out what to return.
305 const std::string
key_str(key
);
306 if (key
== InitParamKey::DEFAULT
)
307 return tc
->getCpuPtr()->system
->init_param
;
308 else if (key
== InitParamKey::DIST_RANK
)
309 return DistIface::rankParam();
310 else if (key
== InitParamKey::DIST_SIZE
)
311 return DistIface::sizeParam();
313 panic("Unknown key for initparam pseudo instruction:\"%s\"", key_str
);
318 resetstats(ThreadContext
*tc
, Tick delay
, Tick period
)
320 DPRINTF(PseudoInst
, "PseudoInst::resetstats(%i, %i)\n", delay
, period
);
321 if (!tc
->getCpuPtr()->params().do_statistics_insts
)
325 Tick when
= curTick() + delay
* SimClock::Int::ns
;
326 Tick repeat
= period
* SimClock::Int::ns
;
328 Stats::schedStatEvent(false, true, when
, repeat
);
332 dumpstats(ThreadContext
*tc
, Tick delay
, Tick period
)
334 DPRINTF(PseudoInst
, "PseudoInst::dumpstats(%i, %i)\n", delay
, period
);
335 if (!tc
->getCpuPtr()->params().do_statistics_insts
)
339 Tick when
= curTick() + delay
* SimClock::Int::ns
;
340 Tick repeat
= period
* SimClock::Int::ns
;
342 Stats::schedStatEvent(true, false, when
, repeat
);
346 dumpresetstats(ThreadContext
*tc
, Tick delay
, Tick period
)
348 DPRINTF(PseudoInst
, "PseudoInst::dumpresetstats(%i, %i)\n", delay
, period
);
349 if (!tc
->getCpuPtr()->params().do_statistics_insts
)
353 Tick when
= curTick() + delay
* SimClock::Int::ns
;
354 Tick repeat
= period
* SimClock::Int::ns
;
356 Stats::schedStatEvent(true, true, when
, repeat
);
360 m5checkpoint(ThreadContext
*tc
, Tick delay
, Tick period
)
362 DPRINTF(PseudoInst
, "PseudoInst::m5checkpoint(%i, %i)\n", delay
, period
);
363 if (!tc
->getCpuPtr()->params().do_checkpoint_insts
)
366 if (DistIface::readyToCkpt(delay
, period
)) {
367 Tick when
= curTick() + delay
* SimClock::Int::ns
;
368 Tick repeat
= period
* SimClock::Int::ns
;
369 exitSimLoop("checkpoint", 0, when
, repeat
);
374 readfile(ThreadContext
*tc
, Addr vaddr
, uint64_t len
, uint64_t offset
)
376 DPRINTF(PseudoInst
, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n",
379 panicFsOnlyPseudoInst("readfile");
383 const string
&file
= tc
->getSystemPtr()->params().readfile
;
390 int fd
= ::open(file
.c_str(), O_RDONLY
, 0);
392 panic("could not open file %s\n", file
);
394 if (::lseek(fd
, offset
, SEEK_SET
) < 0)
395 panic("could not seek: %s", strerror(errno
));
397 char *buf
= new char[len
];
400 int bytes
= ::read(fd
, p
, len
);
410 tc
->getVirtProxy().writeBlob(vaddr
, buf
, result
);
416 writefile(ThreadContext
*tc
, Addr vaddr
, uint64_t len
, uint64_t offset
,
419 DPRINTF(PseudoInst
, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n",
420 vaddr
, len
, offset
, filename_addr
);
422 // copy out target filename
423 std::string filename
;
424 tc
->getVirtProxy().readString(filename
, filename_addr
);
428 // create a new file (truncate)
429 out
= simout
.create(filename
, true, true);
431 // do not truncate file if offset is non-zero
432 // (ios::in flag is required as well to keep the existing data
433 // intact, otherwise existing data will be zeroed out.)
434 out
= simout
.open(filename
, ios::in
| ios::out
| ios::binary
, true);
437 ostream
*os(out
->stream());
439 panic("could not open file %s\n", filename
);
446 // copy out data and write to file
447 char *buf
= new char[len
];
448 tc
->getVirtProxy().readBlob(vaddr
, buf
, len
);
450 if (os
->fail() || os
->bad())
451 panic("Error while doing writefile!\n");
461 debugbreak(ThreadContext
*tc
)
463 DPRINTF(PseudoInst
, "PseudoInst::debugbreak()\n");
468 switchcpu(ThreadContext
*tc
)
470 DPRINTF(PseudoInst
, "PseudoInst::switchcpu()\n");
471 exitSimLoop("switchcpu");
475 togglesync(ThreadContext
*tc
)
477 DPRINTF(PseudoInst
, "PseudoInst::togglesync()\n");
478 DistIface::toggleSync(tc
);
482 triggerWorkloadEvent(ThreadContext
*tc
)
484 DPRINTF(PseudoInst
, "PseudoInst::triggerWorkloadEvent()\n");
485 tc
->getSystemPtr()->workload
->event(tc
);
489 // This function is executed when annotated work items begin. Depending on
490 // what the user specified at the command line, the simulation may exit and/or
491 // take a checkpoint when a certain work item begins.
494 workbegin(ThreadContext
*tc
, uint64_t workid
, uint64_t threadid
)
496 DPRINTF(PseudoInst
, "PseudoInst::workbegin(%i, %i)\n", workid
, threadid
);
497 System
*sys
= tc
->getSystemPtr();
498 const System::Params
¶ms
= sys
->params();
500 if (params
.exit_on_work_items
) {
501 exitSimLoop("workbegin", static_cast<int>(workid
));
505 DPRINTF(WorkItems
, "Work Begin workid: %d, threadid %d\n", workid
,
507 tc
->getCpuPtr()->workItemBegin();
508 sys
->workItemBegin(threadid
, workid
);
511 // If specified, determine if this is the specific work item the user
514 if (params
.work_item_id
== -1 || params
.work_item_id
== workid
) {
516 uint64_t systemWorkBeginCount
= sys
->incWorkItemsBegin();
517 int cpuId
= tc
->getCpuPtr()->cpuId();
519 if (params
.work_cpus_ckpt_count
!= 0 &&
520 sys
->markWorkItem(cpuId
) >= params
.work_cpus_ckpt_count
) {
522 // If active cpus equals checkpoint count, create checkpoint
524 exitSimLoop("checkpoint");
527 if (systemWorkBeginCount
== params
.work_begin_ckpt_count
) {
529 // Note: the string specified as the cause of the exit event must
530 // exactly equal "checkpoint" inorder to create a checkpoint
532 exitSimLoop("checkpoint");
535 if (systemWorkBeginCount
== params
.work_begin_exit_count
) {
537 // If a certain number of work items started, exit simulation
539 exitSimLoop("work started count reach");
542 if (cpuId
== params
.work_begin_cpu_id_exit
) {
544 // If work started on the cpu id specified, exit simulation
546 exitSimLoop("work started on specific cpu");
552 // This function is executed when annotated work items end. Depending on
553 // what the user specified at the command line, the simulation may exit and/or
554 // take a checkpoint when a certain work item ends.
557 workend(ThreadContext
*tc
, uint64_t workid
, uint64_t threadid
)
559 DPRINTF(PseudoInst
, "PseudoInst::workend(%i, %i)\n", workid
, threadid
);
560 System
*sys
= tc
->getSystemPtr();
561 const System::Params
¶ms
= sys
->params();
563 if (params
.exit_on_work_items
) {
564 exitSimLoop("workend", static_cast<int>(workid
));
568 DPRINTF(WorkItems
, "Work End workid: %d, threadid %d\n", workid
, threadid
);
569 tc
->getCpuPtr()->workItemEnd();
570 sys
->workItemEnd(threadid
, workid
);
573 // If specified, determine if this is the specific work item the user
576 if (params
.work_item_id
== -1 || params
.work_item_id
== workid
) {
578 uint64_t systemWorkEndCount
= sys
->incWorkItemsEnd();
579 int cpuId
= tc
->getCpuPtr()->cpuId();
581 if (params
.work_cpus_ckpt_count
!= 0 &&
582 sys
->markWorkItem(cpuId
) >= params
.work_cpus_ckpt_count
) {
584 // If active cpus equals checkpoint count, create checkpoint
586 exitSimLoop("checkpoint");
589 if (params
.work_end_ckpt_count
!= 0 &&
590 systemWorkEndCount
== params
.work_end_ckpt_count
) {
592 // If total work items completed equals checkpoint count, create
595 exitSimLoop("checkpoint");
598 if (params
.work_end_exit_count
!= 0 &&
599 systemWorkEndCount
== params
.work_end_exit_count
) {
601 // If total work items completed equals exit count, exit simulation
603 exitSimLoop("work items exit count reached");
608 } // namespace PseudoInst