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