/*
- * Copyright (c) 2012-2014 ARM Limited
+ * Copyright (c) 2012-2014, 2017 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* 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: Andrew Bardsley
*/
-#include "arch/utility.hh"
#include "cpu/minor/cpu.hh"
+
+#include "arch/utility.hh"
#include "cpu/minor/dyn_inst.hh"
#include "cpu/minor/fetch1.hh"
#include "cpu/minor/pipeline.hh"
#include "debug/MinorCPU.hh"
#include "debug/Quiesce.hh"
-MinorCPU::MinorCPU(MinorCPUParams *params) :
- BaseCPU(params)
+MinorCPU::MinorCPU(const MinorCPUParams ¶ms) :
+ BaseCPU(params),
+ threadPolicy(params.threadPolicy)
{
/* This is only written for one thread at the moment */
Minor::MinorThread *thread;
- if (FullSystem) {
- thread = new Minor::MinorThread(this, 0, params->system, params->itb,
- params->dtb, params->isa[0]);
- } else {
- /* thread_id 0 */
- thread = new Minor::MinorThread(this, 0, params->system,
- params->workload[0], params->itb, params->dtb, params->isa[0]);
- }
-
- threads.push_back(thread);
+ for (ThreadID i = 0; i < numThreads; i++) {
+ if (FullSystem) {
+ thread = new Minor::MinorThread(this, i, params.system,
+ params.mmu, params.isa[i]);
+ thread->setStatus(ThreadContext::Halted);
+ } else {
+ thread = new Minor::MinorThread(this, i, params.system,
+ params.workload[i], params.mmu,
+ params.isa[i]);
+ }
- thread->setStatus(ThreadContext::Halted);
+ threads.push_back(thread);
+ ThreadContext *tc = thread->getTC();
+ threadContexts.push_back(tc);
+ }
- ThreadContext *tc = thread->getTC();
- if (params->checker) {
+ if (params.checker) {
fatal("The Minor model doesn't support checking (yet)\n");
}
- threadContexts.push_back(tc);
-
Minor::MinorDynInst::init();
- pipeline = new Minor::Pipeline(*this, *params);
+ pipeline = new Minor::Pipeline(*this, params);
activityRecorder = pipeline->getActivityRecorder();
}
{
BaseCPU::init();
- if (!params()->switched_out &&
+ if (!params().switched_out &&
system->getMemoryMode() != Enums::timing)
{
fatal("The Minor CPU requires the memory system to be in "
tc->initMemProxies(tc);
}
-
- /* Initialise CPUs (== threads in the ISA) */
- if (FullSystem && !params()->switched_out) {
- for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
- {
- ThreadContext *tc = getContext(thread_id);
-
- /* Initialize CPU, including PC */
- TheISA::initCPU(tc, cpuId());
- }
- }
}
/** Stats interface from SimObject (by way of BaseCPU) */
void
MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
{
- if (thread_id != 0)
- fatal("Trying to load more than one thread into a MinorCPU\n");
-
threads[thread_id]->unserialize(cp);
}
BaseCPU::unserialize(cp);
}
-Addr
-MinorCPU::dbg_vtophys(Addr addr)
-{
- /* Note that this gives you the translation for thread 0 */
- panic("No implementation for vtophy\n");
-
- return 0;
-}
-
void
-MinorCPU::wakeup()
+MinorCPU::wakeup(ThreadID tid)
{
- DPRINTF(Drain, "MinorCPU wakeup\n");
+ DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
+ assert(tid < numThreads);
- for (auto i = threads.begin(); i != threads.end(); i ++) {
- if ((*i)->status() == ThreadContext::Suspended)
- (*i)->activate();
+ if (threads[tid]->status() == ThreadContext::Suspended) {
+ threads[tid]->activate();
}
-
- DPRINTF(Drain,"Suspended Processor awoke\n");
}
void
BaseCPU::startup();
- for (auto i = threads.begin(); i != threads.end(); i ++)
- (*i)->startup();
-
- /* Workaround cases in SE mode where a thread is activated with an
- * incorrect PC that is updated after the call to activate. This
- * causes problems for Minor since it instantiates a virtual
- * branch instruction when activateContext() is called which ends
- * up pointing to an illegal address. */
- if (threads[0]->status() == ThreadContext::Active)
- activateContext(0);
+ for (ThreadID tid = 0; tid < numThreads; tid++)
+ pipeline->wakeupFetch(tid);
}
DrainState
MinorCPU::drain()
{
+ // Deschedule any power gating event (if any)
+ deschedulePowerGatingEvent();
+
+ if (switchedOut()) {
+ DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
+ return DrainState::Drained;
+ }
+
DPRINTF(Drain, "MinorCPU drain\n");
/* Need to suspend all threads and wait for Execute to idle.
void
MinorCPU::drainResume()
{
+ /* When taking over from another cpu make sure lastStopped
+ * is reset since it might have not been defined previously
+ * and might lead to a stats corruption */
+ pipeline->resetLastStopped();
+
if (switchedOut()) {
DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
return;
"'timing' mode.\n");
}
- wakeup();
+ for (ThreadID tid = 0; tid < numThreads; tid++){
+ wakeup(tid);
+ }
+
pipeline->drainResume();
+
+ // Reschedule any power gating event (if any)
+ schedulePowerGatingEvent();
}
void
DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
BaseCPU::takeOverFrom(old_cpu);
-
- /* Don't think I need to do anything here */
}
void
MinorCPU::activateContext(ThreadID thread_id)
{
- DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
+ DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id);
/* Do some cycle accounting. lastStopped is reset to stop the
* wakeup call on the pipeline from adding the quiesce period
/* Wake up the thread, wakeup the pipeline tick */
threads[thread_id]->activate();
wakeupOnEvent(Minor::Pipeline::CPUStageId);
- pipeline->wakeupFetch();
+ pipeline->wakeupFetch(thread_id);
+
+ BaseCPU::activateContext(thread_id);
}
void
DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
threads[thread_id]->suspend();
+
+ BaseCPU::suspendContext(thread_id);
}
void
}
MinorCPU *
-MinorCPUParams::create()
+MinorCPUParams::create() const
{
- numThreads = 1;
- if (!FullSystem && workload.size() != 1)
- panic("only one workload allowed");
- return new MinorCPU(this);
+ return new MinorCPU(*this);
}
-MasterPort &MinorCPU::getInstPort()
+Port &
+MinorCPU::getInstPort()
{
return pipeline->getInstPort();
}
-MasterPort &MinorCPU::getDataPort()
+Port &
+MinorCPU::getDataPort()
{
return pipeline->getDataPort();
}