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
;
61 SharedData
*shared_data
= NULL
;
64 ////////////////////////////////////////////////////////////////////////
66 // Methods for the InstRecord object
69 #if THE_ISA == SPARC_ISA
71 inline char * genCenteredLabel(int length
, char * buffer
, char * label
)
73 int labelLength
= strlen(label
);
74 assert(labelLength
<= length
);
75 int leftPad
= (length
- labelLength
) / 2;
76 int rightPad
= length
- leftPad
- labelLength
;
78 sprintf(format
, "%%%ds%%s%%%ds", leftPad
, rightPad
);
79 sprintf(buffer
, format
, "", label
, "");
83 inline void printRegPair(ostream
& os
, char const * title
, uint64_t a
, uint64_t b
)
85 ccprintf(os
, " %16s | %#018x %s %#-018x \n",
86 title
, a
, (a
== b
) ? "|" : "X", b
);
89 inline void printColumnLabels(ostream
& os
)
91 static char * regLabel
= genCenteredLabel(16, new char[17], "Register");
92 static char * m5Label
= genCenteredLabel(18, new char[18], "M5");
93 static char * legionLabel
= genCenteredLabel(18, new char[18], "Legion");
94 ccprintf(os
, " %s | %s | %s \n", regLabel
, m5Label
, legionLabel
);
95 ccprintf(os
, "--------------------+-----------------------+-----------------------\n");
98 inline void printSectionHeader(ostream
& os
, char * name
)
100 char sectionString
[70];
101 genCenteredLabel(69, sectionString
, name
);
102 ccprintf(os
, "====================================================================\n");
103 ccprintf(os
, "%69s\n", sectionString
);
104 ccprintf(os
, "====================================================================\n");
107 inline void printLevelHeader(ostream
& os
, int level
)
109 char sectionString
[70];
111 sprintf(levelName
, "Trap stack level %d", level
);
112 genCenteredLabel(69, sectionString
, levelName
);
113 ccprintf(os
, "====================================================================\n");
114 ccprintf(os
, "%69s\n", sectionString
);
115 ccprintf(os
, "====================================================================\n");
121 Trace::InstRecord::dump(ostream
&outs
)
123 if (flags
[PRINT_REG_DELTA
])
125 #if THE_ISA == SPARC_ISA
126 //Don't print what happens for each micro-op, just print out
127 //once at the last op, and for regular instructions.
128 if(!staticInst
->isMicroOp() || staticInst
->isLastMicroOp())
130 static uint64_t regs
[32] = {
131 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0, 0};
135 static uint64_t ccr
= 0;
136 static uint64_t y
= 0;
137 static uint64_t floats
[32];
139 static const char * prefixes
[4] = {"G", "O", "L", "I"};
142 outs
<< "PC = " << thread
->readNextPC();
143 outs
<< " NPC = " << thread
->readNextNPC();
144 newVal
= thread
->readMiscReg(SparcISA::MISCREG_CCR
);
147 outs
<< " CCR = " << newVal
;
150 newVal
= thread
->readMiscReg(SparcISA::MISCREG_Y
);
153 outs
<< " Y = " << newVal
;
156 for(int y
= 0; y
< 4; y
++)
158 for(int x
= 0; x
< 8; x
++)
160 int index
= x
+ 8 * y
;
161 newVal
= thread
->readIntReg(index
);
162 if(regs
[index
] != newVal
)
164 outs
<< " " << prefixes
[y
] << dec
<< x
<< " = " << hex
<< newVal
;
165 regs
[index
] = newVal
;
169 for(int y
= 0; y
< 32; y
++)
171 newVal
= thread
->readFloatRegBits(2 * y
, 64);
172 if(floats
[y
] != newVal
)
174 outs
<< " F" << dec
<< (2 * y
) << " = " << hex
<< newVal
;
182 else if (flags
[INTEL_FORMAT
]) {
184 bool is_trace_system
= (thread
->getCpuPtr()->system
->name() == trace_system
);
186 bool is_trace_system
= true;
188 if (is_trace_system
) {
189 ccprintf(outs
, "%7d ) ", cycle
);
190 outs
<< "0x" << hex
<< PC
<< ":\t";
191 if (staticInst
->isLoad()) {
192 outs
<< "<RD 0x" << hex
<< addr
;
194 } else if (staticInst
->isStore()) {
195 outs
<< "<WR 0x" << hex
<< addr
;
201 if (flags
[PRINT_CYCLE
])
202 ccprintf(outs
, "%7d: ", cycle
);
204 outs
<< thread
->getCpuPtr()->name() << " ";
206 if (flags
[TRACE_MISSPEC
])
207 outs
<< (misspeculating
? "-" : "+") << " ";
209 if (flags
[PRINT_THREAD_NUM
])
210 outs
<< "T" << thread
->getThreadNum() << " : ";
216 && debugSymbolTable
->findNearestSymbol(PC
, sym_str
, sym_addr
)
217 && flags
[PC_SYMBOL
]) {
219 sym_str
+= csprintf("+%d", PC
- sym_addr
);
220 outs
<< "@" << sym_str
<< " : ";
223 outs
<< "0x" << hex
<< PC
<< " : ";
227 // Print decoded instruction
230 #if defined(__GNUC__) && (__GNUC__ < 3)
231 // There's a bug in gcc 2.x library that prevents setw()
232 // from working properly on strings
233 string
mc(staticInst
->disassemble(PC
, debugSymbolTable
));
234 while (mc
.length() < 26)
238 outs
<< setw(26) << left
<< staticInst
->disassemble(PC
, debugSymbolTable
);
243 if (flags
[PRINT_OP_CLASS
]) {
244 outs
<< opClassStrings
[staticInst
->opClass()] << " : ";
247 if (flags
[PRINT_RESULT_DATA
] && data_status
!= DataInvalid
) {
250 if (data_status
== DataDouble
)
251 ccprintf(outs
, "%f", data
.as_double
);
253 ccprintf(outs
, "%#018x", data
.as_int
);
255 ccprintf(outs
, "%#018x", data
.as_int
);
259 if (flags
[PRINT_EFF_ADDR
] && addr_valid
)
260 outs
<< " A=0x" << hex
<< addr
;
262 if (flags
[PRINT_INT_REGS
] && regs_valid
) {
263 for (int i
= 0; i
< TheISA::NumIntRegs
;)
264 for (int j
= i
+ 1; i
<= j
; i
++)
265 ccprintf(outs
, "r%02d = %#018x%s", i
,
266 iregs
->regs
.readReg(i
),
267 ((i
== j
) ? "\n" : " "));
271 if (flags
[PRINT_FETCH_SEQ
] && fetch_seq_valid
)
272 outs
<< " FetchSeq=" << dec
<< fetch_seq
;
274 if (flags
[PRINT_CP_SEQ
] && cp_seq_valid
)
275 outs
<< " CPSeq=" << dec
<< cp_seq
;
282 #if THE_ISA == SPARC_ISA && FULL_SYSTEM
284 if (flags
[LEGION_LOCKSTEP
])
286 bool compared
= false;
289 bool diffInst
= false;
290 bool diffRegs
= false;
291 bool diffTpc
= false;
292 bool diffTnpc
= false;
293 bool diffTstate
= false;
295 bool diffTba
= false;
296 bool diffHpstate
= false;
297 bool diffHtstate
= false;
298 bool diffHtba
= false;
299 bool diffPstate
= false;
301 bool diffCcr
= false;
304 bool diffAsi
= false;
305 bool diffPil
= false;
306 bool diffCwp
= false;
307 bool diffCansave
= false;
308 bool diffCanrestore
= false;
309 bool diffOtherwin
= false;
310 bool diffCleanwin
= false;
314 if(!staticInst
->isMicroOp() || staticInst
->isLastMicroOp()) {
316 if (shared_data
->flags
== OWN_M5
) {
317 m5Pc
= PC
& TheISA::PAddrImplMask
;
318 lgnPc
= shared_data
->pc
& TheISA::PAddrImplMask
;
322 if (shared_data
->cycle_count
!=
323 thread
->getCpuPtr()->instCount())
326 if (shared_data
->instruction
!=
327 (SparcISA::MachInst
)staticInst
->machInst
) {
330 for (int i
= 0; i
< TheISA::NumIntArchRegs
; i
++) {
331 if (thread
->readIntReg(i
) != shared_data
->intregs
[i
]) {
335 uint64_t oldTl
= thread
->readMiscReg(MISCREG_TL
);
336 if (oldTl
!= shared_data
->tl
)
338 for (int i
= 1; i
<= MaxTL
; i
++) {
339 thread
->setMiscReg(MISCREG_TL
, i
);
340 if (thread
->readMiscReg(MISCREG_TPC
) !=
341 shared_data
->tpc
[i
-1])
343 if (thread
->readMiscReg(MISCREG_TNPC
) !=
344 shared_data
->tnpc
[i
-1])
346 if (thread
->readMiscReg(MISCREG_TSTATE
) !=
347 shared_data
->tstate
[i
-1])
349 if (thread
->readMiscReg(MISCREG_TT
) !=
350 shared_data
->tt
[i
-1])
352 if (thread
->readMiscReg(MISCREG_HTSTATE
) !=
353 shared_data
->htstate
[i
-1])
356 thread
->setMiscReg(MISCREG_TL
, oldTl
);
358 if(shared_data
->tba
!= thread
->readMiscReg(MISCREG_TBA
))
360 //When the hpstate register is read by an instruction,
361 //legion has bit 11 set. When it's in storage, it doesn't.
362 //Since we don't directly support seperate interpretations
363 //of the registers like that, the bit is always set to 1 and
364 //we just don't compare it. It's not supposed to matter
366 if((shared_data
->hpstate
| (1 << 11)) != thread
->readMiscReg(MISCREG_HPSTATE
))
368 if(shared_data
->htba
!= thread
->readMiscReg(MISCREG_HTBA
))
370 if(shared_data
->pstate
!= thread
->readMiscReg(MISCREG_PSTATE
))
372 if(shared_data
->y
!= thread
->readMiscReg(MISCREG_Y
))
374 if(shared_data
->ccr
!= thread
->readMiscReg(MISCREG_CCR
))
376 if(shared_data
->gl
!= thread
->readMiscReg(MISCREG_GL
))
378 if(shared_data
->asi
!= thread
->readMiscReg(MISCREG_ASI
))
380 if(shared_data
->pil
!= thread
->readMiscReg(MISCREG_PIL
))
382 if(shared_data
->cwp
!= thread
->readMiscReg(MISCREG_CWP
))
384 if(shared_data
->cansave
!= thread
->readMiscReg(MISCREG_CANSAVE
))
386 if(shared_data
->canrestore
!=
387 thread
->readMiscReg(MISCREG_CANRESTORE
))
388 diffCanrestore
= true;
389 if(shared_data
->otherwin
!= thread
->readMiscReg(MISCREG_OTHERWIN
))
391 if(shared_data
->cleanwin
!= thread
->readMiscReg(MISCREG_CLEANWIN
))
394 if (diffPC
|| diffCC
|| diffInst
|| diffRegs
|| diffTpc
||
395 diffTnpc
|| diffTstate
|| diffTt
|| diffHpstate
||
396 diffHtstate
|| diffHtba
|| diffPstate
|| diffY
||
397 diffCcr
|| diffTl
|| diffGl
|| diffAsi
|| diffPil
||
398 diffCwp
|| diffCansave
|| diffCanrestore
||
399 diffOtherwin
|| diffCleanwin
) {
400 outs
<< "Differences found between M5 and Legion:";
406 outs
<< " [Instruction]";
408 outs
<< " [IntRegs]";
418 outs
<< " [Hpstate]";
420 outs
<< " [Htstate]";
440 outs
<< " [Cansave]";
442 outs
<< " [Canrestore]";
444 outs
<< " [Otherwin]";
446 outs
<< " [Cleanwin]";
447 outs
<< endl
<< endl
;
449 outs
<< right
<< setfill(' ') << setw(15)
450 << "M5 PC: " << "0x"<< setw(16) << setfill('0')
451 << hex
<< m5Pc
<< endl
;
452 outs
<< setfill(' ') << setw(15)
453 << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex
454 << lgnPc
<< endl
<< endl
;
456 outs
<< right
<< setfill(' ') << setw(15)
457 << "M5 CC: " << "0x"<< setw(16) << setfill('0')
458 << hex
<< thread
->getCpuPtr()->instCount() << endl
;
459 outs
<< setfill(' ') << setw(15)
460 << "Legion CC: " << "0x"<< setw(16) << setfill('0') << hex
461 << shared_data
->cycle_count
<< endl
<< endl
;
463 outs
<< setfill(' ') << setw(15)
464 << "M5 Inst: " << "0x"<< setw(8)
465 << setfill('0') << hex
<< staticInst
->machInst
466 << staticInst
->disassemble(m5Pc
, debugSymbolTable
)
469 StaticInstPtr legionInst
=
470 StaticInst::decode(makeExtMI(shared_data
->instruction
,
472 outs
<< setfill(' ') << setw(15)
474 << "0x" << setw(8) << setfill('0') << hex
475 << shared_data
->instruction
476 << legionInst
->disassemble(lgnPc
, debugSymbolTable
)
479 printSectionHeader(outs
, "General State");
480 printColumnLabels(outs
);
481 printRegPair(outs
, "HPstate",
482 thread
->readMiscReg(MISCREG_HPSTATE
),
483 shared_data
->hpstate
| (1 << 11));
484 printRegPair(outs
, "Htba",
485 thread
->readMiscReg(MISCREG_HTBA
),
487 printRegPair(outs
, "Pstate",
488 thread
->readMiscReg(MISCREG_PSTATE
),
489 shared_data
->pstate
);
490 printRegPair(outs
, "Y",
491 thread
->readMiscReg(MISCREG_Y
),
493 printRegPair(outs
, "Ccr",
494 thread
->readMiscReg(MISCREG_CCR
),
496 printRegPair(outs
, "Tl",
497 thread
->readMiscReg(MISCREG_TL
),
499 printRegPair(outs
, "Gl",
500 thread
->readMiscReg(MISCREG_GL
),
502 printRegPair(outs
, "Asi",
503 thread
->readMiscReg(MISCREG_ASI
),
505 printRegPair(outs
, "Pil",
506 thread
->readMiscReg(MISCREG_PIL
),
508 printRegPair(outs
, "Cwp",
509 thread
->readMiscReg(MISCREG_CWP
),
511 printRegPair(outs
, "Cansave",
512 thread
->readMiscReg(MISCREG_CANSAVE
),
513 shared_data
->cansave
);
514 printRegPair(outs
, "Canrestore",
515 thread
->readMiscReg(MISCREG_CANRESTORE
),
516 shared_data
->canrestore
);
517 printRegPair(outs
, "Otherwin",
518 thread
->readMiscReg(MISCREG_OTHERWIN
),
519 shared_data
->otherwin
);
520 printRegPair(outs
, "Cleanwin",
521 thread
->readMiscReg(MISCREG_CLEANWIN
),
522 shared_data
->cleanwin
);
524 for (int i
= 1; i
<= MaxTL
; i
++) {
525 printLevelHeader(outs
, i
);
526 printColumnLabels(outs
);
527 thread
->setMiscReg(MISCREG_TL
, i
);
528 printRegPair(outs
, "Tpc",
529 thread
->readMiscReg(MISCREG_TPC
),
530 shared_data
->tpc
[i
-1]);
531 printRegPair(outs
, "Tnpc",
532 thread
->readMiscReg(MISCREG_TNPC
),
533 shared_data
->tnpc
[i
-1]);
534 printRegPair(outs
, "Tstate",
535 thread
->readMiscReg(MISCREG_TSTATE
),
536 shared_data
->tstate
[i
-1]);
537 printRegPair(outs
, "Tt",
538 thread
->readMiscReg(MISCREG_TT
),
539 shared_data
->tt
[i
-1]);
540 printRegPair(outs
, "Htstate",
541 thread
->readMiscReg(MISCREG_HTSTATE
),
542 shared_data
->htstate
[i
-1]);
544 thread
->setMiscReg(MISCREG_TL
, oldTl
);
547 printSectionHeader(outs
, "General Purpose Registers");
548 static const char * regtypes
[4] = {"%g", "%o", "%l", "%i"};
549 for(int y
= 0; y
< 4; y
++)
551 for(int x
= 0; x
< 8; x
++)
554 sprintf(label
, "%s%d", regtypes
[y
], x
);
555 printRegPair(outs
, label
,
556 thread
->readIntReg(y
*8+x
),
557 shared_data
->intregs
[y
*8+x
]);
558 /*outs << regtypes[y] << x << " " ;
559 outs << "0x" << hex << setw(16)
560 << thread->readIntReg(y*8+x);
561 if (thread->readIntReg(y*8 + x)
562 != shared_data->intregs[y*8+x])
566 outs << "0x" << setw(16) << hex
567 << shared_data->intregs[y*8+x]
571 fatal("Differences found between Legion and M5\n");
575 shared_data
->flags
= OWN_LEGION
;
584 vector
<bool> Trace::InstRecord::flags(NUM_BITS
);
585 string
Trace::InstRecord::trace_system
;
587 ////////////////////////////////////////////////////////////////////////
589 // Parameter space for per-cycle execution address tracing options.
590 // Derive from ParamContext so we can override checkParams() function.
592 class ExecutionTraceParamContext
: public ParamContext
595 ExecutionTraceParamContext(const string
&_iniSection
)
596 : ParamContext(_iniSection
)
600 void checkParams(); // defined at bottom of file
603 ExecutionTraceParamContext
exeTraceParams("exetrace");
605 Param
<bool> exe_trace_spec(&exeTraceParams
, "speculative",
606 "capture speculative instructions", true);
608 Param
<bool> exe_trace_print_cycle(&exeTraceParams
, "print_cycle",
609 "print cycle number", true);
610 Param
<bool> exe_trace_print_opclass(&exeTraceParams
, "print_opclass",
611 "print op class", true);
612 Param
<bool> exe_trace_print_thread(&exeTraceParams
, "print_thread",
613 "print thread number", true);
614 Param
<bool> exe_trace_print_effaddr(&exeTraceParams
, "print_effaddr",
615 "print effective address", true);
616 Param
<bool> exe_trace_print_data(&exeTraceParams
, "print_data",
617 "print result data", true);
618 Param
<bool> exe_trace_print_iregs(&exeTraceParams
, "print_iregs",
619 "print all integer regs", false);
620 Param
<bool> exe_trace_print_fetchseq(&exeTraceParams
, "print_fetchseq",
621 "print fetch sequence number", false);
622 Param
<bool> exe_trace_print_cp_seq(&exeTraceParams
, "print_cpseq",
623 "print correct-path sequence number", false);
624 Param
<bool> exe_trace_print_reg_delta(&exeTraceParams
, "print_reg_delta",
625 "print which registers changed to what", false);
626 Param
<bool> exe_trace_pc_symbol(&exeTraceParams
, "pc_symbol",
627 "Use symbols for the PC if available", true);
628 Param
<bool> exe_trace_intel_format(&exeTraceParams
, "intel_format",
629 "print trace in intel compatible format", false);
630 Param
<bool> exe_trace_legion_lockstep(&exeTraceParams
, "legion_lockstep",
631 "Compare sim state to legion state every cycle",
633 Param
<string
> exe_trace_system(&exeTraceParams
, "trace_system",
634 "print trace of which system (client or server)",
639 // Helper function for ExecutionTraceParamContext::checkParams() just
640 // to get us into the InstRecord namespace
643 Trace::InstRecord::setParams()
645 flags
[TRACE_MISSPEC
] = exe_trace_spec
;
647 flags
[PRINT_CYCLE
] = exe_trace_print_cycle
;
648 flags
[PRINT_OP_CLASS
] = exe_trace_print_opclass
;
649 flags
[PRINT_THREAD_NUM
] = exe_trace_print_thread
;
650 flags
[PRINT_RESULT_DATA
] = exe_trace_print_effaddr
;
651 flags
[PRINT_EFF_ADDR
] = exe_trace_print_data
;
652 flags
[PRINT_INT_REGS
] = exe_trace_print_iregs
;
653 flags
[PRINT_FETCH_SEQ
] = exe_trace_print_fetchseq
;
654 flags
[PRINT_CP_SEQ
] = exe_trace_print_cp_seq
;
655 flags
[PRINT_REG_DELTA
] = exe_trace_print_reg_delta
;
656 flags
[PC_SYMBOL
] = exe_trace_pc_symbol
;
657 flags
[INTEL_FORMAT
] = exe_trace_intel_format
;
658 flags
[LEGION_LOCKSTEP
] = exe_trace_legion_lockstep
;
659 trace_system
= exe_trace_system
;
661 // If were going to be in lockstep with Legion
662 // Setup shared memory, and get otherwise ready
663 if (flags
[LEGION_LOCKSTEP
]) {
664 int shmfd
= shmget('M' << 24 | getuid(), sizeof(SharedData
), 0777);
666 fatal("Couldn't get shared memory fd. Is Legion running?");
668 shared_data
= (SharedData
*)shmat(shmfd
, NULL
, SHM_RND
);
669 if (shared_data
== (SharedData
*)-1)
670 fatal("Couldn't allocate shared memory");
672 if (shared_data
->flags
!= OWN_M5
)
673 fatal("Shared memory has invalid owner");
675 if (shared_data
->version
!= VERSION
)
676 fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION
,
677 shared_data
->version
);
679 // step legion forward one cycle so we can get register values
680 shared_data
->flags
= OWN_LEGION
;
685 ExecutionTraceParamContext::checkParams()
687 Trace::InstRecord::setParams();