cpu.cc revision 10949:7fc527ab626a
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()
171{
172    DPRINTF(Drain, "MinorCPU wakeup\n");
173
174    for (auto i = threads.begin(); i != threads.end(); i ++) {
175        if ((*i)->status() == ThreadContext::Suspended)
176            (*i)->activate();
177    }
178
179    DPRINTF(Drain,"Suspended Processor awoke\n");
180}
181
182void
183MinorCPU::startup()
184{
185    DPRINTF(MinorCPU, "MinorCPU startup\n");
186
187    BaseCPU::startup();
188
189    for (auto i = threads.begin(); i != threads.end(); i ++)
190        (*i)->startup();
191
192    /* Workaround cases in SE mode where a thread is activated with an
193     * incorrect PC that is updated after the call to activate. This
194     * causes problems for Minor since it instantiates a virtual
195     * branch instruction when activateContext() is called which ends
196     * up pointing to an illegal address.  */
197    if (threads[0]->status() == ThreadContext::Active)
198        activateContext(0);
199}
200
201DrainState
202MinorCPU::drain()
203{
204    if (switchedOut()) {
205        DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
206        return DrainState::Drained;
207    }
208
209    DPRINTF(Drain, "MinorCPU drain\n");
210
211    /* Need to suspend all threads and wait for Execute to idle.
212     * Tell Fetch1 not to fetch */
213    if (pipeline->drain()) {
214        DPRINTF(Drain, "MinorCPU drained\n");
215        return DrainState::Drained;
216    } else {
217        DPRINTF(Drain, "MinorCPU not finished draining\n");
218        return DrainState::Draining;
219    }
220}
221
222void
223MinorCPU::signalDrainDone()
224{
225    DPRINTF(Drain, "MinorCPU drain done\n");
226    Drainable::signalDrainDone();
227}
228
229void
230MinorCPU::drainResume()
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    wakeup();
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    /* Don't think I need to do anything here */
274}
275
276void
277MinorCPU::activateContext(ThreadID thread_id)
278{
279    DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
280
281    /* Do some cycle accounting.  lastStopped is reset to stop the
282     *  wakeup call on the pipeline from adding the quiesce period
283     *  to BaseCPU::numCycles */
284    stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
285    pipeline->resetLastStopped();
286
287    /* Wake up the thread, wakeup the pipeline tick */
288    threads[thread_id]->activate();
289    wakeupOnEvent(Minor::Pipeline::CPUStageId);
290    pipeline->wakeupFetch();
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
301void
302MinorCPU::wakeupOnEvent(unsigned int stage_id)
303{
304    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
305
306    /* Mark that some activity has taken place and start the pipeline */
307    activityRecorder->activateStage(stage_id);
308    pipeline->start();
309}
310
311MinorCPU *
312MinorCPUParams::create()
313{
314    numThreads = 1;
315    if (!FullSystem && workload.size() != 1)
316        panic("only one workload allowed");
317    return new MinorCPU(this);
318}
319
320MasterPort &MinorCPU::getInstPort()
321{
322    return pipeline->getInstPort();
323}
324
325MasterPort &MinorCPU::getDataPort()
326{
327    return pipeline->getDataPort();
328}
329
330Counter
331MinorCPU::totalInsts() const
332{
333    Counter ret = 0;
334
335    for (auto i = threads.begin(); i != threads.end(); i ++)
336        ret += (*i)->numInst;
337
338    return ret;
339}
340
341Counter
342MinorCPU::totalOps() const
343{
344    Counter ret = 0;
345
346    for (auto i = threads.begin(); i != threads.end(); i ++)
347        ret += (*i)->numOp;
348
349    return ret;
350}
351