cpu.cc revision 10945:369861e3d5af
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    /* CPU state setup, activate initial context */
193    activateContext(0);
194}
195
196DrainState
197MinorCPU::drain()
198{
199    DPRINTF(Drain, "MinorCPU drain\n");
200
201    /* Need to suspend all threads and wait for Execute to idle.
202     * Tell Fetch1 not to fetch */
203    if (pipeline->drain()) {
204        DPRINTF(Drain, "MinorCPU drained\n");
205        return DrainState::Drained;
206    } else {
207        DPRINTF(Drain, "MinorCPU not finished draining\n");
208        return DrainState::Draining;
209    }
210}
211
212void
213MinorCPU::signalDrainDone()
214{
215    DPRINTF(Drain, "MinorCPU drain done\n");
216    Drainable::signalDrainDone();
217}
218
219void
220MinorCPU::drainResume()
221{
222    if (switchedOut()) {
223        DPRINTF(Drain, "drainResume while switched out.  Ignoring\n");
224        return;
225    }
226
227    DPRINTF(Drain, "MinorCPU drainResume\n");
228
229    if (!system->isTimingMode()) {
230        fatal("The Minor CPU requires the memory system to be in "
231            "'timing' mode.\n");
232    }
233
234    wakeup();
235    pipeline->drainResume();
236}
237
238void
239MinorCPU::memWriteback()
240{
241    DPRINTF(Drain, "MinorCPU memWriteback\n");
242}
243
244void
245MinorCPU::switchOut()
246{
247    DPRINTF(MinorCPU, "MinorCPU switchOut\n");
248
249    assert(!switchedOut());
250    BaseCPU::switchOut();
251
252    /* Check that the CPU is drained? */
253    activityRecorder->reset();
254}
255
256void
257MinorCPU::takeOverFrom(BaseCPU *old_cpu)
258{
259    DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
260
261    BaseCPU::takeOverFrom(old_cpu);
262
263    /* Don't think I need to do anything here */
264}
265
266void
267MinorCPU::activateContext(ThreadID thread_id)
268{
269    DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
270
271    /* Do some cycle accounting.  lastStopped is reset to stop the
272     *  wakeup call on the pipeline from adding the quiesce period
273     *  to BaseCPU::numCycles */
274    stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
275    pipeline->resetLastStopped();
276
277    /* Wake up the thread, wakeup the pipeline tick */
278    threads[thread_id]->activate();
279    wakeupOnEvent(Minor::Pipeline::CPUStageId);
280    pipeline->wakeupFetch();
281}
282
283void
284MinorCPU::suspendContext(ThreadID thread_id)
285{
286    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
287
288    threads[thread_id]->suspend();
289}
290
291void
292MinorCPU::wakeupOnEvent(unsigned int stage_id)
293{
294    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
295
296    /* Mark that some activity has taken place and start the pipeline */
297    activityRecorder->activateStage(stage_id);
298    pipeline->start();
299}
300
301MinorCPU *
302MinorCPUParams::create()
303{
304    numThreads = 1;
305    if (!FullSystem && workload.size() != 1)
306        panic("only one workload allowed");
307    return new MinorCPU(this);
308}
309
310MasterPort &MinorCPU::getInstPort()
311{
312    return pipeline->getInstPort();
313}
314
315MasterPort &MinorCPU::getDataPort()
316{
317    return pipeline->getDataPort();
318}
319
320Counter
321MinorCPU::totalInsts() const
322{
323    Counter ret = 0;
324
325    for (auto i = threads.begin(); i != threads.end(); i ++)
326        ret += (*i)->numInst;
327
328    return ret;
329}
330
331Counter
332MinorCPU::totalOps() const
333{
334    Counter ret = 0;
335
336    for (auto i = threads.begin(); i != threads.end(); i ++)
337        ret += (*i)->numOp;
338
339    return ret;
340}
341