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