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