9c03137215cfc967446546eb94d9afbf1b458baf
[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 <string>
35 #include <sstream>
36
37 #include "arch/faults.hh"
38 #include "base/cprintf.hh"
39 #include "base/trace.hh"
40 #include "config/the_isa.hh"
41 #include "cpu/exetrace.hh"
42 #include "cpu/inorder/cpu.hh"
43 #include "cpu/inorder/inorder_dyn_inst.hh"
44 #include "mem/request.hh"
45
46 using namespace std;
47 using namespace TheISA;
48 using namespace ThePipeline;
49
50 InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC,
51 Addr pred_PC, InstSeqNum seq_num,
52 InOrderCPU *cpu)
53 : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu)
54 {
55 seqNum = seq_num;
56
57 PC = inst_PC;
58 nextPC = PC + sizeof(MachInst);
59 nextNPC = nextPC + sizeof(MachInst);
60 predPC = pred_PC;
61
62 initVars();
63 }
64
65 InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
66 InOrderThreadState *state,
67 InstSeqNum seq_num,
68 ThreadID tid,
69 unsigned _asid)
70 : traceData(NULL), cpu(cpu)
71 {
72 seqNum = seq_num;
73 thread = state;
74 threadNumber = tid;
75 asid = _asid;
76 initVars();
77 }
78
79 InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst)
80 : seqNum(0), staticInst(_staticInst), traceData(NULL)
81 {
82 initVars();
83 }
84
85 InOrderDynInst::InOrderDynInst()
86 : seqNum(0), traceData(NULL), cpu(cpu)
87 {
88 initVars();
89 }
90
91 int InOrderDynInst::instcount = 0;
92
93
94 void
95 InOrderDynInst::setMachInst(ExtMachInst machInst)
96 {
97 staticInst = StaticInst::decode(machInst, PC);
98
99 for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
100 _destRegIdx[i] = this->staticInst->destRegIdx(i);
101 }
102
103 for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
104 _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
105 this->_readySrcRegIdx[i] = 0;
106 }
107 }
108
109 void
110 InOrderDynInst::initVars()
111 {
112 fetchMemReq = NULL;
113 dataMemReq = NULL;
114 splitMemData = NULL;
115 split2ndAccess = false;
116 splitInst = false;
117 splitFinishCnt = 0;
118
119 effAddr = 0;
120 physEffAddr = 0;
121
122 readyRegs = 0;
123
124 nextStage = 0;
125 nextInstStageNum = 0;
126
127 for(int i = 0; i < MaxInstDestRegs; i++)
128 instResult[i].val.integer = 0;
129
130 status.reset();
131
132 memAddrReady = false;
133 eaCalcDone = false;
134 memOpDone = false;
135
136 predictTaken = false;
137 procDelaySlotOnMispred = false;
138
139 lqIdx = -1;
140 sqIdx = -1;
141
142 // Also make this a parameter, or perhaps get it from xc or cpu.
143 asid = 0;
144
145 virtProcNumber = 0;
146
147 // Initialize the fault to be NoFault.
148 fault = NoFault;
149
150 // Make sure to have the renamed register entries set to the same
151 // as the normal register entries. It will allow the IQ to work
152 // without any modifications.
153 if (this->staticInst) {
154 for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
155 _destRegIdx[i] = this->staticInst->destRegIdx(i);
156 }
157
158 for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
159 _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
160 this->_readySrcRegIdx[i] = 0;
161 }
162 }
163
164 // Update Instruction Count for this instruction
165 ++instcount;
166 if (instcount > 500) {
167 fatal("Number of Active Instructions in CPU is too high. "
168 "(Not Dereferencing Ptrs. Correctly?)\n");
169 }
170
171
172
173 DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n",
174 threadNumber, seqNum, instcount);
175 }
176
177
178 InOrderDynInst::~InOrderDynInst()
179 {
180 if (fetchMemReq != 0x0) {
181 delete fetchMemReq;
182 fetchMemReq = NULL;
183 }
184
185 if (dataMemReq != 0x0) {
186 delete dataMemReq;
187 dataMemReq = NULL;
188 }
189
190 if (traceData) {
191 delete traceData;
192 }
193
194 if (splitMemData) {
195 delete splitMemData;
196 }
197
198 fault = NoFault;
199
200 --instcount;
201
202 deleteStages();
203
204 DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n",
205 threadNumber, seqNum, instcount);
206 }
207
208 void
209 InOrderDynInst::setStaticInst(StaticInstPtr &static_inst)
210 {
211 this->staticInst = static_inst;
212
213 // Make sure to have the renamed register entries set to the same
214 // as the normal register entries. It will allow the IQ to work
215 // without any modifications.
216 if (this->staticInst) {
217 for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
218 _destRegIdx[i] = this->staticInst->destRegIdx(i);
219 }
220
221 for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
222 _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
223 this->_readySrcRegIdx[i] = 0;
224 }
225 }
226 }
227
228 Fault
229 InOrderDynInst::execute()
230 {
231 // @todo: Pretty convoluted way to avoid squashing from happening
232 // when using the TC during an instruction's execution
233 // (specifically for instructions that have side-effects that use
234 // the TC). Fix this.
235 bool in_syscall = this->thread->inSyscall;
236 this->thread->inSyscall = true;
237
238 this->fault = this->staticInst->execute(this, this->traceData);
239
240 this->thread->inSyscall = in_syscall;
241
242 return this->fault;
243 }
244
245 Fault
246 InOrderDynInst::calcEA()
247 {
248 this->fault = this->staticInst->eaComp(this, this->traceData);
249 return this->fault;
250 }
251
252 Fault
253 InOrderDynInst::initiateAcc()
254 {
255 // @todo: Pretty convoluted way to avoid squashing from happening
256 // when using the TC during an instruction's execution
257 // (specifically for instructions that have side-effects that use
258 // the TC). Fix this.
259 bool in_syscall = this->thread->inSyscall;
260 this->thread->inSyscall = true;
261
262 this->fault = this->staticInst->initiateAcc(this, this->traceData);
263
264 this->thread->inSyscall = in_syscall;
265
266 return this->fault;
267 }
268
269
270 Fault
271 InOrderDynInst::completeAcc(Packet *pkt)
272 {
273 this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
274
275 return this->fault;
276 }
277
278 InstStage *InOrderDynInst::addStage()
279 {
280 this->currentInstStage = new InstStage(this, nextInstStageNum++);
281 instStageList.push_back( this->currentInstStage );
282 return this->currentInstStage;
283 }
284
285 InstStage *InOrderDynInst::addStage(int stage_num)
286 {
287 nextInstStageNum = stage_num;
288 return InOrderDynInst::addStage();
289 }
290
291 void InOrderDynInst::deleteStages() {
292 std::list<InstStage*>::iterator list_it = instStageList.begin();
293 std::list<InstStage*>::iterator list_end = instStageList.end();
294
295 while(list_it != list_end) {
296 delete *list_it;
297 list_it++;
298 }
299 }
300
301 Fault
302 InOrderDynInst::memAccess()
303 {
304 return initiateAcc();
305 }
306
307
308 #if FULL_SYSTEM
309
310 Fault
311 InOrderDynInst::hwrei()
312 {
313 panic("InOrderDynInst: hwrei: unimplemented\n");
314 return NoFault;
315 }
316
317
318 void
319 InOrderDynInst::trap(Fault fault)
320 {
321 this->cpu->trap(fault, this->threadNumber);
322 }
323
324
325 bool
326 InOrderDynInst::simPalCheck(int palFunc)
327 {
328 #if THE_ISA != ALPHA_ISA
329 panic("simPalCheck called, but PAL only exists in Alpha!\n");
330 #endif
331 return this->cpu->simPalCheck(palFunc, this->threadNumber);
332 }
333 #else
334 void
335 InOrderDynInst::syscall(int64_t callnum)
336 {
337 cpu->syscall(callnum, this->threadNumber);
338 }
339 #endif
340
341 void
342 InOrderDynInst::prefetch(Addr addr, unsigned flags)
343 {
344 cpu->prefetch(this);
345 }
346
347 void
348 InOrderDynInst::writeHint(Addr addr, int size, unsigned flags)
349 {
350 cpu->writeHint(this);
351 }
352
353 /**
354 * @todo Need to find a way to get the cache block size here.
355 */
356 Fault
357 InOrderDynInst::copySrcTranslate(Addr src)
358 {
359 // Not currently supported.
360 return NoFault;
361 }
362
363 /**
364 * @todo Need to find a way to get the cache block size here.
365 */
366 Fault
367 InOrderDynInst::copy(Addr dest)
368 {
369 // Not currently supported.
370 return NoFault;
371 }
372
373 void
374 InOrderDynInst::releaseReq(ResourceRequest* req)
375 {
376 std::list<ResourceRequest*>::iterator list_it = reqList.begin();
377 std::list<ResourceRequest*>::iterator list_end = reqList.end();
378
379 while(list_it != list_end) {
380 if((*list_it)->getResIdx() == req->getResIdx() &&
381 (*list_it)->getSlot() == req->getSlot()) {
382 DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n",
383 threadNumber, seqNum, req->res->name());
384 reqList.erase(list_it);
385 return;
386 }
387 list_it++;
388 }
389
390 panic("Releasing Res. Request That Isnt There!\n");
391 }
392
393 /** Records an integer source register being set to a value. */
394 void
395 InOrderDynInst::setIntSrc(int idx, uint64_t val)
396 {
397 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n",
398 threadNumber, seqNum, idx, val);
399 instSrc[idx].integer = val;
400 }
401
402 /** Records an fp register being set to a value. */
403 void
404 InOrderDynInst::setFloatSrc(int idx, FloatReg val)
405 {
406 instSrc[idx].dbl = val;
407 }
408
409 /** Records an fp register being set to an integer value. */
410 void
411 InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val)
412 {
413 instSrc[idx].integer = val;
414 }
415
416 /** Reads a integer register. */
417 IntReg
418 InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, ThreadID tid)
419 {
420 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
421 threadNumber, seqNum, idx, instSrc[idx].integer);
422 return instSrc[idx].integer;
423 }
424
425 /** Reads a FP register. */
426 FloatReg
427 InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx)
428 {
429 return instSrc[idx].dbl;
430 }
431
432
433 /** Reads a FP register as a integer. */
434 FloatRegBits
435 InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx)
436 {
437 return instSrc[idx].integer;
438 }
439
440 /** Reads a miscellaneous register. */
441 MiscReg
442 InOrderDynInst::readMiscReg(int misc_reg)
443 {
444 return this->cpu->readMiscReg(misc_reg, threadNumber);
445 }
446
447 /** Reads a misc. register, including any side-effects the read
448 * might have as defined by the architecture.
449 */
450 MiscReg
451 InOrderDynInst::readMiscRegNoEffect(int misc_reg)
452 {
453 return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber);
454 }
455
456 /** Reads a miscellaneous register. */
457 MiscReg
458 InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx)
459 {
460 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
461 " read as %#x.\n", threadNumber, seqNum, idx,
462 instSrc[idx].integer);
463 return instSrc[idx].integer;
464 }
465
466 /** Reads a misc. register, including any side-effects the read
467 * might have as defined by the architecture.
468 */
469 MiscReg
470 InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx)
471 {
472 // For In-Order, the side-effect of reading a register happens
473 // when explicitly executing a "ReadSrc" command. This simply returns
474 // a value.
475 return readMiscRegOperandNoEffect(si, idx);
476 }
477
478 /** Sets a misc. register. */
479 void
480 InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx,
481 const MiscReg &val)
482 {
483 instResult[idx].type = Integer;
484 instResult[idx].val.integer = val;
485 instResult[idx].tick = curTick;
486
487 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
488 "being set to %#x.\n", threadNumber, seqNum, idx, val);
489 }
490
491 /** Sets a misc. register, including any side-effects the write
492 * might have as defined by the architecture.
493 */
494 void
495 InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
496 const MiscReg &val)
497 {
498 // For In-Order, the side-effect of setting a register happens
499 // when explicitly writing back the register value. This
500 // simply maintains the operand value.
501 setMiscRegOperandNoEffect(si, idx, val);
502 }
503
504 MiscReg
505 InOrderDynInst::readRegOtherThread(unsigned reg_idx, ThreadID tid)
506 {
507 if (tid == -1) {
508 tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
509 }
510
511 if (reg_idx < FP_Base_DepTag) { // Integer Register File
512 return this->cpu->readIntReg(reg_idx, tid);
513 } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
514 reg_idx -= FP_Base_DepTag;
515 return this->cpu->readFloatRegBits(reg_idx, tid);
516 } else {
517 reg_idx -= Ctrl_Base_DepTag;
518 return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File
519 }
520 }
521
522 /** Sets a Integer register. */
523 void
524 InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val)
525 {
526 instResult[idx].type = Integer;
527 instResult[idx].val.integer = val;
528 instResult[idx].tick = curTick;
529 }
530
531 /** Sets a FP register. */
532 void
533 InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
534 {
535 instResult[idx].val.dbl = val;
536 instResult[idx].type = Float;
537
538 instResult[idx].tick = curTick;
539 }
540
541 /** Sets a FP register as a integer. */
542 void
543 InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
544 FloatRegBits val)
545 {
546 instResult[idx].type = Integer;
547 instResult[idx].val.integer = val;
548 instResult[idx].tick = curTick;
549 }
550
551 /** Sets a misc. register. */
552 /* Alter this when wanting to *speculate* on Miscellaneous registers */
553 void
554 InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
555 {
556 this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber);
557 }
558
559 /** Sets a misc. register, including any side-effects the write
560 * might have as defined by the architecture.
561 */
562 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
563 void
564 InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
565 {
566 this->cpu->setMiscReg(misc_reg, val, threadNumber);
567 }
568
569 void
570 InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
571 ThreadID tid)
572 {
573 if (tid == InvalidThreadID) {
574 tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
575 }
576
577 if (reg_idx < FP_Base_DepTag) { // Integer Register File
578 this->cpu->setIntReg(reg_idx, val, tid);
579 } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
580 reg_idx -= FP_Base_DepTag;
581 this->cpu->setFloatRegBits(reg_idx, val, tid);
582 } else {
583 reg_idx -= Ctrl_Base_DepTag;
584 this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File
585 }
586 }
587
588 void
589 InOrderDynInst::deallocateContext(int thread_num)
590 {
591 this->cpu->deallocateContext(thread_num);
592 }
593
594 template<class T>
595 inline Fault
596 InOrderDynInst::read(Addr addr, T &data, unsigned flags)
597 {
598 return cpu->read(this, addr, data, flags);
599 }
600
601 #ifndef DOXYGEN_SHOULD_SKIP_THIS
602
603 template
604 Fault
605 InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags);
606
607 template
608 Fault
609 InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags);
610
611 template
612 Fault
613 InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags);
614
615 template
616 Fault
617 InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags);
618
619 #endif //DOXYGEN_SHOULD_SKIP_THIS
620
621 template<>
622 Fault
623 InOrderDynInst::read(Addr addr, double &data, unsigned flags)
624 {
625 return read(addr, *(uint64_t*)&data, flags);
626 }
627
628 template<>
629 Fault
630 InOrderDynInst::read(Addr addr, float &data, unsigned flags)
631 {
632 return read(addr, *(uint32_t*)&data, flags);
633 }
634
635 template<>
636 Fault
637 InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags)
638 {
639 return read(addr, (uint32_t&)data, flags);
640 }
641
642 template<class T>
643 inline Fault
644 InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res)
645 {
646 //memcpy(memData, gtoh(data), sizeof(T));
647 storeData = data;
648
649 DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n",
650 threadNumber, seqNum, memData);
651 return cpu->write(this, data, addr, flags, res);
652 }
653
654 #ifndef DOXYGEN_SHOULD_SKIP_THIS
655 template
656 Fault
657 InOrderDynInst::write(uint64_t data, Addr addr,
658 unsigned flags, uint64_t *res);
659
660 template
661 Fault
662 InOrderDynInst::write(uint32_t data, Addr addr,
663 unsigned flags, uint64_t *res);
664
665 template
666 Fault
667 InOrderDynInst::write(uint16_t data, Addr addr,
668 unsigned flags, uint64_t *res);
669
670 template
671 Fault
672 InOrderDynInst::write(uint8_t data, Addr addr,
673 unsigned flags, uint64_t *res);
674
675 #endif //DOXYGEN_SHOULD_SKIP_THIS
676
677 template<>
678 Fault
679 InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res)
680 {
681 return write(*(uint64_t*)&data, addr, flags, res);
682 }
683
684 template<>
685 Fault
686 InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res)
687 {
688 return write(*(uint32_t*)&data, addr, flags, res);
689 }
690
691
692 template<>
693 Fault
694 InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
695 {
696 return write((uint32_t)data, addr, flags, res);
697 }
698
699
700 void
701 InOrderDynInst::dump()
702 {
703 cprintf("T%d : %#08d `", threadNumber, PC);
704 cout << staticInst->disassemble(PC);
705 cprintf("'\n");
706 }
707
708 void
709 InOrderDynInst::dump(std::string &outstring)
710 {
711 std::ostringstream s;
712 s << "T" << threadNumber << " : 0x" << PC << " "
713 << staticInst->disassemble(PC);
714
715 outstring = s.str();
716 }
717
718
719 #define NOHASH
720 #ifndef NOHASH
721
722 #include "base/hashmap.hh"
723
724 unsigned int MyHashFunc(const InOrderDynInst *addr)
725 {
726 unsigned a = (unsigned)addr;
727 unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
728
729 return hash;
730 }
731
732 typedef m5::hash_map<const InOrderDynInst *, const InOrderDynInst *, MyHashFunc>
733 my_hash_t;
734
735 my_hash_t thishash;
736 #endif