cpu.cc revision 13632:483aaa00c69c
1/*
2 * Copyright (c) 2012-2014, 2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andrew Bardsley
38 */
39
40#include "cpu/minor/cpu.hh"
41
42#include "arch/utility.hh"
43#include "cpu/minor/dyn_inst.hh"
44#include "cpu/minor/fetch1.hh"
45#include "cpu/minor/pipeline.hh"
46#include "debug/Drain.hh"
47#include "debug/MinorCPU.hh"
48#include "debug/Quiesce.hh"
49
50MinorCPU::MinorCPU(MinorCPUParams *params) :
51    BaseCPU(params),
52    pipelineStartupEvent([this]{ wakeupPipeline(); }, name()),
53    threadPolicy(params->threadPolicy)
54{
55    /* This is only written for one thread at the moment */
56    Minor::MinorThread *thread;
57
58    for (ThreadID i = 0; i < numThreads; i++) {
59        if (FullSystem) {
60            thread = new Minor::MinorThread(this, i, params->system,
61                    params->itb, params->dtb, params->isa[i]);
62            thread->setStatus(ThreadContext::Halted);
63        } else {
64            thread = new Minor::MinorThread(this, i, params->system,
65                    params->workload[i], params->itb, params->dtb,
66                    params->isa[i]);
67        }
68
69        threads.push_back(thread);
70        ThreadContext *tc = thread->getTC();
71        threadContexts.push_back(tc);
72    }
73
74
75    if (params->checker) {
76        fatal("The Minor model doesn't support checking (yet)\n");
77    }
78
79    Minor::MinorDynInst::init();
80
81    pipeline = new Minor::Pipeline(*this, *params);
82    activityRecorder = pipeline->getActivityRecorder();
83}
84
85MinorCPU::~MinorCPU()
86{
87    delete pipeline;
88
89    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
90        delete threads[thread_id];
91    }
92}
93
94void
95MinorCPU::init()
96{
97    BaseCPU::init();
98
99    if (!params()->switched_out &&
100        system->getMemoryMode() != Enums::timing)
101    {
102        fatal("The Minor CPU requires the memory system to be in "
103            "'timing' mode.\n");
104    }
105
106    /* Initialise the ThreadContext's memory proxies */
107    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
108        ThreadContext *tc = getContext(thread_id);
109
110        tc->initMemProxies(tc);
111    }
112
113    /* Initialise CPUs (== threads in the ISA) */
114    if (FullSystem && !params()->switched_out) {
115        for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
116        {
117            ThreadContext *tc = getContext(thread_id);
118
119            /* Initialize CPU, including PC */
120            TheISA::initCPU(tc, cpuId());
121        }
122    }
123}
124
125/** Stats interface from SimObject (by way of BaseCPU) */
126void
127MinorCPU::regStats()
128{
129    BaseCPU::regStats();
130    stats.regStats(name(), *this);
131    pipeline->regStats();
132}
133
134void
135MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
136{
137    threads[thread_id]->serialize(cp);
138}
139
140void
141MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
142{
143    threads[thread_id]->unserialize(cp);
144}
145
146void
147MinorCPU::serialize(CheckpointOut &cp) const
148{
149    pipeline->serialize(cp);
150    BaseCPU::serialize(cp);
151}
152
153void
154MinorCPU::unserialize(CheckpointIn &cp)
155{
156    pipeline->unserialize(cp);
157    BaseCPU::unserialize(cp);
158}
159
160Addr
161MinorCPU::dbg_vtophys(Addr addr)
162{
163    /* Note that this gives you the translation for thread 0 */
164    panic("No implementation for vtophy\n");
165
166    return 0;
167}
168
169void
170MinorCPU::wakeup(ThreadID tid)
171{
172    DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
173    assert(tid < numThreads);
174
175    if (threads[tid]->status() == ThreadContext::Suspended) {
176        threads[tid]->activate();
177    }
178}
179
180void
181MinorCPU::startup()
182{
183    DPRINTF(MinorCPU, "MinorCPU startup\n");
184
185    BaseCPU::startup();
186
187    for (ThreadID tid = 0; tid < numThreads; tid++) {
188        threads[tid]->startup();
189        pipeline->wakeupFetch(tid);
190    }
191}
192
193DrainState
194MinorCPU::drain()
195{
196    // Deschedule any power gating event (if any)
197    deschedulePowerGatingEvent();
198
199    if (switchedOut()) {
200        DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
201        return DrainState::Drained;
202    }
203
204    DPRINTF(Drain, "MinorCPU drain\n");
205
206    /* Need to suspend all threads and wait for Execute to idle.
207     * Tell Fetch1 not to fetch */
208    if (pipeline->drain()) {
209        DPRINTF(Drain, "MinorCPU drained\n");
210        return DrainState::Drained;
211    } else {
212        DPRINTF(Drain, "MinorCPU not finished draining\n");
213        return DrainState::Draining;
214    }
215}
216
217void
218MinorCPU::signalDrainDone()
219{
220    DPRINTF(Drain, "MinorCPU drain done\n");
221    Drainable::signalDrainDone();
222}
223
224void
225MinorCPU::drainResume()
226{
227    /* When taking over from another cpu make sure lastStopped
228     * is reset since it might have not been defined previously
229     * and might lead to a stats corruption */
230    pipeline->resetLastStopped();
231
232    if (switchedOut()) {
233        DPRINTF(Drain, "drainResume while switched out.  Ignoring\n");
234        return;
235    }
236
237    DPRINTF(Drain, "MinorCPU drainResume\n");
238
239    if (!system->isTimingMode()) {
240        fatal("The Minor CPU requires the memory system to be in "
241            "'timing' mode.\n");
242    }
243
244    for (ThreadID tid = 0; tid < numThreads; tid++){
245        wakeup(tid);
246    }
247
248    pipeline->drainResume();
249
250    // Reschedule any power gating event (if any)
251    schedulePowerGatingEvent();
252}
253
254void
255MinorCPU::memWriteback()
256{
257    DPRINTF(Drain, "MinorCPU memWriteback\n");
258}
259
260void
261MinorCPU::switchOut()
262{
263    DPRINTF(MinorCPU, "MinorCPU switchOut\n");
264
265    assert(!switchedOut());
266    BaseCPU::switchOut();
267
268    /* Check that the CPU is drained? */
269    activityRecorder->reset();
270}
271
272void
273MinorCPU::takeOverFrom(BaseCPU *old_cpu)
274{
275    DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
276
277    BaseCPU::takeOverFrom(old_cpu);
278}
279
280void
281MinorCPU::activateContext(ThreadID thread_id)
282{
283    /* Remember to wake up this thread_id by scheduling the
284     * pipelineStartup event.
285     * We can't wakeupFetch the thread right away because its context may
286     * not have been fully initialized. For example, in the case of clone
287     * syscall, this activateContext function is called in the middle of
288     * the syscall and before the new thread context is initialized.
289     * If we start fetching right away, the new thread will fetch from an
290     * invalid address (i.e., pc is not initialized yet), which could lead
291     * to a page fault. Instead, we remember which threads to wake up and
292     * schedule an event to wake all them up after their contexts are
293     * fully initialized */
294    readyThreads.push_back(thread_id);
295    if (!pipelineStartupEvent.scheduled())
296        schedule(pipelineStartupEvent, clockEdge(Cycles(0)));
297}
298
299void
300MinorCPU::wakeupPipeline()
301{
302    for (auto thread_id : readyThreads) {
303        DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id);
304
305        /* Do some cycle accounting.  lastStopped is reset to stop the
306         *  wakeup call on the pipeline from adding the quiesce period
307         *  to BaseCPU::numCycles */
308        stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
309        pipeline->resetLastStopped();
310
311        /* Wake up the thread, wakeup the pipeline tick */
312        threads[thread_id]->activate();
313        wakeupOnEvent(Minor::Pipeline::CPUStageId);
314
315        pipeline->wakeupFetch(thread_id);
316        BaseCPU::activateContext(thread_id);
317    }
318
319    readyThreads.clear();
320}
321
322void
323MinorCPU::suspendContext(ThreadID thread_id)
324{
325    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
326
327    threads[thread_id]->suspend();
328
329    BaseCPU::suspendContext(thread_id);
330}
331
332void
333MinorCPU::wakeupOnEvent(unsigned int stage_id)
334{
335    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
336
337    /* Mark that some activity has taken place and start the pipeline */
338    activityRecorder->activateStage(stage_id);
339    pipeline->start();
340}
341
342MinorCPU *
343MinorCPUParams::create()
344{
345    return new MinorCPU(this);
346}
347
348MasterPort &MinorCPU::getInstPort()
349{
350    return pipeline->getInstPort();
351}
352
353MasterPort &MinorCPU::getDataPort()
354{
355    return pipeline->getDataPort();
356}
357
358Counter
359MinorCPU::totalInsts() const
360{
361    Counter ret = 0;
362
363    for (auto i = threads.begin(); i != threads.end(); i ++)
364        ret += (*i)->numInst;
365
366    return ret;
367}
368
369Counter
370MinorCPU::totalOps() const
371{
372    Counter ret = 0;
373
374    for (auto i = threads.begin(); i != threads.end(); i ++)
375        ret += (*i)->numOp;
376
377    return ret;
378}
379