c2765a3ba25958861174ff0017a3fab15a0e7dd8
[gem5.git] / src / cpu / inorder / inorder_dyn_inst.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Korey Sewell
30 *
31 */
32
33 #include <iostream>
34 #include <set>
35 #include <sstream>
36 #include <string>
37
38 #include "base/bigint.hh"
39 #include "base/cp_annotate.hh"
40 #include "base/cprintf.hh"
41 #include "base/trace.hh"
42 #include "config/the_isa.hh"
43 #include "cpu/inorder/cpu.hh"
44 #include "cpu/inorder/inorder_dyn_inst.hh"
45 #include "cpu/exetrace.hh"
46 #include "cpu/reg_class.hh"
47 #include "debug/InOrderDynInst.hh"
48 #include "mem/request.hh"
49 #include "sim/fault_fwd.hh"
50 #include "sim/full_system.hh"
51
52 using namespace std;
53 using namespace TheISA;
54 using namespace ThePipeline;
55
56 InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
57 InOrderThreadState *state,
58 InstSeqNum seq_num,
59 ThreadID tid,
60 unsigned _asid)
61 : seqNum(seq_num), squashSeqNum(0), threadNumber(tid), asid(_asid),
62 virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu),
63 thread(state), fault(NoFault), memData(NULL), loadData(0),
64 storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
65 readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
66 memTime(0), splitMemData(NULL), splitMemReq(NULL), totalSize(0),
67 split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
68 split2ndDataPtr(NULL), split2ndFlags(0), splitInst(false),
69 splitFinishCnt(0), split2ndStoreDataPtr(NULL), splitInstSked(false),
70 inFrontEnd(true), frontSked(NULL), backSked(NULL),
71 squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
72 fetchMemReq(NULL), dataMemReq(NULL), instEffAddr(0), eaCalcDone(false),
73 lqIdx(0), sqIdx(0), onInstList(false)
74 {
75 for(int i = 0; i < MaxInstSrcRegs; i++) {
76 _readySrcRegIdx[i] = false;
77 _srcRegIdx[i] = 0;
78 }
79
80 for(int j = 0; j < MaxInstDestRegs; j++) {
81 _destRegIdx[j] = 0;
82 _prevDestRegIdx[j] = 0;
83 }
84
85 ++instcount;
86 DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created."
87 " (active insts: %i)\n", threadNumber, seqNum, instcount);
88
89 }
90
91 int InOrderDynInst::instcount = 0;
92
93 int
94 InOrderDynInst::cpuId()
95 {
96 return cpu->cpuId();
97 }
98
99 void
100 InOrderDynInst::setStaticInst(StaticInstPtr si)
101 {
102 staticInst = si;
103
104 for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
105 _destRegIdx[i] = this->staticInst->destRegIdx(i);
106 }
107
108 for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
109 _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
110 this->_readySrcRegIdx[i] = 0;
111 }
112 }
113
114 void
115 InOrderDynInst::initVars()
116 {
117 inFrontEnd = true;
118
119 fetchMemReq = NULL;
120 dataMemReq = NULL;
121 splitMemData = NULL;
122 split2ndAddr = 0;
123 split2ndAccess = false;
124 splitInst = false;
125 splitInstSked = false;
126 splitFinishCnt = 0;
127
128 effAddr = 0;
129 physEffAddr = 0;
130
131 readyRegs = 0;
132
133 nextStage = 0;
134
135 status.reset();
136
137 memAddrReady = false;
138 eaCalcDone = false;
139
140 predictTaken = false;
141 procDelaySlotOnMispred = false;
142
143 lqIdx = -1;
144 sqIdx = -1;
145
146 // Also make this a parameter, or perhaps get it from xc or cpu.
147 asid = 0;
148
149 virtProcNumber = 0;
150
151 // Initialize the fault to be NoFault.
152 fault = NoFault;
153
154 // Make sure to have the renamed register entries set to the same
155 // as the normal register entries. It will allow the IQ to work
156 // without any modifications.
157 if (this->staticInst) {
158 for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
159 _destRegIdx[i] = this->staticInst->destRegIdx(i);
160 }
161
162 for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
163 _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
164 this->_readySrcRegIdx[i] = 0;
165 }
166 }
167
168 // Update Instruction Count for this instruction
169 if (instcount > 100) {
170 fatal("Number of Active Instructions in CPU is too high. "
171 "(Not Dereferencing Ptrs. Correctly?)\n");
172 }
173 }
174
175 void
176 InOrderDynInst::resetInstCount()
177 {
178 instcount = 0;
179 }
180
181
182 InOrderDynInst::~InOrderDynInst()
183 {
184 if (traceData)
185 delete traceData;
186
187 if (splitMemData)
188 delete [] splitMemData;
189
190 fault = NoFault;
191
192 --instcount;
193
194 DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
195 " (active insts: %i)\n", threadNumber, seqNum, instcount);
196 }
197
198 void
199 InOrderDynInst::setStaticInst(StaticInstPtr &static_inst)
200 {
201 this->staticInst = static_inst;
202
203 // Make sure to have the renamed register entries set to the same
204 // as the normal register entries. It will allow the IQ to work
205 // without any modifications.
206 if (this->staticInst) {
207 for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
208 _destRegIdx[i] = this->staticInst->destRegIdx(i);
209 }
210
211 for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
212 _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
213 this->_readySrcRegIdx[i] = 0;
214 }
215 }
216 }
217
218 Fault
219 InOrderDynInst::execute()
220 {
221 // @todo: Pretty convoluted way to avoid squashing from happening
222 // when using the TC during an instruction's execution
223 // (specifically for instructions that have side-effects that use
224 // the TC). Fix this.
225 bool no_squash_from_TC = this->thread->noSquashFromTC;
226 this->thread->noSquashFromTC = true;
227
228 this->fault = this->staticInst->execute(this, this->traceData);
229
230 this->thread->noSquashFromTC = no_squash_from_TC;
231
232 return this->fault;
233 }
234
235 Fault
236 InOrderDynInst::calcEA()
237 {
238 this->fault = this->staticInst->eaComp(this, this->traceData);
239 return this->fault;
240 }
241
242 Fault
243 InOrderDynInst::initiateAcc()
244 {
245 // @todo: Pretty convoluted way to avoid squashing from happening
246 // when using the TC during an instruction's execution
247 // (specifically for instructions that have side-effects that use
248 // the TC). Fix this.
249 bool no_squash_from_TC = this->thread->noSquashFromTC;
250 this->thread->noSquashFromTC = true;
251
252 this->fault = this->staticInst->initiateAcc(this, this->traceData);
253
254 this->thread->noSquashFromTC = no_squash_from_TC;
255
256 return this->fault;
257 }
258
259
260 Fault
261 InOrderDynInst::completeAcc(Packet *pkt)
262 {
263 this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
264
265 return this->fault;
266 }
267
268 Fault
269 InOrderDynInst::memAccess()
270 {
271 return initiateAcc();
272 }
273
274
275 Fault
276 InOrderDynInst::hwrei()
277 {
278 #if THE_ISA == ALPHA_ISA
279 // Can only do a hwrei when in pal mode.
280 if (!(this->instAddr() & 0x3))
281 return new AlphaISA::UnimplementedOpcodeFault;
282
283 // Set the next PC based on the value of the EXC_ADDR IPR.
284 AlphaISA::PCState pc = this->pcState();
285 pc.npc(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
286 this->threadNumber));
287 this->pcState(pc);
288 if (CPA::available()) {
289 ThreadContext *tc = this->cpu->tcBase(this->threadNumber);
290 CPA::cpa()->swAutoBegin(tc, this->nextInstAddr());
291 }
292
293 // Tell CPU to clear any state it needs to if a hwrei is taken.
294 this->cpu->hwrei(this->threadNumber);
295 #endif
296 return NoFault;
297 }
298
299
300 void
301 InOrderDynInst::trap(Fault fault)
302 {
303 this->cpu->trap(fault, this->threadNumber, this);
304 }
305
306
307 bool
308 InOrderDynInst::simPalCheck(int palFunc)
309 {
310 #if THE_ISA != ALPHA_ISA
311 panic("simPalCheck called, but PAL only exists in Alpha!\n");
312 #endif
313 return this->cpu->simPalCheck(palFunc, this->threadNumber);
314 }
315
316 void
317 InOrderDynInst::syscall(int64_t callnum)
318 {
319 if (FullSystem)
320 panic("Syscall emulation isn't available in FS mode.\n");
321
322 syscallNum = callnum;
323 cpu->syscallContext(NoFault, this->threadNumber, this);
324 }
325
326 void
327 InOrderDynInst::setSquashInfo(unsigned stage_num)
328 {
329 squashingStage = stage_num;
330
331 // If it's a fault, then we need to squash
332 // the faulting instruction too. Squash
333 // functions squash above a seqNum, so we
334 // decrement here for that case
335 if (fault != NoFault) {
336 squashSeqNum = seqNum - 1;
337 return;
338 } else
339 squashSeqNum = seqNum;
340
341 #if ISA_HAS_DELAY_SLOT
342 if (staticInst && isControl()) {
343 TheISA::PCState nextPC = pc;
344 TheISA::advancePC(nextPC, staticInst);
345
346 // Check to see if we should squash after the
347 // branch or after a branch delay slot.
348 if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
349 squashSeqNum = seqNum + 1;
350 else
351 squashSeqNum = seqNum;
352 }
353 #endif
354 }
355
356 void
357 InOrderDynInst::releaseReq(ResourceRequest* req)
358 {
359 std::list<ResourceRequest*>::iterator list_it = reqList.begin();
360 std::list<ResourceRequest*>::iterator list_end = reqList.end();
361
362 while(list_it != list_end) {
363 if((*list_it)->getResIdx() == req->getResIdx() &&
364 (*list_it)->getSlot() == req->getSlot()) {
365 DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request "
366 "to %s.\n", threadNumber, seqNum, req->res->name());
367 reqList.erase(list_it);
368 return;
369 }
370 list_it++;
371 }
372
373 panic("Releasing Res. Request That Isnt There!\n");
374 }
375
376 /** Records an integer source register being set to a value. */
377 void
378 InOrderDynInst::setIntSrc(int idx, uint64_t val)
379 {
380 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] Int being set "
381 "to %#x.\n", threadNumber, seqNum, idx, val);
382 instSrc[idx].intVal = val;
383 }
384
385 /** Records an fp register being set to a value. */
386 void
387 InOrderDynInst::setFloatSrc(int idx, FloatReg val)
388 {
389 instSrc[idx].fpVal.f = val;
390 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FP being set "
391 "to %x, %08f...%08f\n", threadNumber, seqNum, idx,
392 instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
393 }
394
395 /** Records an fp register being set to an integer value. */
396 void
397 InOrderDynInst::setFloatRegBitsSrc(int idx, FloatRegBits val)
398 {
399 instSrc[idx].fpVal.i = val;
400 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
401 "to %x, %08f...%x\n", threadNumber, seqNum, idx,
402 instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
403 }
404
405 /** Reads a integer register. */
406 IntReg
407 InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, ThreadID tid)
408 {
409 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
410 threadNumber, seqNum, idx, instSrc[idx].intVal);
411 return instSrc[idx].intVal;
412 }
413
414 /** Reads a FP register. */
415 FloatReg
416 InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx)
417 {
418 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
419 "as %x, %08f.\n", threadNumber, seqNum, idx,
420 instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
421 return instSrc[idx].fpVal.f;
422 }
423
424
425 /** Reads a FP register as a integer. */
426 FloatRegBits
427 InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx)
428 {
429 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
430 "as %x, %08f.\n", threadNumber, seqNum, idx,
431 instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
432 return instSrc[idx].fpVal.i;
433 }
434
435 /** Reads a miscellaneous register. */
436 MiscReg
437 InOrderDynInst::readMiscReg(int misc_reg)
438 {
439 return this->cpu->readMiscReg(misc_reg, threadNumber);
440 }
441
442
443 /** Reads a misc. register, including any side-effects the read
444 * might have as defined by the architecture.
445 */
446 MiscReg
447 InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx)
448 {
449 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
450 " read as %#x.\n", threadNumber, seqNum, idx,
451 instSrc[idx].intVal);
452 return instSrc[idx].intVal;
453 }
454
455
456 /** Sets a misc. register, including any side-effects the write
457 * might have as defined by the architecture.
458 */
459 void
460 InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
461 const MiscReg &val)
462 {
463 instResult[idx].type = Integer;
464 instResult[idx].res.intVal = val;
465 instResult[idx].tick = curTick();
466
467 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
468 "being set to %#x.\n", threadNumber, seqNum, idx, val);
469 }
470
471 MiscReg
472 InOrderDynInst::readRegOtherThread(unsigned reg_idx, ThreadID tid)
473 {
474 if (tid == -1) {
475 tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
476 }
477
478 RegIndex rel_idx;
479
480 switch (regIdxToClass(reg_idx, &rel_idx)) {
481 case IntRegClass:
482 return this->cpu->readIntReg(rel_idx, tid);
483
484 case FloatRegClass:
485 return this->cpu->readFloatRegBits(rel_idx, tid);
486
487 case MiscRegClass:
488 return this->cpu->readMiscReg(rel_idx, tid); // Misc. Register File
489
490 default:
491 panic("register %d out of range\n", reg_idx);
492
493 }
494 }
495
496 /** Sets a Integer register. */
497 void
498 InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val)
499 {
500 instResult[idx].type = Integer;
501 instResult[idx].res.intVal = val;
502 instResult[idx].tick = curTick();
503
504 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
505 "being set to %#x (result-tick:%i).\n",
506 threadNumber, seqNum, idx, val, instResult[idx].tick);
507 }
508
509 /** Sets a FP register. */
510 void
511 InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
512 {
513 instResult[idx].type = Float;
514 instResult[idx].res.fpVal.f = val;
515 instResult[idx].tick = curTick();
516
517 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. %i "
518 "being set to %#x, %08f (result-tick:%i).\n",
519 threadNumber, seqNum, idx, val, val, instResult[idx].tick);
520 }
521
522 /** Sets a FP register as a integer. */
523 void
524 InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
525 FloatRegBits val)
526 {
527 instResult[idx].type = FloatBits;
528 instResult[idx].res.fpVal.i = val;
529 instResult[idx].tick = curTick();
530
531 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
532 "being set to %#x (result-tick:%i).\n",
533 threadNumber, seqNum, idx, val, instResult[idx].tick);
534 }
535
536 /** Sets a misc. register, including any side-effects the write
537 * might have as defined by the architecture.
538 */
539 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
540 void
541 InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
542 {
543 this->cpu->setMiscReg(misc_reg, val, threadNumber);
544 }
545
546 void
547 InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
548 ThreadID tid)
549 {
550 if (tid == InvalidThreadID) {
551 tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
552 }
553
554 RegIndex rel_idx;
555
556 switch (regIdxToClass(reg_idx, &rel_idx)) {
557 case IntRegClass:
558 this->cpu->setIntReg(rel_idx, val, tid);
559 break;
560
561 case FloatRegClass:
562 this->cpu->setFloatRegBits(rel_idx, val, tid);
563 break;
564
565 case MiscRegClass:
566 this->cpu->setMiscReg(rel_idx, val, tid); // Misc. Register File
567 break;
568 }
569 }
570
571 void
572 InOrderDynInst::deallocateContext(int thread_num)
573 {
574 this->cpu->deallocateContext(thread_num);
575 }
576
577 Fault
578 InOrderDynInst::readMem(Addr addr, uint8_t *data,
579 unsigned size, unsigned flags)
580 {
581 return cpu->read(this, addr, data, size, flags);
582 }
583
584 Fault
585 InOrderDynInst::writeMem(uint8_t *data, unsigned size,
586 Addr addr, unsigned flags, uint64_t *res)
587 {
588 return cpu->write(this, data, size, addr, flags, res);
589 }
590
591
592 void
593 InOrderDynInst::dump()
594 {
595 cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
596 cout << staticInst->disassemble(pc.instAddr());
597 cprintf("'\n");
598 }
599
600 void
601 InOrderDynInst::dump(std::string &outstring)
602 {
603 std::ostringstream s;
604 s << "T" << threadNumber << " : " << pc << " "
605 << staticInst->disassemble(pc.instAddr());
606
607 outstring = s.str();
608 }