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 "base/str.hh"
33 #include "cpu/inorder/first_stage.hh"
34 #include "cpu/inorder/resources/resource_list.hh"
35 #include "cpu/inorder/resource_pool.hh"
36 #include "cpu/inorder/cpu.hh"
37 #include "params/InOrderTrace.hh"
40 using namespace ThePipeline
;
42 FirstStage::FirstStage(Params
*params
, unsigned stage_num
)
43 : PipelineStage(params
, stage_num
), numFetchingThreads(1),
44 fetchPolicy(FirstStage::RoundRobin
)
46 for(ThreadID tid
= 0; tid
< this->numThreads
; tid
++) {
47 stageStatus
[tid
] = Running
;
52 FirstStage::setCPU(InOrderCPU
*cpu_ptr
)
56 fetchPriorityList
= &cpu
->fetchPriorityList
;
58 DPRINTF(InOrderStage
, "Set CPU pointer.\n");
63 FirstStage::squash(InstSeqNum squash_seq_num
, ThreadID tid
)
65 // Set status to squashing.
66 //stageStatus[tid] = Squashing;
68 // Clear the instruction list and skid buffer in case they have any
70 DPRINTF(InOrderStage
, "Removing instructions from stage instruction "
72 while (!insts
[tid
].empty()) {
73 if (insts
[tid
].front()->seqNum
<= squash_seq_num
) {
74 DPRINTF(InOrderStage
,"[tid:%i]: Cannot remove [sn:%i] because "
75 "it's <= squashing seqNum %i.\n",
77 insts
[tid
].front()->seqNum
,
80 DPRINTF(InOrderStage
, "[tid:%i]: Cannot remove incoming "
81 "instructions before delay slot [sn:%i]. %i insts"
82 "left.\n", tid
, squash_seq_num
,
86 DPRINTF(InOrderStage
, "[tid:%i]: Removing instruction, [sn:%i] "
87 "PC %08p.\n", tid
, insts
[tid
].front()->seqNum
,
88 insts
[tid
].front()->PC
);
92 // Now that squash has propagated to the first stage,
93 // Alert CPU to remove instructions from the CPU instruction list.
94 // @todo: Move this to the CPU object.
95 cpu
->removeInstsUntil(squash_seq_num
, tid
);
99 FirstStage::squashDueToMemStall(InstSeqNum seq_num
, ThreadID tid
)
101 // Need to preserve the stalling instruction in first-stage
102 // since the squash() from first stage also removes
103 // the instruction from the CPU (removeInstsUntil). If that
104 // functionality gets changed then you can move this offset.
105 // (stalling instruction = seq_num + 1)
106 squash(seq_num
+1, tid
);
111 FirstStage::processStage(bool &status_change
)
113 list
<ThreadID
>::iterator threads
= activeThreads
->begin();
115 //Check stall and squash signals.
116 while (threads
!= activeThreads
->end()) {
117 ThreadID tid
= *threads
++;
118 status_change
= checkSignalsAndUpdate(tid
) || status_change
;
121 for (int insts_fetched
= 0;
122 insts_fetched
< stageWidth
&& canSendInstToStage(1);
124 ThreadID tid
= getFetchingThread(fetchPolicy
);
127 DPRINTF(InOrderStage
, "Processing [tid:%i]\n",tid
);
128 processThread(status_change
, tid
);
130 DPRINTF(InOrderStage
, "No more threads to fetch from.\n");
134 if (instsProcessed
> 0) {
144 //@TODO: Note in documentation, that when you make a pipeline stage change,
145 //then make sure you change the first stage too
147 FirstStage::processInsts(ThreadID tid
)
149 bool all_reqs_completed
= true;
151 for (int insts_fetched
= 0;
152 insts_fetched
< stageWidth
&& canSendInstToStage(1);
156 bool new_inst
= false;
158 if (!insts
[tid
].empty()) {
159 inst
= insts
[tid
].front();
161 // Get new instruction.
164 inst
= new InOrderDynInst(cpu
,
166 cpu
->nextInstSeqNum(tid
),
172 tracer
->getInstRecord(ThePipeline::NumStages
,
174 cpu
->thread
[tid
]->getTC());
177 inst
->traceData
= NULL
;
180 // Add instruction to the CPU's list of instructions.
181 inst
->setInstListIt(cpu
->addInst(inst
));
183 // Create Front-End Resource Schedule For Instruction
184 ThePipeline::createFrontEndSchedule(inst
);
187 int reqs_processed
= 0;
188 all_reqs_completed
= processInstSchedule(inst
, reqs_processed
);
190 // If the instruction isnt squashed & we've completed one request
191 // Then we can officially count this instruction toward the stage's
193 if (reqs_processed
> 0)
196 if (!all_reqs_completed
) {
198 DPRINTF(InOrderStage
, "[tid:%u]: [sn:%u] Did not finish all "
199 "requests for this stage. Keep in stage inst. "
200 "list.\n", tid
, inst
->seqNum
);
201 insts
[tid
].push(inst
);
204 } else if (!insts
[tid
].empty()){
208 sendInstToNextStage(inst
);
211 // Record that stage has written to the time buffer for activity
213 if (toNextStageIndex
) {
214 wroteToTimeBuffer
= true;
219 FirstStage::getFetchingThread(FetchPriority
&fetch_priority
)
221 ThreadID num_active_threads
= cpu
->numActiveThreads();
223 if (num_active_threads
> 1) {
224 switch (fetch_priority
) {
226 return cpu
->activeThreadId();
232 return InvalidThreadID
;
234 } else if (num_active_threads
== 1) {
235 ThreadID tid
= *activeThreads
->begin();
237 if (stageStatus
[tid
] == Running
||
238 stageStatus
[tid
] == Idle
) {
241 return InvalidThreadID
;
244 return InvalidThreadID
;
249 FirstStage::roundRobin()
251 list
<ThreadID
>::iterator pri_iter
= fetchPriorityList
->begin();
252 list
<ThreadID
>::iterator end
= fetchPriorityList
->end();
256 while (pri_iter
!= end
) {
257 high_pri
= *pri_iter
;
259 assert(high_pri
<= numThreads
);
261 if (stageStatus
[high_pri
] == Running
||
262 stageStatus
[high_pri
] == Idle
) {
264 fetchPriorityList
->erase(pri_iter
);
265 fetchPriorityList
->push_back(high_pri
);
273 return InvalidThreadID
;