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