pwr: Low-power idle power state for idle CPUs
[gem5.git] / src / cpu / minor / cpu.cc
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
49 MinorCPU::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
82 MinorCPU::~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
91 void
92 MinorCPU::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) */
123 void
124 MinorCPU::regStats()
125 {
126 BaseCPU::regStats();
127 stats.regStats(name(), *this);
128 pipeline->regStats();
129 }
130
131 void
132 MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
133 {
134 threads[thread_id]->serialize(cp);
135 }
136
137 void
138 MinorCPU::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
146 void
147 MinorCPU::serialize(CheckpointOut &cp) const
148 {
149 pipeline->serialize(cp);
150 BaseCPU::serialize(cp);
151 }
152
153 void
154 MinorCPU::unserialize(CheckpointIn &cp)
155 {
156 pipeline->unserialize(cp);
157 BaseCPU::unserialize(cp);
158 }
159
160 Addr
161 MinorCPU::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
169 void
170 MinorCPU::wakeup(ThreadID tid)
171 {
172 DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
173
174 if (threads[tid]->status() == ThreadContext::Suspended)
175 threads[tid]->activate();
176
177 DPRINTF(Drain,"Suspended Processor awoke\n");
178 }
179
180 void
181 MinorCPU::startup()
182 {
183 DPRINTF(MinorCPU, "MinorCPU startup\n");
184
185 BaseCPU::startup();
186
187 for (auto i = threads.begin(); i != threads.end(); i ++)
188 (*i)->startup();
189
190 /* Workaround cases in SE mode where a thread is activated with an
191 * incorrect PC that is updated after the call to activate. This
192 * causes problems for Minor since it instantiates a virtual
193 * branch instruction when activateContext() is called which ends
194 * up pointing to an illegal address. */
195 if (threads[0]->status() == ThreadContext::Active)
196 activateContext(0);
197 }
198
199 DrainState
200 MinorCPU::drain()
201 {
202 if (switchedOut()) {
203 DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
204 return DrainState::Drained;
205 }
206
207 DPRINTF(Drain, "MinorCPU drain\n");
208
209 /* Need to suspend all threads and wait for Execute to idle.
210 * Tell Fetch1 not to fetch */
211 if (pipeline->drain()) {
212 DPRINTF(Drain, "MinorCPU drained\n");
213 return DrainState::Drained;
214 } else {
215 DPRINTF(Drain, "MinorCPU not finished draining\n");
216 return DrainState::Draining;
217 }
218 }
219
220 void
221 MinorCPU::signalDrainDone()
222 {
223 DPRINTF(Drain, "MinorCPU drain done\n");
224 Drainable::signalDrainDone();
225 }
226
227 void
228 MinorCPU::drainResume()
229 {
230 /* When taking over from another cpu make sure lastStopped
231 * is reset since it might have not been defined previously
232 * and might lead to a stats corruption */
233 pipeline->resetLastStopped();
234
235 if (switchedOut()) {
236 DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
237 return;
238 }
239
240 DPRINTF(Drain, "MinorCPU drainResume\n");
241
242 if (!system->isTimingMode()) {
243 fatal("The Minor CPU requires the memory system to be in "
244 "'timing' mode.\n");
245 }
246
247 for (ThreadID tid = 0; tid < numThreads; tid++)
248 wakeup(tid);
249 pipeline->drainResume();
250 }
251
252 void
253 MinorCPU::memWriteback()
254 {
255 DPRINTF(Drain, "MinorCPU memWriteback\n");
256 }
257
258 void
259 MinorCPU::switchOut()
260 {
261 DPRINTF(MinorCPU, "MinorCPU switchOut\n");
262
263 assert(!switchedOut());
264 BaseCPU::switchOut();
265
266 /* Check that the CPU is drained? */
267 activityRecorder->reset();
268 }
269
270 void
271 MinorCPU::takeOverFrom(BaseCPU *old_cpu)
272 {
273 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
274
275 BaseCPU::takeOverFrom(old_cpu);
276 }
277
278 void
279 MinorCPU::activateContext(ThreadID thread_id)
280 {
281 DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
282
283 /* Do some cycle accounting. lastStopped is reset to stop the
284 * wakeup call on the pipeline from adding the quiesce period
285 * to BaseCPU::numCycles */
286 stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
287 pipeline->resetLastStopped();
288
289 /* Wake up the thread, wakeup the pipeline tick */
290 threads[thread_id]->activate();
291 wakeupOnEvent(Minor::Pipeline::CPUStageId);
292 pipeline->wakeupFetch();
293
294 BaseCPU::activateContext(thread_id);
295 }
296
297 void
298 MinorCPU::suspendContext(ThreadID thread_id)
299 {
300 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
301
302 threads[thread_id]->suspend();
303
304 BaseCPU::suspendContext(thread_id);
305 }
306
307 void
308 MinorCPU::wakeupOnEvent(unsigned int stage_id)
309 {
310 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
311
312 /* Mark that some activity has taken place and start the pipeline */
313 activityRecorder->activateStage(stage_id);
314 pipeline->start();
315 }
316
317 MinorCPU *
318 MinorCPUParams::create()
319 {
320 numThreads = 1;
321 if (!FullSystem && workload.size() != 1)
322 panic("only one workload allowed");
323 return new MinorCPU(this);
324 }
325
326 MasterPort &MinorCPU::getInstPort()
327 {
328 return pipeline->getInstPort();
329 }
330
331 MasterPort &MinorCPU::getDataPort()
332 {
333 return pipeline->getDataPort();
334 }
335
336 Counter
337 MinorCPU::totalInsts() const
338 {
339 Counter ret = 0;
340
341 for (auto i = threads.begin(); i != threads.end(); i ++)
342 ret += (*i)->numInst;
343
344 return ret;
345 }
346
347 Counter
348 MinorCPU::totalOps() const
349 {
350 Counter ret = 0;
351
352 for (auto i = threads.begin(); i != threads.end(); i ++)
353 ret += (*i)->numOp;
354
355 return ret;
356 }