cpu.cc revision 13632:483aaa00c69c
1360SN/A/* 21458SN/A * Copyright (c) 2012-2014, 2017 ARM Limited 3360SN/A * All rights reserved 4360SN/A * 5360SN/A * The license below extends only to copyright in the software and shall 6360SN/A * not be construed as granting a license to any other intellectual 7360SN/A * property including but not limited to intellectual property relating 8360SN/A * to a hardware implementation of the functionality of the software 9360SN/A * licensed hereunder. You may use the software subject to the license 10360SN/A * terms below provided that you ensure that this notice is replicated 11360SN/A * unmodified and in its entirety in all distributions of the software, 12360SN/A * modified or unmodified, in source code or in binary form. 13360SN/A * 14360SN/A * Redistribution and use in source and binary forms, with or without 15360SN/A * modification, are permitted provided that the following conditions are 16360SN/A * met: redistributions of source code must retain the above copyright 17360SN/A * notice, this list of conditions and the following disclaimer; 18360SN/A * redistributions in binary form must reproduce the above copyright 19360SN/A * notice, this list of conditions and the following disclaimer in the 20360SN/A * documentation and/or other materials provided with the distribution; 21360SN/A * neither the name of the copyright holders nor the names of its 22360SN/A * contributors may be used to endorse or promote products derived from 23360SN/A * this software without specific prior written permission. 24360SN/A * 25360SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292665Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31360SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321354SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331354SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34360SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352764Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362764Sstever@eecs.umich.edu * 372064SN/A * Authors: Andrew Bardsley 38360SN/A */ 39360SN/A 40360SN/A#include "cpu/minor/cpu.hh" 41360SN/A 42360SN/A#include "arch/utility.hh" 43360SN/A#include "cpu/minor/dyn_inst.hh" 441354SN/A#include "cpu/minor/fetch1.hh" 45360SN/A#include "cpu/minor/pipeline.hh" 461809SN/A#include "debug/Drain.hh" 471809SN/A#include "debug/MinorCPU.hh" 481809SN/A#include "debug/Quiesce.hh" 493113Sgblack@eecs.umich.edu 503113Sgblack@eecs.umich.eduMinorCPU::MinorCPU(MinorCPUParams *params) : 511999SN/A BaseCPU(params), 52360SN/A pipelineStartupEvent([this]{ wakeupPipeline(); }, name()), 533113Sgblack@eecs.umich.edu threadPolicy(params->threadPolicy) 542474SN/A{ 55360SN/A /* This is only written for one thread at the moment */ 562462SN/A Minor::MinorThread *thread; 571354SN/A 582474SN/A for (ThreadID i = 0; i < numThreads; i++) { 592680Sktlim@umich.edu if (FullSystem) { 602474SN/A thread = new Minor::MinorThread(this, i, params->system, 612474SN/A params->itb, params->dtb, params->isa[i]); 621354SN/A thread->setStatus(ThreadContext::Halted); 63360SN/A } else { 64360SN/A thread = new Minor::MinorThread(this, i, params->system, 65360SN/A params->workload[i], params->itb, params->dtb, 66360SN/A params->isa[i]); 67360SN/A } 68360SN/A 69360SN/A threads.push_back(thread); 70360SN/A ThreadContext *tc = thread->getTC(); 71378SN/A threadContexts.push_back(tc); 721450SN/A } 733114Sgblack@eecs.umich.edu 74360SN/A 75360SN/A if (params->checker) { 76360SN/A fatal("The Minor model doesn't support checking (yet)\n"); 77360SN/A } 78360SN/A 79360SN/A Minor::MinorDynInst::init(); 80360SN/A 81360SN/A pipeline = new Minor::Pipeline(*this, *params); 82360SN/A activityRecorder = pipeline->getActivityRecorder(); 832680Sktlim@umich.edu} 84360SN/A 85360SN/AMinorCPU::~MinorCPU() 86360SN/A{ 87360SN/A delete pipeline; 88360SN/A 89360SN/A for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 90360SN/A delete threads[thread_id]; 91360SN/A } 92360SN/A} 93360SN/A 94360SN/Avoid 953114Sgblack@eecs.umich.eduMinorCPU::init() 96360SN/A{ 97360SN/A BaseCPU::init(); 98360SN/A 99360SN/A if (!params()->switched_out && 100360SN/A system->getMemoryMode() != Enums::timing) 101360SN/A { 102360SN/A fatal("The Minor CPU requires the memory system to be in " 103360SN/A "'timing' mode.\n"); 104360SN/A } 105360SN/A 106360SN/A /* Initialise the ThreadContext's memory proxies */ 107360SN/A for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 108360SN/A ThreadContext *tc = getContext(thread_id); 109360SN/A 110360SN/A tc->initMemProxies(tc); 111360SN/A } 112360SN/A 113360SN/A /* Initialise CPUs (== threads in the ISA) */ 114360SN/A if (FullSystem && !params()->switched_out) { 115360SN/A for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) 116360SN/A { 1172400SN/A ThreadContext *tc = getContext(thread_id); 118360SN/A 1192461SN/A /* Initialize CPU, including PC */ 120360SN/A TheISA::initCPU(tc, cpuId()); 121360SN/A } 122360SN/A } 123360SN/A} 124360SN/A 125360SN/A/** Stats interface from SimObject (by way of BaseCPU) */ 1262400SN/Avoid 127360SN/AMinorCPU::regStats() 1282461SN/A{ 129360SN/A BaseCPU::regStats(); 130360SN/A stats.regStats(name(), *this); 131360SN/A pipeline->regStats(); 132360SN/A} 133360SN/A 134360SN/Avoid 135360SN/AMinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const 136360SN/A{ 137360SN/A threads[thread_id]->serialize(cp); 138360SN/A} 139360SN/A 140360SN/Avoid 141360SN/AMinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id) 142360SN/A{ 143360SN/A threads[thread_id]->unserialize(cp); 144360SN/A} 145360SN/A 146360SN/Avoid 147360SN/AMinorCPU::serialize(CheckpointOut &cp) const 148360SN/A{ 149360SN/A pipeline->serialize(cp); 150360SN/A BaseCPU::serialize(cp); 151360SN/A} 152360SN/A 153360SN/Avoid 154360SN/AMinorCPU::unserialize(CheckpointIn &cp) 155360SN/A{ 156360SN/A pipeline->unserialize(cp); 157360SN/A BaseCPU::unserialize(cp); 158360SN/A} 159360SN/A 160360SN/AAddr 161502SN/AMinorCPU::dbg_vtophys(Addr addr) 162360SN/A{ 163502SN/A /* Note that this gives you the translation for thread 0 */ 164360SN/A panic("No implementation for vtophy\n"); 165360SN/A 166360SN/A return 0; 167360SN/A} 168360SN/A 169360SN/Avoid 170360SN/AMinorCPU::wakeup(ThreadID tid) 171360SN/A{ 172360SN/A DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid); 173360SN/A assert(tid < numThreads); 174360SN/A 175378SN/A if (threads[tid]->status() == ThreadContext::Suspended) { 1761706SN/A threads[tid]->activate(); 1773114Sgblack@eecs.umich.edu } 178378SN/A} 179378SN/A 180378SN/Avoid 181378SN/AMinorCPU::startup() 182378SN/A{ 1831706SN/A DPRINTF(MinorCPU, "MinorCPU startup\n"); 1843114Sgblack@eecs.umich.edu 185360SN/A BaseCPU::startup(); 186378SN/A 1871706SN/A for (ThreadID tid = 0; tid < numThreads; tid++) { 1883114Sgblack@eecs.umich.edu threads[tid]->startup(); 189378SN/A pipeline->wakeupFetch(tid); 190378SN/A } 1911706SN/A} 1923114Sgblack@eecs.umich.edu 193378SN/ADrainState 194378SN/AMinorCPU::drain() 1951706SN/A{ 1963114Sgblack@eecs.umich.edu // Deschedule any power gating event (if any) 197378SN/A deschedulePowerGatingEvent(); 198378SN/A 1991706SN/A if (switchedOut()) { 2003114Sgblack@eecs.umich.edu DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n"); 201378SN/A return DrainState::Drained; 202378SN/A } 2031706SN/A 2043114Sgblack@eecs.umich.edu DPRINTF(Drain, "MinorCPU drain\n"); 205378SN/A 206378SN/A /* Need to suspend all threads and wait for Execute to idle. 2071706SN/A * Tell Fetch1 not to fetch */ 2083114Sgblack@eecs.umich.edu if (pipeline->drain()) { 209378SN/A DPRINTF(Drain, "MinorCPU drained\n"); 210378SN/A return DrainState::Drained; 2111706SN/A } else { 2123114Sgblack@eecs.umich.edu DPRINTF(Drain, "MinorCPU not finished draining\n"); 213378SN/A return DrainState::Draining; 2144118Sgblack@eecs.umich.edu } 2154118Sgblack@eecs.umich.edu} 2164118Sgblack@eecs.umich.edu 2174118Sgblack@eecs.umich.eduvoid 218378SN/AMinorCPU::signalDrainDone() 2191706SN/A{ 2203114Sgblack@eecs.umich.edu DPRINTF(Drain, "MinorCPU drain done\n"); 221378SN/A Drainable::signalDrainDone(); 222378SN/A} 2231706SN/A 2243114Sgblack@eecs.umich.eduvoid 225360SN/AMinorCPU::drainResume() 226511SN/A{ 2271706SN/A /* When taking over from another cpu make sure lastStopped 2283114Sgblack@eecs.umich.edu * is reset since it might have not been defined previously 229511SN/A * and might lead to a stats corruption */ 230511SN/A pipeline->resetLastStopped(); 2311706SN/A 2323114Sgblack@eecs.umich.edu if (switchedOut()) { 2331706SN/A DPRINTF(Drain, "drainResume while switched out. Ignoring\n"); 2341706SN/A return; 2351706SN/A } 2361706SN/A 2373114Sgblack@eecs.umich.edu DPRINTF(Drain, "MinorCPU drainResume\n"); 2381706SN/A 2391706SN/A if (!system->isTimingMode()) { 2401706SN/A fatal("The Minor CPU requires the memory system to be in " 2411706SN/A "'timing' mode.\n"); 2423114Sgblack@eecs.umich.edu } 2431706SN/A 244511SN/A for (ThreadID tid = 0; tid < numThreads; tid++){ 2451999SN/A wakeup(tid); 2461999SN/A } 2473114Sgblack@eecs.umich.edu 2481999SN/A pipeline->drainResume(); 2491999SN/A 2501999SN/A // Reschedule any power gating event (if any) 2511999SN/A schedulePowerGatingEvent(); 2523114Sgblack@eecs.umich.edu} 2531999SN/A 2543079Sstever@eecs.umich.eduvoid 2553079Sstever@eecs.umich.eduMinorCPU::memWriteback() 2563114Sgblack@eecs.umich.edu{ 2573079Sstever@eecs.umich.edu DPRINTF(Drain, "MinorCPU memWriteback\n"); 2582093SN/A} 2592093SN/A 2603114Sgblack@eecs.umich.eduvoid 2612093SN/AMinorCPU::switchOut() 2622687Sksewell@umich.edu{ 2632687Sksewell@umich.edu DPRINTF(MinorCPU, "MinorCPU switchOut\n"); 2643114Sgblack@eecs.umich.edu 2652687Sksewell@umich.edu assert(!switchedOut()); 2662238SN/A BaseCPU::switchOut(); 2672238SN/A 2683114Sgblack@eecs.umich.edu /* Check that the CPU is drained? */ 2692238SN/A activityRecorder->reset(); 2702238SN/A} 2712238SN/A 2723114Sgblack@eecs.umich.eduvoid 2732238SN/AMinorCPU::takeOverFrom(BaseCPU *old_cpu) 2742238SN/A{ 2752238SN/A DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n"); 2763114Sgblack@eecs.umich.edu 2772238SN/A BaseCPU::takeOverFrom(old_cpu); 2782238SN/A} 2792238SN/A 2803114Sgblack@eecs.umich.eduvoid 2812238SN/AMinorCPU::activateContext(ThreadID thread_id) 2822238SN/A{ 2832238SN/A /* Remember to wake up this thread_id by scheduling the 2843114Sgblack@eecs.umich.edu * pipelineStartup event. 2852238SN/A * We can't wakeupFetch the thread right away because its context may 2862238SN/A * not have been fully initialized. For example, in the case of clone 2872238SN/A * syscall, this activateContext function is called in the middle of 2883114Sgblack@eecs.umich.edu * the syscall and before the new thread context is initialized. 2892238SN/A * If we start fetching right away, the new thread will fetch from an 2902238SN/A * invalid address (i.e., pc is not initialized yet), which could lead 2912238SN/A * to a page fault. Instead, we remember which threads to wake up and 2923114Sgblack@eecs.umich.edu * schedule an event to wake all them up after their contexts are 2932238SN/A * fully initialized */ 2942238SN/A readyThreads.push_back(thread_id); 2952238SN/A if (!pipelineStartupEvent.scheduled()) 2962238SN/A schedule(pipelineStartupEvent, clockEdge(Cycles(0))); 2972238SN/A} 2982238SN/A 2993114Sgblack@eecs.umich.eduvoid 3002238SN/AMinorCPU::wakeupPipeline() 3012238SN/A{ 3022238SN/A for (auto thread_id : readyThreads) { 3033114Sgblack@eecs.umich.edu DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id); 3042238SN/A 3052238SN/A /* Do some cycle accounting. lastStopped is reset to stop the 3062238SN/A * wakeup call on the pipeline from adding the quiesce period 3073114Sgblack@eecs.umich.edu * to BaseCPU::numCycles */ 3082238SN/A stats.quiesceCycles += pipeline->cyclesSinceLastStopped(); 3092238SN/A pipeline->resetLastStopped(); 3102238SN/A 3113114Sgblack@eecs.umich.edu /* Wake up the thread, wakeup the pipeline tick */ 3122238SN/A threads[thread_id]->activate(); 3132238SN/A wakeupOnEvent(Minor::Pipeline::CPUStageId); 3141354SN/A 3151354SN/A pipeline->wakeupFetch(thread_id); 3161354SN/A BaseCPU::activateContext(thread_id); 3171354SN/A } 3181354SN/A 3191354SN/A readyThreads.clear(); 3201354SN/A} 3211354SN/A 3221354SN/Avoid 3231354SN/AMinorCPU::suspendContext(ThreadID thread_id) 3241354SN/A{ 3251354SN/A DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id); 3261354SN/A 3271354SN/A threads[thread_id]->suspend(); 3281609SN/A 3291354SN/A BaseCPU::suspendContext(thread_id); 3301354SN/A} 3311354SN/A 3321354SN/Avoid 333360SN/AMinorCPU::wakeupOnEvent(unsigned int stage_id) 334360SN/A{ 335360SN/A DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id); 336360SN/A 337360SN/A /* Mark that some activity has taken place and start the pipeline */ 338360SN/A activityRecorder->activateStage(stage_id); 339360SN/A pipeline->start(); 3403113Sgblack@eecs.umich.edu} 3413113Sgblack@eecs.umich.edu 3423113Sgblack@eecs.umich.eduMinorCPU * 3433113Sgblack@eecs.umich.eduMinorCPUParams::create() 3443113Sgblack@eecs.umich.edu{ 3453113Sgblack@eecs.umich.edu return new MinorCPU(this); 3463113Sgblack@eecs.umich.edu} 3473113Sgblack@eecs.umich.edu 3483113Sgblack@eecs.umich.eduMasterPort &MinorCPU::getInstPort() 3493113Sgblack@eecs.umich.edu{ 3503113Sgblack@eecs.umich.edu return pipeline->getInstPort(); 3513113Sgblack@eecs.umich.edu} 3523113Sgblack@eecs.umich.edu 3533113Sgblack@eecs.umich.eduMasterPort &MinorCPU::getDataPort() 3543113Sgblack@eecs.umich.edu{ 3553113Sgblack@eecs.umich.edu return pipeline->getDataPort(); 3564189Sgblack@eecs.umich.edu} 3574189Sgblack@eecs.umich.edu 3583113Sgblack@eecs.umich.eduCounter 3593113Sgblack@eecs.umich.eduMinorCPU::totalInsts() const 3603113Sgblack@eecs.umich.edu{ 3613113Sgblack@eecs.umich.edu Counter ret = 0; 3623113Sgblack@eecs.umich.edu 3633113Sgblack@eecs.umich.edu for (auto i = threads.begin(); i != threads.end(); i ++) 3643113Sgblack@eecs.umich.edu ret += (*i)->numInst; 3653277Sgblack@eecs.umich.edu 3663277Sgblack@eecs.umich.edu return ret; 3673277Sgblack@eecs.umich.edu} 3683277Sgblack@eecs.umich.edu 3693277Sgblack@eecs.umich.eduCounter 3703277Sgblack@eecs.umich.eduMinorCPU::totalOps() const 3713277Sgblack@eecs.umich.edu{ 3723277Sgblack@eecs.umich.edu Counter ret = 0; 3733113Sgblack@eecs.umich.edu 3743113Sgblack@eecs.umich.edu for (auto i = threads.begin(); i != threads.end(); i ++) 3753113Sgblack@eecs.umich.edu ret += (*i)->numOp; 3763113Sgblack@eecs.umich.edu 3773113Sgblack@eecs.umich.edu return ret; 3783113Sgblack@eecs.umich.edu} 3793113Sgblack@eecs.umich.edu