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