5edc570c72aefd0630bfb1531e3ced443658b442
[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
113 /** Stats interface from SimObject (by way of BaseCPU) */
114 void
115 MinorCPU::regStats()
116 {
117 BaseCPU::regStats();
118 stats.regStats(name(), *this);
119 pipeline->regStats();
120 }
121
122 void
123 MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
124 {
125 threads[thread_id]->serialize(cp);
126 }
127
128 void
129 MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
130 {
131 threads[thread_id]->unserialize(cp);
132 }
133
134 void
135 MinorCPU::serialize(CheckpointOut &cp) const
136 {
137 pipeline->serialize(cp);
138 BaseCPU::serialize(cp);
139 }
140
141 void
142 MinorCPU::unserialize(CheckpointIn &cp)
143 {
144 pipeline->unserialize(cp);
145 BaseCPU::unserialize(cp);
146 }
147
148 Addr
149 MinorCPU::dbg_vtophys(Addr addr)
150 {
151 /* Note that this gives you the translation for thread 0 */
152 panic("No implementation for vtophy\n");
153
154 return 0;
155 }
156
157 void
158 MinorCPU::wakeup(ThreadID tid)
159 {
160 DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
161 assert(tid < numThreads);
162
163 if (threads[tid]->status() == ThreadContext::Suspended) {
164 threads[tid]->activate();
165 }
166 }
167
168 void
169 MinorCPU::startup()
170 {
171 DPRINTF(MinorCPU, "MinorCPU startup\n");
172
173 BaseCPU::startup();
174
175 for (ThreadID tid = 0; tid < numThreads; tid++) {
176 threads[tid]->startup();
177 pipeline->wakeupFetch(tid);
178 }
179 }
180
181 DrainState
182 MinorCPU::drain()
183 {
184 // Deschedule any power gating event (if any)
185 deschedulePowerGatingEvent();
186
187 if (switchedOut()) {
188 DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
189 return DrainState::Drained;
190 }
191
192 DPRINTF(Drain, "MinorCPU drain\n");
193
194 /* Need to suspend all threads and wait for Execute to idle.
195 * Tell Fetch1 not to fetch */
196 if (pipeline->drain()) {
197 DPRINTF(Drain, "MinorCPU drained\n");
198 return DrainState::Drained;
199 } else {
200 DPRINTF(Drain, "MinorCPU not finished draining\n");
201 return DrainState::Draining;
202 }
203 }
204
205 void
206 MinorCPU::signalDrainDone()
207 {
208 DPRINTF(Drain, "MinorCPU drain done\n");
209 Drainable::signalDrainDone();
210 }
211
212 void
213 MinorCPU::drainResume()
214 {
215 /* When taking over from another cpu make sure lastStopped
216 * is reset since it might have not been defined previously
217 * and might lead to a stats corruption */
218 pipeline->resetLastStopped();
219
220 if (switchedOut()) {
221 DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
222 return;
223 }
224
225 DPRINTF(Drain, "MinorCPU drainResume\n");
226
227 if (!system->isTimingMode()) {
228 fatal("The Minor CPU requires the memory system to be in "
229 "'timing' mode.\n");
230 }
231
232 for (ThreadID tid = 0; tid < numThreads; tid++){
233 wakeup(tid);
234 }
235
236 pipeline->drainResume();
237
238 // Reschedule any power gating event (if any)
239 schedulePowerGatingEvent();
240 }
241
242 void
243 MinorCPU::memWriteback()
244 {
245 DPRINTF(Drain, "MinorCPU memWriteback\n");
246 }
247
248 void
249 MinorCPU::switchOut()
250 {
251 DPRINTF(MinorCPU, "MinorCPU switchOut\n");
252
253 assert(!switchedOut());
254 BaseCPU::switchOut();
255
256 /* Check that the CPU is drained? */
257 activityRecorder->reset();
258 }
259
260 void
261 MinorCPU::takeOverFrom(BaseCPU *old_cpu)
262 {
263 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
264
265 BaseCPU::takeOverFrom(old_cpu);
266 }
267
268 void
269 MinorCPU::activateContext(ThreadID thread_id)
270 {
271 DPRINTF(MinorCPU, "ActivateContext thread: %d\n", 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(thread_id);
283
284 BaseCPU::activateContext(thread_id);
285 }
286
287 void
288 MinorCPU::suspendContext(ThreadID thread_id)
289 {
290 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
291
292 threads[thread_id]->suspend();
293
294 BaseCPU::suspendContext(thread_id);
295 }
296
297 void
298 MinorCPU::wakeupOnEvent(unsigned int stage_id)
299 {
300 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
301
302 /* Mark that some activity has taken place and start the pipeline */
303 activityRecorder->activateStage(stage_id);
304 pipeline->start();
305 }
306
307 MinorCPU *
308 MinorCPUParams::create()
309 {
310 return new MinorCPU(this);
311 }
312
313 Port &
314 MinorCPU::getInstPort()
315 {
316 return pipeline->getInstPort();
317 }
318
319 Port &
320 MinorCPU::getDataPort()
321 {
322 return pipeline->getDataPort();
323 }
324
325 Counter
326 MinorCPU::totalInsts() const
327 {
328 Counter ret = 0;
329
330 for (auto i = threads.begin(); i != threads.end(); i ++)
331 ret += (*i)->numInst;
332
333 return ret;
334 }
335
336 Counter
337 MinorCPU::totalOps() const
338 {
339 Counter ret = 0;
340
341 for (auto i = threads.begin(); i != threads.end(); i ++)
342 ret += (*i)->numOp;
343
344 return ret;
345 }