cpu.cc revision 11429:cf5af0cc3be4
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{
52    /* This is only written for one thread at the moment */
53    Minor::MinorThread *thread;
54
55    if (FullSystem) {
56        thread = new Minor::MinorThread(this, 0, params->system, params->itb,
57            params->dtb, params->isa[0]);
58    } else {
59        /* thread_id 0 */
60        thread = new Minor::MinorThread(this, 0, params->system,
61            params->workload[0], params->itb, params->dtb, params->isa[0]);
62    }
63
64    threads.push_back(thread);
65
66    thread->setStatus(ThreadContext::Halted);
67
68    ThreadContext *tc = thread->getTC();
69
70    if (params->checker) {
71        fatal("The Minor model doesn't support checking (yet)\n");
72    }
73
74    threadContexts.push_back(tc);
75
76    Minor::MinorDynInst::init();
77
78    pipeline = new Minor::Pipeline(*this, *params);
79    activityRecorder = pipeline->getActivityRecorder();
80}
81
82MinorCPU::~MinorCPU()
83{
84    delete pipeline;
85
86    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
87        delete threads[thread_id];
88    }
89}
90
91void
92MinorCPU::init()
93{
94    BaseCPU::init();
95
96    if (!params()->switched_out &&
97        system->getMemoryMode() != Enums::timing)
98    {
99        fatal("The Minor CPU requires the memory system to be in "
100            "'timing' mode.\n");
101    }
102
103    /* Initialise the ThreadContext's memory proxies */
104    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
105        ThreadContext *tc = getContext(thread_id);
106
107        tc->initMemProxies(tc);
108    }
109
110    /* Initialise CPUs (== threads in the ISA) */
111    if (FullSystem && !params()->switched_out) {
112        for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
113        {
114            ThreadContext *tc = getContext(thread_id);
115
116            /* Initialize CPU, including PC */
117            TheISA::initCPU(tc, cpuId());
118        }
119    }
120}
121
122/** Stats interface from SimObject (by way of BaseCPU) */
123void
124MinorCPU::regStats()
125{
126    BaseCPU::regStats();
127    stats.regStats(name(), *this);
128    pipeline->regStats();
129}
130
131void
132MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
133{
134    threads[thread_id]->serialize(cp);
135}
136
137void
138MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
139{
140    if (thread_id != 0)
141        fatal("Trying to load more than one thread into a MinorCPU\n");
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
174    if (threads[tid]->status() == ThreadContext::Suspended)
175        threads[tid]->activate();
176
177    DPRINTF(Drain,"Suspended Processor awoke\n");
178}
179
180void
181MinorCPU::startup()
182{
183    DPRINTF(MinorCPU, "MinorCPU startup\n");
184
185    BaseCPU::startup();
186
187    for (auto i = threads.begin(); i != threads.end(); i ++)
188        (*i)->startup();
189
190    /* Workaround cases in SE mode where a thread is activated with an
191     * incorrect PC that is updated after the call to activate. This
192     * causes problems for Minor since it instantiates a virtual
193     * branch instruction when activateContext() is called which ends
194     * up pointing to an illegal address.  */
195    if (threads[0]->status() == ThreadContext::Active)
196        activateContext(0);
197}
198
199DrainState
200MinorCPU::drain()
201{
202    if (switchedOut()) {
203        DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
204        return DrainState::Drained;
205    }
206
207    DPRINTF(Drain, "MinorCPU drain\n");
208
209    /* Need to suspend all threads and wait for Execute to idle.
210     * Tell Fetch1 not to fetch */
211    if (pipeline->drain()) {
212        DPRINTF(Drain, "MinorCPU drained\n");
213        return DrainState::Drained;
214    } else {
215        DPRINTF(Drain, "MinorCPU not finished draining\n");
216        return DrainState::Draining;
217    }
218}
219
220void
221MinorCPU::signalDrainDone()
222{
223    DPRINTF(Drain, "MinorCPU drain done\n");
224    Drainable::signalDrainDone();
225}
226
227void
228MinorCPU::drainResume()
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    pipeline->drainResume();
245}
246
247void
248MinorCPU::memWriteback()
249{
250    DPRINTF(Drain, "MinorCPU memWriteback\n");
251}
252
253void
254MinorCPU::switchOut()
255{
256    DPRINTF(MinorCPU, "MinorCPU switchOut\n");
257
258    assert(!switchedOut());
259    BaseCPU::switchOut();
260
261    /* Check that the CPU is drained? */
262    activityRecorder->reset();
263}
264
265void
266MinorCPU::takeOverFrom(BaseCPU *old_cpu)
267{
268    DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
269
270    BaseCPU::takeOverFrom(old_cpu);
271
272    /* Don't think I need to do anything here */
273}
274
275void
276MinorCPU::activateContext(ThreadID thread_id)
277{
278    DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
279
280    /* Do some cycle accounting.  lastStopped is reset to stop the
281     *  wakeup call on the pipeline from adding the quiesce period
282     *  to BaseCPU::numCycles */
283    stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
284    pipeline->resetLastStopped();
285
286    /* Wake up the thread, wakeup the pipeline tick */
287    threads[thread_id]->activate();
288    wakeupOnEvent(Minor::Pipeline::CPUStageId);
289    pipeline->wakeupFetch();
290}
291
292void
293MinorCPU::suspendContext(ThreadID thread_id)
294{
295    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
296
297    threads[thread_id]->suspend();
298}
299
300void
301MinorCPU::wakeupOnEvent(unsigned int stage_id)
302{
303    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
304
305    /* Mark that some activity has taken place and start the pipeline */
306    activityRecorder->activateStage(stage_id);
307    pipeline->start();
308}
309
310MinorCPU *
311MinorCPUParams::create()
312{
313    numThreads = 1;
314    if (!FullSystem && workload.size() != 1)
315        panic("only one workload allowed");
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