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