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