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
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"
40 using namespace ThePipeline
;
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
)
60 MultDivUnit::regStats()
63 .name(name() + ".multiplies")
64 .desc("Number of Multipy Operations Executed");
67 .name(name() + ".divides")
68 .desc("Number of Divide Operations Executed");
76 // Set Up Resource Events to Appropriate Resource BandWidth
77 resourceEvent
= new MDUEvent
[width
];
83 MultDivUnit::findSlot(DynInstPtr inst
)
85 DPRINTF(InOrderMDU
, "Finding slot for inst:%i\n | slots-free:%i | "
86 "slots-used:%i\n", inst
->seqNum
, slotsAvail(), slotsInUse());
88 return Resource::findSlot(inst
);
92 MultDivUnit::freeSlot(int slot_idx
)
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());
98 Resource::freeSlot(slot_idx
);
101 //@TODO: Should we push this behavior into base-class to generically
102 // accomodate all multicyle resources?
104 MultDivUnit::requestAgain(DynInstPtr inst
, bool &service_request
)
106 ResReqPtr mult_div_req
= findRequest(inst
);
107 assert(mult_div_req
);
109 service_request
= true;
111 // Check to see if this instruction is requesting the same command
112 // or a different one
113 if (mult_div_req
->cmd
!= inst
->curSkedEntry
->cmd
) {
114 // If different, then update command in the request
115 mult_div_req
->cmd
= inst
->curSkedEntry
->cmd
;
117 "[tid:%i]: [sn:%i]: Updating the command for this "
118 "instruction\n", inst
->readTid(), inst
->seqNum
);
120 // If same command, just check to see if memory access was completed
121 // but dont try to re-execute
123 "[tid:%i]: [sn:%i]: requesting this resource again\n",
124 inst
->readTid(), inst
->seqNum
);
128 MultDivUnit::getSlot(DynInstPtr inst
)
130 // If MDU already has instruction, return current slot.
131 int slot_num
= findSlot(inst
);
133 // If we have this instruction's request already then return
134 if (slot_num
!= -1 &&
135 inst
->curSkedEntry
->cmd
== reqMap
[slot_num
]->cmd
)
138 unsigned repeat_rate
= 0;
140 /** Enforce MDU dependencies after a multiply is seen last */
141 if (lastOpType
== IntMultOp
) {
142 repeat_rate
= multRepeatRate
;
145 /** Enforce dependencies after a divide is seen last */
146 if (lastOpType
== IntDivOp
) {
147 switch (lastDivSize
) {
149 repeat_rate
= div8RepeatRate
;
153 repeat_rate
= div16RepeatRate
;
157 repeat_rate
= div24RepeatRate
;
161 repeat_rate
= div32RepeatRate
;
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
);
171 int rval
= Resource::getSlot(inst
);
172 DPRINTF(InOrderMDU
, "MDU request should pass: %i.\n",
176 lastMDUCycle
= curTick();
177 lastOpType
= inst
->opClass();
178 lastInstName
= inst
->staticInst
->getName();
186 MultDivUnit::getDivOpSize(DynInstPtr inst
)
188 // Get RT Register from instruction (index #1)
189 uint32_t div_op
= inst
->readIntSrc(1);
191 if (div_op
<= 0xFF) {
193 } else if (div_op
<= 0xFFFF) {
195 } else if (div_op
<= 0xFFFFFF) {
203 MultDivUnit::execute(int slot_num
)
205 ResourceRequest
* mult_div_req
= reqMap
[slot_num
];
206 DynInstPtr inst
= reqMap
[slot_num
]->inst
;
208 switch (mult_div_req
->cmd
)
211 DPRINTF(InOrderMDU
, "Start MDU called ...\n");
213 if (inst
->opClass() == IntMultOp
) {
214 scheduleEvent(slot_num
, multLatency
);
215 } else if (inst
->opClass() == IntDivOp
) {
216 int op_size
= getDivOpSize(inst
);
221 scheduleEvent(slot_num
, div8Latency
);
225 scheduleEvent(slot_num
, div16Latency
);
229 scheduleEvent(slot_num
, div24Latency
);
233 scheduleEvent(slot_num
, div32Latency
);
237 lastDivSize
= op_size
;
240 // Allow to pass through to next stage while
242 mult_div_req
->setCompleted();
246 DPRINTF(InOrderMDU
, "Execute MDU called ...\n");
248 mult_div_req
->done();
253 //@TODO: Why not allow high-latency requests to sleep
254 // within stage until event wakes up????
255 // Seems wasteful to continually check to see if
256 // this is done when we have a event in parallel
257 // counting down the time
259 DPRINTF(InOrderMDU
, "End MDU called ...\n");
260 if (mult_div_req
->getInst()->isExecuted()) {
261 DPRINTF(InOrderMDU
, "Mult/Div finished.\n");
262 mult_div_req
->done();
264 mult_div_req
->setCompleted(false);
271 fatal("Unrecognized command to %s", resName
);
276 MultDivUnit::exeMulDiv(int slot_num
)
278 ResourceRequest
* mult_div_req
= reqMap
[slot_num
];
279 DynInstPtr inst
= reqMap
[slot_num
]->inst
;
281 inst
->fault
= inst
->execute();
283 if (inst
->opClass() == IntMultOp
) {
285 } else if (inst
->opClass() == IntDivOp
) {
289 if (inst
->fault
== NoFault
) {
291 mult_div_req
->setCompleted();
293 DPRINTF(InOrderMDU
, "[tid:%i]: The result of execution is 0x%x.\n",
294 inst
->readTid(), inst
->readIntResult(0));
296 DPRINTF(InOrderMDU
, "[tid:%i]: [sn:%i]: had a %s "
297 "fault.\n", inst
->readTid(), inst
->seqNum
, inst
->fault
->name());
309 MultDivUnit
* mdu_res
= reinterpret_cast<MultDivUnit
*>(resource
);
311 mdu_res
->exeMulDiv(slotIdx
);
313 ResourceRequest
* mult_div_req
= resource
->reqMap
[slotIdx
];
315 mult_div_req
->done();