diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 2b3dcc6a16..cfed0e9ee6 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -45,6 +45,7 @@ from m5.objects.ClockDomain import * from m5.objects.ClockedObject import ClockedObject from m5.objects.CPUTracers import ExeTracer from m5.objects.InstTracer import InstTracer +from m5.objects.IntPin import VectorIntSourcePin from m5.objects.Platform import Platform from m5.objects.ResetPort import ResetResponsePort from m5.objects.SubSystem import SubSystem @@ -155,6 +156,13 @@ class BaseCPU(ClockedObject): model_reset = ResetResponsePort("Generic reset for the CPU") + cpu_idle_pins = VectorIntSourcePin( + "This signal indicates the thread context of CPU is idle. Should be " + "equal to the numThreads or keep empty to ignore idle signals. If the " + "user specifies cpu_idle_pins less than numThreads. The ContextId " + "greater than the size of cpu_idle_pins will be ignored." + ) + tracer = Param.InstTracer(default_tracer, "Instruction tracer") icache_port = RequestPort("Instruction Port") diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 9e015f8c16..f8220cef31 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -191,6 +191,12 @@ BaseCPU::BaseCPU(const Params &p, bool is_checker) modelResetPort.onChange([this](const bool &new_val) { setReset(new_val); }); + + for (int i = 0; i < params().port_cpu_idle_pins_connection_count; i++) { + cpuIdlePins.emplace_back(new IntSourcePin( + csprintf("%s.cpu_idle_pins[%d]", name(), i), i, this)); + } + // create a stat group object for each thread on this core fetchStats.reserve(numThreads); executeStats.reserve(numThreads); @@ -463,6 +469,8 @@ BaseCPU::getPort(const std::string &if_name, PortID idx) return getInstPort(); else if (if_name == "model_reset") return modelResetPort; + else if (if_name == "cpu_idle_pins") + return *cpuIdlePins[idx]; else return ClockedObject::getPort(if_name, idx); } @@ -537,6 +545,11 @@ BaseCPU::activateContext(ThreadID thread_num) DPRINTF(Thread, "activate contextId %d\n", threadContexts[thread_num]->contextId()); + + if (thread_num < cpuIdlePins.size()) { + cpuIdlePins[thread_num]->lower(); + } + // Squash enter power gating event while cpu gets activated if (enterPwrGatingEvent.scheduled()) deschedule(enterPwrGatingEvent); @@ -551,6 +564,11 @@ BaseCPU::suspendContext(ThreadID thread_num) { DPRINTF(Thread, "suspend contextId %d\n", threadContexts[thread_num]->contextId()); + + if (thread_num < cpuIdlePins.size()) { + cpuIdlePins[thread_num]->raise(); + } + // Check if all threads are suspended for (auto t : threadContexts) { if (t->status() != ThreadContext::Suspended) { diff --git a/src/cpu/base.hh b/src/cpu/base.hh index a6c80dadbe..0be0eda344 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -48,6 +48,7 @@ #include "arch/generic/interrupts.hh" #include "base/statistics.hh" #include "debug/Mwait.hh" +#include "dev/intpin.hh" #include "mem/htm.hh" #include "mem/port_proxy.hh" #include "sim/clocked_object.hh" @@ -259,6 +260,8 @@ class BaseCPU : public ClockedObject protected: std::vector threadContexts; + std::vector>> cpuIdlePins; + trace::InstTracer * tracer; public: