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