2 * Copyright (c) 2006 The Regents of The University of Michigan
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.
31 #include "arch/faults.hh"
32 #include "arch/isa_traits.hh"
33 #include "cpu/ozone/inorder_back_end.hh"
34 #include "cpu/ozone/thread_state.hh"
36 using namespace TheISA;
39 InorderBackEnd<Impl>::InorderBackEnd(Params *params)
40 : squashPending(false),
43 faultFromFetch(NoFault),
44 interruptBlocked(false),
45 cacheCompletionEvent(this),
46 dcacheInterface(params->dcacheInterface),
47 width(params->backEndWidth),
48 latency(params->backEndLatency),
49 squashLatency(params->backEndSquashLatency),
50 numInstsToWB(0, latency + 1)
52 instsAdded = numInstsToWB.getWire(latency);
53 instsToExecute = numInstsToWB.getWire(0);
56 memReq->data = new uint8_t[64];
62 InorderBackEnd<Impl>::name() const
64 return cpu->name() + ".inorderbackend";
69 InorderBackEnd<Impl>::setXC(ExecContext *xc_ptr)
77 InorderBackEnd<Impl>::setThreadState(OzoneThreadState<Impl> *thread_ptr)
80 thread->setFuncExeInst(0);
86 InorderBackEnd<Impl>::checkInterrupts()
88 //Check if there are any outstanding interrupts
89 //Handle the interrupts
93 cpu->checkInterrupts = false;
95 if (thread->readMiscReg(IPR_ASTRR))
96 panic("asynchronous traps not implemented\n");
98 if (thread->readMiscReg(IPR_SIRR)) {
99 for (int i = INTLEVEL_SOFTWARE_MIN;
100 i < INTLEVEL_SOFTWARE_MAX; i++) {
101 if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
102 // See table 4-19 of the 21164 hardware reference
103 ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
104 summary |= (ULL(1) << i);
109 uint64_t interrupts = cpu->intr_status();
112 for (int i = INTLEVEL_EXTERNAL_MIN;
113 i < INTLEVEL_EXTERNAL_MAX; i++) {
114 if (interrupts & (ULL(1) << i)) {
115 // See table 4-19 of the 21164 hardware reference
117 summary |= (ULL(1) << i);
122 if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) {
123 thread->inSyscall = true;
125 thread->setMiscReg(IPR_ISR, summary);
126 thread->setMiscReg(IPR_INTID, ipl);
127 Fault(new InterruptFault)->invoke(xc);
128 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
129 thread->readMiscReg(IPR_IPLR), ipl, summary);
131 // May need to go 1 inst prior
132 squashPending = true;
134 thread->inSyscall = false;
136 setSquashInfoFromXC();
141 template <class Impl>
143 InorderBackEnd<Impl>::tick()
145 // Squash due to an external source
146 // Not sure if this or an interrupt has higher priority
148 squash(squashSeqNum, squashNextPC);
152 // if (interrupt) then set thread PC, stall front end, record that
153 // I'm waiting for it to drain. (for now just squash)
155 if (interruptBlocked ||
156 (cpu->checkInterrupts &&
157 cpu->check_interrupts() &&
158 !cpu->inPalMode())) {
160 interruptBlocked = true;
161 } else if (robEmpty() && cpu->inPalMode()) {
162 // Will need to let the front end continue a bit until
163 // we're out of pal mode. Hopefully we never get into an
165 interruptBlocked = false;
167 interruptBlocked = false;
174 if (status != DcacheMissLoadStall &&
175 status != DcacheMissStoreStall) {
176 for (int i = 0; i < width && (*instsAdded) < width; ++i) {
177 DynInstPtr inst = frontEnd->getInst();
182 instList.push_back(inst);
188 if (faultFromFetch && robEmpty() && frontEnd->isEmpty()) {
199 template <class Impl>
201 InorderBackEnd<Impl>::executeInsts()
203 bool completed_last_inst = true;
204 int insts_to_execute = *instsToExecute;
207 while (insts_to_execute > 0) {
208 assert(!instList.empty());
209 DynInstPtr inst = instList.front();
211 commitPC = inst->readPC();
213 thread->setPC(commitPC);
214 thread->setNextPC(inst->readNextPC());
221 assert(!thread->inSyscall && !thread->trapPending);
222 oldpc = thread->readPC();
223 cpu->system->pcEventQueue.service(
224 thread->getXCProxy());
226 } while (oldpc != thread->readPC());
228 DPRINTF(IBE, "PC skip function event, stopping commit\n");
229 completed_last_inst = false;
230 squashPending = true;
235 Fault inst_fault = NoFault;
237 if (status == DcacheMissComplete) {
238 DPRINTF(IBE, "Completing inst [sn:%lli]\n", inst->seqNum);
240 } else if (inst->isMemRef() && status != DcacheMissComplete &&
241 (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
242 DPRINTF(IBE, "Initiating mem op inst [sn:%lli] PC: %#x\n",
243 inst->seqNum, inst->readPC());
245 cacheCompletionEvent.inst = inst;
246 inst_fault = inst->initiateAcc();
247 if (inst_fault == NoFault &&
248 status != DcacheMissLoadStall &&
249 status != DcacheMissStoreStall) {
250 inst_fault = inst->completeAcc();
252 ++thread->funcExeInst;
254 DPRINTF(IBE, "Executing inst [sn:%lli] PC: %#x\n",
255 inst->seqNum, inst->readPC());
256 inst_fault = inst->execute();
257 ++thread->funcExeInst;
260 // Will need to be able to break this loop in case the load
261 // misses. Split access/complete ops would be useful here
262 // with writeback events.
263 if (status == DcacheMissLoadStall) {
264 *instsToExecute = insts_to_execute;
266 completed_last_inst = false;
268 } else if (status == DcacheMissStoreStall) {
269 // Figure out how to fix this hack. Probably have DcacheMissLoad
270 // vs DcacheMissStore.
271 *instsToExecute = insts_to_execute;
272 completed_last_inst = false;
274 instList.pop_front();
276 if (inst->traceData) {
277 inst->traceData->finalize();
281 // Don't really need to stop for a store stall as long as
282 // the memory system is able to handle store forwarding
283 // and such. Breaking out might help avoid the cache
284 // interface becoming blocked.
289 inst->setCompleted();
290 inst->setCanCommit();
292 instList.pop_front();
297 if (inst->traceData) {
298 inst->traceData->finalize();
299 inst->traceData = NULL;
302 if (inst_fault != NoFault) {
304 DPRINTF(IBE, "Inst [sn:%lli] PC %#x has a fault\n",
305 inst->seqNum, inst->readPC());
307 assert(!thread->inSyscall);
309 thread->inSyscall = true;
311 // Hack for now; DTB will sometimes need the machine instruction
312 // for when faults happen. So we will set it here, prior to the
313 // DTB possibly needing it for this translation.
315 static_cast<TheISA::MachInst>(inst->staticInst->machInst));
317 // Consider holding onto the trap and waiting until the trap event
318 // happens for this to be executed.
319 inst_fault->invoke(xc);
321 // Exit state update mode to avoid accidental updating.
322 thread->inSyscall = false;
324 squashPending = true;
326 // Generate trap squash event.
327 // generateTrapEvent(tid);
328 completed_last_inst = false;
330 #else // !FULL_SYSTEM
331 panic("fault (%d) detected @ PC %08p", inst_fault,
333 #endif // FULL_SYSTEM
336 for (int i = 0; i < inst->numDestRegs(); ++i) {
337 renameTable[inst->destRegIdx(i)] = inst;
338 thread->renameTable[inst->destRegIdx(i)] = inst;
342 inst->clearDependents();
344 comm->access(0)->doneSeqNum = inst->seqNum;
346 if (inst->mispredicted()) {
347 squash(inst->seqNum, inst->readNextPC());
349 thread->setNextPC(inst->readNextPC());
352 } else if (squashPending) {
353 // Something external happened that caused the CPU to squash.
354 // Break out of commit and handle the squash next cycle.
357 // If it didn't mispredict, then it executed fine. Send back its
358 // registers and BP info? What about insts that may still have
359 // latency, like loads? Probably can send back the information after
362 // keep an instruction count
367 frontEnd->addFreeRegs(freed_regs);
369 assert(insts_to_execute >= 0);
371 // Should only advance this if I have executed all instructions.
372 if (insts_to_execute == 0) {
373 numInstsToWB.advance();
376 // Should I set the PC to the next PC here? What do I set next PC to?
377 if (completed_last_inst) {
378 thread->setPC(thread->readNextPC());
379 thread->setNextPC(thread->readPC() + sizeof(MachInst));
383 setSquashInfoFromXC();
387 template <class Impl>
389 InorderBackEnd<Impl>::handleFault()
391 DPRINTF(Commit, "Handling fault from fetch\n");
393 assert(!thread->inSyscall);
395 thread->inSyscall = true;
397 // Consider holding onto the trap and waiting until the trap event
398 // happens for this to be executed.
399 faultFromFetch->invoke(xc);
401 // Exit state update mode to avoid accidental updating.
402 thread->inSyscall = false;
404 squashPending = true;
406 setSquashInfoFromXC();
409 template <class Impl>
411 InorderBackEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC)
413 DPRINTF(IBE, "Squashing from [sn:%lli], setting PC to %#x\n",
414 squash_num, next_PC);
416 InstListIt squash_it = --(instList.end());
420 while (!instList.empty() && (*squash_it)->seqNum > squash_num) {
421 DynInstPtr inst = *squash_it;
423 DPRINTF(IBE, "Squashing instruction PC %#x, [sn:%lli].\n",
427 // May cause problems with misc regs
428 freed_regs+= inst->numDestRegs();
429 inst->clearDependents();
434 frontEnd->addFreeRegs(freed_regs);
436 for (int i = 0; i < latency+1; ++i) {
437 numInstsToWB.advance();
440 squashPending = false;
442 // Probably want to make sure that this squash is the one that set the
443 // thread into inSyscall mode.
444 thread->inSyscall = false;
446 // Tell front end to squash, reset PC to new one.
447 frontEnd->squash(squash_num, next_PC);
449 faultFromFetch = NULL;
452 template <class Impl>
454 InorderBackEnd<Impl>::squashFromXC()
456 // Record that I need to squash
457 squashPending = true;
459 thread->inSyscall = true;
462 template <class Impl>
464 InorderBackEnd<Impl>::setSquashInfoFromXC()
466 // Need to handle the case of the instList being empty. In that case
467 // probably any number works, except maybe with stores in the store buffer.
468 squashSeqNum = instList.empty() ? 0 : instList.front()->seqNum - 1;
470 squashNextPC = thread->PC;
473 template <class Impl>
475 InorderBackEnd<Impl>::fetchFault(Fault &fault)
477 faultFromFetch = fault;
480 template <class Impl>
482 InorderBackEnd<Impl>::dumpInsts()
487 InstListIt inst_list_it = instList.begin();
489 cprintf("Inst list size: %i\n", instList.size());
491 while (inst_list_it != instList.end())
493 cprintf("Instruction:%i\n",
495 if (!(*inst_list_it)->isSquashed()) {
496 if (!(*inst_list_it)->isIssued()) {
498 cprintf("Count:%i\n", valid_num);
499 } else if ((*inst_list_it)->isMemRef() &&
500 !(*inst_list_it)->memOpDone) {
501 // Loads that have not been marked as executed still count
502 // towards the total instructions.
504 cprintf("Count:%i\n", valid_num);
508 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
509 "Issued:%i\nSquashed:%i\n",
510 (*inst_list_it)->readPC(),
511 (*inst_list_it)->seqNum,
512 (*inst_list_it)->threadNumber,
513 (*inst_list_it)->isIssued(),
514 (*inst_list_it)->isSquashed());
516 if ((*inst_list_it)->isMemRef()) {
517 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
527 template <class Impl>
528 InorderBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(
530 : Event(&mainEventQueue, CPU_Tick_Pri), be(_be)
532 // this->setFlags(Event::AutoDelete);
535 template <class Impl>
537 InorderBackEnd<Impl>::DCacheCompletionEvent::process()
540 be->status = DcacheMissComplete;
543 template <class Impl>
545 InorderBackEnd<Impl>::DCacheCompletionEvent::description()
547 return "DCache completion event";