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
, 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
)
54 MultDivUnit::regStats()
57 .name(name() + ".multiplies")
58 .desc("Number of Multipy Operations Executed");
61 .name(name() + ".divides")
62 .desc("Number of Divide Operations Executed");
70 // Set Up Resource Events to Appropriate Resource BandWidth
71 resourceEvent
= new MDUEvent
[width
];
77 MultDivUnit::findSlot(DynInstPtr inst
)
79 DPRINTF(InOrderMDU
, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
80 inst
->seqNum
, slotsAvail(), slotsInUse());
82 return Resource::findSlot(inst
);
86 MultDivUnit::freeSlot(int slot_idx
)
88 DPRINTF(InOrderMDU
, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
89 reqMap
[slot_idx
]->getInst()->seqNum
, slotsAvail(), slotsInUse());
91 Resource::freeSlot(slot_idx
);
94 //@TODO: Should we push this behavior into base-class to generically
95 // accomodate all multicyle resources?
97 MultDivUnit::requestAgain(DynInstPtr inst
, bool &service_request
)
99 ResReqPtr mult_div_req
= findRequest(inst
);
100 assert(mult_div_req
);
102 service_request
= true;
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
;
110 "[tid:%i]: [sn:%i]: Updating the command for this instruction\n",
111 inst
->readTid(), inst
->seqNum
);
113 // If same command, just check to see if memory access was completed
114 // but dont try to re-execute
116 "[tid:%i]: [sn:%i]: requesting this resource again\n",
117 inst
->readTid(), inst
->seqNum
);
121 MultDivUnit::getSlot(DynInstPtr inst
)
123 // If MDU already has instruction, return current slot.
124 int slot_num
= findSlot(inst
);
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
)
131 unsigned repeat_rate
= 0;
133 /** Enforce MDU dependencies after a multiply is seen last */
134 if (lastOpType
== IntMultOp
) {
135 repeat_rate
= multRepeatRate
;
138 /** Enforce dependencies after a divide is seen last */
139 if (lastOpType
== IntDivOp
) {
140 switch (lastDivSize
) {
142 repeat_rate
= div8RepeatRate
;
146 repeat_rate
= div16RepeatRate
;
150 repeat_rate
= div24RepeatRate
;
154 repeat_rate
= div32RepeatRate
;
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
);
164 int rval
= Resource::getSlot(inst
);
165 DPRINTF(InOrderMDU
, "MDU request should pass: %i.\n",
169 lastMDUCycle
= curTick
;
170 lastOpType
= inst
->opClass();
171 lastInstName
= inst
->staticInst
->getName();
179 MultDivUnit::getDivOpSize(DynInstPtr inst
)
181 // Get RT Register from instruction (index #1)
182 uint32_t div_op
= inst
->readIntSrc(1);
184 if (div_op
<= 0xFF) {
186 } else if (div_op
<= 0xFFFF) {
188 } else if (div_op
<= 0xFFFFFF) {
196 MultDivUnit::execute(int slot_num
)
198 ResourceRequest
* mult_div_req
= reqMap
[slot_num
];
199 DynInstPtr inst
= reqMap
[slot_num
]->inst
;
200 Fault fault
= reqMap
[slot_num
]->fault
;
202 //ThreadID tid = inst->readTid();
203 //int seq_num = inst->seqNum;
205 switch (mult_div_req
->cmd
)
208 DPRINTF(InOrderMDU
, "Start MDU called ...\n");
210 if (inst
->opClass() == IntMultOp
) {
211 scheduleEvent(slot_num
, multLatency
);
212 } else if (inst
->opClass() == IntDivOp
) {
213 int op_size
= getDivOpSize(inst
);
218 scheduleEvent(slot_num
, div8Latency
);
222 scheduleEvent(slot_num
, div16Latency
);
226 scheduleEvent(slot_num
, div24Latency
);
230 scheduleEvent(slot_num
, div32Latency
);
234 lastDivSize
= op_size
;
237 // Allow to pass through to next stage while
239 mult_div_req
->setCompleted();
243 DPRINTF(InOrderMDU
, "Execute MDU called ...\n");
245 mult_div_req
->done();
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
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();
261 mult_div_req
->setCompleted(false);
268 fatal("Unrecognized command to %s", resName
);
273 MultDivUnit::exeMulDiv(int slot_num
)
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
;
281 fault
= inst
->execute();
283 if (inst
->opClass() == IntMultOp
) {
285 } else if (inst
->opClass() == IntDivOp
) {
289 if (fault
== NoFault
) {
291 mult_div_req
->setCompleted();
293 DPRINTF(Resource
, "[tid:%i]: The result of execution is 0x%x.\n",
294 inst
->readTid(), inst
->readIntResult(0));
296 warn("inst [sn:%i] had a %s fault", seq_num
, fault
->name());
297 cpu
->trap(fault
, tid
);
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();