cpu: Add HTM ExecContext API
[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
38 #include "cpu/minor/cpu.hh"
39
40 #include "arch/utility.hh"
41 #include "cpu/minor/dyn_inst.hh"
42 #include "cpu/minor/fetch1.hh"
43 #include "cpu/minor/pipeline.hh"
44 #include "debug/Drain.hh"
45 #include "debug/MinorCPU.hh"
46 #include "debug/Quiesce.hh"
47
48 MinorCPU::MinorCPU(MinorCPUParams *params) :
49 BaseCPU(params),
50 threadPolicy(params->threadPolicy)
51 {
52 /* This is only written for one thread at the moment */
53 Minor::MinorThread *thread;
54
55 for (ThreadID i = 0; i < numThreads; i++) {
56 if (FullSystem) {
57 thread = new Minor::MinorThread(this, i, params->system,
58 params->itb, params->dtb, params->isa[i]);
59 thread->setStatus(ThreadContext::Halted);
60 } else {
61 thread = new Minor::MinorThread(this, i, params->system,
62 params->workload[i], params->itb, params->dtb,
63 params->isa[i]);
64 }
65
66 threads.push_back(thread);
67 ThreadContext *tc = thread->getTC();
68 threadContexts.push_back(tc);
69 }
70
71
72 if (params->checker) {
73 fatal("The Minor model doesn't support checking (yet)\n");
74 }
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
111 /** Stats interface from SimObject (by way of BaseCPU) */
112 void
113 MinorCPU::regStats()
114 {
115 BaseCPU::regStats();
116 stats.regStats(name(), *this);
117 pipeline->regStats();
118 }
119
120 void
121 MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const
122 {
123 threads[thread_id]->serialize(cp);
124 }
125
126 void
127 MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id)
128 {
129 threads[thread_id]->unserialize(cp);
130 }
131
132 void
133 MinorCPU::serialize(CheckpointOut &cp) const
134 {
135 pipeline->serialize(cp);
136 BaseCPU::serialize(cp);
137 }
138
139 void
140 MinorCPU::unserialize(CheckpointIn &cp)
141 {
142 pipeline->unserialize(cp);
143 BaseCPU::unserialize(cp);
144 }
145
146 void
147 MinorCPU::wakeup(ThreadID tid)
148 {
149 DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid);
150 assert(tid < numThreads);
151
152 if (threads[tid]->status() == ThreadContext::Suspended) {
153 threads[tid]->activate();
154 }
155 }
156
157 void
158 MinorCPU::startup()
159 {
160 DPRINTF(MinorCPU, "MinorCPU startup\n");
161
162 BaseCPU::startup();
163
164 for (ThreadID tid = 0; tid < numThreads; tid++)
165 pipeline->wakeupFetch(tid);
166 }
167
168 DrainState
169 MinorCPU::drain()
170 {
171 // Deschedule any power gating event (if any)
172 deschedulePowerGatingEvent();
173
174 if (switchedOut()) {
175 DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
176 return DrainState::Drained;
177 }
178
179 DPRINTF(Drain, "MinorCPU drain\n");
180
181 /* Need to suspend all threads and wait for Execute to idle.
182 * Tell Fetch1 not to fetch */
183 if (pipeline->drain()) {
184 DPRINTF(Drain, "MinorCPU drained\n");
185 return DrainState::Drained;
186 } else {
187 DPRINTF(Drain, "MinorCPU not finished draining\n");
188 return DrainState::Draining;
189 }
190 }
191
192 void
193 MinorCPU::signalDrainDone()
194 {
195 DPRINTF(Drain, "MinorCPU drain done\n");
196 Drainable::signalDrainDone();
197 }
198
199 void
200 MinorCPU::drainResume()
201 {
202 /* When taking over from another cpu make sure lastStopped
203 * is reset since it might have not been defined previously
204 * and might lead to a stats corruption */
205 pipeline->resetLastStopped();
206
207 if (switchedOut()) {
208 DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
209 return;
210 }
211
212 DPRINTF(Drain, "MinorCPU drainResume\n");
213
214 if (!system->isTimingMode()) {
215 fatal("The Minor CPU requires the memory system to be in "
216 "'timing' mode.\n");
217 }
218
219 for (ThreadID tid = 0; tid < numThreads; tid++){
220 wakeup(tid);
221 }
222
223 pipeline->drainResume();
224
225 // Reschedule any power gating event (if any)
226 schedulePowerGatingEvent();
227 }
228
229 void
230 MinorCPU::memWriteback()
231 {
232 DPRINTF(Drain, "MinorCPU memWriteback\n");
233 }
234
235 void
236 MinorCPU::switchOut()
237 {
238 DPRINTF(MinorCPU, "MinorCPU switchOut\n");
239
240 assert(!switchedOut());
241 BaseCPU::switchOut();
242
243 /* Check that the CPU is drained? */
244 activityRecorder->reset();
245 }
246
247 void
248 MinorCPU::takeOverFrom(BaseCPU *old_cpu)
249 {
250 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
251
252 BaseCPU::takeOverFrom(old_cpu);
253 }
254
255 void
256 MinorCPU::activateContext(ThreadID thread_id)
257 {
258 DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id);
259
260 /* Do some cycle accounting. lastStopped is reset to stop the
261 * wakeup call on the pipeline from adding the quiesce period
262 * to BaseCPU::numCycles */
263 stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
264 pipeline->resetLastStopped();
265
266 /* Wake up the thread, wakeup the pipeline tick */
267 threads[thread_id]->activate();
268 wakeupOnEvent(Minor::Pipeline::CPUStageId);
269 pipeline->wakeupFetch(thread_id);
270
271 BaseCPU::activateContext(thread_id);
272 }
273
274 void
275 MinorCPU::suspendContext(ThreadID thread_id)
276 {
277 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
278
279 threads[thread_id]->suspend();
280
281 BaseCPU::suspendContext(thread_id);
282 }
283
284 void
285 MinorCPU::wakeupOnEvent(unsigned int stage_id)
286 {
287 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
288
289 /* Mark that some activity has taken place and start the pipeline */
290 activityRecorder->activateStage(stage_id);
291 pipeline->start();
292 }
293
294 MinorCPU *
295 MinorCPUParams::create()
296 {
297 return new MinorCPU(this);
298 }
299
300 Port &
301 MinorCPU::getInstPort()
302 {
303 return pipeline->getInstPort();
304 }
305
306 Port &
307 MinorCPU::getDataPort()
308 {
309 return pipeline->getDataPort();
310 }
311
312 Counter
313 MinorCPU::totalInsts() const
314 {
315 Counter ret = 0;
316
317 for (auto i = threads.begin(); i != threads.end(); i ++)
318 ret += (*i)->numInst;
319
320 return ret;
321 }
322
323 Counter
324 MinorCPU::totalOps() const
325 {
326 Counter ret = 0;
327
328 for (auto i = threads.begin(); i != threads.end(); i ++)
329 ret += (*i)->numOp;
330
331 return ret;
332 }