8ffb13e3b33025653c3cf58f7a0b333c901a3271
2 * Copyright (c) 2010-2012, 2015, 2017 ARM Limited
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.
14 * Copyright (c) 2011 Advanced Micro Devices, Inc.
15 * Copyright (c) 2003-2006 The Regents of The University of Michigan
16 * All rights reserved.
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.
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.
41 * Authors: Nathan Binkert
44 #include "sim/pseudo_inst.hh"
54 #include <gem5/asm/generic/m5ops.h>
56 #include "arch/pseudo_inst.hh"
57 #include "arch/utility.hh"
58 #include "arch/vtophys.hh"
59 #include "base/debug.hh"
60 #include "base/output.hh"
61 #include "config/the_isa.hh"
62 #include "cpu/base.hh"
63 #include "cpu/quiesce_event.hh"
64 #include "cpu/thread_context.hh"
65 #include "debug/Loader.hh"
66 #include "debug/PseudoInst.hh"
67 #include "debug/Quiesce.hh"
68 #include "debug/WorkItems.hh"
69 #include "dev/net/dist_iface.hh"
70 #include "kern/kernel_stats.hh"
71 #include "params/BaseCPU.hh"
72 #include "sim/full_system.hh"
73 #include "sim/initparam_keys.hh"
74 #include "sim/process.hh"
75 #include "sim/serialize.hh"
76 #include "sim/sim_events.hh"
77 #include "sim/sim_exit.hh"
78 #include "sim/stat_control.hh"
79 #include "sim/stats.hh"
80 #include "sim/system.hh"
81 #include "sim/vptr.hh"
85 using namespace Stats
;
86 using namespace TheISA
;
88 namespace PseudoInst
{
91 panicFsOnlyPseudoInst(const char *name
)
93 panic("Pseudo inst \"%s\" is only available in Full System mode.");
97 pseudoInst(ThreadContext
*tc
, uint8_t func
, uint8_t subfunc
)
101 DPRINTF(PseudoInst
, "PseudoInst::pseudoInst(%i, %i)\n", func
, subfunc
);
103 // We need to do this in a slightly convoluted way since
104 // getArgument() might have side-effects on arg_num. We could have
105 // used the Argument class, but due to the possible side effects
106 // from getArgument, it'd most likely break.
108 for (int i
= 0; i
< sizeof(args
) / sizeof(*args
); ++i
) {
109 args
[arg_num
] = getArgument(tc
, arg_num
, sizeof(uint64_t), false);
122 case M5OP_QUIESCE_NS
:
123 quiesceNs(tc
, args
[0]);
126 case M5OP_QUIESCE_CYCLE
:
127 quiesceCycles(tc
, args
[0]);
130 case M5OP_QUIESCE_TIME
:
131 return quiesceTime(tc
);
137 wakeCPU(tc
, args
[0]);
145 m5fail(tc
, args
[0], args
[1]);
148 case M5OP_INIT_PARAM
:
149 return initParam(tc
, args
[0], args
[1]);
151 case M5OP_LOAD_SYMBOL
:
155 case M5OP_RESET_STATS
:
156 resetstats(tc
, args
[0], args
[1]);
159 case M5OP_DUMP_STATS
:
160 dumpstats(tc
, args
[0], args
[1]);
163 case M5OP_DUMP_RESET_STATS
:
164 dumpresetstats(tc
, args
[0], args
[1]);
167 case M5OP_CHECKPOINT
:
168 m5checkpoint(tc
, args
[0], args
[1]);
171 case M5OP_WRITE_FILE
:
172 return writefile(tc
, args
[0], args
[1], args
[2], args
[3]);
175 return readfile(tc
, args
[0], args
[1], args
[2]);
177 case M5OP_DEBUG_BREAK
:
181 case M5OP_SWITCH_CPU
:
185 case M5OP_ADD_SYMBOL
:
186 addsymbol(tc
, args
[0], args
[1]);
190 panic("M5 panic instruction called at %s\n", tc
->pcState());
192 case M5OP_WORK_BEGIN
:
193 workbegin(tc
, args
[0], args
[1]);
197 workend(tc
, args
[0], args
[1]);
205 warn("Unimplemented m5 op (0x%x)\n", func
);
208 /* SE mode functions */
209 case M5OP_SE_SYSCALL
:
213 case M5OP_SE_PAGE_FAULT
:
217 /* dist-gem5 functions */
218 case M5OP_DIST_TOGGLE_SYNC
:
223 warn("Unhandled m5 op: 0x%x\n", func
);
231 arm(ThreadContext
*tc
)
233 DPRINTF(PseudoInst
, "PseudoInst::arm()\n");
235 panicFsOnlyPseudoInst("arm");
237 if (tc
->getKernelStats())
238 tc
->getKernelStats()->arm();
242 quiesce(ThreadContext
*tc
)
244 DPRINTF(PseudoInst
, "PseudoInst::quiesce()\n");
249 quiesceSkip(ThreadContext
*tc
)
251 DPRINTF(PseudoInst
, "PseudoInst::quiesceSkip()\n");
252 tc
->quiesceTick(tc
->getCpuPtr()->nextCycle() + 1);
256 quiesceNs(ThreadContext
*tc
, uint64_t ns
)
258 DPRINTF(PseudoInst
, "PseudoInst::quiesceNs(%i)\n", ns
);
259 tc
->quiesceTick(curTick() + SimClock::Int::ns
* ns
);
263 quiesceCycles(ThreadContext
*tc
, uint64_t cycles
)
265 DPRINTF(PseudoInst
, "PseudoInst::quiesceCycles(%i)\n", cycles
);
266 tc
->quiesceTick(tc
->getCpuPtr()->clockEdge(Cycles(cycles
)));
270 quiesceTime(ThreadContext
*tc
)
272 DPRINTF(PseudoInst
, "PseudoInst::quiesceTime()\n");
274 return (tc
->readLastActivate() - tc
->readLastSuspend()) /
279 rpns(ThreadContext
*tc
)
281 DPRINTF(PseudoInst
, "PseudoInst::rpns()\n");
282 return curTick() / SimClock::Int::ns
;
286 wakeCPU(ThreadContext
*tc
, uint64_t cpuid
)
288 DPRINTF(PseudoInst
, "PseudoInst::wakeCPU(%i)\n", cpuid
);
289 System
*sys
= tc
->getSystemPtr();
291 if (sys
->numContexts() <= cpuid
) {
292 warn("PseudoInst::wakeCPU(%i), cpuid greater than number of contexts"
293 "(%i)\n",cpuid
, sys
->numContexts());
297 ThreadContext
*other_tc
= sys
->threadContexts
[cpuid
];
298 if (other_tc
->status() == ThreadContext::Suspended
)
299 other_tc
->activate();
303 m5exit(ThreadContext
*tc
, Tick delay
)
305 DPRINTF(PseudoInst
, "PseudoInst::m5exit(%i)\n", delay
);
306 if (DistIface::readyToExit(delay
)) {
307 Tick when
= curTick() + delay
* SimClock::Int::ns
;
308 exitSimLoop("m5_exit instruction encountered", 0, when
, 0, true);
313 m5fail(ThreadContext
*tc
, Tick delay
, uint64_t code
)
315 DPRINTF(PseudoInst
, "PseudoInst::m5fail(%i, %i)\n", delay
, code
);
316 Tick when
= curTick() + delay
* SimClock::Int::ns
;
317 exitSimLoop("m5_fail instruction encountered", code
, when
, 0, true);
321 loadsymbol(ThreadContext
*tc
)
323 DPRINTF(PseudoInst
, "PseudoInst::loadsymbol()\n");
325 panicFsOnlyPseudoInst("loadsymbol");
327 const string
&filename
= tc
->getCpuPtr()->system
->params()->symbolfile
;
328 if (filename
.empty()) {
333 ifstream
file(filename
.c_str());
336 fatal("file error: Can't open symbol table file %s\n", filename
);
338 while (!file
.eof()) {
339 getline(file
, buffer
);
344 string::size_type idx
= buffer
.find(' ');
345 if (idx
== string::npos
)
348 string address
= "0x" + buffer
.substr(0, idx
);
353 // Skip over letter and space
354 string symbol
= buffer
.substr(idx
+ 3);
360 if (!to_number(address
, addr
))
363 if (!tc
->getSystemPtr()->kernelSymtab
->insert(addr
, symbol
))
367 DPRINTF(Loader
, "Loaded symbol: %s @ %#llx\n", symbol
, addr
);
373 addsymbol(ThreadContext
*tc
, Addr addr
, Addr symbolAddr
)
375 DPRINTF(PseudoInst
, "PseudoInst::addsymbol(0x%x, 0x%x)\n",
378 panicFsOnlyPseudoInst("addSymbol");
381 CopyStringOut(tc
, symb
, symbolAddr
, 100);
382 std::string
symbol(symb
);
384 DPRINTF(Loader
, "Loaded symbol: %s @ %#llx\n", symbol
, addr
);
386 tc
->getSystemPtr()->kernelSymtab
->insert(addr
,symbol
);
387 debugSymbolTable
->insert(addr
,symbol
);
391 initParam(ThreadContext
*tc
, uint64_t key_str1
, uint64_t key_str2
)
393 DPRINTF(PseudoInst
, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1
,
396 panicFsOnlyPseudoInst("initParam");
400 // The key parameter string is passed in via two 64-bit registers. We copy
401 // out the characters from the 64-bit integer variables here and concatenate
402 // them in the key_str character buffer
403 const int len
= 2 * sizeof(uint64_t) + 1;
405 memset(key_str
, '\0', len
);
407 assert(key_str2
== 0);
409 strncpy(key_str
, (char *)&key_str1
, sizeof(uint64_t));
412 if (strlen(key_str
) == sizeof(uint64_t)) {
413 strncpy(key_str
+ sizeof(uint64_t), (char *)&key_str2
,
416 assert(key_str2
== 0);
419 // Compare the key parameter with the known values to select the return
422 if (strcmp(key_str
, InitParamKey::DEFAULT
) == 0) {
423 val
= tc
->getCpuPtr()->system
->init_param
;
424 } else if (strcmp(key_str
, InitParamKey::DIST_RANK
) == 0) {
425 val
= DistIface::rankParam();
426 } else if (strcmp(key_str
, InitParamKey::DIST_SIZE
) == 0) {
427 val
= DistIface::sizeParam();
429 panic("Unknown key for initparam pseudo instruction:\"%s\"", key_str
);
436 resetstats(ThreadContext
*tc
, Tick delay
, Tick period
)
438 DPRINTF(PseudoInst
, "PseudoInst::resetstats(%i, %i)\n", delay
, period
);
439 if (!tc
->getCpuPtr()->params()->do_statistics_insts
)
443 Tick when
= curTick() + delay
* SimClock::Int::ns
;
444 Tick repeat
= period
* SimClock::Int::ns
;
446 Stats::schedStatEvent(false, true, when
, repeat
);
450 dumpstats(ThreadContext
*tc
, Tick delay
, Tick period
)
452 DPRINTF(PseudoInst
, "PseudoInst::dumpstats(%i, %i)\n", delay
, period
);
453 if (!tc
->getCpuPtr()->params()->do_statistics_insts
)
457 Tick when
= curTick() + delay
* SimClock::Int::ns
;
458 Tick repeat
= period
* SimClock::Int::ns
;
460 Stats::schedStatEvent(true, false, when
, repeat
);
464 dumpresetstats(ThreadContext
*tc
, Tick delay
, Tick period
)
466 DPRINTF(PseudoInst
, "PseudoInst::dumpresetstats(%i, %i)\n", delay
, period
);
467 if (!tc
->getCpuPtr()->params()->do_statistics_insts
)
471 Tick when
= curTick() + delay
* SimClock::Int::ns
;
472 Tick repeat
= period
* SimClock::Int::ns
;
474 Stats::schedStatEvent(true, true, when
, repeat
);
478 m5checkpoint(ThreadContext
*tc
, Tick delay
, Tick period
)
480 DPRINTF(PseudoInst
, "PseudoInst::m5checkpoint(%i, %i)\n", delay
, period
);
481 if (!tc
->getCpuPtr()->params()->do_checkpoint_insts
)
484 if (DistIface::readyToCkpt(delay
, period
)) {
485 Tick when
= curTick() + delay
* SimClock::Int::ns
;
486 Tick repeat
= period
* SimClock::Int::ns
;
487 exitSimLoop("checkpoint", 0, when
, repeat
);
492 readfile(ThreadContext
*tc
, Addr vaddr
, uint64_t len
, uint64_t offset
)
494 DPRINTF(PseudoInst
, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n",
497 panicFsOnlyPseudoInst("readfile");
501 const string
&file
= tc
->getSystemPtr()->params()->readfile
;
508 int fd
= ::open(file
.c_str(), O_RDONLY
, 0);
510 panic("could not open file %s\n", file
);
512 if (::lseek(fd
, offset
, SEEK_SET
) < 0)
513 panic("could not seek: %s", strerror(errno
));
515 char *buf
= new char[len
];
518 int bytes
= ::read(fd
, p
, len
);
528 CopyIn(tc
, vaddr
, buf
, result
);
534 writefile(ThreadContext
*tc
, Addr vaddr
, uint64_t len
, uint64_t offset
,
537 DPRINTF(PseudoInst
, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n",
538 vaddr
, len
, offset
, filename_addr
);
540 // copy out target filename
542 std::string filename
;
543 CopyStringOut(tc
, fn
, filename_addr
, 100);
544 filename
= std::string(fn
);
548 // create a new file (truncate)
549 out
= simout
.create(filename
, true, true);
551 // do not truncate file if offset is non-zero
552 // (ios::in flag is required as well to keep the existing data
553 // intact, otherwise existing data will be zeroed out.)
554 out
= simout
.open(filename
, ios::in
| ios::out
| ios::binary
, true);
557 ostream
*os(out
->stream());
559 panic("could not open file %s\n", filename
);
564 // copy out data and write to file
565 char *buf
= new char[len
];
566 CopyOut(tc
, buf
, vaddr
, len
);
568 if (os
->fail() || os
->bad())
569 panic("Error while doing writefile!\n");
579 debugbreak(ThreadContext
*tc
)
581 DPRINTF(PseudoInst
, "PseudoInst::debugbreak()\n");
586 switchcpu(ThreadContext
*tc
)
588 DPRINTF(PseudoInst
, "PseudoInst::switchcpu()\n");
589 exitSimLoop("switchcpu");
593 togglesync(ThreadContext
*tc
)
595 DPRINTF(PseudoInst
, "PseudoInst::togglesync()\n");
596 DistIface::toggleSync(tc
);
600 // This function is executed when annotated work items begin. Depending on
601 // what the user specified at the command line, the simulation may exit and/or
602 // take a checkpoint when a certain work item begins.
605 workbegin(ThreadContext
*tc
, uint64_t workid
, uint64_t threadid
)
607 DPRINTF(PseudoInst
, "PseudoInst::workbegin(%i, %i)\n", workid
, threadid
);
608 System
*sys
= tc
->getSystemPtr();
609 const System::Params
*params
= sys
->params();
611 if (params
->exit_on_work_items
) {
612 exitSimLoop("workbegin", static_cast<int>(workid
));
616 DPRINTF(WorkItems
, "Work Begin workid: %d, threadid %d\n", workid
,
618 tc
->getCpuPtr()->workItemBegin();
619 sys
->workItemBegin(threadid
, workid
);
622 // If specified, determine if this is the specific work item the user
625 if (params
->work_item_id
== -1 || params
->work_item_id
== workid
) {
627 uint64_t systemWorkBeginCount
= sys
->incWorkItemsBegin();
628 int cpuId
= tc
->getCpuPtr()->cpuId();
630 if (params
->work_cpus_ckpt_count
!= 0 &&
631 sys
->markWorkItem(cpuId
) >= params
->work_cpus_ckpt_count
) {
633 // If active cpus equals checkpoint count, create checkpoint
635 exitSimLoop("checkpoint");
638 if (systemWorkBeginCount
== params
->work_begin_ckpt_count
) {
640 // Note: the string specified as the cause of the exit event must
641 // exactly equal "checkpoint" inorder to create a checkpoint
643 exitSimLoop("checkpoint");
646 if (systemWorkBeginCount
== params
->work_begin_exit_count
) {
648 // If a certain number of work items started, exit simulation
650 exitSimLoop("work started count reach");
653 if (cpuId
== params
->work_begin_cpu_id_exit
) {
655 // If work started on the cpu id specified, exit simulation
657 exitSimLoop("work started on specific cpu");
663 // This function is executed when annotated work items end. Depending on
664 // what the user specified at the command line, the simulation may exit and/or
665 // take a checkpoint when a certain work item ends.
668 workend(ThreadContext
*tc
, uint64_t workid
, uint64_t threadid
)
670 DPRINTF(PseudoInst
, "PseudoInst::workend(%i, %i)\n", workid
, threadid
);
671 System
*sys
= tc
->getSystemPtr();
672 const System::Params
*params
= sys
->params();
674 if (params
->exit_on_work_items
) {
675 exitSimLoop("workend", static_cast<int>(workid
));
679 DPRINTF(WorkItems
, "Work End workid: %d, threadid %d\n", workid
, threadid
);
680 tc
->getCpuPtr()->workItemEnd();
681 sys
->workItemEnd(threadid
, workid
);
684 // If specified, determine if this is the specific work item the user
687 if (params
->work_item_id
== -1 || params
->work_item_id
== workid
) {
689 uint64_t systemWorkEndCount
= sys
->incWorkItemsEnd();
690 int cpuId
= tc
->getCpuPtr()->cpuId();
692 if (params
->work_cpus_ckpt_count
!= 0 &&
693 sys
->markWorkItem(cpuId
) >= params
->work_cpus_ckpt_count
) {
695 // If active cpus equals checkpoint count, create checkpoint
697 exitSimLoop("checkpoint");
700 if (params
->work_end_ckpt_count
!= 0 &&
701 systemWorkEndCount
== params
->work_end_ckpt_count
) {
703 // If total work items completed equals checkpoint count, create
706 exitSimLoop("checkpoint");
709 if (params
->work_end_exit_count
!= 0 &&
710 systemWorkEndCount
== params
->work_end_exit_count
) {
712 // If total work items completed equals exit count, exit simulation
714 exitSimLoop("work items exit count reached");
719 } // namespace PseudoInst