2 * Copyright (c) 2007 MIPS Technologies, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Authors: Korey Sewell
32 #include "config/the_isa.hh"
33 #include "cpu/inorder/resources/fetch_seq_unit.hh"
34 #include "cpu/inorder/resource_pool.hh"
37 using namespace TheISA
;
38 using namespace ThePipeline
;
40 FetchSeqUnit::FetchSeqUnit(std::string res_name
, int res_id
, int res_width
,
41 int res_latency
, InOrderCPU
*_cpu
,
42 ThePipeline::Params
*params
)
43 : Resource(res_name
, res_id
, res_width
, res_latency
, _cpu
),
44 instSize(sizeof(MachInst
))
46 for (ThreadID tid
= 0; tid
< ThePipeline::MaxThreads
; tid
++) {
48 pcBlockStage
[tid
] = 0;
50 squashSeqNum
[tid
] = (InstSeqNum
)-1;
51 lastSquashCycle
[tid
] = 0;
55 FetchSeqUnit::~FetchSeqUnit()
57 delete [] resourceEvent
;
63 resourceEvent
= new FetchSeqEvent
[width
];
65 for (int i
= 0; i
< width
; i
++) {
66 reqs
[i
] = new ResourceRequest(this);
73 FetchSeqUnit::execute(int slot_num
)
75 ResourceRequest
* fs_req
= reqs
[slot_num
];
76 DynInstPtr inst
= fs_req
->inst
;
77 ThreadID tid
= inst
->readTid();
78 int stage_num
= fs_req
->getStageNum();
79 int seq_num
= inst
->seqNum
;
81 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Current PC is %s\n", tid
,
89 inst
->pcState(pc
[tid
]);
90 inst
->setMemAddr(pc
[tid
].instAddr());
92 // Advance to next PC (typically PC + 4)
95 inst
->setSeqNum(cpu
->getAndIncrementInstSeq(tid
));
97 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Assigning [sn:%i] to "
98 "PC %s\n", tid
, inst
->seqNum
, inst
->pcState());
102 DPRINTF(InOrderStall
, "STALL: [tid:%i]: NPC not valid\n", tid
);
103 fs_req
->setCompleted(false);
110 if (inst
->isControl()) {
111 // If it's a return, then we must wait for resolved address.
112 if (inst
->isReturn() && !inst
->predTaken()) {
113 cpu
->pipelineStage
[stage_num
]->
114 toPrevStages
->stageBlock
[stage_num
][tid
] = true;
115 pcValid
[tid
] = false;
116 pcBlockStage
[tid
] = stage_num
;
117 } else if (inst
->isCondDelaySlot() && !inst
->predTaken()) {
118 // Not-Taken AND Conditional Control
119 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: [PC:%s] "
120 "Predicted Not-Taken Cond. Delay inst. Skipping "
121 "delay slot and Updating PC to %s\n",
122 tid
, inst
->seqNum
, inst
->pcState(),
123 inst
->readPredTarg());
125 DPRINTF(InOrderFetchSeq
, "[tid:%i] Setting up squash to "
126 "start from stage %i, after [sn:%i].\n", tid
,
129 inst
->bdelaySeqNum
= seq_num
;
130 inst
->squashingStage
= stage_num
;
132 squashAfterInst(inst
, stage_num
, tid
);
133 } else if (!inst
->isCondDelaySlot() && !inst
->predTaken()) {
135 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: Predicted "
137 "inst. updating PC to %s\n", tid
, inst
->seqNum
,
138 inst
->readPredTarg());
139 #if ISA_HAS_DELAY_SLOT
140 pc
[tid
] = inst
->pcState();
141 advancePC(pc
[tid
], inst
->staticInst
);
143 } else if (inst
->predTaken()) {
145 #if ISA_HAS_DELAY_SLOT
146 pc
[tid
] = inst
->readPredTarg();
148 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i] Updating delay"
149 " slot target to PC %s\n", tid
, inst
->seqNum
,
150 inst
->readPredTarg());
151 inst
->bdelaySeqNum
= seq_num
+ 1;
153 inst
->bdelaySeqNum
= seq_num
;
156 inst
->squashingStage
= stage_num
;
157 DPRINTF(InOrderFetchSeq
, "[tid:%i] Setting up squash to "
158 "start from stage %i, after [sn:%i].\n",
159 tid
, stage_num
, inst
->bdelaySeqNum
);
162 squashAfterInst(inst
, stage_num
, tid
);
165 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: Ignoring branch "
166 "target update since then is not a control "
167 "instruction.\n", tid
, inst
->seqNum
);
175 fatal("Unrecognized command to %s", resName
);
180 FetchSeqUnit::squashAfterInst(DynInstPtr inst
, int stage_num
, ThreadID tid
)
182 // Squash In Pipeline Stage
183 cpu
->pipelineStage
[stage_num
]->squashDueToBranch(inst
, tid
);
185 // Squash inside current resource, so if there needs to be fetching on
186 // same cycle the fetch information will be correct.
188 // Schedule Squash Through-out Resource Pool
189 cpu
->resPool
->scheduleEvent(
190 (InOrderCPU::CPUEventType
)ResourcePool::SquashAll
, inst
, 0);
194 FetchSeqUnit::squash(DynInstPtr inst
, int squash_stage
,
195 InstSeqNum squash_seq_num
, ThreadID tid
)
197 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Updating due to squash from stage %i."
198 "\n", tid
, squash_stage
);
200 InstSeqNum done_seq_num
= inst
->bdelaySeqNum
;
202 // Handles the case where we are squashing because of something that is
203 // not a branch...like a memory stall
204 TheISA::PCState newPC
;
205 if (inst
->isControl()) {
206 newPC
= inst
->readPredTarg();
208 TheISA::PCState thisPC
= inst
->pcState();
209 assert(inst
->staticInst
);
210 advancePC(thisPC
, inst
->staticInst
);
214 if (squashSeqNum
[tid
] <= done_seq_num
&&
215 lastSquashCycle
[tid
] == curTick()) {
216 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Ignoring squash from stage %i, "
217 "since there is an outstanding squash that is older.\n",
220 squashSeqNum
[tid
] = done_seq_num
;
221 lastSquashCycle
[tid
] = curTick();
223 // If The very next instruction number is the done seq. num,
224 // then we haven't seen the delay slot yet ... if it isn't
225 // the last done_seq_num then this is the delay slot inst.
226 if (cpu
->nextInstSeqNum(tid
) != done_seq_num
&&
227 !inst
->procDelaySlotOnMispred
) {
231 #if ISA_HAS_DELAY_SLOT
232 TheISA::advancePC(pc
[tid
], inst
->staticInst
);
235 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC to %s.\n",
238 assert(ISA_HAS_DELAY_SLOT
);
240 pc
[tid
] = (inst
->procDelaySlotOnMispred
) ?
241 inst
->branchTarget() : newPC
;
243 // Reset PC to Delay Slot Instruction
244 if (inst
->procDelaySlotOnMispred
) {
251 // Unblock Any Stages Waiting for this information to be updated ...
253 cpu
->pipelineStage
[pcBlockStage
[tid
]]->
254 toPrevStages
->stageUnblock
[pcBlockStage
[tid
]][tid
] = true;
260 Resource::squash(inst
, squash_stage
, squash_seq_num
, tid
);
263 FetchSeqUnit::FetchSeqEvent::FetchSeqEvent()
268 FetchSeqUnit::FetchSeqEvent::process()
270 FetchSeqUnit
* fs_res
= dynamic_cast<FetchSeqUnit
*>(resource
);
273 for (int i
= 0; i
< MaxThreads
; i
++) {
274 fs_res
->pc
[i
] = fs_res
->cpu
->pcState(i
);
275 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC: %s.\n",
278 fs_res
->pcValid
[i
] = true;
284 FetchSeqUnit::activateThread(ThreadID tid
)
288 pc
[tid
] = cpu
->pcState(tid
);
290 cpu
->fetchPriorityList
.push_back(tid
);
292 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Reading PC: %s.\n",
297 FetchSeqUnit::deactivateThread(ThreadID tid
)
299 pcValid
[tid
] = false;
300 pcBlockStage
[tid
] = 0;
302 squashSeqNum
[tid
] = (InstSeqNum
)-1;
303 lastSquashCycle
[tid
] = 0;
305 list
<ThreadID
>::iterator thread_it
= find(cpu
->fetchPriorityList
.begin(),
306 cpu
->fetchPriorityList
.end(),
309 if (thread_it
!= cpu
->fetchPriorityList
.end())
310 cpu
->fetchPriorityList
.erase(thread_it
);
314 FetchSeqUnit::suspendThread(ThreadID tid
)
316 deactivateThread(tid
);
320 FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst
, ThreadID tid
)
324 if (cpu
->thread
[tid
]->lastGradIsBranch
) {
325 /** This function assumes that the instruction causing the context
326 * switch was right after the branch. Thus, if it's not, then
327 * we are updating incorrectly here
329 assert(cpu
->nextInstAddr(tid
) == inst
->instAddr());
330 pc
[tid
] = cpu
->thread
[tid
]->lastBranchPC
;
332 pc
[tid
] = inst
->pcState();
334 assert(inst
->staticInst
);
335 advancePC(pc
[tid
], inst
->staticInst
);
337 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Updating PCs due to Context Switch."
338 "Assigning PC: %s.\n", tid
, pc
[tid
]);