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