2 * Copyright (c) 2012-2014, 2017 ARM Limited
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.
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.
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.
37 * Authors: Andrew Bardsley
40 #include "cpu/minor/cpu.hh"
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"
50 MinorCPU::MinorCPU(MinorCPUParams
*params
) :
52 pipelineStartupEvent([this]{ wakeupPipeline(); }, name()),
53 threadPolicy(params
->threadPolicy
)
55 /* This is only written for one thread at the moment */
56 Minor::MinorThread
*thread
;
58 for (ThreadID i
= 0; i
< numThreads
; i
++) {
60 thread
= new Minor::MinorThread(this, i
, params
->system
,
61 params
->itb
, params
->dtb
, params
->isa
[i
]);
62 thread
->setStatus(ThreadContext::Halted
);
64 thread
= new Minor::MinorThread(this, i
, params
->system
,
65 params
->workload
[i
], params
->itb
, params
->dtb
,
69 threads
.push_back(thread
);
70 ThreadContext
*tc
= thread
->getTC();
71 threadContexts
.push_back(tc
);
75 if (params
->checker
) {
76 fatal("The Minor model doesn't support checking (yet)\n");
79 Minor::MinorDynInst::init();
81 pipeline
= new Minor::Pipeline(*this, *params
);
82 activityRecorder
= pipeline
->getActivityRecorder();
89 for (ThreadID thread_id
= 0; thread_id
< threads
.size(); thread_id
++) {
90 delete threads
[thread_id
];
99 if (!params()->switched_out
&&
100 system
->getMemoryMode() != Enums::timing
)
102 fatal("The Minor CPU requires the memory system to be in "
106 /* Initialise the ThreadContext's memory proxies */
107 for (ThreadID thread_id
= 0; thread_id
< threads
.size(); thread_id
++) {
108 ThreadContext
*tc
= getContext(thread_id
);
110 tc
->initMemProxies(tc
);
113 /* Initialise CPUs (== threads in the ISA) */
114 if (FullSystem
&& !params()->switched_out
) {
115 for (ThreadID thread_id
= 0; thread_id
< threads
.size(); thread_id
++)
117 ThreadContext
*tc
= getContext(thread_id
);
119 /* Initialize CPU, including PC */
120 TheISA::initCPU(tc
, cpuId());
125 /** Stats interface from SimObject (by way of BaseCPU) */
130 stats
.regStats(name(), *this);
131 pipeline
->regStats();
135 MinorCPU::serializeThread(CheckpointOut
&cp
, ThreadID thread_id
) const
137 threads
[thread_id
]->serialize(cp
);
141 MinorCPU::unserializeThread(CheckpointIn
&cp
, ThreadID thread_id
)
143 threads
[thread_id
]->unserialize(cp
);
147 MinorCPU::serialize(CheckpointOut
&cp
) const
149 pipeline
->serialize(cp
);
150 BaseCPU::serialize(cp
);
154 MinorCPU::unserialize(CheckpointIn
&cp
)
156 pipeline
->unserialize(cp
);
157 BaseCPU::unserialize(cp
);
161 MinorCPU::dbg_vtophys(Addr addr
)
163 /* Note that this gives you the translation for thread 0 */
164 panic("No implementation for vtophy\n");
170 MinorCPU::wakeup(ThreadID tid
)
172 DPRINTF(Drain
, "[tid:%d] MinorCPU wakeup\n", tid
);
173 assert(tid
< numThreads
);
175 if (threads
[tid
]->status() == ThreadContext::Suspended
) {
176 threads
[tid
]->activate();
183 DPRINTF(MinorCPU
, "MinorCPU startup\n");
187 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
188 threads
[tid
]->startup();
189 pipeline
->wakeupFetch(tid
);
196 // Deschedule any power gating event (if any)
197 deschedulePowerGatingEvent();
200 DPRINTF(Drain
, "Minor CPU switched out, draining not needed.\n");
201 return DrainState::Drained
;
204 DPRINTF(Drain
, "MinorCPU drain\n");
206 /* Need to suspend all threads and wait for Execute to idle.
207 * Tell Fetch1 not to fetch */
208 if (pipeline
->drain()) {
209 DPRINTF(Drain
, "MinorCPU drained\n");
210 return DrainState::Drained
;
212 DPRINTF(Drain
, "MinorCPU not finished draining\n");
213 return DrainState::Draining
;
218 MinorCPU::signalDrainDone()
220 DPRINTF(Drain
, "MinorCPU drain done\n");
221 Drainable::signalDrainDone();
225 MinorCPU::drainResume()
227 /* When taking over from another cpu make sure lastStopped
228 * is reset since it might have not been defined previously
229 * and might lead to a stats corruption */
230 pipeline
->resetLastStopped();
233 DPRINTF(Drain
, "drainResume while switched out. Ignoring\n");
237 DPRINTF(Drain
, "MinorCPU drainResume\n");
239 if (!system
->isTimingMode()) {
240 fatal("The Minor CPU requires the memory system to be in "
244 for (ThreadID tid
= 0; tid
< numThreads
; tid
++){
248 pipeline
->drainResume();
250 // Reschedule any power gating event (if any)
251 schedulePowerGatingEvent();
255 MinorCPU::memWriteback()
257 DPRINTF(Drain
, "MinorCPU memWriteback\n");
261 MinorCPU::switchOut()
263 DPRINTF(MinorCPU
, "MinorCPU switchOut\n");
265 assert(!switchedOut());
266 BaseCPU::switchOut();
268 /* Check that the CPU is drained? */
269 activityRecorder
->reset();
273 MinorCPU::takeOverFrom(BaseCPU
*old_cpu
)
275 DPRINTF(MinorCPU
, "MinorCPU takeOverFrom\n");
277 BaseCPU::takeOverFrom(old_cpu
);
281 MinorCPU::activateContext(ThreadID thread_id
)
283 /* Remember to wake up this thread_id by scheduling the
284 * pipelineStartup event.
285 * We can't wakeupFetch the thread right away because its context may
286 * not have been fully initialized. For example, in the case of clone
287 * syscall, this activateContext function is called in the middle of
288 * the syscall and before the new thread context is initialized.
289 * If we start fetching right away, the new thread will fetch from an
290 * invalid address (i.e., pc is not initialized yet), which could lead
291 * to a page fault. Instead, we remember which threads to wake up and
292 * schedule an event to wake all them up after their contexts are
293 * fully initialized */
294 readyThreads
.push_back(thread_id
);
295 if (!pipelineStartupEvent
.scheduled())
296 schedule(pipelineStartupEvent
, clockEdge(Cycles(0)));
300 MinorCPU::wakeupPipeline()
302 for (auto thread_id
: readyThreads
) {
303 DPRINTF(MinorCPU
, "ActivateContext thread: %d\n", thread_id
);
305 /* Do some cycle accounting. lastStopped is reset to stop the
306 * wakeup call on the pipeline from adding the quiesce period
307 * to BaseCPU::numCycles */
308 stats
.quiesceCycles
+= pipeline
->cyclesSinceLastStopped();
309 pipeline
->resetLastStopped();
311 /* Wake up the thread, wakeup the pipeline tick */
312 threads
[thread_id
]->activate();
313 wakeupOnEvent(Minor::Pipeline::CPUStageId
);
315 pipeline
->wakeupFetch(thread_id
);
316 BaseCPU::activateContext(thread_id
);
319 readyThreads
.clear();
323 MinorCPU::suspendContext(ThreadID thread_id
)
325 DPRINTF(MinorCPU
, "SuspendContext %d\n", thread_id
);
327 threads
[thread_id
]->suspend();
329 BaseCPU::suspendContext(thread_id
);
333 MinorCPU::wakeupOnEvent(unsigned int stage_id
)
335 DPRINTF(Quiesce
, "Event wakeup from stage %d\n", stage_id
);
337 /* Mark that some activity has taken place and start the pipeline */
338 activityRecorder
->activateStage(stage_id
);
343 MinorCPUParams::create()
345 return new MinorCPU(this);
348 MasterPort
&MinorCPU::getInstPort()
350 return pipeline
->getInstPort();
353 MasterPort
&MinorCPU::getDataPort()
355 return pipeline
->getDataPort();
359 MinorCPU::totalInsts() const
363 for (auto i
= threads
.begin(); i
!= threads
.end(); i
++)
364 ret
+= (*i
)->numInst
;
370 MinorCPU::totalOps() const
374 for (auto i
= threads
.begin(); i
!= threads
.end(); i
++)