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