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