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