2 * Copyright (c) 2010-2012 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
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 "params/BaseCPU.hh"
67 #include "sim/full_system.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"
80 using namespace Stats
;
81 using namespace TheISA
;
83 namespace PseudoInst
{
86 panicFsOnlyPseudoInst(const char *name
)
88 panic("Pseudo inst \"%s\" is only available in Full System mode.");
92 pseudoInst(ThreadContext
*tc
, uint8_t func
, uint8_t subfunc
)
96 DPRINTF(PseudoInst
, "PseudoInst::pseudoInst(%i, %i)\n", func
, subfunc
);
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.
103 for (int i
= 0; i
< sizeof(args
) / sizeof(*args
); ++i
) {
104 args
[arg_num
] = getArgument(tc
, arg_num
, sizeof(uint64_t), false);
109 case 0x00: // arm_func
113 case 0x01: // quiesce_func
117 case 0x02: // quiescens_func
121 case 0x03: // quiescecycle_func
122 quiesceNs(tc
, args
[0]);
125 case 0x04: // quiescetime_func
126 return quiesceTime(tc
);
128 case 0x07: // rpns_func
131 case 0x09: // wakecpu_func
132 wakeCPU(tc
, args
[0]);
135 case 0x21: // exit_func
140 m5fail(tc
, args
[0], args
[1]);
143 case 0x30: // initparam_func
144 return initParam(tc
);
146 case 0x31: // loadsymbol_func
150 case 0x40: // resetstats_func
151 resetstats(tc
, args
[0], args
[1]);
154 case 0x41: // dumpstats_func
155 dumpstats(tc
, args
[0], args
[1]);
158 case 0x42: // dumprststats_func
159 dumpresetstats(tc
, args
[0], args
[1]);
162 case 0x43: // ckpt_func
163 m5checkpoint(tc
, args
[0], args
[1]);
166 case 0x4f: // writefile_func
167 return writefile(tc
, args
[0], args
[1], args
[2], args
[3]);
169 case 0x50: // readfile_func
170 return readfile(tc
, args
[0], args
[1], args
[2]);
172 case 0x51: // debugbreak_func
176 case 0x52: // switchcpu_func
180 case 0x53: // addsymbol_func
181 addsymbol(tc
, args
[0], args
[1]);
184 case 0x54: // panic_func
185 panic("M5 panic instruction called at %s\n", tc
->pcState());
187 case 0x5a: // work_begin_func
188 workbegin(tc
, args
[0], args
[1]);
191 case 0x5b: // work_end_func
192 workend(tc
, args
[0], args
[1]);
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
);
203 /* SE mode functions */
204 case 0x60: // syscall_func
208 case 0x61: // pagefault_func
213 warn("Unhandled m5 op: 0x%x\n", func
);
221 arm(ThreadContext
*tc
)
223 DPRINTF(PseudoInst
, "PseudoInst::arm()\n");
225 panicFsOnlyPseudoInst("arm");
227 if (tc
->getKernelStats())
228 tc
->getKernelStats()->arm();
232 quiesce(ThreadContext
*tc
)
234 DPRINTF(PseudoInst
, "PseudoInst::quiesce()\n");
236 panicFsOnlyPseudoInst("quiesce");
238 if (!tc
->getCpuPtr()->params()->do_quiesce
)
241 DPRINTF(Quiesce
, "%s: quiesce()\n", tc
->getCpuPtr()->name());
244 if (tc
->getKernelStats())
245 tc
->getKernelStats()->quiesce();
249 quiesceSkip(ThreadContext
*tc
)
251 DPRINTF(PseudoInst
, "PseudoInst::quiesceSkip()\n");
253 panicFsOnlyPseudoInst("quiesceSkip");
255 BaseCPU
*cpu
= tc
->getCpuPtr();
257 if (!cpu
->params()->do_quiesce
)
260 EndQuiesceEvent
*quiesceEvent
= tc
->getQuiesceEvent();
262 Tick resume
= curTick() + 1;
264 cpu
->reschedule(quiesceEvent
, resume
, true);
266 DPRINTF(Quiesce
, "%s: quiesceSkip() until %d\n",
267 cpu
->name(), resume
);
270 if (tc
->getKernelStats())
271 tc
->getKernelStats()->quiesce();
275 quiesceNs(ThreadContext
*tc
, uint64_t ns
)
277 DPRINTF(PseudoInst
, "PseudoInst::quiesceNs(%i)\n", ns
);
279 panicFsOnlyPseudoInst("quiesceNs");
281 BaseCPU
*cpu
= tc
->getCpuPtr();
283 if (!cpu
->params()->do_quiesce
|| ns
== 0)
286 EndQuiesceEvent
*quiesceEvent
= tc
->getQuiesceEvent();
288 Tick resume
= curTick() + SimClock::Int::ns
* ns
;
290 cpu
->reschedule(quiesceEvent
, resume
, true);
292 DPRINTF(Quiesce
, "%s: quiesceNs(%d) until %d\n",
293 cpu
->name(), ns
, resume
);
296 if (tc
->getKernelStats())
297 tc
->getKernelStats()->quiesce();
301 quiesceCycles(ThreadContext
*tc
, uint64_t cycles
)
303 DPRINTF(PseudoInst
, "PseudoInst::quiesceCycles(%i)\n", cycles
);
305 panicFsOnlyPseudoInst("quiesceCycles");
307 BaseCPU
*cpu
= tc
->getCpuPtr();
309 if (!cpu
->params()->do_quiesce
|| cycles
== 0)
312 EndQuiesceEvent
*quiesceEvent
= tc
->getQuiesceEvent();
314 Tick resume
= cpu
->clockEdge(Cycles(cycles
));
316 cpu
->reschedule(quiesceEvent
, resume
, true);
318 DPRINTF(Quiesce
, "%s: quiesceCycles(%d) until %d\n",
319 cpu
->name(), cycles
, resume
);
322 if (tc
->getKernelStats())
323 tc
->getKernelStats()->quiesce();
327 quiesceTime(ThreadContext
*tc
)
329 DPRINTF(PseudoInst
, "PseudoInst::quiesceTime()\n");
331 panicFsOnlyPseudoInst("quiesceTime");
335 return (tc
->readLastActivate() - tc
->readLastSuspend()) /
340 rpns(ThreadContext
*tc
)
342 DPRINTF(PseudoInst
, "PseudoInst::rpns()\n");
343 return curTick() / SimClock::Int::ns
;
347 wakeCPU(ThreadContext
*tc
, uint64_t cpuid
)
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();
357 m5exit(ThreadContext
*tc
, Tick delay
)
359 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);
365 m5fail(ThreadContext
*tc
, Tick delay
, uint64_t code
)
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);
373 loadsymbol(ThreadContext
*tc
)
375 DPRINTF(PseudoInst
, "PseudoInst::loadsymbol()\n");
377 panicFsOnlyPseudoInst("loadsymbol");
379 const string
&filename
= tc
->getCpuPtr()->system
->params()->symbolfile
;
380 if (filename
.empty()) {
385 ifstream
file(filename
.c_str());
388 fatal("file error: Can't open symbol table file %s\n", filename
);
390 while (!file
.eof()) {
391 getline(file
, buffer
);
396 string::size_type idx
= buffer
.find(' ');
397 if (idx
== string::npos
)
400 string address
= "0x" + buffer
.substr(0, idx
);
405 // Skip over letter and space
406 string symbol
= buffer
.substr(idx
+ 3);
412 if (!to_number(address
, addr
))
415 if (!tc
->getSystemPtr()->kernelSymtab
->insert(addr
, symbol
))
419 DPRINTF(Loader
, "Loaded symbol: %s @ %#llx\n", symbol
, addr
);
425 addsymbol(ThreadContext
*tc
, Addr addr
, Addr symbolAddr
)
427 DPRINTF(PseudoInst
, "PseudoInst::addsymbol(0x%x, 0x%x)\n",
430 panicFsOnlyPseudoInst("addSymbol");
433 CopyStringOut(tc
, symb
, symbolAddr
, 100);
434 std::string
symbol(symb
);
436 DPRINTF(Loader
, "Loaded symbol: %s @ %#llx\n", symbol
, addr
);
438 tc
->getSystemPtr()->kernelSymtab
->insert(addr
,symbol
);
439 debugSymbolTable
->insert(addr
,symbol
);
443 initParam(ThreadContext
*tc
)
445 DPRINTF(PseudoInst
, "PseudoInst::initParam()\n");
447 panicFsOnlyPseudoInst("initParam");
451 return tc
->getCpuPtr()->system
->init_param
;
456 resetstats(ThreadContext
*tc
, Tick delay
, Tick period
)
458 DPRINTF(PseudoInst
, "PseudoInst::resetstats(%i, %i)\n", delay
, period
);
459 if (!tc
->getCpuPtr()->params()->do_statistics_insts
)
463 Tick when
= curTick() + delay
* SimClock::Int::ns
;
464 Tick repeat
= period
* SimClock::Int::ns
;
466 Stats::schedStatEvent(false, true, when
, repeat
);
470 dumpstats(ThreadContext
*tc
, Tick delay
, Tick period
)
472 DPRINTF(PseudoInst
, "PseudoInst::dumpstats(%i, %i)\n", delay
, period
);
473 if (!tc
->getCpuPtr()->params()->do_statistics_insts
)
477 Tick when
= curTick() + delay
* SimClock::Int::ns
;
478 Tick repeat
= period
* SimClock::Int::ns
;
480 Stats::schedStatEvent(true, false, when
, repeat
);
484 dumpresetstats(ThreadContext
*tc
, Tick delay
, Tick period
)
486 DPRINTF(PseudoInst
, "PseudoInst::dumpresetstats(%i, %i)\n", delay
, period
);
487 if (!tc
->getCpuPtr()->params()->do_statistics_insts
)
491 Tick when
= curTick() + delay
* SimClock::Int::ns
;
492 Tick repeat
= period
* SimClock::Int::ns
;
494 Stats::schedStatEvent(true, true, when
, repeat
);
498 m5checkpoint(ThreadContext
*tc
, Tick delay
, Tick period
)
500 DPRINTF(PseudoInst
, "PseudoInst::m5checkpoint(%i, %i)\n", delay
, period
);
501 if (!tc
->getCpuPtr()->params()->do_checkpoint_insts
)
504 Tick when
= curTick() + delay
* SimClock::Int::ns
;
505 Tick repeat
= period
* SimClock::Int::ns
;
507 exitSimLoop("checkpoint", 0, when
, repeat
);
511 readfile(ThreadContext
*tc
, Addr vaddr
, uint64_t len
, uint64_t offset
)
513 DPRINTF(PseudoInst
, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n",
516 panicFsOnlyPseudoInst("readfile");
520 const string
&file
= tc
->getSystemPtr()->params()->readfile
;
527 int fd
= ::open(file
.c_str(), O_RDONLY
, 0);
529 panic("could not open file %s\n", file
);
531 if (::lseek(fd
, offset
, SEEK_SET
) < 0)
532 panic("could not seek: %s", strerror(errno
));
534 char *buf
= new char[len
];
537 int bytes
= ::read(fd
, p
, len
);
547 CopyIn(tc
, vaddr
, buf
, result
);
553 writefile(ThreadContext
*tc
, Addr vaddr
, uint64_t len
, uint64_t offset
,
556 DPRINTF(PseudoInst
, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n",
557 vaddr
, len
, offset
, filename_addr
);
560 // copy out target filename
562 std::string filename
;
563 CopyStringOut(tc
, fn
, filename_addr
, 100);
564 filename
= std::string(fn
);
567 // create a new file (truncate)
568 os
= simout
.create(filename
, true);
570 // do not truncate file if offset is non-zero
571 // (ios::in flag is required as well to keep the existing data
572 // intact, otherwise existing data will be zeroed out.)
573 os
= simout
.openFile(simout
.directory() + filename
,
574 ios::in
| ios::out
| ios::binary
);
577 panic("could not open file %s\n", filename
);
582 // copy out data and write to file
583 char *buf
= new char[len
];
584 CopyOut(tc
, buf
, vaddr
, len
);
586 if (os
->fail() || os
->bad())
587 panic("Error while doing writefile!\n");
597 debugbreak(ThreadContext
*tc
)
599 DPRINTF(PseudoInst
, "PseudoInst::debugbreak()\n");
604 switchcpu(ThreadContext
*tc
)
606 DPRINTF(PseudoInst
, "PseudoInst::switchcpu()\n");
607 exitSimLoop("switchcpu");
611 // This function is executed when annotated work items begin. Depending on
612 // what the user specified at the command line, the simulation may exit and/or
613 // take a checkpoint when a certain work item begins.
616 workbegin(ThreadContext
*tc
, uint64_t workid
, uint64_t threadid
)
618 DPRINTF(PseudoInst
, "PseudoInst::workbegin(%i, %i)\n", workid
, threadid
);
619 tc
->getCpuPtr()->workItemBegin();
620 System
*sys
= tc
->getSystemPtr();
621 const System::Params
*params
= sys
->params();
622 sys
->workItemBegin(threadid
, workid
);
624 DPRINTF(WorkItems
, "Work Begin workid: %d, threadid %d\n", workid
,
628 // If specified, determine if this is the specific work item the user
631 if (params
->work_item_id
== -1 || params
->work_item_id
== workid
) {
633 uint64_t systemWorkBeginCount
= sys
->incWorkItemsBegin();
634 int cpuId
= tc
->getCpuPtr()->cpuId();
636 if (params
->work_cpus_ckpt_count
!= 0 &&
637 sys
->markWorkItem(cpuId
) >= params
->work_cpus_ckpt_count
) {
639 // If active cpus equals checkpoint count, create checkpoint
641 exitSimLoop("checkpoint");
644 if (systemWorkBeginCount
== params
->work_begin_ckpt_count
) {
646 // Note: the string specified as the cause of the exit event must
647 // exactly equal "checkpoint" inorder to create a checkpoint
649 exitSimLoop("checkpoint");
652 if (systemWorkBeginCount
== params
->work_begin_exit_count
) {
654 // If a certain number of work items started, exit simulation
656 exitSimLoop("work started count reach");
659 if (cpuId
== params
->work_begin_cpu_id_exit
) {
661 // If work started on the cpu id specified, exit simulation
663 exitSimLoop("work started on specific cpu");
669 // This function is executed when annotated work items end. Depending on
670 // what the user specified at the command line, the simulation may exit and/or
671 // take a checkpoint when a certain work item ends.
674 workend(ThreadContext
*tc
, uint64_t workid
, uint64_t threadid
)
676 DPRINTF(PseudoInst
, "PseudoInst::workend(%i, %i)\n", workid
, threadid
);
677 tc
->getCpuPtr()->workItemEnd();
678 System
*sys
= tc
->getSystemPtr();
679 const System::Params
*params
= sys
->params();
680 sys
->workItemEnd(threadid
, workid
);
682 DPRINTF(WorkItems
, "Work End workid: %d, threadid %d\n", workid
, threadid
);
685 // If specified, determine if this is the specific work item the user
688 if (params
->work_item_id
== -1 || params
->work_item_id
== workid
) {
690 uint64_t systemWorkEndCount
= sys
->incWorkItemsEnd();
691 int cpuId
= tc
->getCpuPtr()->cpuId();
693 if (params
->work_cpus_ckpt_count
!= 0 &&
694 sys
->markWorkItem(cpuId
) >= params
->work_cpus_ckpt_count
) {
696 // If active cpus equals checkpoint count, create checkpoint
698 exitSimLoop("checkpoint");
701 if (params
->work_end_ckpt_count
!= 0 &&
702 systemWorkEndCount
== params
->work_end_ckpt_count
) {
704 // If total work items completed equals checkpoint count, create
707 exitSimLoop("checkpoint");
710 if (params
->work_end_exit_count
!= 0 &&
711 systemWorkEndCount
== params
->work_end_exit_count
) {
713 // If total work items completed equals exit count, exit simulation
715 exitSimLoop("work items exit count reached");
720 } // namespace PseudoInst