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 "base/str.hh"
36 #include "cpu/inorder/cpu.hh"
37 #include "cpu/inorder/resource.hh"
38 #include "cpu/inorder/resource_pool.hh"
39 #include "debug/ExecFaulting.hh"
40 #include "debug/RefCount.hh"
41 #include "debug/ResReqCount.hh"
42 #include "debug/Resource.hh"
46 Resource::Resource(string res_name
, int res_id
, int res_width
,
47 int res_latency
, InOrderCPU
*_cpu
)
48 : resName(res_name
), id(res_id
),
49 width(res_width
), latency(res_latency
), cpu(_cpu
),
54 // Use to deny a instruction a resource.
55 deniedReq
= new ResourceRequest(this);
56 deniedReq
->valid
= true;
62 delete [] resourceEvent
;
67 for (int i
= 0; i
< width
; i
++) {
76 // If the resource has a zero-cycle (no latency)
77 // function, then no reason to have events
78 // that will process them for the right tick
80 resourceEvent
= new ResourceEvent
[width
];
83 for (int i
= 0; i
< width
; i
++)
84 reqs
[i
] = new ResourceRequest(this);
93 // Add available slot numbers for resource
94 for (int slot_idx
= 0; slot_idx
< width
; slot_idx
++) {
95 availSlots
.push_back(slot_idx
);
98 resourceEvent
[slot_idx
].init(this, slot_idx
);
106 return cpu
->name() + "." + resName
;
110 Resource::slotsAvail()
112 return availSlots
.size();
116 Resource::slotsInUse()
118 return width
- availSlots
.size();
122 Resource::freeSlot(int slot_idx
)
124 DPRINTF(Resource
, "Deallocating [slot:%i].\n",
127 // Put slot number on this resource's free list
128 availSlots
.push_back(slot_idx
);
130 // Invalidate Request & Reset it's flags
131 reqs
[slot_idx
]->clearRequest();
135 Resource::findSlot(DynInstPtr inst
)
139 for (int i
= 0; i
< width
; i
++) {
140 if (reqs
[i
]->valid
&&
141 reqs
[i
]->getInst()->seqNum
== inst
->seqNum
) {
142 slot_num
= reqs
[i
]->getSlot();
149 Resource::getSlot(DynInstPtr inst
)
153 if (slotsAvail() != 0) {
154 slot_num
= availSlots
[0];
156 vector
<int>::iterator vect_it
= availSlots
.begin();
158 assert(slot_num
== *vect_it
);
160 availSlots
.erase(vect_it
);
167 Resource::request(DynInstPtr inst
)
169 // See if the resource is already serving this instruction.
170 // If so, use that request;
171 bool try_request
= false;
174 ResReqPtr inst_req
= findRequest(inst
);
177 // If some preprocessing has to be done on instruction
178 // that has already requested once, then handle it here.
179 // update the 'try_request' variable if we should
180 // re-execute the request.
181 requestAgain(inst
, try_request
);
183 slot_num
= inst_req
->getSlot();
184 stage_num
= inst_req
->getStageNum();
186 // Get new slot # for instruction
187 slot_num
= getSlot(inst
);
189 if (slot_num
!= -1) {
190 DPRINTF(Resource
, "Allocating [slot:%i] for [tid:%i]: [sn:%i]\n",
191 slot_num
, inst
->readTid(), inst
->seqNum
);
193 // Get Stage # from Schedule Entry
194 stage_num
= inst
->curSkedEntry
->stageNum
;
195 unsigned cmd
= inst
->curSkedEntry
->cmd
;
197 // Generate Resource Request
198 inst_req
= getRequest(inst
, stage_num
, id
, slot_num
, cmd
);
200 if (inst
->staticInst
) {
201 DPRINTF(Resource
, "[tid:%i]: [sn:%i] requesting this "
203 inst
->readTid(), inst
->seqNum
);
205 DPRINTF(Resource
, "[tid:%i]: instruction requesting this "
212 DPRINTF(Resource
, "No slot available for [tid:%i]: [sn:%i]\n",
213 inst
->readTid(), inst
->seqNum
);
219 // Schedule execution of resource
220 scheduleExecution(slot_num
);
222 inst_req
= deniedReq
;
230 Resource::requestAgain(DynInstPtr inst
, bool &do_request
)
234 if (inst
->staticInst
) {
235 DPRINTF(Resource
, "[tid:%i]: [sn:%i] requesting this resource "
237 inst
->readTid(), inst
->seqNum
);
239 DPRINTF(Resource
, "[tid:%i]: requesting this resource again.\n",
245 Resource::getRequest(DynInstPtr inst
, int stage_num
, int res_idx
,
246 int slot_num
, unsigned cmd
)
248 reqs
[slot_num
]->setRequest(inst
, stage_num
, id
, slot_num
, cmd
);
249 return reqs
[slot_num
];
253 Resource::findRequest(DynInstPtr inst
)
255 for (int i
= 0; i
< width
; i
++) {
256 if (reqs
[i
]->valid
&&
257 reqs
[i
]->getInst() == inst
) {
266 Resource::rejectRequest(DynInstPtr inst
)
268 DPRINTF(RefCount
, "[tid:%i]: Unable to grant request for [sn:%i].\n",
269 inst
->readTid(), inst
->seqNum
);
273 Resource::execute(int slot_idx
)
275 //@todo: have each resource print out command their executing
276 DPRINTF(Resource
, "[tid:%i]: Executing %s resource.\n",
277 reqs
[slot_idx
]->getTid(), name());
278 reqs
[slot_idx
]->setCompleted(true);
279 reqs
[slot_idx
]->done();
283 Resource::deactivateThread(ThreadID tid
)
285 // In the most basic case, deactivation means squashing everything
286 // from a particular thread
287 DynInstPtr dummy_inst
= new InOrderDynInst(cpu
, NULL
, 0, tid
, tid
);
288 squash(dummy_inst
, 0, 0, tid
);
292 Resource::setupSquash(DynInstPtr inst
, int stage_num
, ThreadID tid
)
294 // Squash In Pipeline Stage
295 cpu
->pipelineStage
[stage_num
]->setupSquash(inst
, tid
);
297 // Schedule Squash Through-out Resource Pool
298 cpu
->resPool
->scheduleEvent(
299 (InOrderCPU::CPUEventType
)ResourcePool::SquashAll
, inst
, 0);
303 Resource::squash(DynInstPtr inst
, int stage_num
, InstSeqNum squash_seq_num
,
306 //@todo: check squash seq num before squashing. can save time going
307 // through this function.
308 for (int i
= 0; i
< width
; i
++) {
309 ResReqPtr req_ptr
= reqs
[i
];
310 DynInstPtr inst
= req_ptr
->getInst();
312 if (req_ptr
->valid
&&
313 inst
->readTid() == tid
&&
314 inst
->seqNum
> squash_seq_num
) {
316 DPRINTF(Resource
, "[tid:%i]: Squashing [sn:%i].\n",
317 req_ptr
->getInst()->readTid(),
318 req_ptr
->getInst()->seqNum
);
320 req_ptr
->setSquashed();
322 int req_slot_num
= req_ptr
->getSlot();
325 if (resourceEvent
[req_slot_num
].scheduled())
326 unscheduleEvent(req_slot_num
);
329 freeSlot(req_slot_num
);
335 Resource::squashDueToMemStall(DynInstPtr inst
, int stage_num
,
336 InstSeqNum squash_seq_num
,
339 squash(inst
, stage_num
, squash_seq_num
, tid
);
343 Resource::squashThenTrap(int stage_num
, DynInstPtr inst
)
345 ThreadID tid
= inst
->readTid();
347 inst
->setSquashInfo(stage_num
);
348 setupSquash(inst
, stage_num
, tid
);
350 if (inst
->traceData
) {
351 if (inst
->staticInst
&&
352 inst
->fault
!= NoFault
&& DTRACE(ExecFaulting
)) {
353 inst
->traceData
->setStageCycle(stage_num
, curTick());
354 inst
->traceData
->setFetchSeq(inst
->seqNum
);
355 inst
->traceData
->dump();
358 delete inst
->traceData
;
359 inst
->traceData
= NULL
;
362 cpu
->trapContext(inst
->fault
, tid
, inst
);
366 Resource::ticks(int num_cycles
)
368 return cpu
->ticks(num_cycles
);
373 Resource::scheduleExecution(int slot_num
)
376 scheduleEvent(slot_num
, latency
);
383 Resource::scheduleEvent(int slot_idx
, int delay
)
385 DPRINTF(Resource
, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n",
386 reqs
[slot_idx
]->inst
->readTid(),
387 reqs
[slot_idx
]->inst
->seqNum
,
388 cpu
->ticks(delay
) + curTick());
389 resourceEvent
[slot_idx
].scheduleEvent(delay
);
393 Resource::scheduleEvent(DynInstPtr inst
, int delay
)
395 int slot_idx
= findSlot(inst
);
398 resourceEvent
[slot_idx
].scheduleEvent(delay
);
404 Resource::unscheduleEvent(int slot_idx
)
406 resourceEvent
[slot_idx
].unscheduleEvent();
410 Resource::unscheduleEvent(DynInstPtr inst
)
412 int slot_idx
= findSlot(inst
);
415 resourceEvent
[slot_idx
].unscheduleEvent();
420 int ResourceRequest::resReqID
= 0;
422 int ResourceRequest::maxReqCount
= 0;
424 ResourceRequest::ResourceRequest(Resource
*_res
)
425 : res(_res
), inst(NULL
), stagePasses(0), valid(false), doneInResource(false),
426 completed(false), squashed(false), processing(false),
431 ResourceRequest::~ResourceRequest()
434 res
->cpu
->resReqCount
--;
435 DPRINTF(ResReqCount
, "Res. Req %i deleted. resReqCount=%i.\n", reqID
,
436 res
->cpu
->resReqCount
);
442 ResourceRequest::name()
444 return csprintf("%s[slot:%i]:", res
->name(), slotNum
);
448 ResourceRequest::setRequest(DynInstPtr _inst
, int stage_num
,
449 int res_idx
, int slot_num
, unsigned _cmd
)
453 stageNum
= stage_num
;
460 ResourceRequest::clearRequest()
466 doneInResource
= false;
472 ResourceRequest::freeSlot()
476 // Free Slot So Another Instruction Can Use This Resource
477 res
->freeSlot(slotNum
);
481 ResourceRequest::done(bool completed
)
483 DPRINTF(Resource
, "done with request from "
484 "[sn:%i] [tid:%i].\n",
485 inst
->seqNum
, inst
->readTid());
487 setCompleted(completed
);
489 doneInResource
= true;
492 ResourceEvent::ResourceEvent()
493 : Event((Event::Priority
)Resource_Event_Pri
)
496 ResourceEvent::ResourceEvent(Resource
*res
, int slot_idx
)
497 : Event((Event::Priority
)Resource_Event_Pri
), resource(res
),
502 ResourceEvent::init(Resource
*res
, int slot_idx
)
509 ResourceEvent::process()
511 resource
->execute(slotIdx
);
515 ResourceEvent::description() const
517 string desc
= resource
->name() + "-event:slot[" + to_string(slotIdx
)
524 ResourceEvent::scheduleEvent(int delay
)
526 assert(!scheduled() || squashed());
527 resource
->cpu
->reschedule(this,
528 curTick() + resource
->ticks(delay
), true);