cpu.cc revision 10259:ebb376f73dd2
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    threadActivateEvents.push_back(new ThreadActivateEvent(*this, 0));
67
68    thread->setStatus(ThreadContext::Halted);
69
70    ThreadContext *tc = thread->getTC();
71
72    if (params->checker) {
73        fatal("The Minor model doesn't support checking (yet)\n");
74    }
75
76    threadContexts.push_back(tc);
77
78    Minor::MinorDynInst::init();
79
80    pipeline = new Minor::Pipeline(*this, *params);
81    activityRecorder = pipeline->getActivityRecorder();
82}
83
84MinorCPU::~MinorCPU()
85{
86    delete pipeline;
87
88    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
89        delete threads[thread_id];
90        delete threadActivateEvents[thread_id];
91    }
92}
93
94void
95MinorCPU::init()
96{
97    BaseCPU::init();
98
99    if (!params()->switched_out &&
100        system->getMemoryMode() != Enums::timing)
101    {
102        fatal("The Minor CPU requires the memory system to be in "
103            "'timing' mode.\n");
104    }
105
106    /* Initialise the ThreadContext's memory proxies */
107    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
108        ThreadContext *tc = getContext(thread_id);
109
110        tc->initMemProxies(tc);
111    }
112
113    /* Initialise CPUs (== threads in the ISA) */
114    if (FullSystem && !params()->switched_out) {
115        for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
116        {
117            ThreadContext *tc = getContext(thread_id);
118
119            /* Initialize CPU, including PC */
120            TheISA::initCPU(tc, cpuId());
121        }
122    }
123}
124
125/** Stats interface from SimObject (by way of BaseCPU) */
126void
127MinorCPU::regStats()
128{
129    BaseCPU::regStats();
130    stats.regStats(name(), *this);
131    pipeline->regStats();
132}
133
134void
135MinorCPU::serializeThread(std::ostream &os, ThreadID thread_id)
136{
137    threads[thread_id]->serialize(os);
138}
139
140void
141MinorCPU::unserializeThread(Checkpoint *cp, const std::string &section,
142    ThreadID thread_id)
143{
144    if (thread_id != 0)
145        fatal("Trying to load more than one thread into a MinorCPU\n");
146
147    threads[thread_id]->unserialize(cp, section);
148}
149
150void
151MinorCPU::serialize(std::ostream &os)
152{
153    pipeline->serialize(os);
154    BaseCPU::serialize(os);
155}
156
157void
158MinorCPU::unserialize(Checkpoint *cp, const std::string &section)
159{
160    pipeline->unserialize(cp, section);
161    BaseCPU::unserialize(cp, section);
162}
163
164Addr
165MinorCPU::dbg_vtophys(Addr addr)
166{
167    /* Note that this gives you the translation for thread 0 */
168    panic("No implementation for vtophy\n");
169
170    return 0;
171}
172
173void
174MinorCPU::wakeup()
175{
176    DPRINTF(Drain, "MinorCPU wakeup\n");
177
178    for (auto i = threads.begin(); i != threads.end(); i ++) {
179        if ((*i)->status() == ThreadContext::Suspended)
180            (*i)->activate();
181    }
182
183    DPRINTF(Drain,"Suspended Processor awoke\n");
184}
185
186void
187MinorCPU::startup()
188{
189    DPRINTF(MinorCPU, "MinorCPU startup\n");
190
191    BaseCPU::startup();
192
193    for (auto i = threads.begin(); i != threads.end(); i ++)
194        (*i)->startup();
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(Drainable::Drained);
221    drainManager->signalDrainDone();
222    drainManager = NULL;
223}
224
225void
226MinorCPU::drainResume()
227{
228    assert(getDrainState() == Drainable::Drained ||
229        getDrainState() == Drainable::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(Drainable::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, Cycles delay)
279{
280    DPRINTF(MinorCPU, "ActivateContext thread: %d delay: %d\n",
281        thread_id, delay);
282
283    if (!threadActivateEvents[thread_id]->scheduled()) {
284        schedule(threadActivateEvents[thread_id], clockEdge(delay));
285    }
286}
287
288void
289MinorCPU::ThreadActivateEvent::process()
290{
291    DPRINTFS(MinorCPU, (&cpu), "Activating thread: %d\n", thread_id);
292
293    /* Do some cycle accounting.  lastStopped is reset to stop the
294     *  wakeup call on the pipeline from adding the quiesce period
295     *  to BaseCPU::numCycles */
296    cpu.stats.quiesceCycles += cpu.pipeline->cyclesSinceLastStopped();
297    cpu.pipeline->resetLastStopped();
298
299    /* Wake up the thread, wakeup the pipeline tick */
300    cpu.threads[thread_id]->activate();
301    cpu.wakeupOnEvent(Minor::Pipeline::CPUStageId);
302    cpu.pipeline->wakeupFetch();
303}
304
305void
306MinorCPU::suspendContext(ThreadID thread_id)
307{
308    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
309
310    threads[thread_id]->suspend();
311}
312
313void
314MinorCPU::wakeupOnEvent(unsigned int stage_id)
315{
316    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
317
318    /* Mark that some activity has taken place and start the pipeline */
319    activityRecorder->activateStage(stage_id);
320    pipeline->start();
321}
322
323MinorCPU *
324MinorCPUParams::create()
325{
326    numThreads = 1;
327    if (!FullSystem && workload.size() != 1)
328        panic("only one workload allowed");
329    return new MinorCPU(this);
330}
331
332MasterPort &MinorCPU::getInstPort()
333{
334    return pipeline->getInstPort();
335}
336
337MasterPort &MinorCPU::getDataPort()
338{
339    return pipeline->getDataPort();
340}
341
342Counter
343MinorCPU::totalInsts() const
344{
345    Counter ret = 0;
346
347    for (auto i = threads.begin(); i != threads.end(); i ++)
348        ret += (*i)->numInst;
349
350    return ret;
351}
352
353Counter
354MinorCPU::totalOps() const
355{
356    Counter ret = 0;
357
358    for (auto i = threads.begin(); i != threads.end(); i ++)
359        ret += (*i)->numOp;
360
361    return ret;
362}
363