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