inorder/alpha-isa: create eaComp object visible to StaticInst through ISA
[gem5.git] / src / cpu / ozone / inorder_back_end_impl.hh
1 /*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Kevin Lim
29 */
30
31 #include "sim/faults.hh"
32 #include "arch/types.hh"
33 #include "cpu/ozone/inorder_back_end.hh"
34 #include "cpu/ozone/thread_state.hh"
35
36 template <class Impl>
37 InorderBackEnd<Impl>::InorderBackEnd(Params *params)
38 : squashPending(false),
39 squashSeqNum(0),
40 squashNextPC(0),
41 faultFromFetch(NoFault),
42 interruptBlocked(false),
43 cacheCompletionEvent(this),
44 dcacheInterface(params->dcacheInterface),
45 width(params->backEndWidth),
46 latency(params->backEndLatency),
47 squashLatency(params->backEndSquashLatency),
48 numInstsToWB(0, latency + 1)
49 {
50 instsAdded = numInstsToWB.getWire(latency);
51 instsToExecute = numInstsToWB.getWire(0);
52
53 memReq = new MemReq;
54 memReq->data = new uint8_t[64];
55 status = Running;
56 }
57
58 template <class Impl>
59 std::string
60 InorderBackEnd<Impl>::name() const
61 {
62 return cpu->name() + ".inorderbackend";
63 }
64
65 template <class Impl>
66 void
67 InorderBackEnd<Impl>::setXC(ExecContext *xc_ptr)
68 {
69 xc = xc_ptr;
70 memReq->xc = xc;
71 }
72
73 template <class Impl>
74 void
75 InorderBackEnd<Impl>::setThreadState(OzoneThreadState<Impl> *thread_ptr)
76 {
77 thread = thread_ptr;
78 thread->setFuncExeInst(0);
79 }
80
81 #if FULL_SYSTEM
82 template <class Impl>
83 void
84 InorderBackEnd<Impl>::checkInterrupts()
85 {
86 //Check if there are any outstanding interrupts
87 //Handle the interrupts
88 int ipl = 0;
89 int summary = 0;
90
91
92 if (thread->readMiscRegNoEffect(IPR_ASTRR))
93 panic("asynchronous traps not implemented\n");
94
95 if (thread->readMiscRegNoEffect(IPR_SIRR)) {
96 for (int i = INTLEVEL_SOFTWARE_MIN;
97 i < INTLEVEL_SOFTWARE_MAX; i++) {
98 if (thread->readMiscRegNoEffect(IPR_SIRR) & (ULL(1) << i)) {
99 // See table 4-19 of the 21164 hardware reference
100 ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
101 summary |= (ULL(1) << i);
102 }
103 }
104 }
105
106 uint64_t interrupts = cpu->intr_status();
107
108 if (interrupts) {
109 for (int i = INTLEVEL_EXTERNAL_MIN;
110 i < INTLEVEL_EXTERNAL_MAX; i++) {
111 if (interrupts & (ULL(1) << i)) {
112 // See table 4-19 of the 21164 hardware reference
113 ipl = i;
114 summary |= (ULL(1) << i);
115 }
116 }
117 }
118
119 if (ipl && ipl > thread->readMiscRegNoEffect(IPR_IPLR)) {
120 thread->inSyscall = true;
121
122 thread->setMiscRegNoEffect(IPR_ISR, summary);
123 thread->setMiscRegNoEffect(IPR_INTID, ipl);
124 Fault(new InterruptFault)->invoke(xc);
125 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
126 thread->readMiscRegNoEffect(IPR_IPLR), ipl, summary);
127
128 // May need to go 1 inst prior
129 squashPending = true;
130
131 thread->inSyscall = false;
132
133 setSquashInfoFromXC();
134 }
135 }
136 #endif
137
138 template <class Impl>
139 void
140 InorderBackEnd<Impl>::tick()
141 {
142 // Squash due to an external source
143 // Not sure if this or an interrupt has higher priority
144 if (squashPending) {
145 squash(squashSeqNum, squashNextPC);
146 return;
147 }
148
149 // if (interrupt) then set thread PC, stall front end, record that
150 // I'm waiting for it to drain. (for now just squash)
151 #if FULL_SYSTEM
152 if (interruptBlocked || cpu->checkInterrupts(tc)) {
153 if (!robEmpty()) {
154 interruptBlocked = true;
155 //AlphaDep
156 } else if (robEmpty() && (PC & 0x3)) {
157 // Will need to let the front end continue a bit until
158 // we're out of pal mode. Hopefully we never get into an
159 // infinite loop...
160 interruptBlocked = false;
161 } else {
162 interruptBlocked = false;
163 checkInterrupts();
164 return;
165 }
166 }
167 #endif
168
169 if (status != DcacheMissLoadStall &&
170 status != DcacheMissStoreStall) {
171 for (int i = 0; i < width && (*instsAdded) < width; ++i) {
172 DynInstPtr inst = frontEnd->getInst();
173
174 if (!inst)
175 break;
176
177 instList.push_back(inst);
178
179 (*instsAdded)++;
180 }
181
182 #if FULL_SYSTEM
183 if (faultFromFetch && robEmpty() && frontEnd->isEmpty()) {
184 handleFault();
185 } else {
186 executeInsts();
187 }
188 #else
189 executeInsts();
190 #endif
191 }
192 }
193
194 template <class Impl>
195 void
196 InorderBackEnd<Impl>::executeInsts()
197 {
198 bool completed_last_inst = true;
199 int insts_to_execute = *instsToExecute;
200 int freed_regs = 0;
201
202 while (insts_to_execute > 0) {
203 assert(!instList.empty());
204 DynInstPtr inst = instList.front();
205
206 commitPC = inst->readPC();
207
208 thread->setPC(commitPC);
209 thread->setNextPC(inst->readNextPC());
210
211 #if FULL_SYSTEM
212 int count = 0;
213 Addr oldpc;
214 do {
215 if (count == 0)
216 assert(!thread->inSyscall && !thread->trapPending);
217 oldpc = thread->readPC();
218 cpu->system->pcEventQueue.service(
219 thread->getXCProxy());
220 count++;
221 } while (oldpc != thread->readPC());
222 if (count > 1) {
223 DPRINTF(IBE, "PC skip function event, stopping commit\n");
224 completed_last_inst = false;
225 squashPending = true;
226 break;
227 }
228 #endif
229
230 Fault inst_fault = NoFault;
231
232 if (status == DcacheMissComplete) {
233 DPRINTF(IBE, "Completing inst [sn:%lli]\n", inst->seqNum);
234 status = Running;
235 } else if (inst->isMemRef() && status != DcacheMissComplete &&
236 (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
237 DPRINTF(IBE, "Initiating mem op inst [sn:%lli] PC: %#x\n",
238 inst->seqNum, inst->readPC());
239
240 cacheCompletionEvent.inst = inst;
241 inst_fault = inst->initiateAcc();
242 if (inst_fault == NoFault &&
243 status != DcacheMissLoadStall &&
244 status != DcacheMissStoreStall) {
245 inst_fault = inst->completeAcc();
246 }
247 ++thread->funcExeInst;
248 } else {
249 DPRINTF(IBE, "Executing inst [sn:%lli] PC: %#x\n",
250 inst->seqNum, inst->readPC());
251 inst_fault = inst->execute();
252 ++thread->funcExeInst;
253 }
254
255 // Will need to be able to break this loop in case the load
256 // misses. Split access/complete ops would be useful here
257 // with writeback events.
258 if (status == DcacheMissLoadStall) {
259 *instsToExecute = insts_to_execute;
260
261 completed_last_inst = false;
262 break;
263 } else if (status == DcacheMissStoreStall) {
264 // Figure out how to fix this hack. Probably have DcacheMissLoad
265 // vs DcacheMissStore.
266 *instsToExecute = insts_to_execute;
267 completed_last_inst = false;
268 /*
269 instList.pop_front();
270 --insts_to_execute;
271 if (inst->traceData) {
272 inst->traceData->finalize();
273 }
274 */
275
276 // Don't really need to stop for a store stall as long as
277 // the memory system is able to handle store forwarding
278 // and such. Breaking out might help avoid the cache
279 // interface becoming blocked.
280 break;
281 }
282
283 inst->setExecuted();
284 inst->setResultReady();
285 inst->setCanCommit();
286
287 instList.pop_front();
288
289 --insts_to_execute;
290 --(*instsToExecute);
291
292 if (inst->traceData) {
293 inst->traceData->finalize();
294 inst->traceData = NULL;
295 }
296
297 if (inst_fault != NoFault) {
298 #if FULL_SYSTEM
299 DPRINTF(IBE, "Inst [sn:%lli] PC %#x has a fault\n",
300 inst->seqNum, inst->readPC());
301
302 assert(!thread->inSyscall);
303
304 thread->inSyscall = true;
305
306 // Hack for now; DTB will sometimes need the machine instruction
307 // for when faults happen. So we will set it here, prior to the
308 // DTB possibly needing it for this translation.
309 thread->setInst(
310 static_cast<TheISA::MachInst>(inst->staticInst->machInst));
311
312 // Consider holding onto the trap and waiting until the trap event
313 // happens for this to be executed.
314 inst_fault->invoke(xc);
315
316 // Exit state update mode to avoid accidental updating.
317 thread->inSyscall = false;
318
319 squashPending = true;
320
321 // Generate trap squash event.
322 // generateTrapEvent(tid);
323 completed_last_inst = false;
324 break;
325 #else // !FULL_SYSTEM
326 panic("fault (%d) detected @ PC %08p", inst_fault,
327 inst->PC);
328 #endif // FULL_SYSTEM
329 }
330
331 for (int i = 0; i < inst->numDestRegs(); ++i) {
332 renameTable[inst->destRegIdx(i)] = inst;
333 thread->renameTable[inst->destRegIdx(i)] = inst;
334 ++freed_regs;
335 }
336
337 inst->clearDependents();
338
339 comm->access(0)->doneSeqNum = inst->seqNum;
340
341 if (inst->mispredicted()) {
342 squash(inst->seqNum, inst->readNextPC());
343
344 thread->setNextPC(inst->readNextPC());
345
346 break;
347 } else if (squashPending) {
348 // Something external happened that caused the CPU to squash.
349 // Break out of commit and handle the squash next cycle.
350 break;
351 }
352 // If it didn't mispredict, then it executed fine. Send back its
353 // registers and BP info? What about insts that may still have
354 // latency, like loads? Probably can send back the information after
355 // it is completed.
356
357 // keep an instruction count
358 cpu->numInst++;
359 thread->numInsts++;
360 }
361
362 frontEnd->addFreeRegs(freed_regs);
363
364 assert(insts_to_execute >= 0);
365
366 // Should only advance this if I have executed all instructions.
367 if (insts_to_execute == 0) {
368 numInstsToWB.advance();
369 }
370
371 // Should I set the PC to the next PC here? What do I set next PC to?
372 if (completed_last_inst) {
373 thread->setPC(thread->readNextPC());
374 thread->setNextPC(thread->readPC() + sizeof(MachInst));
375 }
376
377 if (squashPending) {
378 setSquashInfoFromXC();
379 }
380 }
381
382 template <class Impl>
383 void
384 InorderBackEnd<Impl>::handleFault()
385 {
386 DPRINTF(Commit, "Handling fault from fetch\n");
387
388 assert(!thread->inSyscall);
389
390 thread->inSyscall = true;
391
392 // Consider holding onto the trap and waiting until the trap event
393 // happens for this to be executed.
394 faultFromFetch->invoke(xc);
395
396 // Exit state update mode to avoid accidental updating.
397 thread->inSyscall = false;
398
399 squashPending = true;
400
401 setSquashInfoFromXC();
402 }
403
404 template <class Impl>
405 void
406 InorderBackEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC)
407 {
408 DPRINTF(IBE, "Squashing from [sn:%lli], setting PC to %#x\n",
409 squash_num, next_PC);
410
411 InstListIt squash_it = --(instList.end());
412
413 int freed_regs = 0;
414
415 while (!instList.empty() && (*squash_it)->seqNum > squash_num) {
416 DynInstPtr inst = *squash_it;
417
418 DPRINTF(IBE, "Squashing instruction PC %#x, [sn:%lli].\n",
419 inst->readPC(),
420 inst->seqNum);
421
422 // May cause problems with misc regs
423 freed_regs+= inst->numDestRegs();
424 inst->clearDependents();
425 squash_it--;
426 instList.pop_back();
427 }
428
429 frontEnd->addFreeRegs(freed_regs);
430
431 for (int i = 0; i < latency+1; ++i) {
432 numInstsToWB.advance();
433 }
434
435 squashPending = false;
436
437 // Probably want to make sure that this squash is the one that set the
438 // thread into inSyscall mode.
439 thread->inSyscall = false;
440
441 // Tell front end to squash, reset PC to new one.
442 frontEnd->squash(squash_num, next_PC);
443
444 faultFromFetch = NULL;
445 }
446
447 template <class Impl>
448 void
449 InorderBackEnd<Impl>::squashFromXC()
450 {
451 // Record that I need to squash
452 squashPending = true;
453
454 thread->inSyscall = true;
455 }
456
457 template <class Impl>
458 void
459 InorderBackEnd<Impl>::setSquashInfoFromXC()
460 {
461 // Need to handle the case of the instList being empty. In that case
462 // probably any number works, except maybe with stores in the store buffer.
463 squashSeqNum = instList.empty() ? 0 : instList.front()->seqNum - 1;
464
465 squashNextPC = thread->PC;
466 }
467
468 template <class Impl>
469 void
470 InorderBackEnd<Impl>::fetchFault(Fault &fault)
471 {
472 faultFromFetch = fault;
473 }
474
475 template <class Impl>
476 void
477 InorderBackEnd<Impl>::dumpInsts()
478 {
479 int num = 0;
480 int valid_num = 0;
481
482 InstListIt inst_list_it = instList.begin();
483
484 cprintf("Inst list size: %i\n", instList.size());
485
486 while (inst_list_it != instList.end())
487 {
488 cprintf("Instruction:%i\n",
489 num);
490 if (!(*inst_list_it)->isSquashed()) {
491 if (!(*inst_list_it)->isIssued()) {
492 ++valid_num;
493 cprintf("Count:%i\n", valid_num);
494 } else if ((*inst_list_it)->isMemRef() &&
495 !(*inst_list_it)->memOpDone) {
496 // Loads that have not been marked as executed still count
497 // towards the total instructions.
498 ++valid_num;
499 cprintf("Count:%i\n", valid_num);
500 }
501 }
502
503 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
504 "Issued:%i\nSquashed:%i\n",
505 (*inst_list_it)->readPC(),
506 (*inst_list_it)->seqNum,
507 (*inst_list_it)->threadNumber,
508 (*inst_list_it)->isIssued(),
509 (*inst_list_it)->isSquashed());
510
511 if ((*inst_list_it)->isMemRef()) {
512 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
513 }
514
515 cprintf("\n");
516
517 inst_list_it++;
518 ++num;
519 }
520 }
521
522 template <class Impl>
523 InorderBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(
524 InorderBackEnd *_be)
525 : Event(&mainEventQueue, CPU_Tick_Pri), be(_be)
526 {
527 // this->setFlags(Event::AutoDelete);
528 }
529
530 template <class Impl>
531 void
532 InorderBackEnd<Impl>::DCacheCompletionEvent::process()
533 {
534 inst->completeAcc();
535 be->status = DcacheMissComplete;
536 }
537
538 template <class Impl>
539 const char *
540 InorderBackEnd<Impl>::DCacheCompletionEvent::description() const
541 {
542 return "DCache completion";
543 }