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
->readIntReg(SparcISA::NumIntArchRegs
+ 2);
145 //newVal = thread->readMiscReg(SparcISA::MISCREG_CCR);
148 outs
<< " CCR = " << newVal
;
151 newVal
= thread
->readIntReg(SparcISA::NumIntArchRegs
+ 1);
152 //newVal = thread->readMiscReg(SparcISA::MISCREG_Y);
155 outs
<< " Y = " << newVal
;
158 for(int y
= 0; y
< 4; y
++)
160 for(int x
= 0; x
< 8; x
++)
162 int index
= x
+ 8 * y
;
163 newVal
= thread
->readIntReg(index
);
164 if(regs
[index
] != newVal
)
166 outs
<< " " << prefixes
[y
] << dec
<< x
<< " = " << hex
<< newVal
;
167 regs
[index
] = newVal
;
171 for(int y
= 0; y
< 32; y
++)
173 newVal
= thread
->readFloatRegBits(2 * y
, 64);
174 if(floats
[y
] != newVal
)
176 outs
<< " F" << dec
<< (2 * y
) << " = " << hex
<< newVal
;
184 else if (flags
[INTEL_FORMAT
]) {
186 bool is_trace_system
= (thread
->getCpuPtr()->system
->name() == trace_system
);
188 bool is_trace_system
= true;
190 if (is_trace_system
) {
191 ccprintf(outs
, "%7d ) ", cycle
);
192 outs
<< "0x" << hex
<< PC
<< ":\t";
193 if (staticInst
->isLoad()) {
194 outs
<< "<RD 0x" << hex
<< addr
;
196 } else if (staticInst
->isStore()) {
197 outs
<< "<WR 0x" << hex
<< addr
;
203 if (flags
[PRINT_CYCLE
])
204 ccprintf(outs
, "%7d: ", cycle
);
206 outs
<< thread
->getCpuPtr()->name() << " ";
208 if (flags
[TRACE_MISSPEC
])
209 outs
<< (misspeculating
? "-" : "+") << " ";
211 if (flags
[PRINT_THREAD_NUM
])
212 outs
<< "T" << thread
->getThreadNum() << " : ";
218 && debugSymbolTable
->findNearestSymbol(PC
, sym_str
, sym_addr
)
219 && flags
[PC_SYMBOL
]) {
221 sym_str
+= csprintf("+%d", PC
- sym_addr
);
222 outs
<< "@" << sym_str
<< " : ";
225 outs
<< "0x" << hex
<< PC
<< " : ";
229 // Print decoded instruction
232 #if defined(__GNUC__) && (__GNUC__ < 3)
233 // There's a bug in gcc 2.x library that prevents setw()
234 // from working properly on strings
235 string
mc(staticInst
->disassemble(PC
, debugSymbolTable
));
236 while (mc
.length() < 26)
240 outs
<< setw(26) << left
<< staticInst
->disassemble(PC
, debugSymbolTable
);
245 if (flags
[PRINT_OP_CLASS
]) {
246 outs
<< opClassStrings
[staticInst
->opClass()] << " : ";
249 if (flags
[PRINT_RESULT_DATA
] && data_status
!= DataInvalid
) {
252 if (data_status
== DataDouble
)
253 ccprintf(outs
, "%f", data
.as_double
);
255 ccprintf(outs
, "%#018x", data
.as_int
);
257 ccprintf(outs
, "%#018x", data
.as_int
);
261 if (flags
[PRINT_EFF_ADDR
] && addr_valid
)
262 outs
<< " A=0x" << hex
<< addr
;
264 if (flags
[PRINT_INT_REGS
] && regs_valid
) {
265 for (int i
= 0; i
< TheISA::NumIntRegs
;)
266 for (int j
= i
+ 1; i
<= j
; i
++)
267 ccprintf(outs
, "r%02d = %#018x%s", i
,
268 iregs
->regs
.readReg(i
),
269 ((i
== j
) ? "\n" : " "));
273 if (flags
[PRINT_FETCH_SEQ
] && fetch_seq_valid
)
274 outs
<< " FetchSeq=" << dec
<< fetch_seq
;
276 if (flags
[PRINT_CP_SEQ
] && cp_seq_valid
)
277 outs
<< " CPSeq=" << dec
<< cp_seq
;
284 #if THE_ISA == SPARC_ISA
286 if (flags
[LEGION_LOCKSTEP
])
288 bool compared
= false;
290 bool diffInst
= false;
291 bool diffRegs
= false;
292 bool diffTpc
= false;
293 bool diffTnpc
= false;
294 bool diffTstate
= false;
296 bool diffTba
= false;
297 bool diffHpstate
= false;
298 bool diffHtstate
= false;
299 bool diffHtba
= false;
300 bool diffPstate
= false;
302 bool diffCcr
= false;
305 bool diffAsi
= false;
306 bool diffPil
= false;
307 bool diffCwp
= false;
308 bool diffCansave
= false;
309 bool diffCanrestore
= false;
310 bool diffOtherwin
= false;
311 bool diffCleanwin
= false;
315 if(!staticInst
->isMicroOp() || staticInst
->isLastMicroOp()) {
317 if (shared_data
->flags
== OWN_M5
) {
318 m5Pc
= PC
& TheISA::PAddrImplMask
;
319 lgnPc
= shared_data
->pc
& TheISA::PAddrImplMask
;
322 if (shared_data
->instruction
!=
323 (SparcISA::MachInst
)staticInst
->machInst
) {
326 for (int i
= 0; i
< TheISA::NumIntArchRegs
; i
++) {
327 if (thread
->readIntReg(i
) != shared_data
->intregs
[i
]) {
331 uint64_t oldTl
= thread
->readMiscReg(MISCREG_TL
);
332 if (oldTl
!= shared_data
->tl
)
334 for (int i
= 1; i
<= MaxTL
; i
++) {
335 thread
->setMiscReg(MISCREG_TL
, i
);
336 if (thread
->readMiscReg(MISCREG_TPC
) !=
339 if (thread
->readMiscReg(MISCREG_TNPC
) !=
340 shared_data
->tnpc
[i
])
342 if (thread
->readMiscReg(MISCREG_TSTATE
) !=
343 shared_data
->tstate
[i
])
345 if (thread
->readMiscReg(MISCREG_TT
) !=
348 if (thread
->readMiscReg(MISCREG_HTSTATE
) !=
349 shared_data
->htstate
[i
])
352 thread
->setMiscReg(MISCREG_TL
, oldTl
);
354 if(shared_data
->tba
!= thread
->readMiscReg(MISCREG_TBA
))
356 //When the hpstate register is read by an instruction,
357 //legion has bit 11 set. When it's in storage, it doesn't.
358 //Since we don't directly support seperate interpretations
359 //of the registers like that, the bit is always set to 1 and
360 //we just don't compare it. It's not supposed to matter
362 if((shared_data
->hpstate
| (1 << 11)) != thread
->readMiscReg(MISCREG_HPSTATE
))
364 if(shared_data
->htba
!= thread
->readMiscReg(MISCREG_HTBA
))
366 if(shared_data
->pstate
!= thread
->readMiscReg(MISCREG_PSTATE
))
368 //if(shared_data->y != thread->readMiscReg(MISCREG_Y))
370 thread
->readIntReg(NumIntArchRegs
+ 1))
372 //if(shared_data->ccr != thread->readMiscReg(MISCREG_CCR))
373 if(shared_data
->ccr
!=
374 thread
->readIntReg(NumIntArchRegs
+ 2))
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))
385 if(shared_data
->cansave
!=
386 thread
->readIntReg(NumIntArchRegs
+ 3))
388 //if(shared_data->canrestore !=
389 // thread->readMiscReg(MISCREG_CANRESTORE))
390 if(shared_data
->canrestore
!=
391 thread
->readMiscReg(NumIntArchRegs
+ 4))
392 diffCanrestore
= true;
393 //if(shared_data->otherwin != thread->readMiscReg(MISCREG_OTHERWIN))
394 if(shared_data
->otherwin
!=
395 thread
->readIntReg(NumIntArchRegs
+ 5))
397 //if(shared_data->cleanwin != thread->readMiscReg(MISCREG_CLEANWIN))
398 if(shared_data
->cleanwin
!=
399 thread
->readMiscReg(NumIntArchRegs
+ 6))
402 if (diffPC
|| diffInst
|| diffRegs
|| diffTpc
|| diffTnpc
||
403 diffTstate
|| diffTt
|| diffHpstate
||
404 diffHtstate
|| diffHtba
|| diffPstate
|| diffY
||
405 diffCcr
|| diffTl
|| diffGl
|| diffAsi
|| diffPil
||
406 diffCwp
|| diffCansave
|| diffCanrestore
||
407 diffOtherwin
|| diffCleanwin
) {
408 outs
<< "Differences found between M5 and Legion:";
412 outs
<< " [Instruction]";
414 outs
<< " [IntRegs]";
424 outs
<< " [Hpstate]";
426 outs
<< " [Htstate]";
446 outs
<< " [Cansave]";
448 outs
<< " [Canrestore]";
450 outs
<< " [Otherwin]";
452 outs
<< " [Cleanwin]";
453 outs
<< endl
<< endl
;
455 outs
<< right
<< setfill(' ') << setw(15)
456 << "M5 PC: " << "0x"<< setw(16) << setfill('0')
457 << hex
<< m5Pc
<< endl
;
458 outs
<< setfill(' ') << setw(15)
459 << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex
460 << lgnPc
<< endl
<< endl
;
462 outs
<< setfill(' ') << setw(15)
463 << "M5 Inst: " << "0x"<< setw(8)
464 << setfill('0') << hex
<< staticInst
->machInst
465 << staticInst
->disassemble(m5Pc
, debugSymbolTable
)
468 StaticInstPtr legionInst
=
469 StaticInst::decode(makeExtMI(shared_data
->instruction
,
471 outs
<< setfill(' ') << setw(15)
473 << "0x" << setw(8) << setfill('0') << hex
474 << shared_data
->instruction
475 << legionInst
->disassemble(lgnPc
, debugSymbolTable
)
478 printSectionHeader(outs
, "General State");
479 printColumnLabels(outs
);
480 printRegPair(outs
, "HPstate",
481 thread
->readMiscReg(MISCREG_HPSTATE
),
482 shared_data
->hpstate
| (1 << 11));
483 printRegPair(outs
, "Htba",
484 thread
->readMiscReg(MISCREG_HTBA
),
486 printRegPair(outs
, "Pstate",
487 thread
->readMiscReg(MISCREG_PSTATE
),
488 shared_data
->pstate
);
489 printRegPair(outs
, "Y",
490 //thread->readMiscReg(MISCREG_Y),
491 thread
->readMiscReg(NumIntArchRegs
+ 1),
493 printRegPair(outs
, "Ccr",
494 //thread->readMiscReg(MISCREG_CCR),
495 thread
->readMiscReg(NumIntArchRegs
+ 2),
497 printRegPair(outs
, "Tl",
498 thread
->readMiscReg(MISCREG_TL
),
500 printRegPair(outs
, "Gl",
501 thread
->readMiscReg(MISCREG_GL
),
503 printRegPair(outs
, "Asi",
504 thread
->readMiscReg(MISCREG_ASI
),
506 printRegPair(outs
, "Pil",
507 thread
->readMiscReg(MISCREG_PIL
),
509 printRegPair(outs
, "Cwp",
510 thread
->readMiscReg(MISCREG_CWP
),
512 printRegPair(outs
, "Cansave",
513 //thread->readMiscReg(MISCREG_CANSAVE),
514 thread
->readIntReg(NumIntArchRegs
+ 3),
515 shared_data
->cansave
);
516 printRegPair(outs
, "Canrestore",
517 //thread->readMiscReg(MISCREG_CANRESTORE),
518 thread
->readIntReg(NumIntArchRegs
+ 4),
519 shared_data
->canrestore
);
520 printRegPair(outs
, "Otherwin",
521 //thread->readMiscReg(MISCREG_OTHERWIN),
522 thread
->readIntReg(NumIntArchRegs
+ 5),
523 shared_data
->otherwin
);
524 printRegPair(outs
, "Cleanwin",
525 //thread->readMiscReg(MISCREG_CLEANWIN),
526 thread
->readIntReg(NumIntArchRegs
+ 6),
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
]);
536 printRegPair(outs
, "Tnpc",
537 thread
->readMiscReg(MISCREG_TNPC
),
538 shared_data
->tnpc
[i
]);
539 printRegPair(outs
, "Tstate",
540 thread
->readMiscReg(MISCREG_TSTATE
),
541 shared_data
->tstate
[i
]);
542 printRegPair(outs
, "Tt",
543 thread
->readMiscReg(MISCREG_TT
),
545 printRegPair(outs
, "Htstate",
546 thread
->readMiscReg(MISCREG_HTSTATE
),
547 shared_data
->htstate
[i
]);
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 fatal("Differences found between Legion and M5\n");
580 shared_data
->flags
= OWN_LEGION
;
589 vector
<bool> Trace::InstRecord::flags(NUM_BITS
);
590 string
Trace::InstRecord::trace_system
;
592 ////////////////////////////////////////////////////////////////////////
594 // Parameter space for per-cycle execution address tracing options.
595 // Derive from ParamContext so we can override checkParams() function.
597 class ExecutionTraceParamContext
: public ParamContext
600 ExecutionTraceParamContext(const string
&_iniSection
)
601 : ParamContext(_iniSection
)
605 void checkParams(); // defined at bottom of file
608 ExecutionTraceParamContext
exeTraceParams("exetrace");
610 Param
<bool> exe_trace_spec(&exeTraceParams
, "speculative",
611 "capture speculative instructions", true);
613 Param
<bool> exe_trace_print_cycle(&exeTraceParams
, "print_cycle",
614 "print cycle number", true);
615 Param
<bool> exe_trace_print_opclass(&exeTraceParams
, "print_opclass",
616 "print op class", true);
617 Param
<bool> exe_trace_print_thread(&exeTraceParams
, "print_thread",
618 "print thread number", true);
619 Param
<bool> exe_trace_print_effaddr(&exeTraceParams
, "print_effaddr",
620 "print effective address", true);
621 Param
<bool> exe_trace_print_data(&exeTraceParams
, "print_data",
622 "print result data", true);
623 Param
<bool> exe_trace_print_iregs(&exeTraceParams
, "print_iregs",
624 "print all integer regs", false);
625 Param
<bool> exe_trace_print_fetchseq(&exeTraceParams
, "print_fetchseq",
626 "print fetch sequence number", false);
627 Param
<bool> exe_trace_print_cp_seq(&exeTraceParams
, "print_cpseq",
628 "print correct-path sequence number", false);
629 Param
<bool> exe_trace_print_reg_delta(&exeTraceParams
, "print_reg_delta",
630 "print which registers changed to what", false);
631 Param
<bool> exe_trace_pc_symbol(&exeTraceParams
, "pc_symbol",
632 "Use symbols for the PC if available", true);
633 Param
<bool> exe_trace_intel_format(&exeTraceParams
, "intel_format",
634 "print trace in intel compatible format", false);
635 Param
<bool> exe_trace_legion_lockstep(&exeTraceParams
, "legion_lockstep",
636 "Compare sim state to legion state every cycle",
638 Param
<string
> exe_trace_system(&exeTraceParams
, "trace_system",
639 "print trace of which system (client or server)",
644 // Helper function for ExecutionTraceParamContext::checkParams() just
645 // to get us into the InstRecord namespace
648 Trace::InstRecord::setParams()
650 flags
[TRACE_MISSPEC
] = exe_trace_spec
;
652 flags
[PRINT_CYCLE
] = exe_trace_print_cycle
;
653 flags
[PRINT_OP_CLASS
] = exe_trace_print_opclass
;
654 flags
[PRINT_THREAD_NUM
] = exe_trace_print_thread
;
655 flags
[PRINT_RESULT_DATA
] = exe_trace_print_effaddr
;
656 flags
[PRINT_EFF_ADDR
] = exe_trace_print_data
;
657 flags
[PRINT_INT_REGS
] = exe_trace_print_iregs
;
658 flags
[PRINT_FETCH_SEQ
] = exe_trace_print_fetchseq
;
659 flags
[PRINT_CP_SEQ
] = exe_trace_print_cp_seq
;
660 flags
[PRINT_REG_DELTA
] = exe_trace_print_reg_delta
;
661 flags
[PC_SYMBOL
] = exe_trace_pc_symbol
;
662 flags
[INTEL_FORMAT
] = exe_trace_intel_format
;
663 flags
[LEGION_LOCKSTEP
] = exe_trace_legion_lockstep
;
664 trace_system
= exe_trace_system
;
666 // If were going to be in lockstep with Legion
667 // Setup shared memory, and get otherwise ready
668 if (flags
[LEGION_LOCKSTEP
]) {
669 int shmfd
= shmget('M' << 24 | getuid(), sizeof(SharedData
), 0777);
671 fatal("Couldn't get shared memory fd. Is Legion running?");
673 shared_data
= (SharedData
*)shmat(shmfd
, NULL
, SHM_RND
);
674 if (shared_data
== (SharedData
*)-1)
675 fatal("Couldn't allocate shared memory");
677 if (shared_data
->flags
!= OWN_M5
)
678 fatal("Shared memory has invalid owner");
680 if (shared_data
->version
!= VERSION
)
681 fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION
,
682 shared_data
->version
);
684 // step legion forward one cycle so we can get register values
685 shared_data
->flags
= OWN_LEGION
;
690 ExecutionTraceParamContext::checkParams()
692 Trace::InstRecord::setParams();