cpu.cc (13601:f5c84915eb7f) cpu.cc (13610:5d5404ac6288)
1/*
2 * Copyright (c) 2011-2012, 2014, 2016, 2017, 2019 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2004-2006 The Regents of The University of Michigan
16 * Copyright (c) 2011 Regents of the University of California
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met: redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer;
23 * redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution;
26 * neither the name of the copyright holders nor the names of its
27 * contributors may be used to endorse or promote products derived from
28 * this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * Authors: Kevin Lim
43 * Korey Sewell
44 * Rick Strong
45 */
46
47#include "cpu/o3/cpu.hh"
48
49#include "arch/generic/traits.hh"
50#include "arch/kernel_stats.hh"
51#include "config/the_isa.hh"
52#include "cpu/activity.hh"
53#include "cpu/checker/cpu.hh"
54#include "cpu/checker/thread_context.hh"
55#include "cpu/o3/isa_specific.hh"
56#include "cpu/o3/thread_context.hh"
57#include "cpu/quiesce_event.hh"
58#include "cpu/simple_thread.hh"
59#include "cpu/thread_context.hh"
60#include "debug/Activity.hh"
61#include "debug/Drain.hh"
62#include "debug/O3CPU.hh"
63#include "debug/Quiesce.hh"
64#include "enums/MemoryMode.hh"
65#include "sim/core.hh"
66#include "sim/full_system.hh"
67#include "sim/process.hh"
68#include "sim/stat_control.hh"
69#include "sim/system.hh"
70
71#if THE_ISA == ALPHA_ISA
72#include "arch/alpha/osfpal.hh"
73#include "debug/Activity.hh"
74
75#endif
76
77struct BaseCPUParams;
78
79using namespace TheISA;
80using namespace std;
81
82BaseO3CPU::BaseO3CPU(BaseCPUParams *params)
83 : BaseCPU(params)
84{
85}
86
87void
88BaseO3CPU::regStats()
89{
90 BaseCPU::regStats();
91}
92
93template<class Impl>
94bool
95FullO3CPU<Impl>::IcachePort::recvTimingResp(PacketPtr pkt)
96{
97 DPRINTF(O3CPU, "Fetch unit received timing\n");
98 // We shouldn't ever get a cacheable block in Modified state
99 assert(pkt->req->isUncacheable() ||
100 !(pkt->cacheResponding() && !pkt->hasSharers()));
101 fetch->processCacheCompletion(pkt);
102
103 return true;
104}
105
106template<class Impl>
107void
108FullO3CPU<Impl>::IcachePort::recvReqRetry()
109{
110 fetch->recvReqRetry();
111}
112
113template <class Impl>
114bool
115FullO3CPU<Impl>::DcachePort::recvTimingResp(PacketPtr pkt)
116{
117 return lsq->recvTimingResp(pkt);
118}
119
120template <class Impl>
121void
122FullO3CPU<Impl>::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
123{
124 for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
125 if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
126 cpu->wakeup(tid);
127 }
128 }
129 lsq->recvTimingSnoopReq(pkt);
130}
131
132template <class Impl>
133void
134FullO3CPU<Impl>::DcachePort::recvReqRetry()
135{
136 lsq->recvReqRetry();
137}
138
139template <class Impl>
140FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
141 : BaseO3CPU(params),
142 itb(params->itb),
143 dtb(params->dtb),
144 tickEvent([this]{ tick(); }, "FullO3CPU tick",
145 false, Event::CPU_Tick_Pri),
146#ifndef NDEBUG
147 instcount(0),
148#endif
149 removeInstsThisCycle(false),
150 fetch(this, params),
151 decode(this, params),
152 rename(this, params),
153 iew(this, params),
154 commit(this, params),
155
156 /* It is mandatory that all SMT threads use the same renaming mode as
157 * they are sharing registers and rename */
158 vecMode(RenameMode<TheISA::ISA>::init(params->isa[0])),
159 regFile(params->numPhysIntRegs,
160 params->numPhysFloatRegs,
161 params->numPhysVecRegs,
1/*
2 * Copyright (c) 2011-2012, 2014, 2016, 2017, 2019 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2004-2006 The Regents of The University of Michigan
16 * Copyright (c) 2011 Regents of the University of California
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met: redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer;
23 * redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution;
26 * neither the name of the copyright holders nor the names of its
27 * contributors may be used to endorse or promote products derived from
28 * this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * Authors: Kevin Lim
43 * Korey Sewell
44 * Rick Strong
45 */
46
47#include "cpu/o3/cpu.hh"
48
49#include "arch/generic/traits.hh"
50#include "arch/kernel_stats.hh"
51#include "config/the_isa.hh"
52#include "cpu/activity.hh"
53#include "cpu/checker/cpu.hh"
54#include "cpu/checker/thread_context.hh"
55#include "cpu/o3/isa_specific.hh"
56#include "cpu/o3/thread_context.hh"
57#include "cpu/quiesce_event.hh"
58#include "cpu/simple_thread.hh"
59#include "cpu/thread_context.hh"
60#include "debug/Activity.hh"
61#include "debug/Drain.hh"
62#include "debug/O3CPU.hh"
63#include "debug/Quiesce.hh"
64#include "enums/MemoryMode.hh"
65#include "sim/core.hh"
66#include "sim/full_system.hh"
67#include "sim/process.hh"
68#include "sim/stat_control.hh"
69#include "sim/system.hh"
70
71#if THE_ISA == ALPHA_ISA
72#include "arch/alpha/osfpal.hh"
73#include "debug/Activity.hh"
74
75#endif
76
77struct BaseCPUParams;
78
79using namespace TheISA;
80using namespace std;
81
82BaseO3CPU::BaseO3CPU(BaseCPUParams *params)
83 : BaseCPU(params)
84{
85}
86
87void
88BaseO3CPU::regStats()
89{
90 BaseCPU::regStats();
91}
92
93template<class Impl>
94bool
95FullO3CPU<Impl>::IcachePort::recvTimingResp(PacketPtr pkt)
96{
97 DPRINTF(O3CPU, "Fetch unit received timing\n");
98 // We shouldn't ever get a cacheable block in Modified state
99 assert(pkt->req->isUncacheable() ||
100 !(pkt->cacheResponding() && !pkt->hasSharers()));
101 fetch->processCacheCompletion(pkt);
102
103 return true;
104}
105
106template<class Impl>
107void
108FullO3CPU<Impl>::IcachePort::recvReqRetry()
109{
110 fetch->recvReqRetry();
111}
112
113template <class Impl>
114bool
115FullO3CPU<Impl>::DcachePort::recvTimingResp(PacketPtr pkt)
116{
117 return lsq->recvTimingResp(pkt);
118}
119
120template <class Impl>
121void
122FullO3CPU<Impl>::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
123{
124 for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
125 if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
126 cpu->wakeup(tid);
127 }
128 }
129 lsq->recvTimingSnoopReq(pkt);
130}
131
132template <class Impl>
133void
134FullO3CPU<Impl>::DcachePort::recvReqRetry()
135{
136 lsq->recvReqRetry();
137}
138
139template <class Impl>
140FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
141 : BaseO3CPU(params),
142 itb(params->itb),
143 dtb(params->dtb),
144 tickEvent([this]{ tick(); }, "FullO3CPU tick",
145 false, Event::CPU_Tick_Pri),
146#ifndef NDEBUG
147 instcount(0),
148#endif
149 removeInstsThisCycle(false),
150 fetch(this, params),
151 decode(this, params),
152 rename(this, params),
153 iew(this, params),
154 commit(this, params),
155
156 /* It is mandatory that all SMT threads use the same renaming mode as
157 * they are sharing registers and rename */
158 vecMode(RenameMode<TheISA::ISA>::init(params->isa[0])),
159 regFile(params->numPhysIntRegs,
160 params->numPhysFloatRegs,
161 params->numPhysVecRegs,
162 params->numPhysVecPredRegs,
162 params->numPhysCCRegs,
163 vecMode),
164
165 freeList(name() + ".freelist", &regFile),
166
167 rob(this, params),
168
169 scoreboard(name() + ".scoreboard",
170 regFile.totalNumPhysRegs()),
171
172 isa(numThreads, NULL),
173
174 icachePort(&fetch, this),
175 dcachePort(&iew.ldstQueue, this),
176
177 timeBuffer(params->backComSize, params->forwardComSize),
178 fetchQueue(params->backComSize, params->forwardComSize),
179 decodeQueue(params->backComSize, params->forwardComSize),
180 renameQueue(params->backComSize, params->forwardComSize),
181 iewQueue(params->backComSize, params->forwardComSize),
182 activityRec(name(), NumStages,
183 params->backComSize + params->forwardComSize,
184 params->activity),
185
186 globalSeqNum(1),
187 system(params->system),
188 lastRunningCycle(curCycle())
189{
190 if (!params->switched_out) {
191 _status = Running;
192 } else {
193 _status = SwitchedOut;
194 }
195
196 if (params->checker) {
197 BaseCPU *temp_checker = params->checker;
198 checker = dynamic_cast<Checker<Impl> *>(temp_checker);
199 checker->setIcachePort(&icachePort);
200 checker->setSystem(params->system);
201 } else {
202 checker = NULL;
203 }
204
205 if (!FullSystem) {
206 thread.resize(numThreads);
207 tids.resize(numThreads);
208 }
209
210 // The stages also need their CPU pointer setup. However this
211 // must be done at the upper level CPU because they have pointers
212 // to the upper level CPU, and not this FullO3CPU.
213
214 // Set up Pointers to the activeThreads list for each stage
215 fetch.setActiveThreads(&activeThreads);
216 decode.setActiveThreads(&activeThreads);
217 rename.setActiveThreads(&activeThreads);
218 iew.setActiveThreads(&activeThreads);
219 commit.setActiveThreads(&activeThreads);
220
221 // Give each of the stages the time buffer they will use.
222 fetch.setTimeBuffer(&timeBuffer);
223 decode.setTimeBuffer(&timeBuffer);
224 rename.setTimeBuffer(&timeBuffer);
225 iew.setTimeBuffer(&timeBuffer);
226 commit.setTimeBuffer(&timeBuffer);
227
228 // Also setup each of the stages' queues.
229 fetch.setFetchQueue(&fetchQueue);
230 decode.setFetchQueue(&fetchQueue);
231 commit.setFetchQueue(&fetchQueue);
232 decode.setDecodeQueue(&decodeQueue);
233 rename.setDecodeQueue(&decodeQueue);
234 rename.setRenameQueue(&renameQueue);
235 iew.setRenameQueue(&renameQueue);
236 iew.setIEWQueue(&iewQueue);
237 commit.setIEWQueue(&iewQueue);
238 commit.setRenameQueue(&renameQueue);
239
240 commit.setIEWStage(&iew);
241 rename.setIEWStage(&iew);
242 rename.setCommitStage(&commit);
243
244 ThreadID active_threads;
245 if (FullSystem) {
246 active_threads = 1;
247 } else {
248 active_threads = params->workload.size();
249
250 if (active_threads > Impl::MaxThreads) {
251 panic("Workload Size too large. Increase the 'MaxThreads' "
252 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
253 "or edit your workload size.");
254 }
255 }
256
257 //Make Sure That this a Valid Architeture
258 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs);
259 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs);
260 assert(params->numPhysVecRegs >= numThreads * TheISA::NumVecRegs);
163 params->numPhysCCRegs,
164 vecMode),
165
166 freeList(name() + ".freelist", &regFile),
167
168 rob(this, params),
169
170 scoreboard(name() + ".scoreboard",
171 regFile.totalNumPhysRegs()),
172
173 isa(numThreads, NULL),
174
175 icachePort(&fetch, this),
176 dcachePort(&iew.ldstQueue, this),
177
178 timeBuffer(params->backComSize, params->forwardComSize),
179 fetchQueue(params->backComSize, params->forwardComSize),
180 decodeQueue(params->backComSize, params->forwardComSize),
181 renameQueue(params->backComSize, params->forwardComSize),
182 iewQueue(params->backComSize, params->forwardComSize),
183 activityRec(name(), NumStages,
184 params->backComSize + params->forwardComSize,
185 params->activity),
186
187 globalSeqNum(1),
188 system(params->system),
189 lastRunningCycle(curCycle())
190{
191 if (!params->switched_out) {
192 _status = Running;
193 } else {
194 _status = SwitchedOut;
195 }
196
197 if (params->checker) {
198 BaseCPU *temp_checker = params->checker;
199 checker = dynamic_cast<Checker<Impl> *>(temp_checker);
200 checker->setIcachePort(&icachePort);
201 checker->setSystem(params->system);
202 } else {
203 checker = NULL;
204 }
205
206 if (!FullSystem) {
207 thread.resize(numThreads);
208 tids.resize(numThreads);
209 }
210
211 // The stages also need their CPU pointer setup. However this
212 // must be done at the upper level CPU because they have pointers
213 // to the upper level CPU, and not this FullO3CPU.
214
215 // Set up Pointers to the activeThreads list for each stage
216 fetch.setActiveThreads(&activeThreads);
217 decode.setActiveThreads(&activeThreads);
218 rename.setActiveThreads(&activeThreads);
219 iew.setActiveThreads(&activeThreads);
220 commit.setActiveThreads(&activeThreads);
221
222 // Give each of the stages the time buffer they will use.
223 fetch.setTimeBuffer(&timeBuffer);
224 decode.setTimeBuffer(&timeBuffer);
225 rename.setTimeBuffer(&timeBuffer);
226 iew.setTimeBuffer(&timeBuffer);
227 commit.setTimeBuffer(&timeBuffer);
228
229 // Also setup each of the stages' queues.
230 fetch.setFetchQueue(&fetchQueue);
231 decode.setFetchQueue(&fetchQueue);
232 commit.setFetchQueue(&fetchQueue);
233 decode.setDecodeQueue(&decodeQueue);
234 rename.setDecodeQueue(&decodeQueue);
235 rename.setRenameQueue(&renameQueue);
236 iew.setRenameQueue(&renameQueue);
237 iew.setIEWQueue(&iewQueue);
238 commit.setIEWQueue(&iewQueue);
239 commit.setRenameQueue(&renameQueue);
240
241 commit.setIEWStage(&iew);
242 rename.setIEWStage(&iew);
243 rename.setCommitStage(&commit);
244
245 ThreadID active_threads;
246 if (FullSystem) {
247 active_threads = 1;
248 } else {
249 active_threads = params->workload.size();
250
251 if (active_threads > Impl::MaxThreads) {
252 panic("Workload Size too large. Increase the 'MaxThreads' "
253 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
254 "or edit your workload size.");
255 }
256 }
257
258 //Make Sure That this a Valid Architeture
259 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs);
260 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs);
261 assert(params->numPhysVecRegs >= numThreads * TheISA::NumVecRegs);
262 assert(params->numPhysVecPredRegs >= numThreads * TheISA::NumVecPredRegs);
261 assert(params->numPhysCCRegs >= numThreads * TheISA::NumCCRegs);
262
263 rename.setScoreboard(&scoreboard);
264 iew.setScoreboard(&scoreboard);
265
266 // Setup the rename map for whichever stages need it.
267 for (ThreadID tid = 0; tid < numThreads; tid++) {
268 isa[tid] = params->isa[tid];
269 assert(RenameMode<TheISA::ISA>::equalsInit(isa[tid], isa[0]));
270
271 // Only Alpha has an FP zero register, so for other ISAs we
272 // use an invalid FP register index to avoid special treatment
273 // of any valid FP reg.
274 RegIndex invalidFPReg = TheISA::NumFloatRegs + 1;
275 RegIndex fpZeroReg =
276 (THE_ISA == ALPHA_ISA) ? TheISA::ZeroReg : invalidFPReg;
277
278 commitRenameMap[tid].init(&regFile, TheISA::ZeroReg, fpZeroReg,
279 &freeList,
280 vecMode);
281
282 renameMap[tid].init(&regFile, TheISA::ZeroReg, fpZeroReg,
283 &freeList, vecMode);
284 }
285
286 // Initialize rename map to assign physical registers to the
287 // architectural registers for active threads only.
288 for (ThreadID tid = 0; tid < active_threads; tid++) {
289 for (RegIndex ridx = 0; ridx < TheISA::NumIntRegs; ++ridx) {
290 // Note that we can't use the rename() method because we don't
291 // want special treatment for the zero register at this point
292 PhysRegIdPtr phys_reg = freeList.getIntReg();
293 renameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg);
294 commitRenameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg);
295 }
296
297 for (RegIndex ridx = 0; ridx < TheISA::NumFloatRegs; ++ridx) {
298 PhysRegIdPtr phys_reg = freeList.getFloatReg();
299 renameMap[tid].setEntry(RegId(FloatRegClass, ridx), phys_reg);
300 commitRenameMap[tid].setEntry(
301 RegId(FloatRegClass, ridx), phys_reg);
302 }
303
304 /* Here we need two 'interfaces' the 'whole register' and the
305 * 'register element'. At any point only one of them will be
306 * active. */
307 if (vecMode == Enums::Full) {
308 /* Initialize the full-vector interface */
309 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) {
310 RegId rid = RegId(VecRegClass, ridx);
311 PhysRegIdPtr phys_reg = freeList.getVecReg();
312 renameMap[tid].setEntry(rid, phys_reg);
313 commitRenameMap[tid].setEntry(rid, phys_reg);
314 }
315 } else {
316 /* Initialize the vector-element interface */
317 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) {
318 for (ElemIndex ldx = 0; ldx < TheISA::NumVecElemPerVecReg;
319 ++ldx) {
320 RegId lrid = RegId(VecElemClass, ridx, ldx);
321 PhysRegIdPtr phys_elem = freeList.getVecElem();
322 renameMap[tid].setEntry(lrid, phys_elem);
323 commitRenameMap[tid].setEntry(lrid, phys_elem);
324 }
325 }
326 }
327
263 assert(params->numPhysCCRegs >= numThreads * TheISA::NumCCRegs);
264
265 rename.setScoreboard(&scoreboard);
266 iew.setScoreboard(&scoreboard);
267
268 // Setup the rename map for whichever stages need it.
269 for (ThreadID tid = 0; tid < numThreads; tid++) {
270 isa[tid] = params->isa[tid];
271 assert(RenameMode<TheISA::ISA>::equalsInit(isa[tid], isa[0]));
272
273 // Only Alpha has an FP zero register, so for other ISAs we
274 // use an invalid FP register index to avoid special treatment
275 // of any valid FP reg.
276 RegIndex invalidFPReg = TheISA::NumFloatRegs + 1;
277 RegIndex fpZeroReg =
278 (THE_ISA == ALPHA_ISA) ? TheISA::ZeroReg : invalidFPReg;
279
280 commitRenameMap[tid].init(&regFile, TheISA::ZeroReg, fpZeroReg,
281 &freeList,
282 vecMode);
283
284 renameMap[tid].init(&regFile, TheISA::ZeroReg, fpZeroReg,
285 &freeList, vecMode);
286 }
287
288 // Initialize rename map to assign physical registers to the
289 // architectural registers for active threads only.
290 for (ThreadID tid = 0; tid < active_threads; tid++) {
291 for (RegIndex ridx = 0; ridx < TheISA::NumIntRegs; ++ridx) {
292 // Note that we can't use the rename() method because we don't
293 // want special treatment for the zero register at this point
294 PhysRegIdPtr phys_reg = freeList.getIntReg();
295 renameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg);
296 commitRenameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg);
297 }
298
299 for (RegIndex ridx = 0; ridx < TheISA::NumFloatRegs; ++ridx) {
300 PhysRegIdPtr phys_reg = freeList.getFloatReg();
301 renameMap[tid].setEntry(RegId(FloatRegClass, ridx), phys_reg);
302 commitRenameMap[tid].setEntry(
303 RegId(FloatRegClass, ridx), phys_reg);
304 }
305
306 /* Here we need two 'interfaces' the 'whole register' and the
307 * 'register element'. At any point only one of them will be
308 * active. */
309 if (vecMode == Enums::Full) {
310 /* Initialize the full-vector interface */
311 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) {
312 RegId rid = RegId(VecRegClass, ridx);
313 PhysRegIdPtr phys_reg = freeList.getVecReg();
314 renameMap[tid].setEntry(rid, phys_reg);
315 commitRenameMap[tid].setEntry(rid, phys_reg);
316 }
317 } else {
318 /* Initialize the vector-element interface */
319 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) {
320 for (ElemIndex ldx = 0; ldx < TheISA::NumVecElemPerVecReg;
321 ++ldx) {
322 RegId lrid = RegId(VecElemClass, ridx, ldx);
323 PhysRegIdPtr phys_elem = freeList.getVecElem();
324 renameMap[tid].setEntry(lrid, phys_elem);
325 commitRenameMap[tid].setEntry(lrid, phys_elem);
326 }
327 }
328 }
329
330 for (RegIndex ridx = 0; ridx < TheISA::NumVecPredRegs; ++ridx) {
331 PhysRegIdPtr phys_reg = freeList.getVecPredReg();
332 renameMap[tid].setEntry(RegId(VecPredRegClass, ridx), phys_reg);
333 commitRenameMap[tid].setEntry(
334 RegId(VecPredRegClass, ridx), phys_reg);
335 }
336
328 for (RegIndex ridx = 0; ridx < TheISA::NumCCRegs; ++ridx) {
329 PhysRegIdPtr phys_reg = freeList.getCCReg();
330 renameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg);
331 commitRenameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg);
332 }
333 }
334
335 rename.setRenameMap(renameMap);
336 commit.setRenameMap(commitRenameMap);
337 rename.setFreeList(&freeList);
338
339 // Setup the ROB for whichever stages need it.
340 commit.setROB(&rob);
341
342 lastActivatedCycle = 0;
343#if 0
344 // Give renameMap & rename stage access to the freeList;
345 for (ThreadID tid = 0; tid < numThreads; tid++)
346 globalSeqNum[tid] = 1;
347#endif
348
349 DPRINTF(O3CPU, "Creating O3CPU object.\n");
350
351 // Setup any thread state.
352 this->thread.resize(this->numThreads);
353
354 for (ThreadID tid = 0; tid < this->numThreads; ++tid) {
355 if (FullSystem) {
356 // SMT is not supported in FS mode yet.
357 assert(this->numThreads == 1);
358 this->thread[tid] = new Thread(this, 0, NULL);
359 } else {
360 if (tid < params->workload.size()) {
361 DPRINTF(O3CPU, "Workload[%i] process is %#x",
362 tid, this->thread[tid]);
363 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
364 (typename Impl::O3CPU *)(this),
365 tid, params->workload[tid]);
366
367 //usedTids[tid] = true;
368 //threadMap[tid] = tid;
369 } else {
370 //Allocate Empty thread so M5 can use later
371 //when scheduling threads to CPU
372 Process* dummy_proc = NULL;
373
374 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
375 (typename Impl::O3CPU *)(this),
376 tid, dummy_proc);
377 //usedTids[tid] = false;
378 }
379 }
380
381 ThreadContext *tc;
382
383 // Setup the TC that will serve as the interface to the threads/CPU.
384 O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
385
386 tc = o3_tc;
387
388 // If we're using a checker, then the TC should be the
389 // CheckerThreadContext.
390 if (params->checker) {
391 tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
392 o3_tc, this->checker);
393 }
394
395 o3_tc->cpu = (typename Impl::O3CPU *)(this);
396 assert(o3_tc->cpu);
397 o3_tc->thread = this->thread[tid];
398
399 // Setup quiesce event.
400 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc);
401
402 // Give the thread the TC.
403 this->thread[tid]->tc = tc;
404
405 // Add the TC to the CPU's list of TC's.
406 this->threadContexts.push_back(tc);
407 }
408
409 // FullO3CPU always requires an interrupt controller.
410 if (!params->switched_out && interrupts.empty()) {
411 fatal("FullO3CPU %s has no interrupt controller.\n"
412 "Ensure createInterruptController() is called.\n", name());
413 }
414
415 for (ThreadID tid = 0; tid < this->numThreads; tid++)
416 this->thread[tid]->setFuncExeInst(0);
417}
418
419template <class Impl>
420FullO3CPU<Impl>::~FullO3CPU()
421{
422}
423
424template <class Impl>
425void
426FullO3CPU<Impl>::regProbePoints()
427{
428 BaseCPU::regProbePoints();
429
430 ppInstAccessComplete = new ProbePointArg<PacketPtr>(getProbeManager(), "InstAccessComplete");
431 ppDataAccessComplete = new ProbePointArg<std::pair<DynInstPtr, PacketPtr> >(getProbeManager(), "DataAccessComplete");
432
433 fetch.regProbePoints();
434 rename.regProbePoints();
435 iew.regProbePoints();
436 commit.regProbePoints();
437}
438
439template <class Impl>
440void
441FullO3CPU<Impl>::regStats()
442{
443 BaseO3CPU::regStats();
444
445 // Register any of the O3CPU's stats here.
446 timesIdled
447 .name(name() + ".timesIdled")
448 .desc("Number of times that the entire CPU went into an idle state and"
449 " unscheduled itself")
450 .prereq(timesIdled);
451
452 idleCycles
453 .name(name() + ".idleCycles")
454 .desc("Total number of cycles that the CPU has spent unscheduled due "
455 "to idling")
456 .prereq(idleCycles);
457
458 quiesceCycles
459 .name(name() + ".quiesceCycles")
460 .desc("Total number of cycles that CPU has spent quiesced or waiting "
461 "for an interrupt")
462 .prereq(quiesceCycles);
463
464 // Number of Instructions simulated
465 // --------------------------------
466 // Should probably be in Base CPU but need templated
467 // MaxThreads so put in here instead
468 committedInsts
469 .init(numThreads)
470 .name(name() + ".committedInsts")
471 .desc("Number of Instructions Simulated")
472 .flags(Stats::total);
473
474 committedOps
475 .init(numThreads)
476 .name(name() + ".committedOps")
477 .desc("Number of Ops (including micro ops) Simulated")
478 .flags(Stats::total);
479
480 cpi
481 .name(name() + ".cpi")
482 .desc("CPI: Cycles Per Instruction")
483 .precision(6);
484 cpi = numCycles / committedInsts;
485
486 totalCpi
487 .name(name() + ".cpi_total")
488 .desc("CPI: Total CPI of All Threads")
489 .precision(6);
490 totalCpi = numCycles / sum(committedInsts);
491
492 ipc
493 .name(name() + ".ipc")
494 .desc("IPC: Instructions Per Cycle")
495 .precision(6);
496 ipc = committedInsts / numCycles;
497
498 totalIpc
499 .name(name() + ".ipc_total")
500 .desc("IPC: Total IPC of All Threads")
501 .precision(6);
502 totalIpc = sum(committedInsts) / numCycles;
503
504 this->fetch.regStats();
505 this->decode.regStats();
506 this->rename.regStats();
507 this->iew.regStats();
508 this->commit.regStats();
509 this->rob.regStats();
510
511 intRegfileReads
512 .name(name() + ".int_regfile_reads")
513 .desc("number of integer regfile reads")
514 .prereq(intRegfileReads);
515
516 intRegfileWrites
517 .name(name() + ".int_regfile_writes")
518 .desc("number of integer regfile writes")
519 .prereq(intRegfileWrites);
520
521 fpRegfileReads
522 .name(name() + ".fp_regfile_reads")
523 .desc("number of floating regfile reads")
524 .prereq(fpRegfileReads);
525
526 fpRegfileWrites
527 .name(name() + ".fp_regfile_writes")
528 .desc("number of floating regfile writes")
529 .prereq(fpRegfileWrites);
530
531 vecRegfileReads
532 .name(name() + ".vec_regfile_reads")
533 .desc("number of vector regfile reads")
534 .prereq(vecRegfileReads);
535
536 vecRegfileWrites
537 .name(name() + ".vec_regfile_writes")
538 .desc("number of vector regfile writes")
539 .prereq(vecRegfileWrites);
540
337 for (RegIndex ridx = 0; ridx < TheISA::NumCCRegs; ++ridx) {
338 PhysRegIdPtr phys_reg = freeList.getCCReg();
339 renameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg);
340 commitRenameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg);
341 }
342 }
343
344 rename.setRenameMap(renameMap);
345 commit.setRenameMap(commitRenameMap);
346 rename.setFreeList(&freeList);
347
348 // Setup the ROB for whichever stages need it.
349 commit.setROB(&rob);
350
351 lastActivatedCycle = 0;
352#if 0
353 // Give renameMap & rename stage access to the freeList;
354 for (ThreadID tid = 0; tid < numThreads; tid++)
355 globalSeqNum[tid] = 1;
356#endif
357
358 DPRINTF(O3CPU, "Creating O3CPU object.\n");
359
360 // Setup any thread state.
361 this->thread.resize(this->numThreads);
362
363 for (ThreadID tid = 0; tid < this->numThreads; ++tid) {
364 if (FullSystem) {
365 // SMT is not supported in FS mode yet.
366 assert(this->numThreads == 1);
367 this->thread[tid] = new Thread(this, 0, NULL);
368 } else {
369 if (tid < params->workload.size()) {
370 DPRINTF(O3CPU, "Workload[%i] process is %#x",
371 tid, this->thread[tid]);
372 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
373 (typename Impl::O3CPU *)(this),
374 tid, params->workload[tid]);
375
376 //usedTids[tid] = true;
377 //threadMap[tid] = tid;
378 } else {
379 //Allocate Empty thread so M5 can use later
380 //when scheduling threads to CPU
381 Process* dummy_proc = NULL;
382
383 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
384 (typename Impl::O3CPU *)(this),
385 tid, dummy_proc);
386 //usedTids[tid] = false;
387 }
388 }
389
390 ThreadContext *tc;
391
392 // Setup the TC that will serve as the interface to the threads/CPU.
393 O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
394
395 tc = o3_tc;
396
397 // If we're using a checker, then the TC should be the
398 // CheckerThreadContext.
399 if (params->checker) {
400 tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
401 o3_tc, this->checker);
402 }
403
404 o3_tc->cpu = (typename Impl::O3CPU *)(this);
405 assert(o3_tc->cpu);
406 o3_tc->thread = this->thread[tid];
407
408 // Setup quiesce event.
409 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc);
410
411 // Give the thread the TC.
412 this->thread[tid]->tc = tc;
413
414 // Add the TC to the CPU's list of TC's.
415 this->threadContexts.push_back(tc);
416 }
417
418 // FullO3CPU always requires an interrupt controller.
419 if (!params->switched_out && interrupts.empty()) {
420 fatal("FullO3CPU %s has no interrupt controller.\n"
421 "Ensure createInterruptController() is called.\n", name());
422 }
423
424 for (ThreadID tid = 0; tid < this->numThreads; tid++)
425 this->thread[tid]->setFuncExeInst(0);
426}
427
428template <class Impl>
429FullO3CPU<Impl>::~FullO3CPU()
430{
431}
432
433template <class Impl>
434void
435FullO3CPU<Impl>::regProbePoints()
436{
437 BaseCPU::regProbePoints();
438
439 ppInstAccessComplete = new ProbePointArg<PacketPtr>(getProbeManager(), "InstAccessComplete");
440 ppDataAccessComplete = new ProbePointArg<std::pair<DynInstPtr, PacketPtr> >(getProbeManager(), "DataAccessComplete");
441
442 fetch.regProbePoints();
443 rename.regProbePoints();
444 iew.regProbePoints();
445 commit.regProbePoints();
446}
447
448template <class Impl>
449void
450FullO3CPU<Impl>::regStats()
451{
452 BaseO3CPU::regStats();
453
454 // Register any of the O3CPU's stats here.
455 timesIdled
456 .name(name() + ".timesIdled")
457 .desc("Number of times that the entire CPU went into an idle state and"
458 " unscheduled itself")
459 .prereq(timesIdled);
460
461 idleCycles
462 .name(name() + ".idleCycles")
463 .desc("Total number of cycles that the CPU has spent unscheduled due "
464 "to idling")
465 .prereq(idleCycles);
466
467 quiesceCycles
468 .name(name() + ".quiesceCycles")
469 .desc("Total number of cycles that CPU has spent quiesced or waiting "
470 "for an interrupt")
471 .prereq(quiesceCycles);
472
473 // Number of Instructions simulated
474 // --------------------------------
475 // Should probably be in Base CPU but need templated
476 // MaxThreads so put in here instead
477 committedInsts
478 .init(numThreads)
479 .name(name() + ".committedInsts")
480 .desc("Number of Instructions Simulated")
481 .flags(Stats::total);
482
483 committedOps
484 .init(numThreads)
485 .name(name() + ".committedOps")
486 .desc("Number of Ops (including micro ops) Simulated")
487 .flags(Stats::total);
488
489 cpi
490 .name(name() + ".cpi")
491 .desc("CPI: Cycles Per Instruction")
492 .precision(6);
493 cpi = numCycles / committedInsts;
494
495 totalCpi
496 .name(name() + ".cpi_total")
497 .desc("CPI: Total CPI of All Threads")
498 .precision(6);
499 totalCpi = numCycles / sum(committedInsts);
500
501 ipc
502 .name(name() + ".ipc")
503 .desc("IPC: Instructions Per Cycle")
504 .precision(6);
505 ipc = committedInsts / numCycles;
506
507 totalIpc
508 .name(name() + ".ipc_total")
509 .desc("IPC: Total IPC of All Threads")
510 .precision(6);
511 totalIpc = sum(committedInsts) / numCycles;
512
513 this->fetch.regStats();
514 this->decode.regStats();
515 this->rename.regStats();
516 this->iew.regStats();
517 this->commit.regStats();
518 this->rob.regStats();
519
520 intRegfileReads
521 .name(name() + ".int_regfile_reads")
522 .desc("number of integer regfile reads")
523 .prereq(intRegfileReads);
524
525 intRegfileWrites
526 .name(name() + ".int_regfile_writes")
527 .desc("number of integer regfile writes")
528 .prereq(intRegfileWrites);
529
530 fpRegfileReads
531 .name(name() + ".fp_regfile_reads")
532 .desc("number of floating regfile reads")
533 .prereq(fpRegfileReads);
534
535 fpRegfileWrites
536 .name(name() + ".fp_regfile_writes")
537 .desc("number of floating regfile writes")
538 .prereq(fpRegfileWrites);
539
540 vecRegfileReads
541 .name(name() + ".vec_regfile_reads")
542 .desc("number of vector regfile reads")
543 .prereq(vecRegfileReads);
544
545 vecRegfileWrites
546 .name(name() + ".vec_regfile_writes")
547 .desc("number of vector regfile writes")
548 .prereq(vecRegfileWrites);
549
550 vecPredRegfileReads
551 .name(name() + ".pred_regfile_reads")
552 .desc("number of predicate regfile reads")
553 .prereq(vecPredRegfileReads);
554
555 vecPredRegfileWrites
556 .name(name() + ".pred_regfile_writes")
557 .desc("number of predicate regfile writes")
558 .prereq(vecPredRegfileWrites);
559
541 ccRegfileReads
542 .name(name() + ".cc_regfile_reads")
543 .desc("number of cc regfile reads")
544 .prereq(ccRegfileReads);
545
546 ccRegfileWrites
547 .name(name() + ".cc_regfile_writes")
548 .desc("number of cc regfile writes")
549 .prereq(ccRegfileWrites);
550
551 miscRegfileReads
552 .name(name() + ".misc_regfile_reads")
553 .desc("number of misc regfile reads")
554 .prereq(miscRegfileReads);
555
556 miscRegfileWrites
557 .name(name() + ".misc_regfile_writes")
558 .desc("number of misc regfile writes")
559 .prereq(miscRegfileWrites);
560}
561
562template <class Impl>
563void
564FullO3CPU<Impl>::tick()
565{
566 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
567 assert(!switchedOut());
568 assert(drainState() != DrainState::Drained);
569
570 ++numCycles;
571 updateCycleCounters(BaseCPU::CPU_STATE_ON);
572
573// activity = false;
574
575 //Tick each of the stages
576 fetch.tick();
577
578 decode.tick();
579
580 rename.tick();
581
582 iew.tick();
583
584 commit.tick();
585
586 // Now advance the time buffers
587 timeBuffer.advance();
588
589 fetchQueue.advance();
590 decodeQueue.advance();
591 renameQueue.advance();
592 iewQueue.advance();
593
594 activityRec.advance();
595
596 if (removeInstsThisCycle) {
597 cleanUpRemovedInsts();
598 }
599
600 if (!tickEvent.scheduled()) {
601 if (_status == SwitchedOut) {
602 DPRINTF(O3CPU, "Switched out!\n");
603 // increment stat
604 lastRunningCycle = curCycle();
605 } else if (!activityRec.active() || _status == Idle) {
606 DPRINTF(O3CPU, "Idle!\n");
607 lastRunningCycle = curCycle();
608 timesIdled++;
609 } else {
610 schedule(tickEvent, clockEdge(Cycles(1)));
611 DPRINTF(O3CPU, "Scheduling next tick!\n");
612 }
613 }
614
615 if (!FullSystem)
616 updateThreadPriority();
617
618 tryDrain();
619}
620
621template <class Impl>
622void
623FullO3CPU<Impl>::init()
624{
625 BaseCPU::init();
626
627 for (ThreadID tid = 0; tid < numThreads; ++tid) {
628 // Set noSquashFromTC so that the CPU doesn't squash when initially
629 // setting up registers.
630 thread[tid]->noSquashFromTC = true;
631 // Initialise the ThreadContext's memory proxies
632 thread[tid]->initMemProxies(thread[tid]->getTC());
633 }
634
635 if (FullSystem && !params()->switched_out) {
636 for (ThreadID tid = 0; tid < numThreads; tid++) {
637 ThreadContext *src_tc = threadContexts[tid];
638 TheISA::initCPU(src_tc, src_tc->contextId());
639 }
640 }
641
642 // Clear noSquashFromTC.
643 for (int tid = 0; tid < numThreads; ++tid)
644 thread[tid]->noSquashFromTC = false;
645
646 commit.setThreads(thread);
647}
648
649template <class Impl>
650void
651FullO3CPU<Impl>::startup()
652{
653 BaseCPU::startup();
654 for (int tid = 0; tid < numThreads; ++tid)
655 isa[tid]->startup(threadContexts[tid]);
656
657 fetch.startupStage();
658 decode.startupStage();
659 iew.startupStage();
660 rename.startupStage();
661 commit.startupStage();
662}
663
664template <class Impl>
665void
666FullO3CPU<Impl>::activateThread(ThreadID tid)
667{
668 list<ThreadID>::iterator isActive =
669 std::find(activeThreads.begin(), activeThreads.end(), tid);
670
671 DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);
672 assert(!switchedOut());
673
674 if (isActive == activeThreads.end()) {
675 DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
676 tid);
677
678 activeThreads.push_back(tid);
679 }
680}
681
682template <class Impl>
683void
684FullO3CPU<Impl>::deactivateThread(ThreadID tid)
685{
686 //Remove From Active List, if Active
687 list<ThreadID>::iterator thread_it =
688 std::find(activeThreads.begin(), activeThreads.end(), tid);
689
690 DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);
691 assert(!switchedOut());
692
693 if (thread_it != activeThreads.end()) {
694 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
695 tid);
696 activeThreads.erase(thread_it);
697 }
698
699 fetch.deactivateThread(tid);
700 commit.deactivateThread(tid);
701}
702
703template <class Impl>
704Counter
705FullO3CPU<Impl>::totalInsts() const
706{
707 Counter total(0);
708
709 ThreadID size = thread.size();
710 for (ThreadID i = 0; i < size; i++)
711 total += thread[i]->numInst;
712
713 return total;
714}
715
716template <class Impl>
717Counter
718FullO3CPU<Impl>::totalOps() const
719{
720 Counter total(0);
721
722 ThreadID size = thread.size();
723 for (ThreadID i = 0; i < size; i++)
724 total += thread[i]->numOp;
725
726 return total;
727}
728
729template <class Impl>
730void
731FullO3CPU<Impl>::activateContext(ThreadID tid)
732{
733 assert(!switchedOut());
734
735 // Needs to set each stage to running as well.
736 activateThread(tid);
737
738 // We don't want to wake the CPU if it is drained. In that case,
739 // we just want to flag the thread as active and schedule the tick
740 // event from drainResume() instead.
741 if (drainState() == DrainState::Drained)
742 return;
743
744 // If we are time 0 or if the last activation time is in the past,
745 // schedule the next tick and wake up the fetch unit
746 if (lastActivatedCycle == 0 || lastActivatedCycle < curTick()) {
747 scheduleTickEvent(Cycles(0));
748
749 // Be sure to signal that there's some activity so the CPU doesn't
750 // deschedule itself.
751 activityRec.activity();
752 fetch.wakeFromQuiesce();
753
754 Cycles cycles(curCycle() - lastRunningCycle);
755 // @todo: This is an oddity that is only here to match the stats
756 if (cycles != 0)
757 --cycles;
758 quiesceCycles += cycles;
759
760 lastActivatedCycle = curTick();
761
762 _status = Running;
763
764 BaseCPU::activateContext(tid);
765 }
766}
767
768template <class Impl>
769void
770FullO3CPU<Impl>::suspendContext(ThreadID tid)
771{
772 DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
773 assert(!switchedOut());
774
775 deactivateThread(tid);
776
777 // If this was the last thread then unschedule the tick event.
778 if (activeThreads.size() == 0) {
779 unscheduleTickEvent();
780 lastRunningCycle = curCycle();
781 _status = Idle;
782 }
783
784 DPRINTF(Quiesce, "Suspending Context\n");
785
786 BaseCPU::suspendContext(tid);
787}
788
789template <class Impl>
790void
791FullO3CPU<Impl>::haltContext(ThreadID tid)
792{
793 //For now, this is the same as deallocate
794 DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
795 assert(!switchedOut());
796
797 deactivateThread(tid);
798 removeThread(tid);
799
800 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP);
801}
802
803template <class Impl>
804void
805FullO3CPU<Impl>::insertThread(ThreadID tid)
806{
807 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
808 // Will change now that the PC and thread state is internal to the CPU
809 // and not in the ThreadContext.
810 ThreadContext *src_tc;
811 if (FullSystem)
812 src_tc = system->threadContexts[tid];
813 else
814 src_tc = tcBase(tid);
815
816 //Bind Int Regs to Rename Map
817
818 for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs;
819 reg_id.index()++) {
820 PhysRegIdPtr phys_reg = freeList.getIntReg();
821 renameMap[tid].setEntry(reg_id, phys_reg);
822 scoreboard.setReg(phys_reg);
823 }
824
825 //Bind Float Regs to Rename Map
826 for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs;
827 reg_id.index()++) {
828 PhysRegIdPtr phys_reg = freeList.getFloatReg();
829 renameMap[tid].setEntry(reg_id, phys_reg);
830 scoreboard.setReg(phys_reg);
831 }
832
833 //Bind condition-code Regs to Rename Map
834 for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs;
835 reg_id.index()++) {
836 PhysRegIdPtr phys_reg = freeList.getCCReg();
837 renameMap[tid].setEntry(reg_id, phys_reg);
838 scoreboard.setReg(phys_reg);
839 }
840
841 //Copy Thread Data Into RegFile
842 //this->copyFromTC(tid);
843
844 //Set PC/NPC/NNPC
845 pcState(src_tc->pcState(), tid);
846
847 src_tc->setStatus(ThreadContext::Active);
848
849 activateContext(tid);
850
851 //Reset ROB/IQ/LSQ Entries
852 commit.rob->resetEntries();
853}
854
855template <class Impl>
856void
857FullO3CPU<Impl>::removeThread(ThreadID tid)
858{
859 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);
860
861 // Copy Thread Data From RegFile
862 // If thread is suspended, it might be re-allocated
863 // this->copyToTC(tid);
864
865
866 // @todo: 2-27-2008: Fix how we free up rename mappings
867 // here to alleviate the case for double-freeing registers
868 // in SMT workloads.
869
870 // Unbind Int Regs from Rename Map
871 for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs;
872 reg_id.index()++) {
873 PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
874 scoreboard.unsetReg(phys_reg);
875 freeList.addReg(phys_reg);
876 }
877
878 // Unbind Float Regs from Rename Map
879 for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs;
880 reg_id.index()++) {
881 PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
882 scoreboard.unsetReg(phys_reg);
883 freeList.addReg(phys_reg);
884 }
885
560 ccRegfileReads
561 .name(name() + ".cc_regfile_reads")
562 .desc("number of cc regfile reads")
563 .prereq(ccRegfileReads);
564
565 ccRegfileWrites
566 .name(name() + ".cc_regfile_writes")
567 .desc("number of cc regfile writes")
568 .prereq(ccRegfileWrites);
569
570 miscRegfileReads
571 .name(name() + ".misc_regfile_reads")
572 .desc("number of misc regfile reads")
573 .prereq(miscRegfileReads);
574
575 miscRegfileWrites
576 .name(name() + ".misc_regfile_writes")
577 .desc("number of misc regfile writes")
578 .prereq(miscRegfileWrites);
579}
580
581template <class Impl>
582void
583FullO3CPU<Impl>::tick()
584{
585 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
586 assert(!switchedOut());
587 assert(drainState() != DrainState::Drained);
588
589 ++numCycles;
590 updateCycleCounters(BaseCPU::CPU_STATE_ON);
591
592// activity = false;
593
594 //Tick each of the stages
595 fetch.tick();
596
597 decode.tick();
598
599 rename.tick();
600
601 iew.tick();
602
603 commit.tick();
604
605 // Now advance the time buffers
606 timeBuffer.advance();
607
608 fetchQueue.advance();
609 decodeQueue.advance();
610 renameQueue.advance();
611 iewQueue.advance();
612
613 activityRec.advance();
614
615 if (removeInstsThisCycle) {
616 cleanUpRemovedInsts();
617 }
618
619 if (!tickEvent.scheduled()) {
620 if (_status == SwitchedOut) {
621 DPRINTF(O3CPU, "Switched out!\n");
622 // increment stat
623 lastRunningCycle = curCycle();
624 } else if (!activityRec.active() || _status == Idle) {
625 DPRINTF(O3CPU, "Idle!\n");
626 lastRunningCycle = curCycle();
627 timesIdled++;
628 } else {
629 schedule(tickEvent, clockEdge(Cycles(1)));
630 DPRINTF(O3CPU, "Scheduling next tick!\n");
631 }
632 }
633
634 if (!FullSystem)
635 updateThreadPriority();
636
637 tryDrain();
638}
639
640template <class Impl>
641void
642FullO3CPU<Impl>::init()
643{
644 BaseCPU::init();
645
646 for (ThreadID tid = 0; tid < numThreads; ++tid) {
647 // Set noSquashFromTC so that the CPU doesn't squash when initially
648 // setting up registers.
649 thread[tid]->noSquashFromTC = true;
650 // Initialise the ThreadContext's memory proxies
651 thread[tid]->initMemProxies(thread[tid]->getTC());
652 }
653
654 if (FullSystem && !params()->switched_out) {
655 for (ThreadID tid = 0; tid < numThreads; tid++) {
656 ThreadContext *src_tc = threadContexts[tid];
657 TheISA::initCPU(src_tc, src_tc->contextId());
658 }
659 }
660
661 // Clear noSquashFromTC.
662 for (int tid = 0; tid < numThreads; ++tid)
663 thread[tid]->noSquashFromTC = false;
664
665 commit.setThreads(thread);
666}
667
668template <class Impl>
669void
670FullO3CPU<Impl>::startup()
671{
672 BaseCPU::startup();
673 for (int tid = 0; tid < numThreads; ++tid)
674 isa[tid]->startup(threadContexts[tid]);
675
676 fetch.startupStage();
677 decode.startupStage();
678 iew.startupStage();
679 rename.startupStage();
680 commit.startupStage();
681}
682
683template <class Impl>
684void
685FullO3CPU<Impl>::activateThread(ThreadID tid)
686{
687 list<ThreadID>::iterator isActive =
688 std::find(activeThreads.begin(), activeThreads.end(), tid);
689
690 DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);
691 assert(!switchedOut());
692
693 if (isActive == activeThreads.end()) {
694 DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
695 tid);
696
697 activeThreads.push_back(tid);
698 }
699}
700
701template <class Impl>
702void
703FullO3CPU<Impl>::deactivateThread(ThreadID tid)
704{
705 //Remove From Active List, if Active
706 list<ThreadID>::iterator thread_it =
707 std::find(activeThreads.begin(), activeThreads.end(), tid);
708
709 DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);
710 assert(!switchedOut());
711
712 if (thread_it != activeThreads.end()) {
713 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
714 tid);
715 activeThreads.erase(thread_it);
716 }
717
718 fetch.deactivateThread(tid);
719 commit.deactivateThread(tid);
720}
721
722template <class Impl>
723Counter
724FullO3CPU<Impl>::totalInsts() const
725{
726 Counter total(0);
727
728 ThreadID size = thread.size();
729 for (ThreadID i = 0; i < size; i++)
730 total += thread[i]->numInst;
731
732 return total;
733}
734
735template <class Impl>
736Counter
737FullO3CPU<Impl>::totalOps() const
738{
739 Counter total(0);
740
741 ThreadID size = thread.size();
742 for (ThreadID i = 0; i < size; i++)
743 total += thread[i]->numOp;
744
745 return total;
746}
747
748template <class Impl>
749void
750FullO3CPU<Impl>::activateContext(ThreadID tid)
751{
752 assert(!switchedOut());
753
754 // Needs to set each stage to running as well.
755 activateThread(tid);
756
757 // We don't want to wake the CPU if it is drained. In that case,
758 // we just want to flag the thread as active and schedule the tick
759 // event from drainResume() instead.
760 if (drainState() == DrainState::Drained)
761 return;
762
763 // If we are time 0 or if the last activation time is in the past,
764 // schedule the next tick and wake up the fetch unit
765 if (lastActivatedCycle == 0 || lastActivatedCycle < curTick()) {
766 scheduleTickEvent(Cycles(0));
767
768 // Be sure to signal that there's some activity so the CPU doesn't
769 // deschedule itself.
770 activityRec.activity();
771 fetch.wakeFromQuiesce();
772
773 Cycles cycles(curCycle() - lastRunningCycle);
774 // @todo: This is an oddity that is only here to match the stats
775 if (cycles != 0)
776 --cycles;
777 quiesceCycles += cycles;
778
779 lastActivatedCycle = curTick();
780
781 _status = Running;
782
783 BaseCPU::activateContext(tid);
784 }
785}
786
787template <class Impl>
788void
789FullO3CPU<Impl>::suspendContext(ThreadID tid)
790{
791 DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
792 assert(!switchedOut());
793
794 deactivateThread(tid);
795
796 // If this was the last thread then unschedule the tick event.
797 if (activeThreads.size() == 0) {
798 unscheduleTickEvent();
799 lastRunningCycle = curCycle();
800 _status = Idle;
801 }
802
803 DPRINTF(Quiesce, "Suspending Context\n");
804
805 BaseCPU::suspendContext(tid);
806}
807
808template <class Impl>
809void
810FullO3CPU<Impl>::haltContext(ThreadID tid)
811{
812 //For now, this is the same as deallocate
813 DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
814 assert(!switchedOut());
815
816 deactivateThread(tid);
817 removeThread(tid);
818
819 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP);
820}
821
822template <class Impl>
823void
824FullO3CPU<Impl>::insertThread(ThreadID tid)
825{
826 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
827 // Will change now that the PC and thread state is internal to the CPU
828 // and not in the ThreadContext.
829 ThreadContext *src_tc;
830 if (FullSystem)
831 src_tc = system->threadContexts[tid];
832 else
833 src_tc = tcBase(tid);
834
835 //Bind Int Regs to Rename Map
836
837 for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs;
838 reg_id.index()++) {
839 PhysRegIdPtr phys_reg = freeList.getIntReg();
840 renameMap[tid].setEntry(reg_id, phys_reg);
841 scoreboard.setReg(phys_reg);
842 }
843
844 //Bind Float Regs to Rename Map
845 for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs;
846 reg_id.index()++) {
847 PhysRegIdPtr phys_reg = freeList.getFloatReg();
848 renameMap[tid].setEntry(reg_id, phys_reg);
849 scoreboard.setReg(phys_reg);
850 }
851
852 //Bind condition-code Regs to Rename Map
853 for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs;
854 reg_id.index()++) {
855 PhysRegIdPtr phys_reg = freeList.getCCReg();
856 renameMap[tid].setEntry(reg_id, phys_reg);
857 scoreboard.setReg(phys_reg);
858 }
859
860 //Copy Thread Data Into RegFile
861 //this->copyFromTC(tid);
862
863 //Set PC/NPC/NNPC
864 pcState(src_tc->pcState(), tid);
865
866 src_tc->setStatus(ThreadContext::Active);
867
868 activateContext(tid);
869
870 //Reset ROB/IQ/LSQ Entries
871 commit.rob->resetEntries();
872}
873
874template <class Impl>
875void
876FullO3CPU<Impl>::removeThread(ThreadID tid)
877{
878 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);
879
880 // Copy Thread Data From RegFile
881 // If thread is suspended, it might be re-allocated
882 // this->copyToTC(tid);
883
884
885 // @todo: 2-27-2008: Fix how we free up rename mappings
886 // here to alleviate the case for double-freeing registers
887 // in SMT workloads.
888
889 // Unbind Int Regs from Rename Map
890 for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs;
891 reg_id.index()++) {
892 PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
893 scoreboard.unsetReg(phys_reg);
894 freeList.addReg(phys_reg);
895 }
896
897 // Unbind Float Regs from Rename Map
898 for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs;
899 reg_id.index()++) {
900 PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
901 scoreboard.unsetReg(phys_reg);
902 freeList.addReg(phys_reg);
903 }
904
905 // Unbind Float Regs from Rename Map
906 for (unsigned preg = 0; preg < TheISA::NumVecPredRegs; preg++) {
907 PhysRegIdPtr phys_reg = renameMap[tid].lookup(
908 RegId(VecPredRegClass, preg));
909 scoreboard.unsetReg(phys_reg);
910 freeList.addReg(phys_reg);
911 }
912
886 // Unbind condition-code Regs from Rename Map
887 for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs;
888 reg_id.index()++) {
889 PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
890 scoreboard.unsetReg(phys_reg);
891 freeList.addReg(phys_reg);
892 }
893
894 // Squash Throughout Pipeline
895 DynInstPtr inst = commit.rob->readHeadInst(tid);
896 InstSeqNum squash_seq_num = inst->seqNum;
897 fetch.squash(0, squash_seq_num, inst, tid);
898 decode.squash(tid);
899 rename.squash(squash_seq_num, tid);
900 iew.squash(tid);
901 iew.ldstQueue.squash(squash_seq_num, tid);
902 commit.rob->squash(squash_seq_num, tid);
903
904
905 assert(iew.instQueue.getCount(tid) == 0);
906 assert(iew.ldstQueue.getCount(tid) == 0);
907
908 // Reset ROB/IQ/LSQ Entries
909
910 // Commented out for now. This should be possible to do by
911 // telling all the pipeline stages to drain first, and then
912 // checking until the drain completes. Once the pipeline is
913 // drained, call resetEntries(). - 10-09-06 ktlim
914/*
915 if (activeThreads.size() >= 1) {
916 commit.rob->resetEntries();
917 iew.resetEntries();
918 }
919*/
920}
921
922template <class Impl>
923Fault
924FullO3CPU<Impl>::hwrei(ThreadID tid)
925{
926#if THE_ISA == ALPHA_ISA
927 // Need to clear the lock flag upon returning from an interrupt.
928 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
929
930 this->thread[tid]->kernelStats->hwrei();
931
932 // FIXME: XXX check for interrupts? XXX
933#endif
934 return NoFault;
935}
936
937template <class Impl>
938bool
939FullO3CPU<Impl>::simPalCheck(int palFunc, ThreadID tid)
940{
941#if THE_ISA == ALPHA_ISA
942 if (this->thread[tid]->kernelStats)
943 this->thread[tid]->kernelStats->callpal(palFunc,
944 this->threadContexts[tid]);
945
946 switch (palFunc) {
947 case PAL::halt:
948 halt();
949 if (--System::numSystemsRunning == 0)
950 exitSimLoop("all cpus halted");
951 break;
952
953 case PAL::bpt:
954 case PAL::bugchk:
955 if (this->system->breakpoint())
956 return false;
957 break;
958 }
959#endif
960 return true;
961}
962
963template <class Impl>
964void
965FullO3CPU<Impl>::switchRenameMode(ThreadID tid, UnifiedFreeList* freelist)
966{
967 auto pc = this->pcState(tid);
968
969 // new_mode is the new vector renaming mode
970 auto new_mode = RenameMode<TheISA::ISA>::mode(pc);
971
972 // We update vecMode only if there has been a change
973 if (new_mode != vecMode) {
974 vecMode = new_mode;
975
976 renameMap[tid].switchMode(vecMode);
977 commitRenameMap[tid].switchMode(vecMode);
978 renameMap[tid].switchFreeList(freelist);
979 }
980}
981
982template <class Impl>
983Fault
984FullO3CPU<Impl>::getInterrupts()
985{
986 // Check if there are any outstanding interrupts
987 return this->interrupts[0]->getInterrupt(this->threadContexts[0]);
988}
989
990template <class Impl>
991void
992FullO3CPU<Impl>::processInterrupts(const Fault &interrupt)
993{
994 // Check for interrupts here. For now can copy the code that
995 // exists within isa_fullsys_traits.hh. Also assume that thread 0
996 // is the one that handles the interrupts.
997 // @todo: Possibly consolidate the interrupt checking code.
998 // @todo: Allow other threads to handle interrupts.
999
1000 assert(interrupt != NoFault);
1001 this->interrupts[0]->updateIntrInfo(this->threadContexts[0]);
1002
1003 DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
1004 this->trap(interrupt, 0, nullptr);
1005}
1006
1007template <class Impl>
1008void
1009FullO3CPU<Impl>::trap(const Fault &fault, ThreadID tid,
1010 const StaticInstPtr &inst)
1011{
1012 // Pass the thread's TC into the invoke method.
1013 fault->invoke(this->threadContexts[tid], inst);
1014}
1015
1016template <class Impl>
1017void
1018FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid, Fault *fault)
1019{
1020 DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);
1021
1022 DPRINTF(Activity,"Activity: syscall() called.\n");
1023
1024 // Temporarily increase this by one to account for the syscall
1025 // instruction.
1026 ++(this->thread[tid]->funcExeInst);
1027
1028 // Execute the actual syscall.
1029 this->thread[tid]->syscall(callnum, fault);
1030
1031 // Decrease funcExeInst by one as the normal commit will handle
1032 // incrementing it.
1033 --(this->thread[tid]->funcExeInst);
1034}
1035
1036template <class Impl>
1037void
1038FullO3CPU<Impl>::serializeThread(CheckpointOut &cp, ThreadID tid) const
1039{
1040 thread[tid]->serialize(cp);
1041}
1042
1043template <class Impl>
1044void
1045FullO3CPU<Impl>::unserializeThread(CheckpointIn &cp, ThreadID tid)
1046{
1047 thread[tid]->unserialize(cp);
1048}
1049
1050template <class Impl>
1051DrainState
1052FullO3CPU<Impl>::drain()
1053{
1054 // Deschedule any power gating event (if any)
1055 deschedulePowerGatingEvent();
1056
1057 // If the CPU isn't doing anything, then return immediately.
1058 if (switchedOut())
1059 return DrainState::Drained;
1060
1061 DPRINTF(Drain, "Draining...\n");
1062
1063 // We only need to signal a drain to the commit stage as this
1064 // initiates squashing controls the draining. Once the commit
1065 // stage commits an instruction where it is safe to stop, it'll
1066 // squash the rest of the instructions in the pipeline and force
1067 // the fetch stage to stall. The pipeline will be drained once all
1068 // in-flight instructions have retired.
1069 commit.drain();
1070
1071 // Wake the CPU and record activity so everything can drain out if
1072 // the CPU was not able to immediately drain.
1073 if (!isDrained()) {
1074 // If a thread is suspended, wake it up so it can be drained
1075 for (auto t : threadContexts) {
1076 if (t->status() == ThreadContext::Suspended){
1077 DPRINTF(Drain, "Currently suspended so activate %i \n",
1078 t->threadId());
1079 t->activate();
1080 // As the thread is now active, change the power state as well
1081 activateContext(t->threadId());
1082 }
1083 }
1084
1085 wakeCPU();
1086 activityRec.activity();
1087
1088 DPRINTF(Drain, "CPU not drained\n");
1089
1090 return DrainState::Draining;
1091 } else {
1092 DPRINTF(Drain, "CPU is already drained\n");
1093 if (tickEvent.scheduled())
1094 deschedule(tickEvent);
1095
1096 // Flush out any old data from the time buffers. In
1097 // particular, there might be some data in flight from the
1098 // fetch stage that isn't visible in any of the CPU buffers we
1099 // test in isDrained().
1100 for (int i = 0; i < timeBuffer.getSize(); ++i) {
1101 timeBuffer.advance();
1102 fetchQueue.advance();
1103 decodeQueue.advance();
1104 renameQueue.advance();
1105 iewQueue.advance();
1106 }
1107
1108 drainSanityCheck();
1109 return DrainState::Drained;
1110 }
1111}
1112
1113template <class Impl>
1114bool
1115FullO3CPU<Impl>::tryDrain()
1116{
1117 if (drainState() != DrainState::Draining || !isDrained())
1118 return false;
1119
1120 if (tickEvent.scheduled())
1121 deschedule(tickEvent);
1122
1123 DPRINTF(Drain, "CPU done draining, processing drain event\n");
1124 signalDrainDone();
1125
1126 return true;
1127}
1128
1129template <class Impl>
1130void
1131FullO3CPU<Impl>::drainSanityCheck() const
1132{
1133 assert(isDrained());
1134 fetch.drainSanityCheck();
1135 decode.drainSanityCheck();
1136 rename.drainSanityCheck();
1137 iew.drainSanityCheck();
1138 commit.drainSanityCheck();
1139}
1140
1141template <class Impl>
1142bool
1143FullO3CPU<Impl>::isDrained() const
1144{
1145 bool drained(true);
1146
1147 if (!instList.empty() || !removeList.empty()) {
1148 DPRINTF(Drain, "Main CPU structures not drained.\n");
1149 drained = false;
1150 }
1151
1152 if (!fetch.isDrained()) {
1153 DPRINTF(Drain, "Fetch not drained.\n");
1154 drained = false;
1155 }
1156
1157 if (!decode.isDrained()) {
1158 DPRINTF(Drain, "Decode not drained.\n");
1159 drained = false;
1160 }
1161
1162 if (!rename.isDrained()) {
1163 DPRINTF(Drain, "Rename not drained.\n");
1164 drained = false;
1165 }
1166
1167 if (!iew.isDrained()) {
1168 DPRINTF(Drain, "IEW not drained.\n");
1169 drained = false;
1170 }
1171
1172 if (!commit.isDrained()) {
1173 DPRINTF(Drain, "Commit not drained.\n");
1174 drained = false;
1175 }
1176
1177 return drained;
1178}
1179
1180template <class Impl>
1181void
1182FullO3CPU<Impl>::commitDrained(ThreadID tid)
1183{
1184 fetch.drainStall(tid);
1185}
1186
1187template <class Impl>
1188void
1189FullO3CPU<Impl>::drainResume()
1190{
1191 if (switchedOut())
1192 return;
1193
1194 DPRINTF(Drain, "Resuming...\n");
1195 verifyMemoryMode();
1196
1197 fetch.drainResume();
1198 commit.drainResume();
1199
1200 _status = Idle;
1201 for (ThreadID i = 0; i < thread.size(); i++) {
1202 if (thread[i]->status() == ThreadContext::Active) {
1203 DPRINTF(Drain, "Activating thread: %i\n", i);
1204 activateThread(i);
1205 _status = Running;
1206 }
1207 }
1208
1209 assert(!tickEvent.scheduled());
1210 if (_status == Running)
1211 schedule(tickEvent, nextCycle());
1212
1213 // Reschedule any power gating event (if any)
1214 schedulePowerGatingEvent();
1215}
1216
1217template <class Impl>
1218void
1219FullO3CPU<Impl>::switchOut()
1220{
1221 DPRINTF(O3CPU, "Switching out\n");
1222 BaseCPU::switchOut();
1223
1224 activityRec.reset();
1225
1226 _status = SwitchedOut;
1227
1228 if (checker)
1229 checker->switchOut();
1230}
1231
1232template <class Impl>
1233void
1234FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
1235{
1236 BaseCPU::takeOverFrom(oldCPU);
1237
1238 fetch.takeOverFrom();
1239 decode.takeOverFrom();
1240 rename.takeOverFrom();
1241 iew.takeOverFrom();
1242 commit.takeOverFrom();
1243
1244 assert(!tickEvent.scheduled());
1245
1246 FullO3CPU<Impl> *oldO3CPU = dynamic_cast<FullO3CPU<Impl>*>(oldCPU);
1247 if (oldO3CPU)
1248 globalSeqNum = oldO3CPU->globalSeqNum;
1249
1250 lastRunningCycle = curCycle();
1251 _status = Idle;
1252}
1253
1254template <class Impl>
1255void
1256FullO3CPU<Impl>::verifyMemoryMode() const
1257{
1258 if (!system->isTimingMode()) {
1259 fatal("The O3 CPU requires the memory system to be in "
1260 "'timing' mode.\n");
1261 }
1262}
1263
1264template <class Impl>
1265RegVal
1266FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid) const
1267{
1268 return this->isa[tid]->readMiscRegNoEffect(misc_reg);
1269}
1270
1271template <class Impl>
1272RegVal
1273FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid)
1274{
1275 miscRegfileReads++;
1276 return this->isa[tid]->readMiscReg(misc_reg, tcBase(tid));
1277}
1278
1279template <class Impl>
1280void
1281FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, RegVal val, ThreadID tid)
1282{
1283 this->isa[tid]->setMiscRegNoEffect(misc_reg, val);
1284}
1285
1286template <class Impl>
1287void
1288FullO3CPU<Impl>::setMiscReg(int misc_reg, RegVal val, ThreadID tid)
1289{
1290 miscRegfileWrites++;
1291 this->isa[tid]->setMiscReg(misc_reg, val, tcBase(tid));
1292}
1293
1294template <class Impl>
1295RegVal
1296FullO3CPU<Impl>::readIntReg(PhysRegIdPtr phys_reg)
1297{
1298 intRegfileReads++;
1299 return regFile.readIntReg(phys_reg);
1300}
1301
1302template <class Impl>
1303RegVal
1304FullO3CPU<Impl>::readFloatRegBits(PhysRegIdPtr phys_reg)
1305{
1306 fpRegfileReads++;
1307 return regFile.readFloatRegBits(phys_reg);
1308}
1309
1310template <class Impl>
1311auto
1312FullO3CPU<Impl>::readVecReg(PhysRegIdPtr phys_reg) const
1313 -> const VecRegContainer&
1314{
1315 vecRegfileReads++;
1316 return regFile.readVecReg(phys_reg);
1317}
1318
1319template <class Impl>
1320auto
1321FullO3CPU<Impl>::getWritableVecReg(PhysRegIdPtr phys_reg)
1322 -> VecRegContainer&
1323{
1324 vecRegfileWrites++;
1325 return regFile.getWritableVecReg(phys_reg);
1326}
1327
1328template <class Impl>
1329auto
1330FullO3CPU<Impl>::readVecElem(PhysRegIdPtr phys_reg) const -> const VecElem&
1331{
1332 vecRegfileReads++;
1333 return regFile.readVecElem(phys_reg);
1334}
1335
1336template <class Impl>
913 // Unbind condition-code Regs from Rename Map
914 for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs;
915 reg_id.index()++) {
916 PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
917 scoreboard.unsetReg(phys_reg);
918 freeList.addReg(phys_reg);
919 }
920
921 // Squash Throughout Pipeline
922 DynInstPtr inst = commit.rob->readHeadInst(tid);
923 InstSeqNum squash_seq_num = inst->seqNum;
924 fetch.squash(0, squash_seq_num, inst, tid);
925 decode.squash(tid);
926 rename.squash(squash_seq_num, tid);
927 iew.squash(tid);
928 iew.ldstQueue.squash(squash_seq_num, tid);
929 commit.rob->squash(squash_seq_num, tid);
930
931
932 assert(iew.instQueue.getCount(tid) == 0);
933 assert(iew.ldstQueue.getCount(tid) == 0);
934
935 // Reset ROB/IQ/LSQ Entries
936
937 // Commented out for now. This should be possible to do by
938 // telling all the pipeline stages to drain first, and then
939 // checking until the drain completes. Once the pipeline is
940 // drained, call resetEntries(). - 10-09-06 ktlim
941/*
942 if (activeThreads.size() >= 1) {
943 commit.rob->resetEntries();
944 iew.resetEntries();
945 }
946*/
947}
948
949template <class Impl>
950Fault
951FullO3CPU<Impl>::hwrei(ThreadID tid)
952{
953#if THE_ISA == ALPHA_ISA
954 // Need to clear the lock flag upon returning from an interrupt.
955 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
956
957 this->thread[tid]->kernelStats->hwrei();
958
959 // FIXME: XXX check for interrupts? XXX
960#endif
961 return NoFault;
962}
963
964template <class Impl>
965bool
966FullO3CPU<Impl>::simPalCheck(int palFunc, ThreadID tid)
967{
968#if THE_ISA == ALPHA_ISA
969 if (this->thread[tid]->kernelStats)
970 this->thread[tid]->kernelStats->callpal(palFunc,
971 this->threadContexts[tid]);
972
973 switch (palFunc) {
974 case PAL::halt:
975 halt();
976 if (--System::numSystemsRunning == 0)
977 exitSimLoop("all cpus halted");
978 break;
979
980 case PAL::bpt:
981 case PAL::bugchk:
982 if (this->system->breakpoint())
983 return false;
984 break;
985 }
986#endif
987 return true;
988}
989
990template <class Impl>
991void
992FullO3CPU<Impl>::switchRenameMode(ThreadID tid, UnifiedFreeList* freelist)
993{
994 auto pc = this->pcState(tid);
995
996 // new_mode is the new vector renaming mode
997 auto new_mode = RenameMode<TheISA::ISA>::mode(pc);
998
999 // We update vecMode only if there has been a change
1000 if (new_mode != vecMode) {
1001 vecMode = new_mode;
1002
1003 renameMap[tid].switchMode(vecMode);
1004 commitRenameMap[tid].switchMode(vecMode);
1005 renameMap[tid].switchFreeList(freelist);
1006 }
1007}
1008
1009template <class Impl>
1010Fault
1011FullO3CPU<Impl>::getInterrupts()
1012{
1013 // Check if there are any outstanding interrupts
1014 return this->interrupts[0]->getInterrupt(this->threadContexts[0]);
1015}
1016
1017template <class Impl>
1018void
1019FullO3CPU<Impl>::processInterrupts(const Fault &interrupt)
1020{
1021 // Check for interrupts here. For now can copy the code that
1022 // exists within isa_fullsys_traits.hh. Also assume that thread 0
1023 // is the one that handles the interrupts.
1024 // @todo: Possibly consolidate the interrupt checking code.
1025 // @todo: Allow other threads to handle interrupts.
1026
1027 assert(interrupt != NoFault);
1028 this->interrupts[0]->updateIntrInfo(this->threadContexts[0]);
1029
1030 DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
1031 this->trap(interrupt, 0, nullptr);
1032}
1033
1034template <class Impl>
1035void
1036FullO3CPU<Impl>::trap(const Fault &fault, ThreadID tid,
1037 const StaticInstPtr &inst)
1038{
1039 // Pass the thread's TC into the invoke method.
1040 fault->invoke(this->threadContexts[tid], inst);
1041}
1042
1043template <class Impl>
1044void
1045FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid, Fault *fault)
1046{
1047 DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);
1048
1049 DPRINTF(Activity,"Activity: syscall() called.\n");
1050
1051 // Temporarily increase this by one to account for the syscall
1052 // instruction.
1053 ++(this->thread[tid]->funcExeInst);
1054
1055 // Execute the actual syscall.
1056 this->thread[tid]->syscall(callnum, fault);
1057
1058 // Decrease funcExeInst by one as the normal commit will handle
1059 // incrementing it.
1060 --(this->thread[tid]->funcExeInst);
1061}
1062
1063template <class Impl>
1064void
1065FullO3CPU<Impl>::serializeThread(CheckpointOut &cp, ThreadID tid) const
1066{
1067 thread[tid]->serialize(cp);
1068}
1069
1070template <class Impl>
1071void
1072FullO3CPU<Impl>::unserializeThread(CheckpointIn &cp, ThreadID tid)
1073{
1074 thread[tid]->unserialize(cp);
1075}
1076
1077template <class Impl>
1078DrainState
1079FullO3CPU<Impl>::drain()
1080{
1081 // Deschedule any power gating event (if any)
1082 deschedulePowerGatingEvent();
1083
1084 // If the CPU isn't doing anything, then return immediately.
1085 if (switchedOut())
1086 return DrainState::Drained;
1087
1088 DPRINTF(Drain, "Draining...\n");
1089
1090 // We only need to signal a drain to the commit stage as this
1091 // initiates squashing controls the draining. Once the commit
1092 // stage commits an instruction where it is safe to stop, it'll
1093 // squash the rest of the instructions in the pipeline and force
1094 // the fetch stage to stall. The pipeline will be drained once all
1095 // in-flight instructions have retired.
1096 commit.drain();
1097
1098 // Wake the CPU and record activity so everything can drain out if
1099 // the CPU was not able to immediately drain.
1100 if (!isDrained()) {
1101 // If a thread is suspended, wake it up so it can be drained
1102 for (auto t : threadContexts) {
1103 if (t->status() == ThreadContext::Suspended){
1104 DPRINTF(Drain, "Currently suspended so activate %i \n",
1105 t->threadId());
1106 t->activate();
1107 // As the thread is now active, change the power state as well
1108 activateContext(t->threadId());
1109 }
1110 }
1111
1112 wakeCPU();
1113 activityRec.activity();
1114
1115 DPRINTF(Drain, "CPU not drained\n");
1116
1117 return DrainState::Draining;
1118 } else {
1119 DPRINTF(Drain, "CPU is already drained\n");
1120 if (tickEvent.scheduled())
1121 deschedule(tickEvent);
1122
1123 // Flush out any old data from the time buffers. In
1124 // particular, there might be some data in flight from the
1125 // fetch stage that isn't visible in any of the CPU buffers we
1126 // test in isDrained().
1127 for (int i = 0; i < timeBuffer.getSize(); ++i) {
1128 timeBuffer.advance();
1129 fetchQueue.advance();
1130 decodeQueue.advance();
1131 renameQueue.advance();
1132 iewQueue.advance();
1133 }
1134
1135 drainSanityCheck();
1136 return DrainState::Drained;
1137 }
1138}
1139
1140template <class Impl>
1141bool
1142FullO3CPU<Impl>::tryDrain()
1143{
1144 if (drainState() != DrainState::Draining || !isDrained())
1145 return false;
1146
1147 if (tickEvent.scheduled())
1148 deschedule(tickEvent);
1149
1150 DPRINTF(Drain, "CPU done draining, processing drain event\n");
1151 signalDrainDone();
1152
1153 return true;
1154}
1155
1156template <class Impl>
1157void
1158FullO3CPU<Impl>::drainSanityCheck() const
1159{
1160 assert(isDrained());
1161 fetch.drainSanityCheck();
1162 decode.drainSanityCheck();
1163 rename.drainSanityCheck();
1164 iew.drainSanityCheck();
1165 commit.drainSanityCheck();
1166}
1167
1168template <class Impl>
1169bool
1170FullO3CPU<Impl>::isDrained() const
1171{
1172 bool drained(true);
1173
1174 if (!instList.empty() || !removeList.empty()) {
1175 DPRINTF(Drain, "Main CPU structures not drained.\n");
1176 drained = false;
1177 }
1178
1179 if (!fetch.isDrained()) {
1180 DPRINTF(Drain, "Fetch not drained.\n");
1181 drained = false;
1182 }
1183
1184 if (!decode.isDrained()) {
1185 DPRINTF(Drain, "Decode not drained.\n");
1186 drained = false;
1187 }
1188
1189 if (!rename.isDrained()) {
1190 DPRINTF(Drain, "Rename not drained.\n");
1191 drained = false;
1192 }
1193
1194 if (!iew.isDrained()) {
1195 DPRINTF(Drain, "IEW not drained.\n");
1196 drained = false;
1197 }
1198
1199 if (!commit.isDrained()) {
1200 DPRINTF(Drain, "Commit not drained.\n");
1201 drained = false;
1202 }
1203
1204 return drained;
1205}
1206
1207template <class Impl>
1208void
1209FullO3CPU<Impl>::commitDrained(ThreadID tid)
1210{
1211 fetch.drainStall(tid);
1212}
1213
1214template <class Impl>
1215void
1216FullO3CPU<Impl>::drainResume()
1217{
1218 if (switchedOut())
1219 return;
1220
1221 DPRINTF(Drain, "Resuming...\n");
1222 verifyMemoryMode();
1223
1224 fetch.drainResume();
1225 commit.drainResume();
1226
1227 _status = Idle;
1228 for (ThreadID i = 0; i < thread.size(); i++) {
1229 if (thread[i]->status() == ThreadContext::Active) {
1230 DPRINTF(Drain, "Activating thread: %i\n", i);
1231 activateThread(i);
1232 _status = Running;
1233 }
1234 }
1235
1236 assert(!tickEvent.scheduled());
1237 if (_status == Running)
1238 schedule(tickEvent, nextCycle());
1239
1240 // Reschedule any power gating event (if any)
1241 schedulePowerGatingEvent();
1242}
1243
1244template <class Impl>
1245void
1246FullO3CPU<Impl>::switchOut()
1247{
1248 DPRINTF(O3CPU, "Switching out\n");
1249 BaseCPU::switchOut();
1250
1251 activityRec.reset();
1252
1253 _status = SwitchedOut;
1254
1255 if (checker)
1256 checker->switchOut();
1257}
1258
1259template <class Impl>
1260void
1261FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
1262{
1263 BaseCPU::takeOverFrom(oldCPU);
1264
1265 fetch.takeOverFrom();
1266 decode.takeOverFrom();
1267 rename.takeOverFrom();
1268 iew.takeOverFrom();
1269 commit.takeOverFrom();
1270
1271 assert(!tickEvent.scheduled());
1272
1273 FullO3CPU<Impl> *oldO3CPU = dynamic_cast<FullO3CPU<Impl>*>(oldCPU);
1274 if (oldO3CPU)
1275 globalSeqNum = oldO3CPU->globalSeqNum;
1276
1277 lastRunningCycle = curCycle();
1278 _status = Idle;
1279}
1280
1281template <class Impl>
1282void
1283FullO3CPU<Impl>::verifyMemoryMode() const
1284{
1285 if (!system->isTimingMode()) {
1286 fatal("The O3 CPU requires the memory system to be in "
1287 "'timing' mode.\n");
1288 }
1289}
1290
1291template <class Impl>
1292RegVal
1293FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid) const
1294{
1295 return this->isa[tid]->readMiscRegNoEffect(misc_reg);
1296}
1297
1298template <class Impl>
1299RegVal
1300FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid)
1301{
1302 miscRegfileReads++;
1303 return this->isa[tid]->readMiscReg(misc_reg, tcBase(tid));
1304}
1305
1306template <class Impl>
1307void
1308FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, RegVal val, ThreadID tid)
1309{
1310 this->isa[tid]->setMiscRegNoEffect(misc_reg, val);
1311}
1312
1313template <class Impl>
1314void
1315FullO3CPU<Impl>::setMiscReg(int misc_reg, RegVal val, ThreadID tid)
1316{
1317 miscRegfileWrites++;
1318 this->isa[tid]->setMiscReg(misc_reg, val, tcBase(tid));
1319}
1320
1321template <class Impl>
1322RegVal
1323FullO3CPU<Impl>::readIntReg(PhysRegIdPtr phys_reg)
1324{
1325 intRegfileReads++;
1326 return regFile.readIntReg(phys_reg);
1327}
1328
1329template <class Impl>
1330RegVal
1331FullO3CPU<Impl>::readFloatRegBits(PhysRegIdPtr phys_reg)
1332{
1333 fpRegfileReads++;
1334 return regFile.readFloatRegBits(phys_reg);
1335}
1336
1337template <class Impl>
1338auto
1339FullO3CPU<Impl>::readVecReg(PhysRegIdPtr phys_reg) const
1340 -> const VecRegContainer&
1341{
1342 vecRegfileReads++;
1343 return regFile.readVecReg(phys_reg);
1344}
1345
1346template <class Impl>
1347auto
1348FullO3CPU<Impl>::getWritableVecReg(PhysRegIdPtr phys_reg)
1349 -> VecRegContainer&
1350{
1351 vecRegfileWrites++;
1352 return regFile.getWritableVecReg(phys_reg);
1353}
1354
1355template <class Impl>
1356auto
1357FullO3CPU<Impl>::readVecElem(PhysRegIdPtr phys_reg) const -> const VecElem&
1358{
1359 vecRegfileReads++;
1360 return regFile.readVecElem(phys_reg);
1361}
1362
1363template <class Impl>
1364auto
1365FullO3CPU<Impl>::readVecPredReg(PhysRegIdPtr phys_reg) const
1366 -> const VecPredRegContainer&
1367{
1368 vecPredRegfileReads++;
1369 return regFile.readVecPredReg(phys_reg);
1370}
1371
1372template <class Impl>
1373auto
1374FullO3CPU<Impl>::getWritableVecPredReg(PhysRegIdPtr phys_reg)
1375 -> VecPredRegContainer&
1376{
1377 vecPredRegfileWrites++;
1378 return regFile.getWritableVecPredReg(phys_reg);
1379}
1380
1381template <class Impl>
1337CCReg
1338FullO3CPU<Impl>::readCCReg(PhysRegIdPtr phys_reg)
1339{
1340 ccRegfileReads++;
1341 return regFile.readCCReg(phys_reg);
1342}
1343
1344template <class Impl>
1345void
1346FullO3CPU<Impl>::setIntReg(PhysRegIdPtr phys_reg, RegVal val)
1347{
1348 intRegfileWrites++;
1349 regFile.setIntReg(phys_reg, val);
1350}
1351
1352template <class Impl>
1353void
1354FullO3CPU<Impl>::setFloatRegBits(PhysRegIdPtr phys_reg, RegVal val)
1355{
1356 fpRegfileWrites++;
1357 regFile.setFloatRegBits(phys_reg, val);
1358}
1359
1360template <class Impl>
1361void
1362FullO3CPU<Impl>::setVecReg(PhysRegIdPtr phys_reg, const VecRegContainer& val)
1363{
1364 vecRegfileWrites++;
1365 regFile.setVecReg(phys_reg, val);
1366}
1367
1368template <class Impl>
1369void
1370FullO3CPU<Impl>::setVecElem(PhysRegIdPtr phys_reg, const VecElem& val)
1371{
1372 vecRegfileWrites++;
1373 regFile.setVecElem(phys_reg, val);
1374}
1375
1376template <class Impl>
1377void
1382CCReg
1383FullO3CPU<Impl>::readCCReg(PhysRegIdPtr phys_reg)
1384{
1385 ccRegfileReads++;
1386 return regFile.readCCReg(phys_reg);
1387}
1388
1389template <class Impl>
1390void
1391FullO3CPU<Impl>::setIntReg(PhysRegIdPtr phys_reg, RegVal val)
1392{
1393 intRegfileWrites++;
1394 regFile.setIntReg(phys_reg, val);
1395}
1396
1397template <class Impl>
1398void
1399FullO3CPU<Impl>::setFloatRegBits(PhysRegIdPtr phys_reg, RegVal val)
1400{
1401 fpRegfileWrites++;
1402 regFile.setFloatRegBits(phys_reg, val);
1403}
1404
1405template <class Impl>
1406void
1407FullO3CPU<Impl>::setVecReg(PhysRegIdPtr phys_reg, const VecRegContainer& val)
1408{
1409 vecRegfileWrites++;
1410 regFile.setVecReg(phys_reg, val);
1411}
1412
1413template <class Impl>
1414void
1415FullO3CPU<Impl>::setVecElem(PhysRegIdPtr phys_reg, const VecElem& val)
1416{
1417 vecRegfileWrites++;
1418 regFile.setVecElem(phys_reg, val);
1419}
1420
1421template <class Impl>
1422void
1423FullO3CPU<Impl>::setVecPredReg(PhysRegIdPtr phys_reg,
1424 const VecPredRegContainer& val)
1425{
1426 vecPredRegfileWrites++;
1427 regFile.setVecPredReg(phys_reg, val);
1428}
1429
1430template <class Impl>
1431void
1378FullO3CPU<Impl>::setCCReg(PhysRegIdPtr phys_reg, CCReg val)
1379{
1380 ccRegfileWrites++;
1381 regFile.setCCReg(phys_reg, val);
1382}
1383
1384template <class Impl>
1385RegVal
1386FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid)
1387{
1388 intRegfileReads++;
1389 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1390 RegId(IntRegClass, reg_idx));
1391
1392 return regFile.readIntReg(phys_reg);
1393}
1394
1395template <class Impl>
1396RegVal
1397FullO3CPU<Impl>::readArchFloatRegBits(int reg_idx, ThreadID tid)
1398{
1399 fpRegfileReads++;
1400 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1401 RegId(FloatRegClass, reg_idx));
1402
1403 return regFile.readFloatRegBits(phys_reg);
1404}
1405
1406template <class Impl>
1407auto
1408FullO3CPU<Impl>::readArchVecReg(int reg_idx, ThreadID tid) const
1409 -> const VecRegContainer&
1410{
1411 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1412 RegId(VecRegClass, reg_idx));
1413 return readVecReg(phys_reg);
1414}
1415
1416template <class Impl>
1417auto
1418FullO3CPU<Impl>::getWritableArchVecReg(int reg_idx, ThreadID tid)
1419 -> VecRegContainer&
1420{
1421 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1422 RegId(VecRegClass, reg_idx));
1423 return getWritableVecReg(phys_reg);
1424}
1425
1426template <class Impl>
1427auto
1428FullO3CPU<Impl>::readArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
1429 ThreadID tid) const -> const VecElem&
1430{
1431 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1432 RegId(VecElemClass, reg_idx, ldx));
1433 return readVecElem(phys_reg);
1434}
1435
1436template <class Impl>
1432FullO3CPU<Impl>::setCCReg(PhysRegIdPtr phys_reg, CCReg val)
1433{
1434 ccRegfileWrites++;
1435 regFile.setCCReg(phys_reg, val);
1436}
1437
1438template <class Impl>
1439RegVal
1440FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid)
1441{
1442 intRegfileReads++;
1443 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1444 RegId(IntRegClass, reg_idx));
1445
1446 return regFile.readIntReg(phys_reg);
1447}
1448
1449template <class Impl>
1450RegVal
1451FullO3CPU<Impl>::readArchFloatRegBits(int reg_idx, ThreadID tid)
1452{
1453 fpRegfileReads++;
1454 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1455 RegId(FloatRegClass, reg_idx));
1456
1457 return regFile.readFloatRegBits(phys_reg);
1458}
1459
1460template <class Impl>
1461auto
1462FullO3CPU<Impl>::readArchVecReg(int reg_idx, ThreadID tid) const
1463 -> const VecRegContainer&
1464{
1465 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1466 RegId(VecRegClass, reg_idx));
1467 return readVecReg(phys_reg);
1468}
1469
1470template <class Impl>
1471auto
1472FullO3CPU<Impl>::getWritableArchVecReg(int reg_idx, ThreadID tid)
1473 -> VecRegContainer&
1474{
1475 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1476 RegId(VecRegClass, reg_idx));
1477 return getWritableVecReg(phys_reg);
1478}
1479
1480template <class Impl>
1481auto
1482FullO3CPU<Impl>::readArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
1483 ThreadID tid) const -> const VecElem&
1484{
1485 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1486 RegId(VecElemClass, reg_idx, ldx));
1487 return readVecElem(phys_reg);
1488}
1489
1490template <class Impl>
1491auto
1492FullO3CPU<Impl>::readArchVecPredReg(int reg_idx, ThreadID tid) const
1493 -> const VecPredRegContainer&
1494{
1495 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1496 RegId(VecPredRegClass, reg_idx));
1497 return readVecPredReg(phys_reg);
1498}
1499
1500template <class Impl>
1501auto
1502FullO3CPU<Impl>::getWritableArchVecPredReg(int reg_idx, ThreadID tid)
1503 -> VecPredRegContainer&
1504{
1505 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1506 RegId(VecPredRegClass, reg_idx));
1507 return getWritableVecPredReg(phys_reg);
1508}
1509
1510template <class Impl>
1437CCReg
1438FullO3CPU<Impl>::readArchCCReg(int reg_idx, ThreadID tid)
1439{
1440 ccRegfileReads++;
1441 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1442 RegId(CCRegClass, reg_idx));
1443
1444 return regFile.readCCReg(phys_reg);
1445}
1446
1447template <class Impl>
1448void
1449FullO3CPU<Impl>::setArchIntReg(int reg_idx, RegVal val, ThreadID tid)
1450{
1451 intRegfileWrites++;
1452 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1453 RegId(IntRegClass, reg_idx));
1454
1455 regFile.setIntReg(phys_reg, val);
1456}
1457
1458template <class Impl>
1459void
1460FullO3CPU<Impl>::setArchFloatRegBits(int reg_idx, RegVal val, ThreadID tid)
1461{
1462 fpRegfileWrites++;
1463 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1464 RegId(FloatRegClass, reg_idx));
1465
1466 regFile.setFloatRegBits(phys_reg, val);
1467}
1468
1469template <class Impl>
1470void
1471FullO3CPU<Impl>::setArchVecReg(int reg_idx, const VecRegContainer& val,
1472 ThreadID tid)
1473{
1474 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1475 RegId(VecRegClass, reg_idx));
1476 setVecReg(phys_reg, val);
1477}
1478
1479template <class Impl>
1480void
1481FullO3CPU<Impl>::setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
1482 const VecElem& val, ThreadID tid)
1483{
1484 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1485 RegId(VecElemClass, reg_idx, ldx));
1486 setVecElem(phys_reg, val);
1487}
1488
1489template <class Impl>
1490void
1511CCReg
1512FullO3CPU<Impl>::readArchCCReg(int reg_idx, ThreadID tid)
1513{
1514 ccRegfileReads++;
1515 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1516 RegId(CCRegClass, reg_idx));
1517
1518 return regFile.readCCReg(phys_reg);
1519}
1520
1521template <class Impl>
1522void
1523FullO3CPU<Impl>::setArchIntReg(int reg_idx, RegVal val, ThreadID tid)
1524{
1525 intRegfileWrites++;
1526 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1527 RegId(IntRegClass, reg_idx));
1528
1529 regFile.setIntReg(phys_reg, val);
1530}
1531
1532template <class Impl>
1533void
1534FullO3CPU<Impl>::setArchFloatRegBits(int reg_idx, RegVal val, ThreadID tid)
1535{
1536 fpRegfileWrites++;
1537 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1538 RegId(FloatRegClass, reg_idx));
1539
1540 regFile.setFloatRegBits(phys_reg, val);
1541}
1542
1543template <class Impl>
1544void
1545FullO3CPU<Impl>::setArchVecReg(int reg_idx, const VecRegContainer& val,
1546 ThreadID tid)
1547{
1548 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1549 RegId(VecRegClass, reg_idx));
1550 setVecReg(phys_reg, val);
1551}
1552
1553template <class Impl>
1554void
1555FullO3CPU<Impl>::setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
1556 const VecElem& val, ThreadID tid)
1557{
1558 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1559 RegId(VecElemClass, reg_idx, ldx));
1560 setVecElem(phys_reg, val);
1561}
1562
1563template <class Impl>
1564void
1565FullO3CPU<Impl>::setArchVecPredReg(int reg_idx, const VecPredRegContainer& val,
1566 ThreadID tid)
1567{
1568 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1569 RegId(VecPredRegClass, reg_idx));
1570 setVecPredReg(phys_reg, val);
1571}
1572
1573template <class Impl>
1574void
1491FullO3CPU<Impl>::setArchCCReg(int reg_idx, CCReg val, ThreadID tid)
1492{
1493 ccRegfileWrites++;
1494 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1495 RegId(CCRegClass, reg_idx));
1496
1497 regFile.setCCReg(phys_reg, val);
1498}
1499
1500template <class Impl>
1501TheISA::PCState
1502FullO3CPU<Impl>::pcState(ThreadID tid)
1503{
1504 return commit.pcState(tid);
1505}
1506
1507template <class Impl>
1508void
1509FullO3CPU<Impl>::pcState(const TheISA::PCState &val, ThreadID tid)
1510{
1511 commit.pcState(val, tid);
1512}
1513
1514template <class Impl>
1515Addr
1516FullO3CPU<Impl>::instAddr(ThreadID tid)
1517{
1518 return commit.instAddr(tid);
1519}
1520
1521template <class Impl>
1522Addr
1523FullO3CPU<Impl>::nextInstAddr(ThreadID tid)
1524{
1525 return commit.nextInstAddr(tid);
1526}
1527
1528template <class Impl>
1529MicroPC
1530FullO3CPU<Impl>::microPC(ThreadID tid)
1531{
1532 return commit.microPC(tid);
1533}
1534
1535template <class Impl>
1536void
1537FullO3CPU<Impl>::squashFromTC(ThreadID tid)
1538{
1539 this->thread[tid]->noSquashFromTC = true;
1540 this->commit.generateTCEvent(tid);
1541}
1542
1543template <class Impl>
1544typename FullO3CPU<Impl>::ListIt
1545FullO3CPU<Impl>::addInst(const DynInstPtr &inst)
1546{
1547 instList.push_back(inst);
1548
1549 return --(instList.end());
1550}
1551
1552template <class Impl>
1553void
1554FullO3CPU<Impl>::instDone(ThreadID tid, const DynInstPtr &inst)
1555{
1556 // Keep an instruction count.
1557 if (!inst->isMicroop() || inst->isLastMicroop()) {
1558 thread[tid]->numInst++;
1559 thread[tid]->numInsts++;
1560 committedInsts[tid]++;
1561 system->totalNumInsts++;
1562
1563 // Check for instruction-count-based events.
1564 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1565 system->instEventQueue.serviceEvents(system->totalNumInsts);
1566 }
1567 thread[tid]->numOp++;
1568 thread[tid]->numOps++;
1569 committedOps[tid]++;
1570
1571 probeInstCommit(inst->staticInst);
1572}
1573
1574template <class Impl>
1575void
1576FullO3CPU<Impl>::removeFrontInst(const DynInstPtr &inst)
1577{
1578 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %s "
1579 "[sn:%lli]\n",
1580 inst->threadNumber, inst->pcState(), inst->seqNum);
1581
1582 removeInstsThisCycle = true;
1583
1584 // Remove the front instruction.
1585 removeList.push(inst->getInstListIt());
1586}
1587
1588template <class Impl>
1589void
1590FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid)
1591{
1592 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
1593 " list.\n", tid);
1594
1595 ListIt end_it;
1596
1597 bool rob_empty = false;
1598
1599 if (instList.empty()) {
1600 return;
1601 } else if (rob.isEmpty(tid)) {
1602 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
1603 end_it = instList.begin();
1604 rob_empty = true;
1605 } else {
1606 end_it = (rob.readTailInst(tid))->getInstListIt();
1607 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
1608 }
1609
1610 removeInstsThisCycle = true;
1611
1612 ListIt inst_it = instList.end();
1613
1614 inst_it--;
1615
1616 // Walk through the instruction list, removing any instructions
1617 // that were inserted after the given instruction iterator, end_it.
1618 while (inst_it != end_it) {
1619 assert(!instList.empty());
1620
1621 squashInstIt(inst_it, tid);
1622
1623 inst_it--;
1624 }
1625
1626 // If the ROB was empty, then we actually need to remove the first
1627 // instruction as well.
1628 if (rob_empty) {
1629 squashInstIt(inst_it, tid);
1630 }
1631}
1632
1633template <class Impl>
1634void
1635FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1636{
1637 assert(!instList.empty());
1638
1639 removeInstsThisCycle = true;
1640
1641 ListIt inst_iter = instList.end();
1642
1643 inst_iter--;
1644
1645 DPRINTF(O3CPU, "Deleting instructions from instruction "
1646 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1647 tid, seq_num, (*inst_iter)->seqNum);
1648
1649 while ((*inst_iter)->seqNum > seq_num) {
1650
1651 bool break_loop = (inst_iter == instList.begin());
1652
1653 squashInstIt(inst_iter, tid);
1654
1655 inst_iter--;
1656
1657 if (break_loop)
1658 break;
1659 }
1660}
1661
1662template <class Impl>
1663inline void
1664FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid)
1665{
1666 if ((*instIt)->threadNumber == tid) {
1667 DPRINTF(O3CPU, "Squashing instruction, "
1668 "[tid:%i] [sn:%lli] PC %s\n",
1669 (*instIt)->threadNumber,
1670 (*instIt)->seqNum,
1671 (*instIt)->pcState());
1672
1673 // Mark it as squashed.
1674 (*instIt)->setSquashed();
1675
1676 // @todo: Formulate a consistent method for deleting
1677 // instructions from the instruction list
1678 // Remove the instruction from the list.
1679 removeList.push(instIt);
1680 }
1681}
1682
1683template <class Impl>
1684void
1685FullO3CPU<Impl>::cleanUpRemovedInsts()
1686{
1687 while (!removeList.empty()) {
1688 DPRINTF(O3CPU, "Removing instruction, "
1689 "[tid:%i] [sn:%lli] PC %s\n",
1690 (*removeList.front())->threadNumber,
1691 (*removeList.front())->seqNum,
1692 (*removeList.front())->pcState());
1693
1694 instList.erase(removeList.front());
1695
1696 removeList.pop();
1697 }
1698
1699 removeInstsThisCycle = false;
1700}
1701/*
1702template <class Impl>
1703void
1704FullO3CPU<Impl>::removeAllInsts()
1705{
1706 instList.clear();
1707}
1708*/
1709template <class Impl>
1710void
1711FullO3CPU<Impl>::dumpInsts()
1712{
1713 int num = 0;
1714
1715 ListIt inst_list_it = instList.begin();
1716
1717 cprintf("Dumping Instruction List\n");
1718
1719 while (inst_list_it != instList.end()) {
1720 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1721 "Squashed:%i\n\n",
1722 num, (*inst_list_it)->instAddr(), (*inst_list_it)->threadNumber,
1723 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1724 (*inst_list_it)->isSquashed());
1725 inst_list_it++;
1726 ++num;
1727 }
1728}
1729/*
1730template <class Impl>
1731void
1732FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst)
1733{
1734 iew.wakeDependents(inst);
1735}
1736*/
1737template <class Impl>
1738void
1739FullO3CPU<Impl>::wakeCPU()
1740{
1741 if (activityRec.active() || tickEvent.scheduled()) {
1742 DPRINTF(Activity, "CPU already running.\n");
1743 return;
1744 }
1745
1746 DPRINTF(Activity, "Waking up CPU\n");
1747
1748 Cycles cycles(curCycle() - lastRunningCycle);
1749 // @todo: This is an oddity that is only here to match the stats
1750 if (cycles > 1) {
1751 --cycles;
1752 idleCycles += cycles;
1753 numCycles += cycles;
1754 }
1755
1756 schedule(tickEvent, clockEdge());
1757}
1758
1759template <class Impl>
1760void
1761FullO3CPU<Impl>::wakeup(ThreadID tid)
1762{
1763 if (this->thread[tid]->status() != ThreadContext::Suspended)
1764 return;
1765
1766 this->wakeCPU();
1767
1768 DPRINTF(Quiesce, "Suspended Processor woken\n");
1769 this->threadContexts[tid]->activate();
1770}
1771
1772template <class Impl>
1773ThreadID
1774FullO3CPU<Impl>::getFreeTid()
1775{
1776 for (ThreadID tid = 0; tid < numThreads; tid++) {
1777 if (!tids[tid]) {
1778 tids[tid] = true;
1779 return tid;
1780 }
1781 }
1782
1783 return InvalidThreadID;
1784}
1785
1786template <class Impl>
1787void
1788FullO3CPU<Impl>::updateThreadPriority()
1789{
1790 if (activeThreads.size() > 1) {
1791 //DEFAULT TO ROUND ROBIN SCHEME
1792 //e.g. Move highest priority to end of thread list
1793 list<ThreadID>::iterator list_begin = activeThreads.begin();
1794
1795 unsigned high_thread = *list_begin;
1796
1797 activeThreads.erase(list_begin);
1798
1799 activeThreads.push_back(high_thread);
1800 }
1801}
1802
1803// Forward declaration of FullO3CPU.
1804template class FullO3CPU<O3CPUImpl>;
1575FullO3CPU<Impl>::setArchCCReg(int reg_idx, CCReg val, ThreadID tid)
1576{
1577 ccRegfileWrites++;
1578 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1579 RegId(CCRegClass, reg_idx));
1580
1581 regFile.setCCReg(phys_reg, val);
1582}
1583
1584template <class Impl>
1585TheISA::PCState
1586FullO3CPU<Impl>::pcState(ThreadID tid)
1587{
1588 return commit.pcState(tid);
1589}
1590
1591template <class Impl>
1592void
1593FullO3CPU<Impl>::pcState(const TheISA::PCState &val, ThreadID tid)
1594{
1595 commit.pcState(val, tid);
1596}
1597
1598template <class Impl>
1599Addr
1600FullO3CPU<Impl>::instAddr(ThreadID tid)
1601{
1602 return commit.instAddr(tid);
1603}
1604
1605template <class Impl>
1606Addr
1607FullO3CPU<Impl>::nextInstAddr(ThreadID tid)
1608{
1609 return commit.nextInstAddr(tid);
1610}
1611
1612template <class Impl>
1613MicroPC
1614FullO3CPU<Impl>::microPC(ThreadID tid)
1615{
1616 return commit.microPC(tid);
1617}
1618
1619template <class Impl>
1620void
1621FullO3CPU<Impl>::squashFromTC(ThreadID tid)
1622{
1623 this->thread[tid]->noSquashFromTC = true;
1624 this->commit.generateTCEvent(tid);
1625}
1626
1627template <class Impl>
1628typename FullO3CPU<Impl>::ListIt
1629FullO3CPU<Impl>::addInst(const DynInstPtr &inst)
1630{
1631 instList.push_back(inst);
1632
1633 return --(instList.end());
1634}
1635
1636template <class Impl>
1637void
1638FullO3CPU<Impl>::instDone(ThreadID tid, const DynInstPtr &inst)
1639{
1640 // Keep an instruction count.
1641 if (!inst->isMicroop() || inst->isLastMicroop()) {
1642 thread[tid]->numInst++;
1643 thread[tid]->numInsts++;
1644 committedInsts[tid]++;
1645 system->totalNumInsts++;
1646
1647 // Check for instruction-count-based events.
1648 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1649 system->instEventQueue.serviceEvents(system->totalNumInsts);
1650 }
1651 thread[tid]->numOp++;
1652 thread[tid]->numOps++;
1653 committedOps[tid]++;
1654
1655 probeInstCommit(inst->staticInst);
1656}
1657
1658template <class Impl>
1659void
1660FullO3CPU<Impl>::removeFrontInst(const DynInstPtr &inst)
1661{
1662 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %s "
1663 "[sn:%lli]\n",
1664 inst->threadNumber, inst->pcState(), inst->seqNum);
1665
1666 removeInstsThisCycle = true;
1667
1668 // Remove the front instruction.
1669 removeList.push(inst->getInstListIt());
1670}
1671
1672template <class Impl>
1673void
1674FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid)
1675{
1676 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
1677 " list.\n", tid);
1678
1679 ListIt end_it;
1680
1681 bool rob_empty = false;
1682
1683 if (instList.empty()) {
1684 return;
1685 } else if (rob.isEmpty(tid)) {
1686 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
1687 end_it = instList.begin();
1688 rob_empty = true;
1689 } else {
1690 end_it = (rob.readTailInst(tid))->getInstListIt();
1691 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
1692 }
1693
1694 removeInstsThisCycle = true;
1695
1696 ListIt inst_it = instList.end();
1697
1698 inst_it--;
1699
1700 // Walk through the instruction list, removing any instructions
1701 // that were inserted after the given instruction iterator, end_it.
1702 while (inst_it != end_it) {
1703 assert(!instList.empty());
1704
1705 squashInstIt(inst_it, tid);
1706
1707 inst_it--;
1708 }
1709
1710 // If the ROB was empty, then we actually need to remove the first
1711 // instruction as well.
1712 if (rob_empty) {
1713 squashInstIt(inst_it, tid);
1714 }
1715}
1716
1717template <class Impl>
1718void
1719FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1720{
1721 assert(!instList.empty());
1722
1723 removeInstsThisCycle = true;
1724
1725 ListIt inst_iter = instList.end();
1726
1727 inst_iter--;
1728
1729 DPRINTF(O3CPU, "Deleting instructions from instruction "
1730 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1731 tid, seq_num, (*inst_iter)->seqNum);
1732
1733 while ((*inst_iter)->seqNum > seq_num) {
1734
1735 bool break_loop = (inst_iter == instList.begin());
1736
1737 squashInstIt(inst_iter, tid);
1738
1739 inst_iter--;
1740
1741 if (break_loop)
1742 break;
1743 }
1744}
1745
1746template <class Impl>
1747inline void
1748FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid)
1749{
1750 if ((*instIt)->threadNumber == tid) {
1751 DPRINTF(O3CPU, "Squashing instruction, "
1752 "[tid:%i] [sn:%lli] PC %s\n",
1753 (*instIt)->threadNumber,
1754 (*instIt)->seqNum,
1755 (*instIt)->pcState());
1756
1757 // Mark it as squashed.
1758 (*instIt)->setSquashed();
1759
1760 // @todo: Formulate a consistent method for deleting
1761 // instructions from the instruction list
1762 // Remove the instruction from the list.
1763 removeList.push(instIt);
1764 }
1765}
1766
1767template <class Impl>
1768void
1769FullO3CPU<Impl>::cleanUpRemovedInsts()
1770{
1771 while (!removeList.empty()) {
1772 DPRINTF(O3CPU, "Removing instruction, "
1773 "[tid:%i] [sn:%lli] PC %s\n",
1774 (*removeList.front())->threadNumber,
1775 (*removeList.front())->seqNum,
1776 (*removeList.front())->pcState());
1777
1778 instList.erase(removeList.front());
1779
1780 removeList.pop();
1781 }
1782
1783 removeInstsThisCycle = false;
1784}
1785/*
1786template <class Impl>
1787void
1788FullO3CPU<Impl>::removeAllInsts()
1789{
1790 instList.clear();
1791}
1792*/
1793template <class Impl>
1794void
1795FullO3CPU<Impl>::dumpInsts()
1796{
1797 int num = 0;
1798
1799 ListIt inst_list_it = instList.begin();
1800
1801 cprintf("Dumping Instruction List\n");
1802
1803 while (inst_list_it != instList.end()) {
1804 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1805 "Squashed:%i\n\n",
1806 num, (*inst_list_it)->instAddr(), (*inst_list_it)->threadNumber,
1807 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1808 (*inst_list_it)->isSquashed());
1809 inst_list_it++;
1810 ++num;
1811 }
1812}
1813/*
1814template <class Impl>
1815void
1816FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst)
1817{
1818 iew.wakeDependents(inst);
1819}
1820*/
1821template <class Impl>
1822void
1823FullO3CPU<Impl>::wakeCPU()
1824{
1825 if (activityRec.active() || tickEvent.scheduled()) {
1826 DPRINTF(Activity, "CPU already running.\n");
1827 return;
1828 }
1829
1830 DPRINTF(Activity, "Waking up CPU\n");
1831
1832 Cycles cycles(curCycle() - lastRunningCycle);
1833 // @todo: This is an oddity that is only here to match the stats
1834 if (cycles > 1) {
1835 --cycles;
1836 idleCycles += cycles;
1837 numCycles += cycles;
1838 }
1839
1840 schedule(tickEvent, clockEdge());
1841}
1842
1843template <class Impl>
1844void
1845FullO3CPU<Impl>::wakeup(ThreadID tid)
1846{
1847 if (this->thread[tid]->status() != ThreadContext::Suspended)
1848 return;
1849
1850 this->wakeCPU();
1851
1852 DPRINTF(Quiesce, "Suspended Processor woken\n");
1853 this->threadContexts[tid]->activate();
1854}
1855
1856template <class Impl>
1857ThreadID
1858FullO3CPU<Impl>::getFreeTid()
1859{
1860 for (ThreadID tid = 0; tid < numThreads; tid++) {
1861 if (!tids[tid]) {
1862 tids[tid] = true;
1863 return tid;
1864 }
1865 }
1866
1867 return InvalidThreadID;
1868}
1869
1870template <class Impl>
1871void
1872FullO3CPU<Impl>::updateThreadPriority()
1873{
1874 if (activeThreads.size() > 1) {
1875 //DEFAULT TO ROUND ROBIN SCHEME
1876 //e.g. Move highest priority to end of thread list
1877 list<ThreadID>::iterator list_begin = activeThreads.begin();
1878
1879 unsigned high_thread = *list_begin;
1880
1881 activeThreads.erase(list_begin);
1882
1883 activeThreads.push_back(high_thread);
1884 }
1885}
1886
1887// Forward declaration of FullO3CPU.
1888template class FullO3CPU<O3CPUImpl>;