summaryrefslogtreecommitdiff
path: root/src/cpu/minor/cpu.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/minor/cpu.cc')
-rw-r--r--src/cpu/minor/cpu.cc362
1 files changed, 362 insertions, 0 deletions
diff --git a/src/cpu/minor/cpu.cc b/src/cpu/minor/cpu.cc
new file mode 100644
index 000000000..f7007f6ff
--- /dev/null
+++ b/src/cpu/minor/cpu.cc
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2012-2014 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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * 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 "cpu/minor/dyn_inst.hh"
+#include "cpu/minor/fetch1.hh"
+#include "cpu/minor/pipeline.hh"
+#include "debug/Drain.hh"
+#include "debug/MinorCPU.hh"
+#include "debug/Quiesce.hh"
+
+MinorCPU::MinorCPU(MinorCPUParams *params) :
+ BaseCPU(params),
+ drainManager(NULL)
+{
+ /* 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);
+ threadActivateEvents.push_back(new ThreadActivateEvent(*this, 0));
+
+ thread->setStatus(ThreadContext::Halted);
+
+ ThreadContext *tc = thread->getTC();
+
+ 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);
+ activityRecorder = pipeline->getActivityRecorder();
+}
+
+MinorCPU::~MinorCPU()
+{
+ delete pipeline;
+
+ for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
+ delete threads[thread_id];
+ delete threadActivateEvents[thread_id];
+ }
+}
+
+void
+MinorCPU::init()
+{
+ BaseCPU::init();
+
+ if (!params()->switched_out &&
+ system->getMemoryMode() != Enums::timing)
+ {
+ fatal("The Minor CPU requires the memory system to be in "
+ "'timing' mode.\n");
+ }
+
+ /* Initialise the ThreadContext's memory proxies */
+ for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
+ ThreadContext *tc = getContext(thread_id);
+
+ 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::regStats()
+{
+ BaseCPU::regStats();
+ stats.regStats(name(), *this);
+ pipeline->regStats();
+}
+
+void
+MinorCPU::serializeThread(std::ostream &os, ThreadID thread_id)
+{
+ threads[thread_id]->serialize(os);
+}
+
+void
+MinorCPU::unserializeThread(Checkpoint *cp, const std::string &section,
+ ThreadID thread_id)
+{
+ if (thread_id != 0)
+ fatal("Trying to load more than one thread into a MinorCPU\n");
+
+ threads[thread_id]->unserialize(cp, section);
+}
+
+void
+MinorCPU::serialize(std::ostream &os)
+{
+ pipeline->serialize(os);
+ BaseCPU::serialize(os);
+}
+
+void
+MinorCPU::unserialize(Checkpoint *cp, const std::string &section)
+{
+ pipeline->unserialize(cp, section);
+ BaseCPU::unserialize(cp, section);
+}
+
+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()
+{
+ DPRINTF(Drain, "MinorCPU wakeup\n");
+
+ for (auto i = threads.begin(); i != threads.end(); i ++) {
+ if ((*i)->status() == ThreadContext::Suspended)
+ (*i)->activate();
+ }
+
+ DPRINTF(Drain,"Suspended Processor awoke\n");
+}
+
+void
+MinorCPU::startup()
+{
+ DPRINTF(MinorCPU, "MinorCPU startup\n");
+
+ BaseCPU::startup();
+
+ for (auto i = threads.begin(); i != threads.end(); i ++)
+ (*i)->startup();
+}
+
+unsigned int
+MinorCPU::drain(DrainManager *drain_manager)
+{
+ DPRINTF(Drain, "MinorCPU drain\n");
+
+ drainManager = drain_manager;
+
+ /* Need to suspend all threads and wait for Execute to idle.
+ * Tell Fetch1 not to fetch */
+ unsigned int ret = pipeline->drain(drain_manager);
+
+ if (ret == 0)
+ DPRINTF(Drain, "MinorCPU drained\n");
+ else
+ DPRINTF(Drain, "MinorCPU not finished draining\n");
+
+ return ret;
+}
+
+void
+MinorCPU::signalDrainDone()
+{
+ DPRINTF(Drain, "MinorCPU drain done\n");
+ setDrainState(Drainable::Drained);
+ drainManager->signalDrainDone();
+ drainManager = NULL;
+}
+
+void
+MinorCPU::drainResume()
+{
+ assert(getDrainState() == Drainable::Drained ||
+ getDrainState() == Drainable::Running);
+
+ if (switchedOut()) {
+ DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
+ return;
+ }
+
+ DPRINTF(Drain, "MinorCPU drainResume\n");
+
+ if (!system->isTimingMode()) {
+ fatal("The Minor CPU requires the memory system to be in "
+ "'timing' mode.\n");
+ }
+
+ wakeup();
+ pipeline->drainResume();
+
+ setDrainState(Drainable::Running);
+}
+
+void
+MinorCPU::memWriteback()
+{
+ DPRINTF(Drain, "MinorCPU memWriteback\n");
+}
+
+void
+MinorCPU::switchOut()
+{
+ DPRINTF(MinorCPU, "MinorCPU switchOut\n");
+
+ assert(!switchedOut());
+ BaseCPU::switchOut();
+
+ /* Check that the CPU is drained? */
+ activityRecorder->reset();
+}
+
+void
+MinorCPU::takeOverFrom(BaseCPU *old_cpu)
+{
+ DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
+
+ BaseCPU::takeOverFrom(old_cpu);
+
+ /* Don't think I need to do anything here */
+}
+
+void
+MinorCPU::activateContext(ThreadID thread_id, Cycles delay)
+{
+ DPRINTF(MinorCPU, "ActivateContext thread: %d delay: %d\n",
+ thread_id, delay);
+
+ if (!threadActivateEvents[thread_id]->scheduled()) {
+ schedule(threadActivateEvents[thread_id], clockEdge(delay));
+ }
+}
+
+void
+MinorCPU::ThreadActivateEvent::process()
+{
+ DPRINTFS(MinorCPU, (&cpu), "Activating 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
+ * to BaseCPU::numCycles */
+ cpu.stats.quiesceCycles += cpu.pipeline->cyclesSinceLastStopped();
+ cpu.pipeline->resetLastStopped();
+
+ /* Wake up the thread, wakeup the pipeline tick */
+ cpu.threads[thread_id]->activate();
+ cpu.wakeupOnEvent(Minor::Pipeline::CPUStageId);
+ cpu.pipeline->wakeupFetch();
+}
+
+void
+MinorCPU::suspendContext(ThreadID thread_id)
+{
+ DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
+
+ threads[thread_id]->suspend();
+}
+
+void
+MinorCPU::wakeupOnEvent(unsigned int stage_id)
+{
+ DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
+
+ /* Mark that some activity has taken place and start the pipeline */
+ activityRecorder->activateStage(stage_id);
+ pipeline->start();
+}
+
+MinorCPU *
+MinorCPUParams::create()
+{
+ numThreads = 1;
+ if (!FullSystem && workload.size() != 1)
+ panic("only one workload allowed");
+ return new MinorCPU(this);
+}
+
+MasterPort &MinorCPU::getInstPort()
+{
+ return pipeline->getInstPort();
+}
+
+MasterPort &MinorCPU::getDataPort()
+{
+ return pipeline->getDataPort();
+}
+
+Counter
+MinorCPU::totalInsts() const
+{
+ Counter ret = 0;
+
+ for (auto i = threads.begin(); i != threads.end(); i ++)
+ ret += (*i)->numInst;
+
+ return ret;
+}
+
+Counter
+MinorCPU::totalOps() const
+{
+ Counter ret = 0;
+
+ for (auto i = threads.begin(); i != threads.end(); i ++)
+ ret += (*i)->numOp;
+
+ return ret;
+}