X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsim%2Fpseudo_inst.cc;h=8ffb13e3b33025653c3cf58f7a0b333c901a3271;hb=abd33d6fd26bb69d3bf53ceb6c2dc8f90d893e34;hp=0dcf5c32b28985deabc4bb28324ad9cdd11d0c82;hpb=743f80712e08f02f7b3a9a286550e2635104f714;p=gem5.git diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index 0dcf5c32b..8ffb13e3b 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 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,6 +41,8 @@ * Authors: Nathan Binkert */ +#include "sim/pseudo_inst.hh" + #include #include @@ -49,7 +51,9 @@ #include #include -#include "arch/kernel_stats.hh" +#include + +#include "arch/pseudo_inst.hh" #include "arch/utility.hh" #include "arch/vtophys.hh" #include "base/debug.hh" @@ -62,9 +66,12 @@ #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" @@ -98,104 +105,120 @@ pseudoInst(ThreadContext *tc, uint8_t func, uint8_t subfunc) // 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); + for (int i = 0; i < sizeof(args) / sizeof(*args); ++i) { + args[arg_num] = getArgument(tc, arg_num, sizeof(uint64_t), false); + ++arg_num; + } switch (func) { - case 0x00: // arm_func + case M5OP_ARM: arm(tc); break; - case 0x01: // quiesce_func + case M5OP_QUIESCE: quiesce(tc); break; - case 0x02: // quiescens_func - quiesceSkip(tc); + case M5OP_QUIESCE_NS: + quiesceNs(tc, args[0]); break; - case 0x03: // quiescecycle_func - quiesceNs(tc, args[0]); + case M5OP_QUIESCE_CYCLE: + quiesceCycles(tc, args[0]); break; - case 0x04: // quiescetime_func + case M5OP_QUIESCE_TIME: return quiesceTime(tc); - case 0x07: // rpns_func + case M5OP_RPNS: return rpns(tc); - case 0x09: // wakecpu_func + case M5OP_WAKE_CPU: wakeCPU(tc, args[0]); break; - case 0x21: // exit_func + case M5OP_EXIT: m5exit(tc, args[0]); break; - case 0x22: + case M5OP_FAIL: m5fail(tc, args[0], args[1]); break; - case 0x30: // initparam_func - return initParam(tc); + case M5OP_INIT_PARAM: + return initParam(tc, args[0], args[1]); - case 0x31: // loadsymbol_func + case M5OP_LOAD_SYMBOL: loadsymbol(tc); break; - case 0x40: // resetstats_func + case M5OP_RESET_STATS: resetstats(tc, args[0], args[1]); break; - case 0x41: // dumpstats_func + case M5OP_DUMP_STATS: dumpstats(tc, args[0], args[1]); break; - case 0x42: // dumprststats_func + case M5OP_DUMP_RESET_STATS: dumpresetstats(tc, args[0], args[1]); break; - case 0x43: // ckpt_func + case M5OP_CHECKPOINT: m5checkpoint(tc, args[0], args[1]); break; - case 0x4f: // writefile_func + case M5OP_WRITE_FILE: return writefile(tc, args[0], args[1], args[2], args[3]); - case 0x50: // readfile_func + case M5OP_READ_FILE: return readfile(tc, args[0], args[1], args[2]); - case 0x51: // debugbreak_func + case M5OP_DEBUG_BREAK: debugbreak(tc); break; - case 0x52: // switchcpu_func + case M5OP_SWITCH_CPU: switchcpu(tc); break; - case 0x53: // addsymbol_func + case M5OP_ADD_SYMBOL: addsymbol(tc, args[0], args[1]); break; - case 0x54: // panic_func + case M5OP_PANIC: panic("M5 panic instruction called at %s\n", tc->pcState()); - case 0x5a: // work_begin_func + case M5OP_WORK_BEGIN: workbegin(tc, args[0], args[1]); break; - case 0x5b: // work_end_func + case M5OP_WORK_END: workend(tc, args[0], args[1]); break; - case 0x55: // annotate_func - case 0x56: // reserved2_func - case 0x57: // reserved3_func - case 0x58: // reserved4_func - case 0x59: // reserved5_func + 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; @@ -219,105 +242,34 @@ void quiesce(ThreadContext *tc) { DPRINTF(PseudoInst, "PseudoInst::quiesce()\n"); - if (!FullSystem) - panicFsOnlyPseudoInst("quiesce"); - - if (!tc->getCpuPtr()->params()->do_quiesce) - return; - - DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); - - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); + tc->quiesce(); } void quiesceSkip(ThreadContext *tc) { DPRINTF(PseudoInst, "PseudoInst::quiesceSkip()\n"); - if (!FullSystem) - panicFsOnlyPseudoInst("quiesceSkip"); - - BaseCPU *cpu = tc->getCpuPtr(); - - if (!cpu->params()->do_quiesce) - return; - - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); - - Tick resume = curTick() + 1; - - cpu->reschedule(quiesceEvent, resume, true); - - DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n", - cpu->name(), resume); - - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); + tc->quiesceTick(tc->getCpuPtr()->nextCycle() + 1); } void quiesceNs(ThreadContext *tc, uint64_t ns) { DPRINTF(PseudoInst, "PseudoInst::quiesceNs(%i)\n", ns); - if (!FullSystem) - panicFsOnlyPseudoInst("quiesceNs"); - - BaseCPU *cpu = tc->getCpuPtr(); - - if (!cpu->params()->do_quiesce || ns == 0) - return; - - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); - - Tick resume = curTick() + SimClock::Int::ns * ns; - - cpu->reschedule(quiesceEvent, resume, true); - - DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", - cpu->name(), ns, resume); - - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); + tc->quiesceTick(curTick() + SimClock::Int::ns * ns); } void quiesceCycles(ThreadContext *tc, uint64_t cycles) { DPRINTF(PseudoInst, "PseudoInst::quiesceCycles(%i)\n", cycles); - if (!FullSystem) - panicFsOnlyPseudoInst("quiesceCycles"); - - BaseCPU *cpu = tc->getCpuPtr(); - - if (!cpu->params()->do_quiesce || cycles == 0) - return; - - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); - - Tick resume = cpu->clockEdge(Cycles(cycles)); - - cpu->reschedule(quiesceEvent, resume, true); - - DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", - cpu->name(), cycles, resume); - - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); + tc->quiesceTick(tc->getCpuPtr()->clockEdge(Cycles(cycles))); } uint64_t quiesceTime(ThreadContext *tc) { DPRINTF(PseudoInst, "PseudoInst::quiesceTime()\n"); - if (!FullSystem) { - panicFsOnlyPseudoInst("quiesceTime"); - return 0; - } return (tc->readLastActivate() - tc->readLastSuspend()) / SimClock::Int::ns; @@ -335,6 +287,13 @@ 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(); @@ -344,8 +303,10 @@ void m5exit(ThreadContext *tc, Tick delay) { DPRINTF(PseudoInst, "PseudoInst::m5exit(%i)\n", delay); - Tick when = curTick() + delay * SimClock::Int::ns; - exitSimLoop("m5_exit instruction encountered", 0, when); + if (DistIface::readyToExit(delay)) { + Tick when = curTick() + delay * SimClock::Int::ns; + exitSimLoop("m5_exit instruction encountered", 0, when, 0, true); + } } void @@ -353,7 +314,7 @@ 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); + exitSimLoop("m5_fail instruction encountered", code, when, 0, true); } void @@ -427,15 +388,47 @@ addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) } uint64_t -initParam(ThreadContext *tc) +initParam(ThreadContext *tc, uint64_t key_str1, uint64_t key_str2) { - DPRINTF(PseudoInst, "PseudoInst::initParam()\n"); + DPRINTF(PseudoInst, "PseudoInst::initParam() key:%s%s\n", (char *)&key_str1, + (char *)&key_str2); if (!FullSystem) { panicFsOnlyPseudoInst("initParam"); return 0; } - return tc->getCpuPtr()->system->init_param; + // 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; } @@ -488,10 +481,11 @@ m5checkpoint(ThreadContext *tc, Tick delay, Tick 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 @@ -542,7 +536,6 @@ writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, { DPRINTF(PseudoInst, "PseudoInst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n", vaddr, len, offset, filename_addr); - ostream *os; // copy out target filename char fn[100]; @@ -550,16 +543,18 @@ writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, CopyStringOut(tc, fn, filename_addr, 100); filename = std::string(fn); + OutputStream *out; if (offset == 0) { // create a new file (truncate) - os = simout.create(filename, true); + 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.) - os = simout.openFile(simout.directory() + filename, - ios::in | ios::out | ios::binary); + 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); @@ -573,7 +568,7 @@ writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, if (os->fail() || os->bad()) panic("Error while doing writefile!\n"); - simout.close(os); + simout.close(out); delete [] buf; @@ -594,8 +589,15 @@ switchcpu(ThreadContext *tc) 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. // @@ -603,13 +605,18 @@ void workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid) { DPRINTF(PseudoInst, "PseudoInst::workbegin(%i, %i)\n", workid, threadid); - tc->getCpuPtr()->workItemBegin(); 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 @@ -653,7 +660,7 @@ 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. // @@ -661,12 +668,17 @@ void workend(ThreadContext *tc, uint64_t workid, uint64_t threadid) { DPRINTF(PseudoInst, "PseudoInst::workend(%i, %i)\n", workid, threadid); - tc->getCpuPtr()->workItemEnd(); 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