inorder-alpha-port: initial inorder support of ALPHA
[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 multInstReqsProcessed
57 .name(name() + ".multInstReqsProcessed")
58 .desc("Number of Multiply Requests Processed.");
59
60 divInstReqsProcessed
61 .name(name() + ".divInstReqsProcessed")
62 .desc("Number of Divide Requests Processed.");
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
95 int
96 MultDivUnit::getSlot(DynInstPtr inst)
97 {
98 // If MDU already has instruction, return current slot.
99 int slot_num = findSlot(inst);
100
101 // If we have this instruction's request already then return
102 if (slot_num != -1 &&
103 inst->resSched.top()->cmd == reqMap[slot_num]->cmd)
104 return slot_num;
105
106 unsigned repeat_rate = 0;
107
108 /** Enforce MDU dependencies after a multiply is seen last */
109 if (lastOpType == IntMultOp) {
110 repeat_rate = multRepeatRate;
111 }
112
113 /** Enforce dependencies after a divide is seen last */
114 if (lastOpType == IntDivOp) {
115 switch (lastDivSize) {
116 case 8:
117 repeat_rate = div8RepeatRate;
118 break;
119
120 case 16:
121 repeat_rate = div16RepeatRate;
122 break;
123
124 case 24:
125 repeat_rate = div24RepeatRate;
126 break;
127
128 case 32:
129 repeat_rate = div32RepeatRate;
130 break;
131 }
132 }
133
134 if (lastMDUCycle + repeat_rate > curTick) {
135 DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n",
136 lastMDUCycle + repeat_rate);
137 return -1;
138 } else {
139 int rval = Resource::getSlot(inst);
140 DPRINTF(InOrderMDU, "MDU request should pass: %i.\n",
141 rval);
142
143 if (rval != -1) {
144 lastMDUCycle = curTick;
145 lastOpType = inst->opClass();
146 lastInstName = inst->staticInst->getName();
147 }
148
149 return rval;
150 }
151 }
152
153 int
154 MultDivUnit::getDivOpSize(DynInstPtr inst)
155 {
156 // Get RT Register from instruction (index #1)
157 uint32_t div_op = inst->readIntSrc(1);
158
159 if (div_op <= 0xFF) {
160 return 8;
161 } else if (div_op <= 0xFFFF) {
162 return 16;
163 } else if (div_op <= 0xFFFFFF) {
164 return 24;
165 } else {
166 return 32;
167 }
168 }
169
170 void
171 MultDivUnit::execute(int slot_num)
172 {
173 ResourceRequest* mult_div_req = reqMap[slot_num];
174 DynInstPtr inst = reqMap[slot_num]->inst;
175 Fault fault = reqMap[slot_num]->fault;
176
177 //int tid = inst->readTid();
178 //int seq_num = inst->seqNum;
179
180 switch (mult_div_req->cmd)
181 {
182 case StartMultDiv:
183 DPRINTF(InOrderMDU, "Start MDU called ...\n");
184
185 if (inst->opClass() == IntMultOp) {
186 scheduleEvent(slot_num, multLatency);
187 multInstReqsProcessed++;
188 } else if (inst->opClass() == IntDivOp) {
189 int op_size = getDivOpSize(inst);
190
191 switch (op_size)
192 {
193 case 8:
194 scheduleEvent(slot_num, div8Latency);
195 break;
196
197 case 16:
198 scheduleEvent(slot_num, div16Latency);
199 break;
200
201 case 24:
202 scheduleEvent(slot_num, div24Latency);
203 break;
204
205 case 32:
206 scheduleEvent(slot_num, div32Latency);
207 break;
208 }
209
210 lastDivSize = op_size;
211
212 divInstReqsProcessed++;
213 }
214
215 // Allow to pass through to next stage while
216 // event processes
217 mult_div_req->setCompleted();
218 break;
219
220 case MultDiv:
221 DPRINTF(InOrderMDU, "Execute MDU called ...\n");
222 exeMulDiv(slot_num);
223 mult_div_req->done();
224 break;
225
226
227 case EndMultDiv:
228 //@TODO: Why not allow high-latency requests to sleep
229 // within stage until event wakes up????
230 // Seems wasteful to continually check to see if
231 // this is done when we have a event in parallel
232 // counting down the time
233 {
234 DPRINTF(InOrderMDU, "End MDU called ...\n");
235 if (mult_div_req->getInst()->isExecuted())
236 mult_div_req->done();
237 }
238 break;
239
240 default:
241 fatal("Unrecognized command to %s", resName);
242 }
243 }
244
245 void
246 MultDivUnit::exeMulDiv(int slot_num)
247 {
248 ResourceRequest* mult_div_req = reqMap[slot_num];
249 DynInstPtr inst = reqMap[slot_num]->inst;
250 Fault fault = reqMap[slot_num]->fault;
251 int tid = inst->readTid();
252 int seq_num = inst->seqNum;
253
254 fault = inst->execute();
255
256 if (fault == NoFault) {
257 inst->setExecuted();
258 mult_div_req->setCompleted();
259
260 DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
261 inst->readTid(), inst->readIntResult(0));
262 } else {
263 warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
264 cpu->trap(fault, tid);
265 }
266 }
267
268
269 MDUEvent::MDUEvent()
270 : ResourceEvent()
271 { }
272
273 void
274 MDUEvent::process()
275 {
276 MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
277
278 mdu_res->exeMulDiv(slotIdx);
279
280 ResourceRequest* mult_div_req = resource->reqMap[slotIdx];
281
282 mult_div_req->done();
283 }
284
285