2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Steve Reinhardt
39 #include "arch/regfile.hh"
40 #include "arch/utility.hh"
41 #include "base/loader/symtab.hh"
42 #include "config/full_system.hh"
43 #include "cpu/base.hh"
44 #include "cpu/exetrace.hh"
45 #include "cpu/static_inst.hh"
46 #include "sim/param.hh"
47 #include "sim/system.hh"
50 #include "arch/tlb.hh"
53 //XXX This is temporary
54 #include "arch/isa_specific.hh"
55 #include "cpu/m5legion_interface.h"
58 using namespace TheISA
;
60 #if THE_ISA == SPARC_ISA && FULL_SYSTEM
61 static int diffcount
= 0;
65 SharedData
*shared_data
= NULL
;
68 ////////////////////////////////////////////////////////////////////////
70 // Methods for the InstRecord object
73 #if THE_ISA == SPARC_ISA
75 inline char * genCenteredLabel(int length
, char * buffer
, char * label
)
77 int labelLength
= strlen(label
);
78 assert(labelLength
<= length
);
79 int leftPad
= (length
- labelLength
) / 2;
80 int rightPad
= length
- leftPad
- labelLength
;
82 sprintf(format
, "%%%ds%%s%%%ds", leftPad
, rightPad
);
83 sprintf(buffer
, format
, "", label
, "");
87 inline void printRegPair(ostream
& os
, char const * title
, uint64_t a
, uint64_t b
)
89 ccprintf(os
, " %16s | %#018x %s %#-018x \n",
90 title
, a
, (a
== b
) ? "|" : "X", b
);
93 inline void printColumnLabels(ostream
& os
)
95 static char * regLabel
= genCenteredLabel(16, new char[17], "Register");
96 static char * m5Label
= genCenteredLabel(18, new char[18], "M5");
97 static char * legionLabel
= genCenteredLabel(18, new char[18], "Legion");
98 ccprintf(os
, " %s | %s | %s \n", regLabel
, m5Label
, legionLabel
);
99 ccprintf(os
, "--------------------+-----------------------+-----------------------\n");
102 inline void printSectionHeader(ostream
& os
, char * name
)
104 char sectionString
[70];
105 genCenteredLabel(69, sectionString
, name
);
106 ccprintf(os
, "====================================================================\n");
107 ccprintf(os
, "%69s\n", sectionString
);
108 ccprintf(os
, "====================================================================\n");
111 inline void printLevelHeader(ostream
& os
, int level
)
113 char sectionString
[70];
115 sprintf(levelName
, "Trap stack level %d", level
);
116 genCenteredLabel(69, sectionString
, levelName
);
117 ccprintf(os
, "====================================================================\n");
118 ccprintf(os
, "%69s\n", sectionString
);
119 ccprintf(os
, "====================================================================\n");
125 Trace::InstRecord::dump(ostream
&outs
)
127 if (flags
[PRINT_REG_DELTA
])
129 #if THE_ISA == SPARC_ISA
130 //Don't print what happens for each micro-op, just print out
131 //once at the last op, and for regular instructions.
132 if(!staticInst
->isMicroOp() || staticInst
->isLastMicroOp())
134 static uint64_t regs
[32] = {
135 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, 0, 0, 0, 0};
139 static uint64_t ccr
= 0;
140 static uint64_t y
= 0;
141 static uint64_t floats
[32];
143 static const char * prefixes
[4] = {"G", "O", "L", "I"};
146 outs
<< "PC = " << thread
->readNextPC();
147 outs
<< " NPC = " << thread
->readNextNPC();
148 newVal
= thread
->readMiscReg(SparcISA::MISCREG_CCR
);
151 outs
<< " CCR = " << newVal
;
154 newVal
= thread
->readMiscReg(SparcISA::MISCREG_Y
);
157 outs
<< " Y = " << newVal
;
160 for(int y
= 0; y
< 4; y
++)
162 for(int x
= 0; x
< 8; x
++)
164 int index
= x
+ 8 * y
;
165 newVal
= thread
->readIntReg(index
);
166 if(regs
[index
] != newVal
)
168 outs
<< " " << prefixes
[y
] << dec
<< x
<< " = " << hex
<< newVal
;
169 regs
[index
] = newVal
;
173 for(int y
= 0; y
< 32; y
++)
175 newVal
= thread
->readFloatRegBits(2 * y
, 64);
176 if(floats
[y
] != newVal
)
178 outs
<< " F" << dec
<< (2 * y
) << " = " << hex
<< newVal
;
186 else if (flags
[INTEL_FORMAT
]) {
188 bool is_trace_system
= (thread
->getCpuPtr()->system
->name() == trace_system
);
190 bool is_trace_system
= true;
192 if (is_trace_system
) {
193 ccprintf(outs
, "%7d ) ", cycle
);
194 outs
<< "0x" << hex
<< PC
<< ":\t";
195 if (staticInst
->isLoad()) {
196 outs
<< "<RD 0x" << hex
<< addr
;
198 } else if (staticInst
->isStore()) {
199 outs
<< "<WR 0x" << hex
<< addr
;
205 if (flags
[PRINT_CYCLE
])
206 ccprintf(outs
, "%7d: ", cycle
);
208 outs
<< thread
->getCpuPtr()->name() << " ";
210 if (flags
[TRACE_MISSPEC
])
211 outs
<< (misspeculating
? "-" : "+") << " ";
213 if (flags
[PRINT_THREAD_NUM
])
214 outs
<< "T" << thread
->getThreadNum() << " : ";
220 && debugSymbolTable
->findNearestSymbol(PC
, sym_str
, sym_addr
)
221 && flags
[PC_SYMBOL
]) {
223 sym_str
+= csprintf("+%d", PC
- sym_addr
);
224 outs
<< "@" << sym_str
<< " : ";
227 outs
<< "0x" << hex
<< PC
<< " : ";
231 // Print decoded instruction
234 #if defined(__GNUC__) && (__GNUC__ < 3)
235 // There's a bug in gcc 2.x library that prevents setw()
236 // from working properly on strings
237 string
mc(staticInst
->disassemble(PC
, debugSymbolTable
));
238 while (mc
.length() < 26)
242 outs
<< setw(26) << left
<< staticInst
->disassemble(PC
, debugSymbolTable
);
247 if (flags
[PRINT_OP_CLASS
]) {
248 outs
<< opClassStrings
[staticInst
->opClass()] << " : ";
251 if (flags
[PRINT_RESULT_DATA
] && data_status
!= DataInvalid
) {
254 if (data_status
== DataDouble
)
255 ccprintf(outs
, "%f", data
.as_double
);
257 ccprintf(outs
, "%#018x", data
.as_int
);
259 ccprintf(outs
, "%#018x", data
.as_int
);
263 if (flags
[PRINT_EFF_ADDR
] && addr_valid
)
264 outs
<< " A=0x" << hex
<< addr
;
266 if (flags
[PRINT_INT_REGS
] && regs_valid
) {
267 for (int i
= 0; i
< TheISA::NumIntRegs
;)
268 for (int j
= i
+ 1; i
<= j
; i
++)
269 ccprintf(outs
, "r%02d = %#018x%s", i
,
270 iregs
->regs
.readReg(i
),
271 ((i
== j
) ? "\n" : " "));
275 if (flags
[PRINT_FETCH_SEQ
] && fetch_seq_valid
)
276 outs
<< " FetchSeq=" << dec
<< fetch_seq
;
278 if (flags
[PRINT_CP_SEQ
] && cp_seq_valid
)
279 outs
<< " CPSeq=" << dec
<< cp_seq
;
286 #if THE_ISA == SPARC_ISA && FULL_SYSTEM
288 if (flags
[LEGION_LOCKSTEP
])
290 bool compared
= false;
293 bool diffInst
= false;
294 bool diffRegs
= false;
295 bool diffTpc
= false;
296 bool diffTnpc
= false;
297 bool diffTstate
= false;
299 bool diffTba
= false;
300 bool diffHpstate
= false;
301 bool diffHtstate
= false;
302 bool diffHtba
= false;
303 bool diffPstate
= false;
305 bool diffCcr
= false;
308 bool diffAsi
= false;
309 bool diffPil
= false;
310 bool diffCwp
= false;
311 bool diffCansave
= false;
312 bool diffCanrestore
= false;
313 bool diffOtherwin
= false;
314 bool diffCleanwin
= false;
318 if(!staticInst
->isMicroOp() || staticInst
->isLastMicroOp()) {
320 if (shared_data
->flags
== OWN_M5
) {
321 m5Pc
= PC
& TheISA::PAddrImplMask
;
322 lgnPc
= shared_data
->pc
& TheISA::PAddrImplMask
;
326 if (shared_data
->cycle_count
!=
327 thread
->getCpuPtr()->instCount())
330 if (shared_data
->instruction
!=
331 (SparcISA::MachInst
)staticInst
->machInst
) {
334 for (int i
= 0; i
< TheISA::NumIntArchRegs
; i
++) {
335 if (thread
->readIntReg(i
) != shared_data
->intregs
[i
]) {
339 uint64_t oldTl
= thread
->readMiscReg(MISCREG_TL
);
340 if (oldTl
!= shared_data
->tl
)
342 for (int i
= 1; i
<= MaxTL
; i
++) {
343 thread
->setMiscReg(MISCREG_TL
, i
);
344 if (thread
->readMiscReg(MISCREG_TPC
) !=
345 shared_data
->tpc
[i
-1])
347 if (thread
->readMiscReg(MISCREG_TNPC
) !=
348 shared_data
->tnpc
[i
-1])
350 if (thread
->readMiscReg(MISCREG_TSTATE
) !=
351 shared_data
->tstate
[i
-1])
353 if (thread
->readMiscReg(MISCREG_TT
) !=
354 shared_data
->tt
[i
-1])
356 if (thread
->readMiscReg(MISCREG_HTSTATE
) !=
357 shared_data
->htstate
[i
-1])
360 thread
->setMiscReg(MISCREG_TL
, oldTl
);
362 if(shared_data
->tba
!= thread
->readMiscReg(MISCREG_TBA
))
364 //When the hpstate register is read by an instruction,
365 //legion has bit 11 set. When it's in storage, it doesn't.
366 //Since we don't directly support seperate interpretations
367 //of the registers like that, the bit is always set to 1 and
368 //we just don't compare it. It's not supposed to matter
370 if((shared_data
->hpstate
| (1 << 11)) != thread
->readMiscReg(MISCREG_HPSTATE
))
372 if(shared_data
->htba
!= thread
->readMiscReg(MISCREG_HTBA
))
374 if(shared_data
->pstate
!= thread
->readMiscReg(MISCREG_PSTATE
))
376 if(shared_data
->y
!= thread
->readMiscReg(MISCREG_Y
))
378 if(shared_data
->ccr
!= thread
->readMiscReg(MISCREG_CCR
))
380 if(shared_data
->gl
!= thread
->readMiscReg(MISCREG_GL
))
382 if(shared_data
->asi
!= thread
->readMiscReg(MISCREG_ASI
))
384 if(shared_data
->pil
!= thread
->readMiscReg(MISCREG_PIL
))
386 if(shared_data
->cwp
!= thread
->readMiscReg(MISCREG_CWP
))
388 if(shared_data
->cansave
!= thread
->readMiscReg(MISCREG_CANSAVE
))
390 if(shared_data
->canrestore
!=
391 thread
->readMiscReg(MISCREG_CANRESTORE
))
392 diffCanrestore
= true;
393 if(shared_data
->otherwin
!= thread
->readMiscReg(MISCREG_OTHERWIN
))
395 if(shared_data
->cleanwin
!= thread
->readMiscReg(MISCREG_CLEANWIN
))
398 if ((diffPC
|| diffCC
|| diffInst
|| diffRegs
|| diffTpc
||
399 diffTnpc
|| diffTstate
|| diffTt
|| diffHpstate
||
400 diffHtstate
|| diffHtba
|| diffPstate
|| diffY
||
401 diffCcr
|| diffTl
|| diffGl
|| diffAsi
|| diffPil
||
402 diffCwp
|| diffCansave
|| diffCanrestore
||
403 diffOtherwin
|| diffCleanwin
)
404 && !((staticInst
->machInst
& 0xC1F80000) == 0x81D00000)) {
405 outs
<< "Differences found between M5 and Legion:";
411 outs
<< " [Instruction]";
413 outs
<< " [IntRegs]";
423 outs
<< " [Hpstate]";
425 outs
<< " [Htstate]";
445 outs
<< " [Cansave]";
447 outs
<< " [Canrestore]";
449 outs
<< " [Otherwin]";
451 outs
<< " [Cleanwin]";
452 outs
<< endl
<< endl
;
454 outs
<< right
<< setfill(' ') << setw(15)
455 << "M5 PC: " << "0x"<< setw(16) << setfill('0')
456 << hex
<< m5Pc
<< endl
;
457 outs
<< setfill(' ') << setw(15)
458 << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex
459 << lgnPc
<< endl
<< endl
;
461 outs
<< right
<< setfill(' ') << setw(15)
462 << "M5 CC: " << "0x"<< setw(16) << setfill('0')
463 << hex
<< thread
->getCpuPtr()->instCount() << endl
;
464 outs
<< setfill(' ') << setw(15)
465 << "Legion CC: " << "0x"<< setw(16) << setfill('0') << hex
466 << shared_data
->cycle_count
<< endl
<< endl
;
468 outs
<< setfill(' ') << setw(15)
469 << "M5 Inst: " << "0x"<< setw(8)
470 << setfill('0') << hex
<< staticInst
->machInst
471 << staticInst
->disassemble(m5Pc
, debugSymbolTable
)
474 StaticInstPtr legionInst
=
475 StaticInst::decode(makeExtMI(shared_data
->instruction
,
477 outs
<< setfill(' ') << setw(15)
479 << "0x" << setw(8) << setfill('0') << hex
480 << shared_data
->instruction
481 << legionInst
->disassemble(lgnPc
, debugSymbolTable
)
484 printSectionHeader(outs
, "General State");
485 printColumnLabels(outs
);
486 printRegPair(outs
, "HPstate",
487 thread
->readMiscReg(MISCREG_HPSTATE
),
488 shared_data
->hpstate
| (1 << 11));
489 printRegPair(outs
, "Htba",
490 thread
->readMiscReg(MISCREG_HTBA
),
492 printRegPair(outs
, "Pstate",
493 thread
->readMiscReg(MISCREG_PSTATE
),
494 shared_data
->pstate
);
495 printRegPair(outs
, "Y",
496 thread
->readMiscReg(MISCREG_Y
),
498 printRegPair(outs
, "Ccr",
499 thread
->readMiscReg(MISCREG_CCR
),
501 printRegPair(outs
, "Tl",
502 thread
->readMiscReg(MISCREG_TL
),
504 printRegPair(outs
, "Gl",
505 thread
->readMiscReg(MISCREG_GL
),
507 printRegPair(outs
, "Asi",
508 thread
->readMiscReg(MISCREG_ASI
),
510 printRegPair(outs
, "Pil",
511 thread
->readMiscReg(MISCREG_PIL
),
513 printRegPair(outs
, "Cwp",
514 thread
->readMiscReg(MISCREG_CWP
),
516 printRegPair(outs
, "Cansave",
517 thread
->readMiscReg(MISCREG_CANSAVE
),
518 shared_data
->cansave
);
519 printRegPair(outs
, "Canrestore",
520 thread
->readMiscReg(MISCREG_CANRESTORE
),
521 shared_data
->canrestore
);
522 printRegPair(outs
, "Otherwin",
523 thread
->readMiscReg(MISCREG_OTHERWIN
),
524 shared_data
->otherwin
);
525 printRegPair(outs
, "Cleanwin",
526 thread
->readMiscReg(MISCREG_CLEANWIN
),
527 shared_data
->cleanwin
);
529 for (int i
= 1; i
<= MaxTL
; i
++) {
530 printLevelHeader(outs
, i
);
531 printColumnLabels(outs
);
532 thread
->setMiscReg(MISCREG_TL
, i
);
533 printRegPair(outs
, "Tpc",
534 thread
->readMiscReg(MISCREG_TPC
),
535 shared_data
->tpc
[i
-1]);
536 printRegPair(outs
, "Tnpc",
537 thread
->readMiscReg(MISCREG_TNPC
),
538 shared_data
->tnpc
[i
-1]);
539 printRegPair(outs
, "Tstate",
540 thread
->readMiscReg(MISCREG_TSTATE
),
541 shared_data
->tstate
[i
-1]);
542 printRegPair(outs
, "Tt",
543 thread
->readMiscReg(MISCREG_TT
),
544 shared_data
->tt
[i
-1]);
545 printRegPair(outs
, "Htstate",
546 thread
->readMiscReg(MISCREG_HTSTATE
),
547 shared_data
->htstate
[i
-1]);
549 thread
->setMiscReg(MISCREG_TL
, oldTl
);
552 printSectionHeader(outs
, "General Purpose Registers");
553 static const char * regtypes
[4] = {"%g", "%o", "%l", "%i"};
554 for(int y
= 0; y
< 4; y
++)
556 for(int x
= 0; x
< 8; x
++)
559 sprintf(label
, "%s%d", regtypes
[y
], x
);
560 printRegPair(outs
, label
,
561 thread
->readIntReg(y
*8+x
),
562 shared_data
->intregs
[y
*8+x
]);
563 /*outs << regtypes[y] << x << " " ;
564 outs << "0x" << hex << setw(16)
565 << thread->readIntReg(y*8+x);
566 if (thread->readIntReg(y*8 + x)
567 != shared_data->intregs[y*8+x])
571 outs << "0x" << setw(16) << hex
572 << shared_data->intregs[y*8+x]
576 thread
->getITBPtr()->dumpAll();
577 thread
->getDTBPtr()->dumpAll();
581 fatal("Differences found between Legion and M5\n");
585 shared_data
->flags
= OWN_LEGION
;
594 vector
<bool> Trace::InstRecord::flags(NUM_BITS
);
595 string
Trace::InstRecord::trace_system
;
597 ////////////////////////////////////////////////////////////////////////
599 // Parameter space for per-cycle execution address tracing options.
600 // Derive from ParamContext so we can override checkParams() function.
602 class ExecutionTraceParamContext
: public ParamContext
605 ExecutionTraceParamContext(const string
&_iniSection
)
606 : ParamContext(_iniSection
)
610 void checkParams(); // defined at bottom of file
613 ExecutionTraceParamContext
exeTraceParams("exetrace");
615 Param
<bool> exe_trace_spec(&exeTraceParams
, "speculative",
616 "capture speculative instructions", true);
618 Param
<bool> exe_trace_print_cycle(&exeTraceParams
, "print_cycle",
619 "print cycle number", true);
620 Param
<bool> exe_trace_print_opclass(&exeTraceParams
, "print_opclass",
621 "print op class", true);
622 Param
<bool> exe_trace_print_thread(&exeTraceParams
, "print_thread",
623 "print thread number", true);
624 Param
<bool> exe_trace_print_effaddr(&exeTraceParams
, "print_effaddr",
625 "print effective address", true);
626 Param
<bool> exe_trace_print_data(&exeTraceParams
, "print_data",
627 "print result data", true);
628 Param
<bool> exe_trace_print_iregs(&exeTraceParams
, "print_iregs",
629 "print all integer regs", false);
630 Param
<bool> exe_trace_print_fetchseq(&exeTraceParams
, "print_fetchseq",
631 "print fetch sequence number", false);
632 Param
<bool> exe_trace_print_cp_seq(&exeTraceParams
, "print_cpseq",
633 "print correct-path sequence number", false);
634 Param
<bool> exe_trace_print_reg_delta(&exeTraceParams
, "print_reg_delta",
635 "print which registers changed to what", false);
636 Param
<bool> exe_trace_pc_symbol(&exeTraceParams
, "pc_symbol",
637 "Use symbols for the PC if available", true);
638 Param
<bool> exe_trace_intel_format(&exeTraceParams
, "intel_format",
639 "print trace in intel compatible format", false);
640 Param
<bool> exe_trace_legion_lockstep(&exeTraceParams
, "legion_lockstep",
641 "Compare sim state to legion state every cycle",
643 Param
<string
> exe_trace_system(&exeTraceParams
, "trace_system",
644 "print trace of which system (client or server)",
649 // Helper function for ExecutionTraceParamContext::checkParams() just
650 // to get us into the InstRecord namespace
653 Trace::InstRecord::setParams()
655 flags
[TRACE_MISSPEC
] = exe_trace_spec
;
657 flags
[PRINT_CYCLE
] = exe_trace_print_cycle
;
658 flags
[PRINT_OP_CLASS
] = exe_trace_print_opclass
;
659 flags
[PRINT_THREAD_NUM
] = exe_trace_print_thread
;
660 flags
[PRINT_RESULT_DATA
] = exe_trace_print_effaddr
;
661 flags
[PRINT_EFF_ADDR
] = exe_trace_print_data
;
662 flags
[PRINT_INT_REGS
] = exe_trace_print_iregs
;
663 flags
[PRINT_FETCH_SEQ
] = exe_trace_print_fetchseq
;
664 flags
[PRINT_CP_SEQ
] = exe_trace_print_cp_seq
;
665 flags
[PRINT_REG_DELTA
] = exe_trace_print_reg_delta
;
666 flags
[PC_SYMBOL
] = exe_trace_pc_symbol
;
667 flags
[INTEL_FORMAT
] = exe_trace_intel_format
;
668 flags
[LEGION_LOCKSTEP
] = exe_trace_legion_lockstep
;
669 trace_system
= exe_trace_system
;
671 // If were going to be in lockstep with Legion
672 // Setup shared memory, and get otherwise ready
673 if (flags
[LEGION_LOCKSTEP
]) {
674 int shmfd
= shmget('M' << 24 | getuid(), sizeof(SharedData
), 0777);
676 fatal("Couldn't get shared memory fd. Is Legion running?");
678 shared_data
= (SharedData
*)shmat(shmfd
, NULL
, SHM_RND
);
679 if (shared_data
== (SharedData
*)-1)
680 fatal("Couldn't allocate shared memory");
682 if (shared_data
->flags
!= OWN_M5
)
683 fatal("Shared memory has invalid owner");
685 if (shared_data
->version
!= VERSION
)
686 fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION
,
687 shared_data
->version
);
689 // step legion forward one cycle so we can get register values
690 shared_data
->flags
= OWN_LEGION
;
695 ExecutionTraceParamContext::checkParams()
697 Trace::InstRecord::setParams();