cpu.cc (10910:32f3d1c454ec) cpu.cc (10913:38dbdeea7f1f)
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) :
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)
50 BaseCPU(params)
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
67 thread->setStatus(ThreadContext::Halted);
68
69 ThreadContext *tc = thread->getTC();
70
71 if (params->checker) {
72 fatal("The Minor model doesn't support checking (yet)\n");
73 }
74
75 threadContexts.push_back(tc);
76
77 Minor::MinorDynInst::init();
78
79 pipeline = new Minor::Pipeline(*this, *params);
80 activityRecorder = pipeline->getActivityRecorder();
81}
82
83MinorCPU::~MinorCPU()
84{
85 delete pipeline;
86
87 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
88 delete threads[thread_id];
89 }
90}
91
92void
93MinorCPU::init()
94{
95 BaseCPU::init();
96
97 if (!params()->switched_out &&
98 system->getMemoryMode() != Enums::timing)
99 {
100 fatal("The Minor CPU requires the memory system to be in "
101 "'timing' mode.\n");
102 }
103
104 /* Initialise the ThreadContext's memory proxies */
105 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
106 ThreadContext *tc = getContext(thread_id);
107
108 tc->initMemProxies(tc);
109 }
110
111 /* Initialise CPUs (== threads in the ISA) */
112 if (FullSystem && !params()->switched_out) {
113 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
114 {
115 ThreadContext *tc = getContext(thread_id);
116
117 /* Initialize CPU, including PC */
118 TheISA::initCPU(tc, cpuId());
119 }
120 }
121}
122
123/** Stats interface from SimObject (by way of BaseCPU) */
124void
125MinorCPU::regStats()
126{
127 BaseCPU::regStats();
128 stats.regStats(name(), *this);
129 pipeline->regStats();
130}
131
132void
133MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
134{
135 threads[thread_id]->serialize(cp);
136}
137
138void
139MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
140{
141 if (thread_id != 0)
142 fatal("Trying to load more than one thread into a MinorCPU\n");
143
144 threads[thread_id]->unserialize(cp);
145}
146
147void
148MinorCPU::serialize(CheckpointOut &cp) const
149{
150 pipeline->serialize(cp);
151 BaseCPU::serialize(cp);
152}
153
154void
155MinorCPU::unserialize(CheckpointIn &cp)
156{
157 pipeline->unserialize(cp);
158 BaseCPU::unserialize(cp);
159}
160
161Addr
162MinorCPU::dbg_vtophys(Addr addr)
163{
164 /* Note that this gives you the translation for thread 0 */
165 panic("No implementation for vtophy\n");
166
167 return 0;
168}
169
170void
171MinorCPU::wakeup()
172{
173 DPRINTF(Drain, "MinorCPU wakeup\n");
174
175 for (auto i = threads.begin(); i != threads.end(); i ++) {
176 if ((*i)->status() == ThreadContext::Suspended)
177 (*i)->activate();
178 }
179
180 DPRINTF(Drain,"Suspended Processor awoke\n");
181}
182
183void
184MinorCPU::startup()
185{
186 DPRINTF(MinorCPU, "MinorCPU startup\n");
187
188 BaseCPU::startup();
189
190 for (auto i = threads.begin(); i != threads.end(); i ++)
191 (*i)->startup();
192
193 /* CPU state setup, activate initial context */
194 activateContext(0);
195}
196
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
82MinorCPU::~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
91void
92MinorCPU::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) */
123void
124MinorCPU::regStats()
125{
126 BaseCPU::regStats();
127 stats.regStats(name(), *this);
128 pipeline->regStats();
129}
130
131void
132MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
133{
134 threads[thread_id]->serialize(cp);
135}
136
137void
138MinorCPU::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
146void
147MinorCPU::serialize(CheckpointOut &cp) const
148{
149 pipeline->serialize(cp);
150 BaseCPU::serialize(cp);
151}
152
153void
154MinorCPU::unserialize(CheckpointIn &cp)
155{
156 pipeline->unserialize(cp);
157 BaseCPU::unserialize(cp);
158}
159
160Addr
161MinorCPU::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
169void
170MinorCPU::wakeup()
171{
172 DPRINTF(Drain, "MinorCPU wakeup\n");
173
174 for (auto i = threads.begin(); i != threads.end(); i ++) {
175 if ((*i)->status() == ThreadContext::Suspended)
176 (*i)->activate();
177 }
178
179 DPRINTF(Drain,"Suspended Processor awoke\n");
180}
181
182void
183MinorCPU::startup()
184{
185 DPRINTF(MinorCPU, "MinorCPU startup\n");
186
187 BaseCPU::startup();
188
189 for (auto i = threads.begin(); i != threads.end(); i ++)
190 (*i)->startup();
191
192 /* CPU state setup, activate initial context */
193 activateContext(0);
194}
195
197unsigned int
198MinorCPU::drain(DrainManager *drain_manager)
196DrainState
197MinorCPU::drain()
199{
200 DPRINTF(Drain, "MinorCPU drain\n");
201
198{
199 DPRINTF(Drain, "MinorCPU drain\n");
200
202 drainManager = drain_manager;
203
204 /* Need to suspend all threads and wait for Execute to idle.
205 * Tell Fetch1 not to fetch */
201 /* Need to suspend all threads and wait for Execute to idle.
202 * Tell Fetch1 not to fetch */
206 unsigned int ret = pipeline->drain(drain_manager);
207
208 if (ret == 0)
203 if (pipeline->drain()) {
209 DPRINTF(Drain, "MinorCPU drained\n");
204 DPRINTF(Drain, "MinorCPU drained\n");
210 else
205 return DrainState::Drained;
206 } else {
211 DPRINTF(Drain, "MinorCPU not finished draining\n");
207 DPRINTF(Drain, "MinorCPU not finished draining\n");
212
213 return ret;
208 return DrainState::Draining;
209 }
214}
215
216void
217MinorCPU::signalDrainDone()
218{
219 DPRINTF(Drain, "MinorCPU drain done\n");
210}
211
212void
213MinorCPU::signalDrainDone()
214{
215 DPRINTF(Drain, "MinorCPU drain done\n");
220 setDrainState(DrainState::Drained);
221 drainManager->signalDrainDone();
222 drainManager = NULL;
216 signalDrainDone();
223}
224
225void
226MinorCPU::drainResume()
227{
217}
218
219void
220MinorCPU::drainResume()
221{
228 assert(getDrainState() == DrainState::Drained ||
229 getDrainState() == DrainState::Running);
222 assert(drainState() == DrainState::Drained);
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();
223
224 if (switchedOut()) {
225 DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
226 return;
227 }
228
229 DPRINTF(Drain, "MinorCPU drainResume\n");
230
231 if (!system->isTimingMode()) {
232 fatal("The Minor CPU requires the memory system to be in "
233 "'timing' mode.\n");
234 }
235
236 wakeup();
237 pipeline->drainResume();
245
246 setDrainState(DrainState::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)
279{
280 DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
281
282 /* Do some cycle accounting. lastStopped is reset to stop the
283 * wakeup call on the pipeline from adding the quiesce period
284 * to BaseCPU::numCycles */
285 stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
286 pipeline->resetLastStopped();
287
288 /* Wake up the thread, wakeup the pipeline tick */
289 threads[thread_id]->activate();
290 wakeupOnEvent(Minor::Pipeline::CPUStageId);
291 pipeline->wakeupFetch();
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
302void
303MinorCPU::wakeupOnEvent(unsigned int stage_id)
304{
305 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
306
307 /* Mark that some activity has taken place and start the pipeline */
308 activityRecorder->activateStage(stage_id);
309 pipeline->start();
310}
311
312MinorCPU *
313MinorCPUParams::create()
314{
315 numThreads = 1;
316 if (!FullSystem && workload.size() != 1)
317 panic("only one workload allowed");
318 return new MinorCPU(this);
319}
320
321MasterPort &MinorCPU::getInstPort()
322{
323 return pipeline->getInstPort();
324}
325
326MasterPort &MinorCPU::getDataPort()
327{
328 return pipeline->getDataPort();
329}
330
331Counter
332MinorCPU::totalInsts() const
333{
334 Counter ret = 0;
335
336 for (auto i = threads.begin(); i != threads.end(); i ++)
337 ret += (*i)->numInst;
338
339 return ret;
340}
341
342Counter
343MinorCPU::totalOps() const
344{
345 Counter ret = 0;
346
347 for (auto i = threads.begin(); i != threads.end(); i ++)
348 ret += (*i)->numOp;
349
350 return ret;
351}
238}
239
240void
241MinorCPU::memWriteback()
242{
243 DPRINTF(Drain, "MinorCPU memWriteback\n");
244}
245
246void
247MinorCPU::switchOut()
248{
249 DPRINTF(MinorCPU, "MinorCPU switchOut\n");
250
251 assert(!switchedOut());
252 BaseCPU::switchOut();
253
254 /* Check that the CPU is drained? */
255 activityRecorder->reset();
256}
257
258void
259MinorCPU::takeOverFrom(BaseCPU *old_cpu)
260{
261 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
262
263 BaseCPU::takeOverFrom(old_cpu);
264
265 /* Don't think I need to do anything here */
266}
267
268void
269MinorCPU::activateContext(ThreadID thread_id)
270{
271 DPRINTF(MinorCPU, "ActivateContext thread: %d", 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();
283}
284
285void
286MinorCPU::suspendContext(ThreadID thread_id)
287{
288 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
289
290 threads[thread_id]->suspend();
291}
292
293void
294MinorCPU::wakeupOnEvent(unsigned int stage_id)
295{
296 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
297
298 /* Mark that some activity has taken place and start the pipeline */
299 activityRecorder->activateStage(stage_id);
300 pipeline->start();
301}
302
303MinorCPU *
304MinorCPUParams::create()
305{
306 numThreads = 1;
307 if (!FullSystem && workload.size() != 1)
308 panic("only one workload allowed");
309 return new MinorCPU(this);
310}
311
312MasterPort &MinorCPU::getInstPort()
313{
314 return pipeline->getInstPort();
315}
316
317MasterPort &MinorCPU::getDataPort()
318{
319 return pipeline->getDataPort();
320}
321
322Counter
323MinorCPU::totalInsts() const
324{
325 Counter ret = 0;
326
327 for (auto i = threads.begin(); i != threads.end(); i ++)
328 ret += (*i)->numInst;
329
330 return ret;
331}
332
333Counter
334MinorCPU::totalOps() const
335{
336 Counter ret = 0;
337
338 for (auto i = threads.begin(); i != threads.end(); i ++)
339 ret += (*i)->numOp;
340
341 return ret;
342}