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
),
54 MultDivUnit::regStats()
57 .name(name() + ".multInstReqsProcessed")
58 .desc("Number of Multiply Requests Processed.");
61 .name(name() + ".divInstReqsProcessed")
62 .desc("Number of Divide Requests Processed.");
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
);
96 MultDivUnit::getSlot(DynInstPtr inst
)
98 // If MDU already has instruction, return current slot.
99 int slot_num
= findSlot(inst
);
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
)
106 unsigned repeat_rate
= 0;
108 /** Enforce MDU dependencies after a multiply is seen last */
109 if (lastOpType
== IntMultOp
) {
110 repeat_rate
= multRepeatRate
;
113 /** Enforce dependencies after a divide is seen last */
114 if (lastOpType
== IntDivOp
) {
115 switch (lastDivSize
) {
117 repeat_rate
= div8RepeatRate
;
121 repeat_rate
= div16RepeatRate
;
125 repeat_rate
= div24RepeatRate
;
129 repeat_rate
= div32RepeatRate
;
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
);
139 int rval
= Resource::getSlot(inst
);
140 DPRINTF(InOrderMDU
, "MDU request should pass: %i.\n",
144 lastMDUCycle
= curTick
;
145 lastOpType
= inst
->opClass();
146 lastInstName
= inst
->staticInst
->getName();
154 MultDivUnit::getDivOpSize(DynInstPtr inst
)
156 // Get RT Register from instruction (index #1)
157 uint32_t div_op
= inst
->readIntSrc(1);
159 if (div_op
<= 0xFF) {
161 } else if (div_op
<= 0xFFFF) {
163 } else if (div_op
<= 0xFFFFFF) {
171 MultDivUnit::execute(int slot_num
)
173 ResourceRequest
* mult_div_req
= reqMap
[slot_num
];
174 DynInstPtr inst
= reqMap
[slot_num
]->inst
;
175 Fault fault
= reqMap
[slot_num
]->fault
;
177 //int tid = inst->readTid();
178 //int seq_num = inst->seqNum;
180 switch (mult_div_req
->cmd
)
183 DPRINTF(InOrderMDU
, "Start MDU called ...\n");
185 if (inst
->opClass() == IntMultOp
) {
186 scheduleEvent(slot_num
, multLatency
);
187 multInstReqsProcessed
++;
188 } else if (inst
->opClass() == IntDivOp
) {
189 int op_size
= getDivOpSize(inst
);
194 scheduleEvent(slot_num
, div8Latency
);
198 scheduleEvent(slot_num
, div16Latency
);
202 scheduleEvent(slot_num
, div24Latency
);
206 scheduleEvent(slot_num
, div32Latency
);
210 lastDivSize
= op_size
;
212 divInstReqsProcessed
++;
215 // Allow to pass through to next stage while
217 mult_div_req
->setCompleted();
221 DPRINTF(InOrderMDU
, "Execute MDU called ...\n");
223 mult_div_req
->done();
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
234 DPRINTF(InOrderMDU
, "End MDU called ...\n");
235 if (mult_div_req
->getInst()->isExecuted())
236 mult_div_req
->done();
241 fatal("Unrecognized command to %s", resName
);
246 MultDivUnit::exeMulDiv(int slot_num
)
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
;
254 fault
= inst
->execute();
256 if (fault
== NoFault
) {
258 mult_div_req
->setCompleted();
260 DPRINTF(Resource
, "[tid:%i]: The result of execution is 0x%x.\n",
261 inst
->readTid(), inst
->readIntResult(0));
263 warn("inst [sn:%i] had a %s fault", seq_num
, fault
->name());
264 cpu
->trap(fault
, tid
);
276 MultDivUnit
* mdu_res
= reinterpret_cast<MultDivUnit
*>(resource
);
278 mdu_res
->exeMulDiv(slotIdx
);
280 ResourceRequest
* mult_div_req
= resource
->reqMap
[slotIdx
];
282 mult_div_req
->done();