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
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"
43 using namespace ThePipeline
;
45 MultDivUnit::MultDivUnit(string res_name
, int res_id
, int res_width
,
46 int 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
)
63 MultDivUnit::regStats()
66 .name(name() + ".multiplies")
67 .desc("Number of Multipy Operations Executed");
70 .name(name() + ".divides")
71 .desc("Number of Divide Operations Executed");
79 // Set Up Resource Events to Appropriate Resource BandWidth
80 resourceEvent
= new MDUEvent
[width
];
82 for (int i
= 0; i
< width
; i
++) {
83 reqs
[i
] = new ResourceRequest(this);
89 //@TODO: Should we push this behavior into base-class to generically
90 // accomodate all multicyle resources?
92 MultDivUnit::requestAgain(DynInstPtr inst
, bool &service_request
)
94 ResReqPtr mult_div_req
= findRequest(inst
);
97 service_request
= true;
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
;
105 "[tid:%i]: [sn:%i]: Updating the command for this "
106 "instruction\n", inst
->readTid(), inst
->seqNum
);
108 // If same command, just check to see if access was completed
109 // but dont try to re-execute
111 "[tid:%i]: [sn:%i]: requesting this resource again\n",
112 inst
->readTid(), inst
->seqNum
);
116 MultDivUnit::getSlot(DynInstPtr inst
)
118 // If MDU already has instruction, return current slot.
119 int slot_num
= findSlot(inst
);
121 // If we have this instruction's request already then return
122 if (slot_num
!= -1 &&
123 inst
->curSkedEntry
->cmd
== reqs
[slot_num
]->cmd
)
126 unsigned repeat_rate
= 0;
128 /** Enforce MDU dependencies after a multiply is seen last */
129 if (lastOpType
== IntMultOp
) {
130 repeat_rate
= multRepeatRate
;
133 /** Enforce dependencies after a divide is seen last */
134 if (lastOpType
== IntDivOp
) {
135 switch (lastDivSize
) {
137 repeat_rate
= div8RepeatRate
;
141 repeat_rate
= div16RepeatRate
;
145 repeat_rate
= div24RepeatRate
;
149 repeat_rate
= div32RepeatRate
;
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
);
159 int rval
= Resource::getSlot(inst
);
160 DPRINTF(InOrderMDU
, "MDU request should pass: %i.\n",
164 lastMDUCycle
= curTick();
165 lastOpType
= inst
->opClass();
166 lastInstName
= inst
->staticInst
->getName();
174 MultDivUnit::getDivOpSize(DynInstPtr inst
)
176 // Get RT Register from instruction (index #1)
177 uint32_t div_op
= inst
->readIntSrc(1);
179 if (div_op
<= 0xFF) {
181 } else if (div_op
<= 0xFFFF) {
183 } else if (div_op
<= 0xFFFFFF) {
191 MultDivUnit::execute(int slot_num
)
193 ResourceRequest
* mult_div_req
= reqs
[slot_num
];
194 DynInstPtr inst
= reqs
[slot_num
]->inst
;
195 if (inst
->fault
!= NoFault
) {
197 "[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
198 "next stage.\n", inst
->readTid(), inst
->seqNum
, inst
->fault
->name(),
200 mult_div_req
->done();
204 DPRINTF(InOrderMDU
, "Executing [sn:%i] ...\n", slot_num
);
206 switch (mult_div_req
->cmd
)
210 DPRINTF(InOrderMDU
, "Start MDU called ...\n");
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
);
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
->setProcessing();
243 mult_div_req
->setCompleted();
248 DPRINTF(InOrderMDU
, "Execute MDU called ...\n");
250 mult_div_req
->done();
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
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();
266 mult_div_req
->setCompleted(false);
273 fatal("Unrecognized command to %s", resName
);
278 MultDivUnit::exeMulDiv(int slot_num
)
280 ResourceRequest
* mult_div_req
= reqs
[slot_num
];
281 DynInstPtr inst
= reqs
[slot_num
]->inst
;
283 inst
->fault
= inst
->execute();
285 if (inst
->opClass() == IntMultOp
) {
287 } else if (inst
->opClass() == IntDivOp
) {
291 if (inst
->fault
== NoFault
) {
294 DPRINTF(InOrderMDU
, "[tid:%i]: The result of execution is 0x%x.\n",
295 inst
->readTid(), inst
->readIntResult(0));
297 DPRINTF(InOrderMDU
, "[tid:%i]: [sn:%i]: had a %s "
298 "fault.\n", inst
->readTid(), inst
->seqNum
, inst
->fault
->name());
301 mult_div_req
->setProcessing(false);
306 MultDivUnit::squash(DynInstPtr inst
, int stage_num
, InstSeqNum squash_seq_num
,
309 for (int i
= 0; i
< width
; i
++) {
310 ResReqPtr req_ptr
= reqs
[i
];
311 DynInstPtr inst
= req_ptr
->getInst();
313 if (req_ptr
->valid
&&
314 inst
->readTid() == tid
&&
315 inst
->seqNum
> squash_seq_num
) {
317 DPRINTF(InOrderMDU
, "[tid:%i]: Squashing [sn:%i].\n",
318 req_ptr
->getInst()->readTid(),
319 req_ptr
->getInst()->seqNum
);
321 req_ptr
->setSquashed();
323 int req_slot_num
= req_ptr
->getSlot();
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
);
331 freeSlot(req_slot_num
);
343 MultDivUnit
* mdu_res
= reinterpret_cast<MultDivUnit
*>(resource
);
345 mdu_res
->exeMulDiv(slotIdx
);
347 ResourceRequest
* mult_div_req
= resource
->reqs
[slotIdx
];
349 if (mult_div_req
->isSquashed())
350 mdu_res
->freeSlot(slotIdx
);