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
++) {
47 delaySlotInfo
[tid
].numInsts
= 0;
48 delaySlotInfo
[tid
].targetReady
= false;
51 pcBlockStage
[tid
] = 0;
53 squashSeqNum
[tid
] = (InstSeqNum
)-1;
54 lastSquashCycle
[tid
] = 0;
58 FetchSeqUnit::~FetchSeqUnit()
60 delete [] resourceEvent
;
66 resourceEvent
= new FetchSeqEvent
[width
];
72 FetchSeqUnit::execute(int slot_num
)
74 // After this is working, change this to a reinterpret cast
75 // for performance considerations
76 ResourceRequest
* fs_req
= reqMap
[slot_num
];
77 DynInstPtr inst
= fs_req
->inst
;
78 ThreadID tid
= inst
->readTid();
79 int stage_num
= fs_req
->getStageNum();
80 int seq_num
= inst
->seqNum
;
82 fs_req
->fault
= NoFault
;
90 if (delaySlotInfo
[tid
].targetReady
&&
91 delaySlotInfo
[tid
].numInsts
== 0) {
93 PC
[tid
] = delaySlotInfo
[tid
].targetAddr
; //next_PC
94 nextPC
[tid
] = PC
[tid
] + instSize
; //next_NPC
95 nextNPC
[tid
] = PC
[tid
] + (2 * instSize
);
97 delaySlotInfo
[tid
].targetReady
= false;
99 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC to delay "
100 "slot target\n",tid
);
103 inst
->setPC(PC
[tid
]);
104 inst
->setNextPC(PC
[tid
] + instSize
);
105 inst
->setNextNPC(PC
[tid
] + (instSize
* 2));
107 #if ISA_HAS_DELAY_SLOT
108 inst
->setPredTarg(inst
->readNextNPC());
110 inst
->setPredTarg(inst
->readNextPC());
112 inst
->setMemAddr(PC
[tid
]);
113 inst
->setSeqNum(cpu
->getAndIncrementInstSeq(tid
));
115 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Assigning [sn:%i] to "
116 "PC %08p, NPC %08p, NNPC %08p\n", tid
,
117 inst
->seqNum
, inst
->readPC(), inst
->readNextPC(),
118 inst
->readNextNPC());
120 if (delaySlotInfo
[tid
].numInsts
> 0) {
121 --delaySlotInfo
[tid
].numInsts
;
123 // It's OK to set PC to target of branch
124 if (delaySlotInfo
[tid
].numInsts
== 0) {
125 delaySlotInfo
[tid
].targetReady
= true;
128 DPRINTF(InOrderFetchSeq
, "[tid:%i]: %i delay slot inst(s) "
129 "left to process.\n", tid
,
130 delaySlotInfo
[tid
].numInsts
);
133 PC
[tid
] = nextPC
[tid
];
134 nextPC
[tid
] = nextNPC
[tid
];
135 nextNPC
[tid
] += instSize
;
139 DPRINTF(InOrderStall
, "STALL: [tid:%i]: NPC not valid\n", tid
);
140 fs_req
->setCompleted(false);
147 if (inst
->isControl()) {
148 // If it's a return, then we must wait for resolved address.
149 if (inst
->isReturn() && !inst
->predTaken()) {
150 cpu
->pipelineStage
[stage_num
]->toPrevStages
->stageBlock
[stage_num
][tid
] = true;
151 pcValid
[tid
] = false;
152 pcBlockStage
[tid
] = stage_num
;
153 } else if (inst
->isCondDelaySlot() && !inst
->predTaken()) {
154 // Not-Taken AND Conditional Control
155 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: [PC:%08p] "
156 "Predicted Not-Taken Cond. "
157 "Delay inst. Skipping delay slot and Updating PC to %08p\n",
158 tid
, inst
->seqNum
, inst
->readPC(), inst
->readPredTarg());
160 DPRINTF(InOrderFetchSeq
, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
161 tid
, stage_num
, seq_num
);
163 inst
->bdelaySeqNum
= seq_num
;
164 inst
->squashingStage
= stage_num
;
166 squashAfterInst(inst
, stage_num
, tid
);
167 } else if (!inst
->isCondDelaySlot() && !inst
->predTaken()) {
169 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: Predicted "
171 "inst. updating PC to %08p\n", tid
, inst
->seqNum
,
173 #if ISA_HAS_DELAY_SLOT
174 ++delaySlotInfo
[tid
].numInsts
;
175 delaySlotInfo
[tid
].targetReady
= false;
176 delaySlotInfo
[tid
].targetAddr
= inst
->readNextNPC();
178 assert(delaySlotInfo
[tid
].numInsts
== 0);
180 } else if (inst
->predTaken()) {
182 #if ISA_HAS_DELAY_SLOT
183 ++delaySlotInfo
[tid
].numInsts
;
184 delaySlotInfo
[tid
].targetReady
= false;
185 delaySlotInfo
[tid
].targetAddr
= inst
->readPredTarg();
187 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i] Updating delay"
188 " slot target to PC %08p\n", tid
, inst
->seqNum
,
189 inst
->readPredTarg());
190 inst
->bdelaySeqNum
= seq_num
+ 1;
192 inst
->bdelaySeqNum
= seq_num
;
193 assert(delaySlotInfo
[tid
].numInsts
== 0);
196 inst
->squashingStage
= stage_num
;
198 DPRINTF(InOrderFetchSeq
, "[tid:%i] Setting up squash to "
199 "start from stage %i, after [sn:%i].\n",
200 tid
, stage_num
, inst
->bdelaySeqNum
);
203 squashAfterInst(inst
, stage_num
, tid
);
206 DPRINTF(InOrderFetchSeq
, "[tid:%i]: [sn:%i]: Ignoring branch "
207 "target update since then is not a control "
208 "instruction.\n", tid
, inst
->seqNum
);
216 fatal("Unrecognized command to %s", resName
);
221 FetchSeqUnit::squashAfterInst(DynInstPtr inst
, int stage_num
, ThreadID tid
)
223 // Squash In Pipeline Stage
224 cpu
->pipelineStage
[stage_num
]->squashDueToBranch(inst
, tid
);
226 // Squash inside current resource, so if there needs to be fetching on
227 // same cycle the fetch information will be correct.
228 // squash(inst, stage_num, inst->bdelaySeqNum, tid);
230 // Schedule Squash Through-out Resource Pool
231 cpu
->resPool
->scheduleEvent((InOrderCPU::CPUEventType
)ResourcePool::SquashAll
, inst
, 0);
234 FetchSeqUnit::squash(DynInstPtr inst
, int squash_stage
,
235 InstSeqNum squash_seq_num
, ThreadID tid
)
237 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Updating due to squash from stage %i."
238 "\n", tid
, squash_stage
);
240 InstSeqNum done_seq_num
= inst
->bdelaySeqNum
;
242 // Handles the case where we are squashing because of something that is
243 // not a branch...like a memory stall
244 Addr new_PC
= (inst
->isControl()) ?
245 inst
->readPredTarg() : inst
->readPC() + instSize
;
247 if (squashSeqNum
[tid
] <= done_seq_num
&&
248 lastSquashCycle
[tid
] == curTick
) {
249 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Ignoring squash from stage %i, "
250 "since there is an outstanding squash that is older.\n",
253 squashSeqNum
[tid
] = done_seq_num
;
254 lastSquashCycle
[tid
] = curTick
;
256 // If The very next instruction number is the done seq. num,
257 // then we haven't seen the delay slot yet ... if it isn't
258 // the last done_seq_num then this is the delay slot inst.
259 if (cpu
->nextInstSeqNum(tid
) != done_seq_num
&&
260 !inst
->procDelaySlotOnMispred
) {
261 delaySlotInfo
[tid
].numInsts
= 0;
262 delaySlotInfo
[tid
].targetReady
= false;
266 nextPC
[tid
] = new_PC
+ instSize
;
267 nextNPC
[tid
] = new_PC
+ (2 * instSize
);
269 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC to %08p.\n",
272 #if !ISA_HAS_DELAY_SLOT
276 delaySlotInfo
[tid
].numInsts
= 1;
277 delaySlotInfo
[tid
].targetReady
= false;
278 delaySlotInfo
[tid
].targetAddr
= (inst
->procDelaySlotOnMispred
) ?
279 inst
->branchTarget() : new_PC
;
281 // Reset PC to Delay Slot Instruction
282 if (inst
->procDelaySlotOnMispred
) {
284 nextPC
[tid
] = new_PC
+ instSize
;
285 nextNPC
[tid
] = new_PC
+ (2 * instSize
);
290 // Unblock Any Stages Waiting for this information to be updated ...
292 cpu
->pipelineStage
[pcBlockStage
[tid
]]->
293 toPrevStages
->stageUnblock
[pcBlockStage
[tid
]][tid
] = true;
299 Resource::squash(inst
, squash_stage
, squash_seq_num
, tid
);
302 FetchSeqUnit::FetchSeqEvent::FetchSeqEvent()
307 FetchSeqUnit::FetchSeqEvent::process()
309 FetchSeqUnit
* fs_res
= dynamic_cast<FetchSeqUnit
*>(resource
);
312 for (int i
=0; i
< MaxThreads
; i
++) {
313 fs_res
->PC
[i
] = fs_res
->cpu
->readPC(i
);
314 fs_res
->nextPC
[i
] = fs_res
->cpu
->readNextPC(i
);
315 fs_res
->nextNPC
[i
] = fs_res
->cpu
->readNextNPC(i
);
316 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Setting PC:%08p NPC:%08p "
317 "NNPC:%08p.\n", fs_res
->PC
[i
], fs_res
->nextPC
[i
],
320 fs_res
->pcValid
[i
] = true;
323 //cpu->fetchPriorityList.push_back(tid);
328 FetchSeqUnit::activateThread(ThreadID tid
)
332 PC
[tid
] = cpu
->readPC(tid
);
333 nextPC
[tid
] = cpu
->readNextPC(tid
);
334 nextNPC
[tid
] = cpu
->readNextNPC(tid
);
336 cpu
->fetchPriorityList
.push_back(tid
);
338 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Reading PC:%08p NPC:%08p "
339 "NNPC:%08p.\n", tid
, PC
[tid
], nextPC
[tid
], nextNPC
[tid
]);
343 FetchSeqUnit::deactivateThread(ThreadID tid
)
345 delaySlotInfo
[tid
].numInsts
= 0;
346 delaySlotInfo
[tid
].targetReady
= false;
348 pcValid
[tid
] = false;
349 pcBlockStage
[tid
] = 0;
351 squashSeqNum
[tid
] = (InstSeqNum
)-1;
352 lastSquashCycle
[tid
] = 0;
354 list
<ThreadID
>::iterator thread_it
= find(cpu
->fetchPriorityList
.begin(),
355 cpu
->fetchPriorityList
.end(),
358 if (thread_it
!= cpu
->fetchPriorityList
.end())
359 cpu
->fetchPriorityList
.erase(thread_it
);
363 FetchSeqUnit::suspendThread(ThreadID tid
)
365 deactivateThread(tid
);
369 FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst
, ThreadID tid
)
373 if (cpu
->thread
[tid
]->lastGradIsBranch
) {
374 /** This function assumes that the instruction causing the context
375 * switch was right after the branch. Thus, if it's not, then
376 * we are updating incorrectly here
378 assert(cpu
->thread
[tid
]->lastBranchNextPC
== inst
->readPC());
380 PC
[tid
] = cpu
->thread
[tid
]->lastBranchNextNPC
;
381 nextPC
[tid
] = PC
[tid
] + instSize
;
382 nextNPC
[tid
] = nextPC
[tid
] + instSize
;
384 PC
[tid
] = inst
->readNextPC();
385 nextPC
[tid
] = inst
->readNextNPC();
386 nextNPC
[tid
] = inst
->readNextNPC() + instSize
;
389 DPRINTF(InOrderFetchSeq
, "[tid:%i]: Updating PCs due to Context Switch."
390 "Assigning PC:%08p NPC:%08p NNPC:%08p.\n", tid
, PC
[tid
],
391 nextPC
[tid
], nextNPC
[tid
]);