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