inorder: enforce 78-character rule
[gem5.git] / src / cpu / inorder / resources / mult_div_unit.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Korey Sewell
29 *
30 */
31
32 #include <vector>
33 #include <list>
34 #include "cpu/inorder/resources/mult_div_unit.hh"
35 #include "cpu/inorder/resource_pool.hh"
36 #include "cpu/inorder/cpu.hh"
37 #include "cpu/op_class.hh"
38
39 using namespace std;
40 using namespace ThePipeline;
41
42 MultDivUnit::MultDivUnit(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 multRepeatRate(params->multRepeatRate),
47 multLatency(params->multLatency),
48 div8RepeatRate(params->div8RepeatRate),
49 div8Latency(params->div8Latency),
50 div16RepeatRate(params->div16RepeatRate),
51 div16Latency(params->div16Latency),
52 div24RepeatRate(params->div24RepeatRate),
53 div24Latency(params->div24Latency),
54 div32RepeatRate(params->div32RepeatRate),
55 div32Latency(params->div32Latency),
56 lastMDUCycle(0), lastOpType(No_OpClass)
57 { }
58
59 void
60 MultDivUnit::regStats()
61 {
62 multiplies
63 .name(name() + ".multiplies")
64 .desc("Number of Multipy Operations Executed");
65
66 divides
67 .name(name() + ".divides")
68 .desc("Number of Divide Operations Executed");
69
70 Resource::regStats();
71 }
72
73 void
74 MultDivUnit::init()
75 {
76 // Set Up Resource Events to Appropriate Resource BandWidth
77 resourceEvent = new MDUEvent[width];
78
79 initSlots();
80 }
81
82 int
83 MultDivUnit::findSlot(DynInstPtr inst)
84 {
85 DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | "
86 "slots-used:%i\n", inst->seqNum, slotsAvail(), slotsInUse());
87
88 return Resource::findSlot(inst);
89 }
90
91 void
92 MultDivUnit::freeSlot(int slot_idx)
93 {
94 DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | "
95 "slots-used:%i\n", reqMap[slot_idx]->getInst()->seqNum,
96 slotsAvail(), slotsInUse());
97
98 Resource::freeSlot(slot_idx);
99 }
100
101 //@TODO: Should we push this behavior into base-class to generically
102 // accomodate all multicyle resources?
103 void
104 MultDivUnit::requestAgain(DynInstPtr inst, bool &service_request)
105 {
106 ResReqPtr mult_div_req = findRequest(inst);
107 assert(mult_div_req);
108
109 service_request = true;
110
111 // Check to see if this instruction is requesting the same command
112 // or a different one
113 if (mult_div_req->cmd != inst->resSched.top()->cmd) {
114 // If different, then update command in the request
115 mult_div_req->cmd = inst->resSched.top()->cmd;
116 DPRINTF(InOrderMDU,
117 "[tid:%i]: [sn:%i]: Updating the command for this "
118 "instruction\n", inst->readTid(), inst->seqNum);
119 } else {
120 // If same command, just check to see if memory access was completed
121 // but dont try to re-execute
122 DPRINTF(InOrderMDU,
123 "[tid:%i]: [sn:%i]: requesting this resource again\n",
124 inst->readTid(), inst->seqNum);
125 }
126 }
127 int
128 MultDivUnit::getSlot(DynInstPtr inst)
129 {
130 // If MDU already has instruction, return current slot.
131 int slot_num = findSlot(inst);
132
133 // If we have this instruction's request already then return
134 if (slot_num != -1 &&
135 inst->resSched.top()->cmd == reqMap[slot_num]->cmd)
136 return slot_num;
137
138 unsigned repeat_rate = 0;
139
140 /** Enforce MDU dependencies after a multiply is seen last */
141 if (lastOpType == IntMultOp) {
142 repeat_rate = multRepeatRate;
143 }
144
145 /** Enforce dependencies after a divide is seen last */
146 if (lastOpType == IntDivOp) {
147 switch (lastDivSize) {
148 case 8:
149 repeat_rate = div8RepeatRate;
150 break;
151
152 case 16:
153 repeat_rate = div16RepeatRate;
154 break;
155
156 case 24:
157 repeat_rate = div24RepeatRate;
158 break;
159
160 case 32:
161 repeat_rate = div32RepeatRate;
162 break;
163 }
164 }
165
166 if (lastMDUCycle + repeat_rate > curTick) {
167 DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, "
168 "denying request.\n", lastMDUCycle + repeat_rate);
169 return -1;
170 } else {
171 int rval = Resource::getSlot(inst);
172 DPRINTF(InOrderMDU, "MDU request should pass: %i.\n",
173 rval);
174
175 if (rval != -1) {
176 lastMDUCycle = curTick;
177 lastOpType = inst->opClass();
178 lastInstName = inst->staticInst->getName();
179 }
180
181 return rval;
182 }
183 }
184
185 int
186 MultDivUnit::getDivOpSize(DynInstPtr inst)
187 {
188 // Get RT Register from instruction (index #1)
189 uint32_t div_op = inst->readIntSrc(1);
190
191 if (div_op <= 0xFF) {
192 return 8;
193 } else if (div_op <= 0xFFFF) {
194 return 16;
195 } else if (div_op <= 0xFFFFFF) {
196 return 24;
197 } else {
198 return 32;
199 }
200 }
201
202 void
203 MultDivUnit::execute(int slot_num)
204 {
205 ResourceRequest* mult_div_req = reqMap[slot_num];
206 DynInstPtr inst = reqMap[slot_num]->inst;
207 Fault fault = reqMap[slot_num]->fault;
208
209 //ThreadID tid = inst->readTid();
210 //int seq_num = inst->seqNum;
211
212 switch (mult_div_req->cmd)
213 {
214 case StartMultDiv:
215 DPRINTF(InOrderMDU, "Start MDU called ...\n");
216
217 if (inst->opClass() == IntMultOp) {
218 scheduleEvent(slot_num, multLatency);
219 } else if (inst->opClass() == IntDivOp) {
220 int op_size = getDivOpSize(inst);
221
222 switch (op_size)
223 {
224 case 8:
225 scheduleEvent(slot_num, div8Latency);
226 break;
227
228 case 16:
229 scheduleEvent(slot_num, div16Latency);
230 break;
231
232 case 24:
233 scheduleEvent(slot_num, div24Latency);
234 break;
235
236 case 32:
237 scheduleEvent(slot_num, div32Latency);
238 break;
239 }
240
241 lastDivSize = op_size;
242 }
243
244 // Allow to pass through to next stage while
245 // event processes
246 mult_div_req->setCompleted();
247 break;
248
249 case MultDiv:
250 DPRINTF(InOrderMDU, "Execute MDU called ...\n");
251 exeMulDiv(slot_num);
252 mult_div_req->done();
253 break;
254
255
256 case EndMultDiv:
257 //@TODO: Why not allow high-latency requests to sleep
258 // within stage until event wakes up????
259 // Seems wasteful to continually check to see if
260 // this is done when we have a event in parallel
261 // counting down the time
262 {
263 DPRINTF(InOrderMDU, "End MDU called ...\n");
264 if (mult_div_req->getInst()->isExecuted()) {
265 DPRINTF(InOrderMDU, "Mult/Div finished.\n");
266 mult_div_req->done();
267 } else {
268 mult_div_req->setCompleted(false);
269 }
270
271 }
272 break;
273
274 default:
275 fatal("Unrecognized command to %s", resName);
276 }
277 }
278
279 void
280 MultDivUnit::exeMulDiv(int slot_num)
281 {
282 ResourceRequest* mult_div_req = reqMap[slot_num];
283 DynInstPtr inst = reqMap[slot_num]->inst;
284 Fault fault = reqMap[slot_num]->fault;
285 ThreadID tid = inst->readTid();
286 int seq_num = inst->seqNum;
287
288 fault = inst->execute();
289
290 if (inst->opClass() == IntMultOp) {
291 multiplies++;
292 } else if (inst->opClass() == IntDivOp) {
293 divides++;
294 }
295
296 if (fault == NoFault) {
297 inst->setExecuted();
298 mult_div_req->setCompleted();
299
300 DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
301 inst->readTid(), inst->readIntResult(0));
302 } else {
303 warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
304 cpu->trap(fault, tid);
305 }
306 }
307
308
309 MDUEvent::MDUEvent()
310 : ResourceEvent()
311 { }
312
313 void
314 MDUEvent::process()
315 {
316 MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
317
318 mdu_res->exeMulDiv(slotIdx);
319
320 ResourceRequest* mult_div_req = resource->reqMap[slotIdx];
321
322 mult_div_req->done();
323 }
324
325