cpu.cc revision 10910:32f3d1c454ec
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    drainManager(NULL)
52{
53    /* This is only written for one thread at the moment */
54    Minor::MinorThread *thread;
55
56    if (FullSystem) {
57        thread = new Minor::MinorThread(this, 0, params->system, params->itb,
58            params->dtb, params->isa[0]);
59    } else {
60        /* thread_id 0 */
61        thread = new Minor::MinorThread(this, 0, params->system,
62            params->workload[0], params->itb, params->dtb, params->isa[0]);
63    }
64
65    threads.push_back(thread);
66
67    thread->setStatus(ThreadContext::Halted);
68
69    ThreadContext *tc = thread->getTC();
70
71    if (params->checker) {
72        fatal("The Minor model doesn't support checking (yet)\n");
73    }
74
75    threadContexts.push_back(tc);
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    if (thread_id != 0)
142        fatal("Trying to load more than one thread into a MinorCPU\n");
143
144    threads[thread_id]->unserialize(cp);
145}
146
147void
148MinorCPU::serialize(CheckpointOut &cp) const
149{
150    pipeline->serialize(cp);
151    BaseCPU::serialize(cp);
152}
153
154void
155MinorCPU::unserialize(CheckpointIn &cp)
156{
157    pipeline->unserialize(cp);
158    BaseCPU::unserialize(cp);
159}
160
161Addr
162MinorCPU::dbg_vtophys(Addr addr)
163{
164    /* Note that this gives you the translation for thread 0 */
165    panic("No implementation for vtophy\n");
166
167    return 0;
168}
169
170void
171MinorCPU::wakeup()
172{
173    DPRINTF(Drain, "MinorCPU wakeup\n");
174
175    for (auto i = threads.begin(); i != threads.end(); i ++) {
176        if ((*i)->status() == ThreadContext::Suspended)
177            (*i)->activate();
178    }
179
180    DPRINTF(Drain,"Suspended Processor awoke\n");
181}
182
183void
184MinorCPU::startup()
185{
186    DPRINTF(MinorCPU, "MinorCPU startup\n");
187
188    BaseCPU::startup();
189
190    for (auto i = threads.begin(); i != threads.end(); i ++)
191        (*i)->startup();
192
193    /* CPU state setup, activate initial context */
194    activateContext(0);
195}
196
197unsigned int
198MinorCPU::drain(DrainManager *drain_manager)
199{
200    DPRINTF(Drain, "MinorCPU drain\n");
201
202    drainManager = drain_manager;
203
204    /* Need to suspend all threads and wait for Execute to idle.
205     * Tell Fetch1 not to fetch */
206    unsigned int ret = pipeline->drain(drain_manager);
207
208    if (ret == 0)
209        DPRINTF(Drain, "MinorCPU drained\n");
210    else
211        DPRINTF(Drain, "MinorCPU not finished draining\n");
212
213    return ret;
214}
215
216void
217MinorCPU::signalDrainDone()
218{
219    DPRINTF(Drain, "MinorCPU drain done\n");
220    setDrainState(DrainState::Drained);
221    drainManager->signalDrainDone();
222    drainManager = NULL;
223}
224
225void
226MinorCPU::drainResume()
227{
228    assert(getDrainState() == DrainState::Drained ||
229        getDrainState() == DrainState::Running);
230
231    if (switchedOut()) {
232        DPRINTF(Drain, "drainResume while switched out.  Ignoring\n");
233        return;
234    }
235
236    DPRINTF(Drain, "MinorCPU drainResume\n");
237
238    if (!system->isTimingMode()) {
239        fatal("The Minor CPU requires the memory system to be in "
240            "'timing' mode.\n");
241    }
242
243    wakeup();
244    pipeline->drainResume();
245
246    setDrainState(DrainState::Running);
247}
248
249void
250MinorCPU::memWriteback()
251{
252    DPRINTF(Drain, "MinorCPU memWriteback\n");
253}
254
255void
256MinorCPU::switchOut()
257{
258    DPRINTF(MinorCPU, "MinorCPU switchOut\n");
259
260    assert(!switchedOut());
261    BaseCPU::switchOut();
262
263    /* Check that the CPU is drained? */
264    activityRecorder->reset();
265}
266
267void
268MinorCPU::takeOverFrom(BaseCPU *old_cpu)
269{
270    DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
271
272    BaseCPU::takeOverFrom(old_cpu);
273
274    /* Don't think I need to do anything here */
275}
276
277void
278MinorCPU::activateContext(ThreadID thread_id)
279{
280    DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
281
282    /* Do some cycle accounting.  lastStopped is reset to stop the
283     *  wakeup call on the pipeline from adding the quiesce period
284     *  to BaseCPU::numCycles */
285    stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
286    pipeline->resetLastStopped();
287
288    /* Wake up the thread, wakeup the pipeline tick */
289    threads[thread_id]->activate();
290    wakeupOnEvent(Minor::Pipeline::CPUStageId);
291    pipeline->wakeupFetch();
292}
293
294void
295MinorCPU::suspendContext(ThreadID thread_id)
296{
297    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
298
299    threads[thread_id]->suspend();
300}
301
302void
303MinorCPU::wakeupOnEvent(unsigned int stage_id)
304{
305    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
306
307    /* Mark that some activity has taken place and start the pipeline */
308    activityRecorder->activateStage(stage_id);
309    pipeline->start();
310}
311
312MinorCPU *
313MinorCPUParams::create()
314{
315    numThreads = 1;
316    if (!FullSystem && workload.size() != 1)
317        panic("only one workload allowed");
318    return new MinorCPU(this);
319}
320
321MasterPort &MinorCPU::getInstPort()
322{
323    return pipeline->getInstPort();
324}
325
326MasterPort &MinorCPU::getDataPort()
327{
328    return pipeline->getDataPort();
329}
330
331Counter
332MinorCPU::totalInsts() const
333{
334    Counter ret = 0;
335
336    for (auto i = threads.begin(); i != threads.end(); i ++)
337        ret += (*i)->numInst;
338
339    return ret;
340}
341
342Counter
343MinorCPU::totalOps() const
344{
345    Counter ret = 0;
346
347    for (auto i = threads.begin(); i != threads.end(); i ++)
348        ret += (*i)->numOp;
349
350    return ret;
351}
352