X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsim%2Fpseudo_inst.cc;h=8ffb13e3b33025653c3cf58f7a0b333c901a3271;hb=abd33d6fd26bb69d3bf53ceb6c2dc8f90d893e34;hp=d5bc8fa0e73f2f0b65302b525ba51a32b10a10f8;hpb=da2a4acc26ba264c3c4a12495776fd6a1c4fb133;p=gem5.git diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index d5bc8fa0e..8ffb13e3b 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2012, 2015, 2017 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -41,26 +41,37 @@ * Authors: Nathan Binkert */ +#include "sim/pseudo_inst.hh" + #include #include #include #include #include +#include + +#include -#include "arch/kernel_stats.hh" +#include "arch/pseudo_inst.hh" +#include "arch/utility.hh" #include "arch/vtophys.hh" #include "base/debug.hh" +#include "base/output.hh" #include "config/the_isa.hh" #include "cpu/base.hh" #include "cpu/quiesce_event.hh" #include "cpu/thread_context.hh" #include "debug/Loader.hh" +#include "debug/PseudoInst.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/pseudo_inst.hh" +#include "sim/initparam_keys.hh" +#include "sim/process.hh" #include "sim/serialize.hh" #include "sim/sim_events.hh" #include "sim/sim_exit.hh" @@ -82,134 +93,207 @@ panicFsOnlyPseudoInst(const char *name) panic("Pseudo inst \"%s\" is only available in Full System mode."); } -void -arm(ThreadContext *tc) +uint64_t +pseudoInst(ThreadContext *tc, uint8_t func, uint8_t subfunc) { - if (FullSystem) { - if (tc->getKernelStats()) - tc->getKernelStats()->arm(); - } else { - panicFsOnlyPseudoInst("arm"); + uint64_t args[4]; + + DPRINTF(PseudoInst, "PseudoInst::pseudoInst(%i, %i)\n", func, subfunc); + + // We need to do this in a slightly convoluted way since + // getArgument() might have side-effects on arg_num. We could have + // used the Argument class, but due to the possible side effects + // from getArgument, it'd most likely break. + int arg_num(0); + for (int i = 0; i < sizeof(args) / sizeof(*args); ++i) { + args[arg_num] = getArgument(tc, arg_num, sizeof(uint64_t), false); + ++arg_num; } -} -void -quiesce(ThreadContext *tc) -{ - if (FullSystem) { - if (!tc->getCpuPtr()->params()->do_quiesce) - return; + switch (func) { + case M5OP_ARM: + arm(tc); + break; - DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); + case M5OP_QUIESCE: + quiesce(tc); + break; - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } else { - panicFsOnlyPseudoInst("quiesce"); - } -} + case M5OP_QUIESCE_NS: + quiesceNs(tc, args[0]); + break; -void -quiesceSkip(ThreadContext *tc) -{ - if (FullSystem) { - BaseCPU *cpu = tc->getCpuPtr(); + case M5OP_QUIESCE_CYCLE: + quiesceCycles(tc, args[0]); + break; - if (!cpu->params()->do_quiesce) - return; + case M5OP_QUIESCE_TIME: + return quiesceTime(tc); - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + case M5OP_RPNS: + return rpns(tc); - Tick resume = curTick() + 1; + case M5OP_WAKE_CPU: + wakeCPU(tc, args[0]); + break; - cpu->reschedule(quiesceEvent, resume, true); + case M5OP_EXIT: + m5exit(tc, args[0]); + break; - DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n", - cpu->name(), resume); + case M5OP_FAIL: + m5fail(tc, args[0], args[1]); + break; - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } else { - panicFsOnlyPseudoInst("quiesceSkip"); - } -} + case M5OP_INIT_PARAM: + return initParam(tc, args[0], args[1]); -void -quiesceNs(ThreadContext *tc, uint64_t ns) -{ - if (FullSystem) { - BaseCPU *cpu = tc->getCpuPtr(); + case M5OP_LOAD_SYMBOL: + loadsymbol(tc); + break; - if (!cpu->params()->do_quiesce || ns == 0) - return; + case M5OP_RESET_STATS: + resetstats(tc, args[0], args[1]); + break; - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + case M5OP_DUMP_STATS: + dumpstats(tc, args[0], args[1]); + break; - Tick resume = curTick() + SimClock::Int::ns * ns; + case M5OP_DUMP_RESET_STATS: + dumpresetstats(tc, args[0], args[1]); + break; - cpu->reschedule(quiesceEvent, resume, true); + case M5OP_CHECKPOINT: + m5checkpoint(tc, args[0], args[1]); + break; - DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", - cpu->name(), ns, resume); + case M5OP_WRITE_FILE: + return writefile(tc, args[0], args[1], args[2], args[3]); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } else { - panicFsOnlyPseudoInst("quiesceNs"); + case M5OP_READ_FILE: + return readfile(tc, args[0], args[1], args[2]); + + case M5OP_DEBUG_BREAK: + debugbreak(tc); + break; + + case M5OP_SWITCH_CPU: + switchcpu(tc); + break; + + case M5OP_ADD_SYMBOL: + addsymbol(tc, args[0], args[1]); + break; + + case M5OP_PANIC: + panic("M5 panic instruction called at %s\n", tc->pcState()); + + case M5OP_WORK_BEGIN: + workbegin(tc, args[0], args[1]); + break; + + case M5OP_WORK_END: + workend(tc, args[0], args[1]); + break; + + case M5OP_ANNOTATE: + case M5OP_RESERVED2: + case M5OP_RESERVED3: + case M5OP_RESERVED4: + case M5OP_RESERVED5: + warn("Unimplemented m5 op (0x%x)\n", func); + break; + + /* SE mode functions */ + case M5OP_SE_SYSCALL: + m5Syscall(tc); + break; + + case M5OP_SE_PAGE_FAULT: + m5PageFault(tc); + break; + + /* dist-gem5 functions */ + case M5OP_DIST_TOGGLE_SYNC: + togglesync(tc); + break; + + default: + warn("Unhandled m5 op: 0x%x\n", func); + break; } + + return 0; } void -quiesceCycles(ThreadContext *tc, uint64_t cycles) +arm(ThreadContext *tc) { - if (FullSystem) { - BaseCPU *cpu = tc->getCpuPtr(); - - if (!cpu->params()->do_quiesce || cycles == 0) - return; + DPRINTF(PseudoInst, "PseudoInst::arm()\n"); + if (!FullSystem) + panicFsOnlyPseudoInst("arm"); - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + if (tc->getKernelStats()) + tc->getKernelStats()->arm(); +} - Tick resume = curTick() + cpu->ticks(cycles); +void +quiesce(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesce()\n"); + tc->quiesce(); +} - cpu->reschedule(quiesceEvent, resume, true); +void +quiesceSkip(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceSkip()\n"); + tc->quiesceTick(tc->getCpuPtr()->nextCycle() + 1); +} - DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", - cpu->name(), cycles, resume); +void +quiesceNs(ThreadContext *tc, uint64_t ns) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceNs(%i)\n", ns); + tc->quiesceTick(curTick() + SimClock::Int::ns * ns); +} - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } else { - panicFsOnlyPseudoInst("quiesceCycles"); - } +void +quiesceCycles(ThreadContext *tc, uint64_t cycles) +{ + DPRINTF(PseudoInst, "PseudoInst::quiesceCycles(%i)\n", cycles); + tc->quiesceTick(tc->getCpuPtr()->clockEdge(Cycles(cycles))); } uint64_t quiesceTime(ThreadContext *tc) { - if (FullSystem) { - return (tc->readLastActivate() - tc->readLastSuspend()) / - SimClock::Int::ns; - } else { - panicFsOnlyPseudoInst("quiesceTime"); - return 0; - } + DPRINTF(PseudoInst, "PseudoInst::quiesceTime()\n"); + + return (tc->readLastActivate() - tc->readLastSuspend()) / + SimClock::Int::ns; } uint64_t rpns(ThreadContext *tc) { + DPRINTF(PseudoInst, "PseudoInst::rpns()\n"); return curTick() / SimClock::Int::ns; } 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; + } + ThreadContext *other_tc = sys->threadContexts[cpuid]; if (other_tc->status() == ThreadContext::Suspended) other_tc->activate(); @@ -218,94 +302,140 @@ wakeCPU(ThreadContext *tc, uint64_t cpuid) 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); + } +} + +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_exit instruction encountered", 0, when); + exitSimLoop("m5_fail instruction encountered", code, when, 0, true); } void loadsymbol(ThreadContext *tc) { - if (FullSystem) { - const string &filename = tc->getCpuPtr()->system->params()->symbolfile; - if (filename.empty()) { - return; - } + DPRINTF(PseudoInst, "PseudoInst::loadsymbol()\n"); + if (!FullSystem) + panicFsOnlyPseudoInst("loadsymbol"); - std::string buffer; - ifstream file(filename.c_str()); + const string &filename = tc->getCpuPtr()->system->params()->symbolfile; + if (filename.empty()) { + return; + } - if (!file) - fatal("file error: Can't open symbol table file %s\n", filename); + std::string buffer; + ifstream file(filename.c_str()); - while (!file.eof()) { - getline(file, buffer); + if (!file) + fatal("file error: Can't open symbol table file %s\n", filename); - if (buffer.empty()) - continue; + while (!file.eof()) { + getline(file, buffer); - string::size_type idx = buffer.find(' '); - if (idx == string::npos) - continue; + if (buffer.empty()) + continue; - string address = "0x" + buffer.substr(0, idx); - eat_white(address); - if (address.empty()) - continue; + string::size_type idx = buffer.find(' '); + if (idx == string::npos) + continue; - // Skip over letter and space - string symbol = buffer.substr(idx + 3); - eat_white(symbol); - if (symbol.empty()) - continue; + string address = "0x" + buffer.substr(0, idx); + eat_white(address); + if (address.empty()) + continue; - Addr addr; - if (!to_number(address, addr)) - continue; + // Skip over letter and space + string symbol = buffer.substr(idx + 3); + eat_white(symbol); + if (symbol.empty()) + continue; - if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) - continue; + Addr addr; + if (!to_number(address, addr)) + continue; + if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) + continue; - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - } - file.close(); - } else { - panicFsOnlyPseudoInst("loadsymbol"); + + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); } + file.close(); } void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) { - if (FullSystem) { - char symb[100]; - CopyStringOut(tc, symb, symbolAddr, 100); - std::string symbol(symb); + DPRINTF(PseudoInst, "PseudoInst::addsymbol(0x%x, 0x%x)\n", + addr, symbolAddr); + if (!FullSystem) + panicFsOnlyPseudoInst("addSymbol"); - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); + char symb[100]; + CopyStringOut(tc, symb, symbolAddr, 100); + std::string symbol(symb); - tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); - debugSymbolTable->insert(addr,symbol); - } else { - panicFsOnlyPseudoInst("addSymbol"); - } + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); + + tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); + debugSymbolTable->insert(addr,symbol); } uint64_t -initParam(ThreadContext *tc) +initParam(ThreadContext *tc, uint64_t key_str1, uint64_t key_str2) { - if (FullSystem) { - return tc->getCpuPtr()->system->init_param; - } else { + DPRINTF(PseudoInst, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1, + (char *)&key_str2); + if (!FullSystem) { panicFsOnlyPseudoInst("initParam"); return 0; } + + // 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)); + } + + if (strlen(key_str) == sizeof(uint64_t)) { + strncpy(key_str + sizeof(uint64_t), (char *)&key_str2, + sizeof(uint64_t)); + } else { + assert(key_str2 == 0); + } + + // 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; } 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; @@ -319,6 +449,7 @@ resetstats(ThreadContext *tc, Tick delay, Tick period) 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; @@ -332,6 +463,7 @@ dumpstats(ThreadContext *tc, Tick delay, Tick period) 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; @@ -345,82 +477,146 @@ dumpresetstats(ThreadContext *tc, Tick delay, Tick period) 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; - Tick when = curTick() + delay * SimClock::Int::ns; - Tick repeat = period * SimClock::Int::ns; - - exitSimLoop("checkpoint", 0, when, repeat); + if (DistIface::readyToCkpt(delay, period)) { + Tick when = curTick() + delay * SimClock::Int::ns; + Tick repeat = period * SimClock::Int::ns; + exitSimLoop("checkpoint", 0, when, repeat); + } } uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) { - if (FullSystem) { - const string &file = tc->getSystemPtr()->params()->readfile; - if (file.empty()) { - return ULL(0); - } + DPRINTF(PseudoInst, "PseudoInst::readfile(0x%x, 0x%x, 0x%x)\n", + vaddr, len, offset); + if (!FullSystem) { + panicFsOnlyPseudoInst("readfile"); + return 0; + } - uint64_t result = 0; + const string &file = tc->getSystemPtr()->params()->readfile; + if (file.empty()) { + return ULL(0); + } - int fd = ::open(file.c_str(), O_RDONLY, 0); - if (fd < 0) - panic("could not open file %s\n", file); + uint64_t result = 0; - if (::lseek(fd, offset, SEEK_SET) < 0) - panic("could not seek: %s", strerror(errno)); + int fd = ::open(file.c_str(), O_RDONLY, 0); + if (fd < 0) + panic("could not open file %s\n", file); - char *buf = new char[len]; - char *p = buf; - while (len > 0) { - int bytes = ::read(fd, p, len); - if (bytes <= 0) - break; + if (::lseek(fd, offset, SEEK_SET) < 0) + panic("could not seek: %s", strerror(errno)); - p += bytes; - result += bytes; - len -= bytes; - } + char *buf = new char[len]; + char *p = buf; + while (len > 0) { + int bytes = ::read(fd, p, len); + if (bytes <= 0) + break; + + p += bytes; + result += bytes; + len -= bytes; + } - close(fd); - CopyIn(tc, vaddr, buf, result); - delete [] buf; - return result; + close(fd); + CopyIn(tc, vaddr, buf, result); + delete [] buf; + return result; +} + +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 + char fn[100]; + std::string filename; + CopyStringOut(tc, fn, filename_addr, 100); + filename = std::string(fn); + + OutputStream *out; + if (offset == 0) { + // create a new file (truncate) + out = simout.create(filename, true, true); } else { - panicFsOnlyPseudoInst("readfile"); - return 0; + // 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); + + // seek to offset + os->seekp(offset); + + // copy out data and write to file + char *buf = new char[len]; + CopyOut(tc, buf, vaddr, len); + os->write(buf, len); + if (os->fail() || os->bad()) + panic("Error while doing writefile!\n"); + + simout.close(out); + + delete [] buf; + + return len; } void debugbreak(ThreadContext *tc) { + DPRINTF(PseudoInst, "PseudoInst::debugbreak()\n"); Debug::breakpoint(); } void switchcpu(ThreadContext *tc) { + DPRINTF(PseudoInst, "PseudoInst::switchcpu()\n"); exitSimLoop("switchcpu"); } +void +togglesync(ThreadContext *tc) +{ + DPRINTF(PseudoInst, "PseudoInst::togglesync()\n"); + DistIface::toggleSync(tc); +} + // -// This function is executed when annotated work items begin. Depending on +// 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) { - tc->getCpuPtr()->workItemBegin(); + DPRINTF(PseudoInst, "PseudoInst::workbegin(%i, %i)\n", workid, threadid); System *sys = tc->getSystemPtr(); const System::Params *params = sys->params(); - sys->workItemBegin(threadid, workid); - DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid, + if (params->exit_on_work_items) { + exitSimLoop("workbegin", static_cast(workid)); + return; + } + + 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 @@ -464,19 +660,25 @@ workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid) } // -// This function is executed when annotated work items end. Depending on +// 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) { - tc->getCpuPtr()->workItemEnd(); + DPRINTF(PseudoInst, "PseudoInst::workend(%i, %i)\n", workid, threadid); System *sys = tc->getSystemPtr(); const System::Params *params = sys->params(); - sys->workItemEnd(threadid, workid); + + if (params->exit_on_work_items) { + exitSimLoop("workend", static_cast(workid)); + return; + } 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