cpu: Turn the stage 2 ARM MMUs from params to children.
[gem5.git] / src / cpu / minor / cpu.cc
1 /*
2 * Copyright (c) 2012-2014, 2017 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 "cpu/minor/cpu.hh"
41
42 #include "arch/utility.hh"
43 #include "cpu/minor/dyn_inst.hh"
44 #include "cpu/minor/fetch1.hh"
45 #include "cpu/minor/pipeline.hh"
46 #include "debug/Drain.hh"
47 #include "debug/MinorCPU.hh"
48 #include "debug/Quiesce.hh"
49
50 MinorCPU::MinorCPU(MinorCPUParams *params) :
51 BaseCPU(params),
52 threadPolicy(params->threadPolicy)
53 {
54 /* This is only written for one thread at the moment */
55 Minor::MinorThread *thread;
56
57 for (ThreadID i = 0; i < numThreads; i++) {
58 if (FullSystem) {
59 thread = new Minor::MinorThread(this, i, params->system,
60 params->itb, params->dtb, params->isa[i]);
61 thread->setStatus(ThreadContext::Halted);
62 } else {
63 thread = new Minor::MinorThread(this, i, params->system,
64 params->workload[i], params->itb, params->dtb,
65 params->isa[i]);
66 }
67
68 threads.push_back(thread);
69 ThreadContext *tc = thread->getTC();
70 threadContexts.push_back(tc);
71 }
72
73
74 if (params->checker) {
75 fatal("The Minor model doesn't support checking (yet)\n");
76 }
77
78 Minor::MinorDynInst::init();
79
80 pipeline = new Minor::Pipeline(*this, *params);
81 activityRecorder = pipeline->getActivityRecorder();
82 }
83
84 MinorCPU::~MinorCPU()
85 {
86 delete pipeline;
87
88 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
89 delete threads[thread_id];
90 }
91 }
92
93 void
94 MinorCPU::init()
95 {
96 BaseCPU::init();
97
98 if (!params()->switched_out &&
99 system->getMemoryMode() != Enums::timing)
100 {
101 fatal("The Minor CPU requires the memory system to be in "
102 "'timing' mode.\n");
103 }
104
105 /* Initialise the ThreadContext's memory proxies */
106 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
107 ThreadContext *tc = getContext(thread_id);
108
109 tc->initMemProxies(tc);
110 }
111
112 /* Initialise CPUs (== threads in the ISA) */
113 if (FullSystem && !params()->switched_out) {
114 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
115 {
116 ThreadContext *tc = getContext(thread_id);
117
118 /* Initialize CPU, including PC */
119 TheISA::initCPU(tc, cpuId());
120 }
121 }
122 }
123
124 /** Stats interface from SimObject (by way of BaseCPU) */
125 void
126 MinorCPU::regStats()
127 {
128 BaseCPU::regStats();
129 stats.regStats(name(), *this);
130 pipeline->regStats();
131 }
132
133 void
134 MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
135 {
136 threads[thread_id]->serialize(cp);
137 }
138
139 void
140 MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
141 {
142 threads[thread_id]->unserialize(cp);
143 }
144
145 void
146 MinorCPU::serialize(CheckpointOut &cp) const
147 {
148 pipeline->serialize(cp);
149 BaseCPU::serialize(cp);
150 }
151
152 void
153 MinorCPU::unserialize(CheckpointIn &cp)
154 {
155 pipeline->unserialize(cp);
156 BaseCPU::unserialize(cp);
157 }
158
159 Addr
160 MinorCPU::dbg_vtophys(Addr addr)
161 {
162 /* Note that this gives you the translation for thread 0 */
163 panic("No implementation for vtophy\n");
164
165 return 0;
166 }
167
168 void
169 MinorCPU::wakeup(ThreadID tid)
170 {
171 DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
172 assert(tid < numThreads);
173
174 if (threads[tid]->status() == ThreadContext::Suspended) {
175 threads[tid]->activate();
176 }
177 }
178
179 void
180 MinorCPU::startup()
181 {
182 DPRINTF(MinorCPU, "MinorCPU startup\n");
183
184 BaseCPU::startup();
185
186 for (ThreadID tid = 0; tid < numThreads; tid++) {
187 threads[tid]->startup();
188 pipeline->wakeupFetch(tid);
189 }
190 }
191
192 DrainState
193 MinorCPU::drain()
194 {
195 // Deschedule any power gating event (if any)
196 deschedulePowerGatingEvent();
197
198 if (switchedOut()) {
199 DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
200 return DrainState::Drained;
201 }
202
203 DPRINTF(Drain, "MinorCPU drain\n");
204
205 /* Need to suspend all threads and wait for Execute to idle.
206 * Tell Fetch1 not to fetch */
207 if (pipeline->drain()) {
208 DPRINTF(Drain, "MinorCPU drained\n");
209 return DrainState::Drained;
210 } else {
211 DPRINTF(Drain, "MinorCPU not finished draining\n");
212 return DrainState::Draining;
213 }
214 }
215
216 void
217 MinorCPU::signalDrainDone()
218 {
219 DPRINTF(Drain, "MinorCPU drain done\n");
220 Drainable::signalDrainDone();
221 }
222
223 void
224 MinorCPU::drainResume()
225 {
226 /* When taking over from another cpu make sure lastStopped
227 * is reset since it might have not been defined previously
228 * and might lead to a stats corruption */
229 pipeline->resetLastStopped();
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 for (ThreadID tid = 0; tid < numThreads; tid++){
244 wakeup(tid);
245 }
246
247 pipeline->drainResume();
248
249 // Reschedule any power gating event (if any)
250 schedulePowerGatingEvent();
251 }
252
253 void
254 MinorCPU::memWriteback()
255 {
256 DPRINTF(Drain, "MinorCPU memWriteback\n");
257 }
258
259 void
260 MinorCPU::switchOut()
261 {
262 DPRINTF(MinorCPU, "MinorCPU switchOut\n");
263
264 assert(!switchedOut());
265 BaseCPU::switchOut();
266
267 /* Check that the CPU is drained? */
268 activityRecorder->reset();
269 }
270
271 void
272 MinorCPU::takeOverFrom(BaseCPU *old_cpu)
273 {
274 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
275
276 BaseCPU::takeOverFrom(old_cpu);
277 }
278
279 void
280 MinorCPU::activateContext(ThreadID thread_id)
281 {
282 DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id);
283
284 /* Do some cycle accounting. lastStopped is reset to stop the
285 * wakeup call on the pipeline from adding the quiesce period
286 * to BaseCPU::numCycles */
287 stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
288 pipeline->resetLastStopped();
289
290 /* Wake up the thread, wakeup the pipeline tick */
291 threads[thread_id]->activate();
292 wakeupOnEvent(Minor::Pipeline::CPUStageId);
293 pipeline->wakeupFetch(thread_id);
294
295 BaseCPU::activateContext(thread_id);
296 }
297
298 void
299 MinorCPU::suspendContext(ThreadID thread_id)
300 {
301 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
302
303 threads[thread_id]->suspend();
304
305 BaseCPU::suspendContext(thread_id);
306 }
307
308 void
309 MinorCPU::wakeupOnEvent(unsigned int stage_id)
310 {
311 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
312
313 /* Mark that some activity has taken place and start the pipeline */
314 activityRecorder->activateStage(stage_id);
315 pipeline->start();
316 }
317
318 MinorCPU *
319 MinorCPUParams::create()
320 {
321 return new MinorCPU(this);
322 }
323
324 Port &
325 MinorCPU::getInstPort()
326 {
327 return pipeline->getInstPort();
328 }
329
330 Port &
331 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 }