X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsim%2Fpseudo_inst.cc;h=e30738720ef214bfc34a0e3ee20894fa8b7980c1;hb=2f350b822abfe4ed0cf88242e3f833e7a01789ec;hp=56a7796749e316bd2ae34ce8699a6de9f0c972d8;hpb=7a2ecf9e268bf10fc0a2406f3a928a661e97b5fd;p=gem5.git diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index 56a779674..e30738720 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -1,4 +1,17 @@ /* + * Copyright (c) 2010-2012, 2015, 2017 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2011 Advanced Micro Devices, Inc. * Copyright (c) 2003-2006 The Regents of The University of Michigan * All rights reserved. * @@ -24,292 +37,549 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Nathan Binkert */ -#include +#include "sim/pseudo_inst.hh" + #include #include +#include #include #include +#include -#include "arch/vtophys.hh" -#include "base/annotate.hh" +#include "base/debug.hh" +#include "base/output.hh" +#include "config/the_isa.hh" #include "cpu/base.hh" -#include "cpu/thread_context.hh" #include "cpu/quiesce_event.hh" -#include "arch/kernel_stats.hh" -#include "sim/pseudo_inst.hh" +#include "cpu/thread_context.hh" +#include "debug/Loader.hh" +#include "debug/Quiesce.hh" +#include "debug/WorkItems.hh" +#include "dev/net/dist_iface.hh" +#include "kern/kernel_stats.hh" +#include "params/BaseCPU.hh" +#include "sim/full_system.hh" +#include "sim/initparam_keys.hh" +#include "sim/process.hh" #include "sim/serialize.hh" +#include "sim/sim_events.hh" #include "sim/sim_exit.hh" #include "sim/stat_control.hh" #include "sim/stats.hh" #include "sim/system.hh" -#include "sim/debug.hh" #include "sim/vptr.hh" using namespace std; - using namespace Stats; -using namespace TheISA; namespace PseudoInst { - void - arm(ThreadContext *tc) - { - if (tc->getKernelStats()) - tc->getKernelStats()->arm(); - } - void - quiesce(ThreadContext *tc) - { - if (!tc->getCpuPtr()->params->do_quiesce) - return; +static inline void +panicFsOnlyPseudoInst(const char *name) +{ + panic("Pseudo inst \"%s\" is only available in Full System mode."); +} - DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); +void +arm(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::arm()\n"); + if (!FullSystem) + panicFsOnlyPseudoInst("arm"); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } + if (tc->getKernelStats()) + tc->getKernelStats()->arm(); +} - void - quiesceNs(ThreadContext *tc, uint64_t ns) - { - if (!tc->getCpuPtr()->params->do_quiesce || ns == 0) - return; +void +quiesce(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesce()\n"); + tc->quiesce(); +} - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); +void +quiesceSkip(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceSkip()\n"); + tc->quiesceTick(tc->getCpuPtr()->nextCycle() + 1); +} - Tick resume = curTick + Clock::Int::ns * ns; +void +quiesceNs(ThreadContext *tc, uint64_t ns) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceNs(%i)\n", ns); + tc->quiesceTick(curTick() + SimClock::Int::ns * ns); +} - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(resume); - else - quiesceEvent->schedule(resume); +void +quiesceCycles(ThreadContext *tc, uint64_t cycles) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceCycles(%i)\n", cycles); + tc->quiesceTick(tc->getCpuPtr()->clockEdge(Cycles(cycles))); +} - DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", - tc->getCpuPtr()->name(), ns, resume); +uint64_t +quiesceTime(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceTime()\n"); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } + return (tc->readLastActivate() - tc->readLastSuspend()) / + SimClock::Int::ns; +} - void - quiesceCycles(ThreadContext *tc, uint64_t cycles) - { - if (!tc->getCpuPtr()->params->do_quiesce || cycles == 0) - return; +uint64_t +rpns(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::rpns()\n"); + return curTick() / SimClock::Int::ns; +} - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); +void +wakeCPU(ThreadContext *tc, uint64_t cpuid) +{ + DPRINTF(PseudoInst, "PseudoInst::wakeCPU(%i)\n", cpuid); + System *sys = tc->getSystemPtr(); + + if (sys->numContexts() <= cpuid) { + warn("PseudoInst::wakeCPU(%i), cpuid greater than number of contexts" + "(%i)\n",cpuid, sys->numContexts()); + return; + } - Tick resume = curTick + tc->getCpuPtr()->cycles(cycles); + ThreadContext *other_tc = sys->threadContexts[cpuid]; + if (other_tc->status() == ThreadContext::Suspended) + other_tc->activate(); +} + +void +m5exit(ThreadContext *tc, Tick delay) +{ + DPRINTF(PseudoInst, "PseudoInst::m5exit(%i)\n", delay); + if (DistIface::readyToExit(delay)) { + Tick when = curTick() + delay * SimClock::Int::ns; + exitSimLoop("m5_exit instruction encountered", 0, when, 0, true); + } +} - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(resume); - else - quiesceEvent->schedule(resume); +void +m5fail(ThreadContext *tc, Tick delay, uint64_t code) +{ + DPRINTF(PseudoInst, "PseudoInst::m5fail(%i, %i)\n", delay, code); + Tick when = curTick() + delay * SimClock::Int::ns; + exitSimLoop("m5_fail instruction encountered", code, when, 0, true); +} - DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", - tc->getCpuPtr()->name(), cycles, resume); +void +loadsymbol(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::loadsymbol()\n"); + if (!FullSystem) + panicFsOnlyPseudoInst("loadsymbol"); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); + const string &filename = tc->getCpuPtr()->system->params()->symbolfile; + if (filename.empty()) { + return; } - uint64_t - quiesceTime(ThreadContext *tc) - { - return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns; + std::string buffer; + ifstream file(filename.c_str()); + + if (!file) + fatal("file error: Can't open symbol table file %s\n", filename); + + while (!file.eof()) { + getline(file, buffer); + + if (buffer.empty()) + continue; + + string::size_type idx = buffer.find(' '); + if (idx == string::npos) + continue; + + string address = "0x" + buffer.substr(0, idx); + eat_white(address); + if (address.empty()) + continue; + + // Skip over letter and space + string symbol = buffer.substr(idx + 3); + eat_white(symbol); + if (symbol.empty()) + continue; + + Addr addr; + if (!to_number(address, addr)) + continue; + + if (!tc->getSystemPtr()->workload->symtab->insert(addr, symbol)) + continue; + + + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); } + file.close(); +} + +void +addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) +{ + DPRINTF(PseudoInst, "PseudoInst::addsymbol(0x%x, 0x%x)\n", + addr, symbolAddr); + if (!FullSystem) + panicFsOnlyPseudoInst("addSymbol"); + + std::string symbol; + tc->getVirtProxy().readString(symbol, symbolAddr); + + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - void - m5exit_old(ThreadContext *tc) - { - exitSimLoop("m5_exit_old instruction encountered"); + tc->getSystemPtr()->workload->symtab->insert(addr,symbol); + debugSymbolTable->insert(addr,symbol); +} + +uint64_t +initParam(ThreadContext *tc, uint64_t key_str1, uint64_t key_str2) +{ + DPRINTF(PseudoInst, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1, + (char *)&key_str2); + if (!FullSystem) { + panicFsOnlyPseudoInst("initParam"); + return 0; } - void - m5exit(ThreadContext *tc, Tick delay) - { - Tick when = curTick + delay * Clock::Int::ns; - schedExitSimLoop("m5_exit instruction encountered", when); + // The key parameter string is passed in via two 64-bit registers. We copy + // out the characters from the 64-bit integer variables here and concatenate + // them in the key_str character buffer + const int len = 2 * sizeof(uint64_t) + 1; + char key_str[len]; + memset(key_str, '\0', len); + if (key_str1 == 0) { + assert(key_str2 == 0); + } else { + strncpy(key_str, (char *)&key_str1, sizeof(uint64_t)); } - void - loadsymbol(ThreadContext *tc) - { - const string &filename = tc->getCpuPtr()->system->params()->symbolfile; - if (filename.empty()) { - return; - } + if (strlen(key_str) == sizeof(uint64_t)) { + strncpy(key_str + sizeof(uint64_t), (char *)&key_str2, + sizeof(uint64_t)); + } else { + assert(key_str2 == 0); + } - std::string buffer; - ifstream file(filename.c_str()); + // Compare the key parameter with the known values to select the return + // value + uint64_t val; + if (strcmp(key_str, InitParamKey::DEFAULT) == 0) { + val = tc->getCpuPtr()->system->init_param; + } else if (strcmp(key_str, InitParamKey::DIST_RANK) == 0) { + val = DistIface::rankParam(); + } else if (strcmp(key_str, InitParamKey::DIST_SIZE) == 0) { + val = DistIface::sizeParam(); + } else { + panic("Unknown key for initparam pseudo instruction:\"%s\"", key_str); + } + return val; +} - if (!file) - fatal("file error: Can't open symbol table file %s\n", filename); - while (!file.eof()) { - getline(file, buffer); +void +resetstats(ThreadContext *tc, Tick delay, Tick period) +{ + DPRINTF(PseudoInst, "PseudoInst::resetstats(%i, %i)\n", delay, period); + if (!tc->getCpuPtr()->params()->do_statistics_insts) + return; - if (buffer.empty()) - continue; - int idx = buffer.find(' '); - if (idx == string::npos) - continue; + Tick when = curTick() + delay * SimClock::Int::ns; + Tick repeat = period * SimClock::Int::ns; - string address = "0x" + buffer.substr(0, idx); - eat_white(address); - if (address.empty()) - continue; + Stats::schedStatEvent(false, true, when, repeat); +} - // Skip over letter and space - string symbol = buffer.substr(idx + 3); - eat_white(symbol); - if (symbol.empty()) - continue; +void +dumpstats(ThreadContext *tc, Tick delay, Tick period) +{ + DPRINTF(PseudoInst, "PseudoInst::dumpstats(%i, %i)\n", delay, period); + if (!tc->getCpuPtr()->params()->do_statistics_insts) + return; - Addr addr; - if (!to_number(address, addr)) - continue; - if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) - continue; + Tick when = curTick() + delay * SimClock::Int::ns; + Tick repeat = period * SimClock::Int::ns; + Stats::schedStatEvent(true, false, when, repeat); +} - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - } - file.close(); - } +void +dumpresetstats(ThreadContext *tc, Tick delay, Tick period) +{ + DPRINTF(PseudoInst, "PseudoInst::dumpresetstats(%i, %i)\n", delay, period); + if (!tc->getCpuPtr()->params()->do_statistics_insts) + return; - void - resetstats(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_statistics_insts) - return; + Tick when = curTick() + delay * SimClock::Int::ns; + Tick repeat = period * SimClock::Int::ns; - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; + Stats::schedStatEvent(true, true, when, repeat); +} - Stats::StatEvent(false, true, when, repeat); +void +m5checkpoint(ThreadContext *tc, Tick delay, Tick period) +{ + DPRINTF(PseudoInst, "PseudoInst::m5checkpoint(%i, %i)\n", delay, period); + if (!tc->getCpuPtr()->params()->do_checkpoint_insts) + return; + + if (DistIface::readyToCkpt(delay, period)) { + Tick when = curTick() + delay * SimClock::Int::ns; + Tick repeat = period * SimClock::Int::ns; + exitSimLoop("checkpoint", 0, when, repeat); } +} - void - dumpstats(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_statistics_insts) - return; +uint64_t +readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) +{ + DPRINTF(PseudoInst, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n", + vaddr, len, offset); + if (!FullSystem) { + panicFsOnlyPseudoInst("readfile"); + return 0; + } + const string &file = tc->getSystemPtr()->params()->readfile; + if (file.empty()) { + return ULL(0); + } - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; + uint64_t result = 0; - Stats::StatEvent(true, false, when, repeat); - } + int fd = ::open(file.c_str(), O_RDONLY, 0); + if (fd < 0) + panic("could not open file %s\n", file); - void - addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) - { - char symb[100]; - CopyStringOut(tc, symb, symbolAddr, 100); - std::string symbol(symb); + if (::lseek(fd, offset, SEEK_SET) < 0) + panic("could not seek: %s", strerror(errno)); - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); + char *buf = new char[len]; + char *p = buf; + while (len > 0) { + int bytes = ::read(fd, p, len); + if (bytes <= 0) + break; - tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); + p += bytes; + result += bytes; + len -= bytes; } - void - anBegin(ThreadContext *tc, uint64_t cur) - { - Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur & - 0xFFFFFFFF, 0,0); - } + close(fd); + tc->getVirtProxy().writeBlob(vaddr, buf, result); + delete [] buf; + return result; +} - void - anWait(ThreadContext *tc, uint64_t cur, uint64_t wait) - { - Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur & - 0xFFFFFFFF, wait >> 32, wait & 0xFFFFFFFF); +uint64_t +writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, + Addr filename_addr) +{ + DPRINTF(PseudoInst, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n", + vaddr, len, offset, filename_addr); + + // copy out target filename + std::string filename; + tc->getVirtProxy().readString(filename, filename_addr); + + OutputStream *out; + if (offset == 0) { + // create a new file (truncate) + out = simout.create(filename, true, true); + } else { + // do not truncate file if offset is non-zero + // (ios::in flag is required as well to keep the existing data + // intact, otherwise existing data will be zeroed out.) + out = simout.open(filename, ios::in | ios::out | ios::binary, true); } + ostream *os(out->stream()); + if (!os) + panic("could not open file %s\n", filename); - void - dumpresetstats(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_statistics_insts) - return; + // seek to offset + os->seekp(offset); + // copy out data and write to file + char *buf = new char[len]; + tc->getVirtProxy().readBlob(vaddr, buf, len); + os->write(buf, len); + if (os->fail() || os->bad()) + panic("Error while doing writefile!\n"); - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; + simout.close(out); - Stats::StatEvent(true, true, when, repeat); - } + delete [] buf; + + return len; +} - void - m5checkpoint(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_checkpoint_insts) - return; +void +debugbreak(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::debugbreak()\n"); + Debug::breakpoint(); +} - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; +void +switchcpu(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::switchcpu()\n"); + exitSimLoop("switchcpu"); +} - schedExitSimLoop("checkpoint", when, repeat); - } +/* + * This function is executed when the simulation is executing the syscall + * handler in System Emulation mode. + */ +void +m5Syscall(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::m5Syscall()\n"); + Fault fault; + tc->syscall(&fault); +} - uint64_t - readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) - { - const string &file = tc->getSystemPtr()->params()->readfile; - if (file.empty()) { - return ULL(0); - } +void +togglesync(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::togglesync()\n"); + DistIface::toggleSync(tc); +} - uint64_t result = 0; +// +// This function is executed when annotated work items begin. Depending on +// what the user specified at the command line, the simulation may exit and/or +// take a checkpoint when a certain work item begins. +// +void +workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid) +{ + DPRINTF(PseudoInst, "PseudoInst::workbegin(%i, %i)\n", workid, threadid); + System *sys = tc->getSystemPtr(); + const System::Params *params = sys->params(); - int fd = ::open(file.c_str(), O_RDONLY, 0); - if (fd < 0) - panic("could not open file %s\n", file); + if (params->exit_on_work_items) { + exitSimLoop("workbegin", static_cast(workid)); + return; + } - if (::lseek(fd, offset, SEEK_SET) < 0) - panic("could not seek: %s", strerror(errno)); + DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid, + threadid); + tc->getCpuPtr()->workItemBegin(); + sys->workItemBegin(threadid, workid); + + // + // If specified, determine if this is the specific work item the user + // identified + // + if (params->work_item_id == -1 || params->work_item_id == workid) { + + uint64_t systemWorkBeginCount = sys->incWorkItemsBegin(); + int cpuId = tc->getCpuPtr()->cpuId(); + + if (params->work_cpus_ckpt_count != 0 && + sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) { + // + // If active cpus equals checkpoint count, create checkpoint + // + exitSimLoop("checkpoint"); + } - char *buf = new char[len]; - char *p = buf; - while (len > 0) { - int bytes = ::read(fd, p, len); - if (bytes <= 0) - break; + if (systemWorkBeginCount == params->work_begin_ckpt_count) { + // + // Note: the string specified as the cause of the exit event must + // exactly equal "checkpoint" inorder to create a checkpoint + // + exitSimLoop("checkpoint"); + } - p += bytes; - result += bytes; - len -= bytes; + if (systemWorkBeginCount == params->work_begin_exit_count) { + // + // If a certain number of work items started, exit simulation + // + exitSimLoop("work started count reach"); } - close(fd); - CopyIn(tc, vaddr, buf, result); - delete [] buf; - return result; + if (cpuId == params->work_begin_cpu_id_exit) { + // + // If work started on the cpu id specified, exit simulation + // + exitSimLoop("work started on specific cpu"); + } } +} + +// +// This function is executed when annotated work items end. Depending on +// what the user specified at the command line, the simulation may exit and/or +// take a checkpoint when a certain work item ends. +// +void +workend(ThreadContext *tc, uint64_t workid, uint64_t threadid) +{ + DPRINTF(PseudoInst, "PseudoInst::workend(%i, %i)\n", workid, threadid); + System *sys = tc->getSystemPtr(); + const System::Params *params = sys->params(); - void debugbreak(ThreadContext *tc) - { - debug_break(); + if (params->exit_on_work_items) { + exitSimLoop("workend", static_cast(workid)); + return; } - void switchcpu(ThreadContext *tc) - { - exitSimLoop("switchcpu"); + DPRINTF(WorkItems, "Work End workid: %d, threadid %d\n", workid, threadid); + tc->getCpuPtr()->workItemEnd(); + sys->workItemEnd(threadid, workid); + + // + // If specified, determine if this is the specific work item the user + // identified + // + if (params->work_item_id == -1 || params->work_item_id == workid) { + + uint64_t systemWorkEndCount = sys->incWorkItemsEnd(); + int cpuId = tc->getCpuPtr()->cpuId(); + + if (params->work_cpus_ckpt_count != 0 && + sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) { + // + // If active cpus equals checkpoint count, create checkpoint + // + exitSimLoop("checkpoint"); + } + + if (params->work_end_ckpt_count != 0 && + systemWorkEndCount == params->work_end_ckpt_count) { + // + // If total work items completed equals checkpoint count, create + // checkpoint + // + exitSimLoop("checkpoint"); + } + + if (params->work_end_exit_count != 0 && + systemWorkEndCount == params->work_end_exit_count) { + // + // If total work items completed equals exit count, exit simulation + // + exitSimLoop("work items exit count reached"); + } } } + +} // namespace PseudoInst