cpu.cc revision 11567:560d7fbbddd1
1/*
2 * Copyright (c) 2012-2014 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 "arch/utility.hh"
41#include "cpu/minor/cpu.hh"
42#include "cpu/minor/dyn_inst.hh"
43#include "cpu/minor/fetch1.hh"
44#include "cpu/minor/pipeline.hh"
45#include "debug/Drain.hh"
46#include "debug/MinorCPU.hh"
47#include "debug/Quiesce.hh"
48
49MinorCPU::MinorCPU(MinorCPUParams *params) :
50    BaseCPU(params),
51    threadPolicy(params->threadPolicy)
52{
53    /* This is only written for one thread at the moment */
54    Minor::MinorThread *thread;
55
56    for (ThreadID i = 0; i < numThreads; i++) {
57        if (FullSystem) {
58            thread = new Minor::MinorThread(this, i, params->system,
59                    params->itb, params->dtb, params->isa[i]);
60            thread->setStatus(ThreadContext::Halted);
61        } else {
62            thread = new Minor::MinorThread(this, i, params->system,
63                    params->workload[i], params->itb, params->dtb,
64                    params->isa[i]);
65        }
66
67        threads.push_back(thread);
68        ThreadContext *tc = thread->getTC();
69        threadContexts.push_back(tc);
70    }
71
72
73    if (params->checker) {
74        fatal("The Minor model doesn't support checking (yet)\n");
75    }
76
77    Minor::MinorDynInst::init();
78
79    pipeline = new Minor::Pipeline(*this, *params);
80    activityRecorder = pipeline->getActivityRecorder();
81}
82
83MinorCPU::~MinorCPU()
84{
85    delete pipeline;
86
87    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
88        delete threads[thread_id];
89    }
90}
91
92void
93MinorCPU::init()
94{
95    BaseCPU::init();
96
97    if (!params()->switched_out &&
98        system->getMemoryMode() != Enums::timing)
99    {
100        fatal("The Minor CPU requires the memory system to be in "
101            "'timing' mode.\n");
102    }
103
104    /* Initialise the ThreadContext's memory proxies */
105    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
106        ThreadContext *tc = getContext(thread_id);
107
108        tc->initMemProxies(tc);
109    }
110
111    /* Initialise CPUs (== threads in the ISA) */
112    if (FullSystem && !params()->switched_out) {
113        for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
114        {
115            ThreadContext *tc = getContext(thread_id);
116
117            /* Initialize CPU, including PC */
118            TheISA::initCPU(tc, cpuId());
119        }
120    }
121}
122
123/** Stats interface from SimObject (by way of BaseCPU) */
124void
125MinorCPU::regStats()
126{
127    BaseCPU::regStats();
128    stats.regStats(name(), *this);
129    pipeline->regStats();
130}
131
132void
133MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
134{
135    threads[thread_id]->serialize(cp);
136}
137
138void
139MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
140{
141    threads[thread_id]->unserialize(cp);
142}
143
144void
145MinorCPU::serialize(CheckpointOut &cp) const
146{
147    pipeline->serialize(cp);
148    BaseCPU::serialize(cp);
149}
150
151void
152MinorCPU::unserialize(CheckpointIn &cp)
153{
154    pipeline->unserialize(cp);
155    BaseCPU::unserialize(cp);
156}
157
158Addr
159MinorCPU::dbg_vtophys(Addr addr)
160{
161    /* Note that this gives you the translation for thread 0 */
162    panic("No implementation for vtophy\n");
163
164    return 0;
165}
166
167void
168MinorCPU::wakeup(ThreadID tid)
169{
170    DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
171    assert(tid < numThreads);
172
173    if (threads[tid]->status() == ThreadContext::Suspended) {
174        threads[tid]->activate();
175    }
176}
177
178void
179MinorCPU::startup()
180{
181    DPRINTF(MinorCPU, "MinorCPU startup\n");
182
183    BaseCPU::startup();
184
185    for (auto i = threads.begin(); i != threads.end(); i ++)
186        (*i)->startup();
187
188    for (ThreadID tid = 0; tid < numThreads; tid++) {
189        threads[tid]->startup();
190        pipeline->wakeupFetch(tid);
191    }
192}
193
194DrainState
195MinorCPU::drain()
196{
197    if (switchedOut()) {
198        DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
199        return DrainState::Drained;
200    }
201
202    DPRINTF(Drain, "MinorCPU drain\n");
203
204    /* Need to suspend all threads and wait for Execute to idle.
205     * Tell Fetch1 not to fetch */
206    if (pipeline->drain()) {
207        DPRINTF(Drain, "MinorCPU drained\n");
208        return DrainState::Drained;
209    } else {
210        DPRINTF(Drain, "MinorCPU not finished draining\n");
211        return DrainState::Draining;
212    }
213}
214
215void
216MinorCPU::signalDrainDone()
217{
218    DPRINTF(Drain, "MinorCPU drain done\n");
219    Drainable::signalDrainDone();
220}
221
222void
223MinorCPU::drainResume()
224{
225    /* When taking over from another cpu make sure lastStopped
226     * is reset since it might have not been defined previously
227     * and might lead to a stats corruption */
228    pipeline->resetLastStopped();
229
230    if (switchedOut()) {
231        DPRINTF(Drain, "drainResume while switched out.  Ignoring\n");
232        return;
233    }
234
235    DPRINTF(Drain, "MinorCPU drainResume\n");
236
237    if (!system->isTimingMode()) {
238        fatal("The Minor CPU requires the memory system to be in "
239            "'timing' mode.\n");
240    }
241
242    for (ThreadID tid = 0; tid < numThreads; tid++)
243        wakeup(tid);
244
245    pipeline->drainResume();
246}
247
248void
249MinorCPU::memWriteback()
250{
251    DPRINTF(Drain, "MinorCPU memWriteback\n");
252}
253
254void
255MinorCPU::switchOut()
256{
257    DPRINTF(MinorCPU, "MinorCPU switchOut\n");
258
259    assert(!switchedOut());
260    BaseCPU::switchOut();
261
262    /* Check that the CPU is drained? */
263    activityRecorder->reset();
264}
265
266void
267MinorCPU::takeOverFrom(BaseCPU *old_cpu)
268{
269    DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
270
271    BaseCPU::takeOverFrom(old_cpu);
272}
273
274void
275MinorCPU::activateContext(ThreadID thread_id)
276{
277    DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id);
278
279    /* Do some cycle accounting.  lastStopped is reset to stop the
280     *  wakeup call on the pipeline from adding the quiesce period
281     *  to BaseCPU::numCycles */
282    stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
283    pipeline->resetLastStopped();
284
285    /* Wake up the thread, wakeup the pipeline tick */
286    threads[thread_id]->activate();
287    wakeupOnEvent(Minor::Pipeline::CPUStageId);
288    pipeline->wakeupFetch(thread_id);
289
290    BaseCPU::activateContext(thread_id);
291}
292
293void
294MinorCPU::suspendContext(ThreadID thread_id)
295{
296    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
297
298    threads[thread_id]->suspend();
299
300    BaseCPU::suspendContext(thread_id);
301}
302
303void
304MinorCPU::wakeupOnEvent(unsigned int stage_id)
305{
306    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
307
308    /* Mark that some activity has taken place and start the pipeline */
309    activityRecorder->activateStage(stage_id);
310    pipeline->start();
311}
312
313MinorCPU *
314MinorCPUParams::create()
315{
316    return new MinorCPU(this);
317}
318
319MasterPort &MinorCPU::getInstPort()
320{
321    return pipeline->getInstPort();
322}
323
324MasterPort &MinorCPU::getDataPort()
325{
326    return pipeline->getDataPort();
327}
328
329Counter
330MinorCPU::totalInsts() const
331{
332    Counter ret = 0;
333
334    for (auto i = threads.begin(); i != threads.end(); i ++)
335        ret += (*i)->numInst;
336
337    return ret;
338}
339
340Counter
341MinorCPU::totalOps() const
342{
343    Counter ret = 0;
344
345    for (auto i = threads.begin(); i != threads.end(); i ++)
346        ret += (*i)->numOp;
347
348    return ret;
349}
350