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