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"
35 #include "debug/InOrderFetchSeq.hh"
36 #include "debug/InOrderStall.hh"
39 using namespace TheISA
;
40 using namespace ThePipeline
;
42 FetchSeqUnit::FetchSeqUnit(std::string res_name
, int res_id
, int res_width
,
43 int res_latency
, InOrderCPU
*_cpu
,
44 ThePipeline::Params
*params
)
45 : Resource(res_name
, res_id
, res_width
, res_latency
, _cpu
),
46 instSize(sizeof(MachInst
))
48 for (ThreadID tid
= 0; tid
< ThePipeline::MaxThreads
; tid
++) {
50 pcBlockStage
[tid
] = 0;
52 //@todo: Use CPU's squashSeqNum here instead of maintaining our own
54 squashSeqNum
[tid
] = (InstSeqNum
)-1;
55 lastSquashCycle
[tid
] = 0;
59 FetchSeqUnit::~FetchSeqUnit()
61 delete [] resourceEvent
;
67 resourceEvent
= new FetchSeqEvent
[width
];
69 for (int i
= 0; i
< width
; i
++) {
70 reqs
[i
] = new ResourceRequest(this);
77 FetchSeqUnit::execute(int slot_num
)
79 ResourceRequest
* fs_req
= reqs
[slot_num
];
80 DynInstPtr inst
= fs_req
->inst
;
81 ThreadID tid
= inst
->readTid();
82 int stage_num
= fs_req
->getStageNum();
88 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Current PC is %s\n", tid
,
92 inst
->pcState(pc
[tid
]);
93 inst
->setMemAddr(pc
[tid
].instAddr());
95 // Advance to next PC (typically PC + 4)
98 inst
->setSeqNum(cpu
->getAndIncrementInstSeq(tid
));
100 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Assigning [sn:%i] to "
101 "PC %s\n", tid
, inst
->seqNum
, inst
->pcState());
105 DPRINTF(InOrderStall
, "STALL: [tid:%i]: NPC not valid\n", tid
);
113 assert(!inst
->isCondDelaySlot() &&
114 "Not Handling Conditional Delay Slot");
116 if (inst
->isControl()) {
117 if (inst
->isReturn() && !inst
->predTaken()) {
118 // If it's a return, then we must wait for resolved address.
119 // The Predictor will mark a return a false as "not taken"
120 // if there is no RAS entry
121 DPRINTF(InOrderFetchSeq
, "[tid:%d]: Setting block signal "
124 cpu
->pipelineStage
[stage_num
]->
125 toPrevStages
->stageBlock
[stage_num
][tid
] = true;
126 pcValid
[tid
] = false;
127 pcBlockStage
[tid
] = stage_num
;
128 } else if (inst
->predTaken()) {
130 inst
->setSquashInfo(stage_num
);
131 setupSquash(inst
, stage_num
, tid
);
133 DPRINTF(InOrderFetchSeq
, "[tid:%i] Setting up squash to "
134 "start from stage %i, after [sn:%i].\n",
135 tid
, stage_num
, inst
->squashSeqNum
);
138 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: Ignoring branch "
139 "target update since then is not a control "
140 "instruction.\n", tid
, inst
->seqNum
);
148 fatal("Unrecognized command to %s", resName
);
153 FetchSeqUnit::squash(DynInstPtr inst
, int squash_stage
,
154 InstSeqNum squash_seq_num
, ThreadID tid
)
156 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Updating due to squash from %s (%s) "
157 "stage %i.\n", tid
, inst
->instName(), inst
->pcState(),
160 if (lastSquashCycle
[tid
] == curTick() &&
161 squashSeqNum
[tid
] <= squash_seq_num
) {
162 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Ignoring squash from stage %i, "
163 "since there is an outstanding squash that is older.\n",
166 squashSeqNum
[tid
] = squash_seq_num
;
167 lastSquashCycle
[tid
] = curTick();
169 if (inst
->staticInst
) {
170 if (inst
->fault
!= NoFault
) {
171 // A Trap Caused This Fault and will update the pc state
172 // when done trapping
173 DPRINTF(InOrderFetchSeq
, "[tid:%i] Blocking due to fault @ "
174 "[sn:%i].%s %s \n", inst
->seqNum
,
175 inst
->instName(), inst
->pcState());
176 pcValid
[tid
] = false;
178 TheISA::PCState nextPC
;
179 assert(inst
->staticInst
);
180 if (inst
->isControl()) {
181 nextPC
= inst
->readPredTarg();
183 // If we are already fetching this PC then advance to next PC
185 // This should handle ISAs w/delay slots and annulled delay
186 // slots to figure out which is the next PC to fetch after
188 DynInstPtr bdelay_inst
= NULL
;
190 if (inst
->onInstList
) {
191 bdelay_it
= inst
->getInstListIt();
194 InstSeqNum branch_delay_num
= inst
->seqNum
+ 1;
195 bdelay_it
= cpu
->findInst(branch_delay_num
, tid
);
198 if (bdelay_it
!= cpu
->instList
[tid
].end()) {
199 bdelay_inst
= (*bdelay_it
);
203 DPRINTF(Resource
, "Evaluating %s v. %s\n",
204 bdelay_inst
->pc
, nextPC
);
206 if (bdelay_inst
->pc
.instAddr() == nextPC
.instAddr()) {
207 bdelay_inst
->pc
= nextPC
;
208 advancePC(nextPC
, inst
->staticInst
);
209 DPRINTF(Resource
, "Advanced PC to %s\n", nextPC
);
213 nextPC
= inst
->pcState();
214 advancePC(nextPC
, inst
->staticInst
);
218 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC to %s.\n",
222 // Unblock Any Stages Waiting for this information to be updated ...
224 DPRINTF(InOrderFetchSeq
, "[tid:%d]: Setting unblock signal "
226 tid
, pcBlockStage
[tid
]);
228 // Need to use "fromNextStages" instead of "toPrevStages"
229 // because the timebuffer will have already have advanced
230 // in the tick function and this squash function will happen after
232 cpu
->pipelineStage
[pcBlockStage
[tid
]]->
233 fromNextStages
->stageUnblock
[pcBlockStage
[tid
]][tid
] = true;
241 Resource::squash(inst
, squash_stage
, squash_seq_num
, tid
);
244 FetchSeqUnit::FetchSeqEvent::FetchSeqEvent()
249 FetchSeqUnit::FetchSeqEvent::process()
251 FetchSeqUnit
* fs_res
= dynamic_cast<FetchSeqUnit
*>(resource
);
254 for (int i
= 0; i
< MaxThreads
; i
++) {
255 fs_res
->pc
[i
] = fs_res
->cpu
->pcState(i
);
256 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC: %s.\n",
259 fs_res
->pcValid
[i
] = true;
265 FetchSeqUnit::activateThread(ThreadID tid
)
269 pc
[tid
] = cpu
->pcState(tid
);
271 cpu
->fetchPriorityList
.push_back(tid
);
273 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Reading PC: %s.\n",
278 FetchSeqUnit::deactivateThread(ThreadID tid
)
280 pcValid
[tid
] = false;
281 pcBlockStage
[tid
] = 0;
283 squashSeqNum
[tid
] = (InstSeqNum
)-1;
284 lastSquashCycle
[tid
] = 0;
286 list
<ThreadID
>::iterator thread_it
= find(cpu
->fetchPriorityList
.begin(),
287 cpu
->fetchPriorityList
.end(),
290 if (thread_it
!= cpu
->fetchPriorityList
.end())
291 cpu
->fetchPriorityList
.erase(thread_it
);
295 FetchSeqUnit::suspendThread(ThreadID tid
)
297 deactivateThread(tid
);
301 FetchSeqUnit::trap(Fault fault
, ThreadID tid
, DynInstPtr inst
)
304 pc
[tid
] = cpu
->pcState(tid
);
305 DPRINTF(Fault
, "[tid:%i]: Trap updating to PC: "
306 "%s.\n", tid
, pc
[tid
]);
307 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Trap updating to PC: "
308 "%s.\n", tid
, pc
[tid
]);
312 FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst
, ThreadID tid
)
316 if (cpu
->thread
[tid
]->lastGradIsBranch
) {
317 /** This function assumes that the instruction causing the context
318 * switch was right after the branch. Thus, if it's not, then
319 * we are updating incorrectly here
321 assert(cpu
->nextInstAddr(tid
) == inst
->instAddr());
322 pc
[tid
] = cpu
->thread
[tid
]->lastBranchPC
;
324 pc
[tid
] = inst
->pcState();
326 assert(inst
->staticInst
);
327 advancePC(pc
[tid
], inst
->staticInst
);
329 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Updating PCs due to Context Switch."
330 "Assigning PC: %s.\n", tid
, pc
[tid
]);