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