# Script to aid tracing and debugging assembly language diags with the N2 based
# sparc bench. The script reads in the vcs.log file and extracts executed
# instruction and state deltas from the log file. It then allows for printing
# the architeced state at any instruction boundary.
# Requires that the log file have the state delta information (+show_delta).
# $state{$thread}{$instr}{$regname} = value;
# $trace{$thread}{$instr} = <string>
# $fulltrace{$instr} = <string>
# $delta{$thread}{$instr}{reg} = value
# $current{$thread} = <current instr number>
# Track CWP/GL and display for appropriate CWP/GL
# $cwp{$thread}{win}{instr}{regname} = value
# $gl{$thread}{level}{instr}{regname} = value
# $symbols{address} = label
# $offset{tid}{address} = label+offset
chomp(my $prog=`basename $0`);
#chomp(my $progpath=`dirname $0`);
my $progpath = $ENV{DV_ROOT
}."/tools/src";
my $symfile = "symbol.tbl";
my $diagexe = "diag.exe";
our $dis_cmd = (-x
"$progpath/dis") ?
"$progpath/dis " : "g_objdump -dS ";
our $num_threads_per_node = 64;
our $num_threads_per_core = 8;
my $statetype = 0; # Expected = 0, Actual = 1
my $addr_blurb = "Consume less. Share more. Enjoy life";
my $status_blurb = "Insanity: Doing The Same Thing Over And Over Again And Expecting Different Results.";
# Reg definitions and expansions {{{
my @globals = qw(g0 g1 g2 g3 g4 g5 g6 g7);
my @windows = qw(o0 o1 o2 o3 o4 o5 o6 o7
i0 i1 i2 i3 i4 i5 i6 i7);
our @allregs = qw(f0 f2 f4 f6 f8 f10 f12 f14
f16 f18 f20 f22 f24 f26 f28 f30
f32 f34 f36 f38 f40 f42 f44 f46
f48 f50 f52 f54 f56 f58 f60 f62
PC NPC CWP CCR FPRS FSR PSTATE
CANSAVE CANRESTORE CLEANWIN OTHERWIN
TICK_CMPR STICK_CMPR HSTICK_CMPR
HINTP SOFTINT GSR INTR_RECEIVE
HTSTATE1 HTSTATE2 HTSTATE3 HTSTATE4
LSU_CONTROL WATCHPOINT_ADDR
I_TAG_ACC D_TAG_ACC DSFAR
CTXT_Z_TSB_CFG0 CTXT_Z_TSB_CFG1
CTXT_Z_TSB_CFG2 CTXT_Z_TSB_CFG3
CTXT_NZ_TSB_CFG0 CTXT_NZ_TSB_CFG1
CTXT_NZ_TSB_CFG2 CTXT_NZ_TSB_CFG3
"HPSTATE" => {'0:0'=>"tlz", '2:2'=>"hpriv", '5:5'=>"red",
"PSTATE" => {'1:1'=>"ie", '2:2'=>"priv", '3:3'=>"am",
'4:4'=>"pef", '8:8'=>"tle", '9:9'=>"cle",
"CCR" => {'0:0'=>"icc.c", '1:1'=>"icc.v", '2:2'=>"icc.z",
'4:4'=>"xcc.c", '5:5'=>"xcc.v", '6:6'=>"xcc.z",
"FPRS" => {'0:0'=>"dl", '2:2'=>"du", '3:3'=>"fef"},
"FSR" => {'10:11'=>"fcc0",'5:9'=>"aexc",'0:4'=>"cexc",
'13:13'=>"qne",'14:16'=>"ftt",'17:19'=>"\nver",
'22:22'=>"ns",'23:27'=>"tem",'30:31'=>"rd",
'32:33'=>"fcc1",'34:35'=>"fcc2",'36:37'=>"fcc3"},
"GSR" => {'0:2'=>"align", '3:7'=>"scale", '8:15'=>"gcc",
'24:24'=>"gq_rdy", '25.:6'=>"irnd", '27:27'=>"\nim",
"TSTATE1" => {'0:4'=>"cwp", '8:20'=>"\npstate",
'24:31'=>"asi", '32:39'=>"ccr",
"TSTATE2" => {'0:4'=>"cwp", '8:20'=>"\npstate",
'24:31'=>"asi", '32:39'=>"ccr",
"TSTATE3" => {'0:4'=>"cwp", '8:20'=>"\npstate",
'24:31'=>"asi", '32:39'=>"ccr",
"TSTATE4" => {'0:4'=>"cwp", '8:20'=>"\npstate",
'24:31'=>"asi", '32:39'=>"ccr",
"TSTATE5" => {'0:4'=>"cwp", '8:20'=>"\npstate",
'24:31'=>"asi", '32:39'=>"ccr",
"TSTATE6" => {'0:4'=>"cwp", '8:20'=>"\npstate",
'24:31'=>"asi", '32:39'=>"ccr",
"LSU_CONTROL" => { '0:0'=>"ic", '1:1'=>"dc", '2:2'=>"im",
'3:3'=>"dm", '4:4'=>"se", '23:23'=>"we", '24:24'=>"re",
'25:32'=>"bm", '33:34'=>"mode"},
"CTXT_Z_TSB_CFG0" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_Z_TSB_CFG1" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_Z_TSB_CFG2" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_Z_TSB_CFG3" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_NZ_TSB_CFG0" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_NZ_TSB_CFG1" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_NZ_TSB_CFG2" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
"CTXT_NZ_TSB_CFG3" => {'0:3'=>"tsb_size", '4:6'=>"page_size",
'8:8'=>"\nra_not_pa", '13:39'=>"\ntsb_base",
'61:61'=>"use_context_1", '62:62'=>"use_context_0",
$project = (defined($ENV{PROJECT
})&& -r
"$progpath/defaults.$ENV{PROJECTLC}") ?
$ENV{PROJECTLC
} : "generic";
if (-r
"$progpath/defaults.$project") {
require "$progpath/defaults.$project";
Gtrace is a script to aid in tracing processor architectural state for
Gtrace requires that the simulation log file contain delta state
information. This is generated by using \"-vcs_run_args=+show_delta\" as
If gtrace is being invoked with the \"-s\" option to load Riesling's
sas.log, then Riesling must have been run with
\"-sas_run_args=-DPLI_DEBUG=2\" to provide the delta state information in
Gtrace provides the following controls and aids :
Reload the simulation logs without needing to quit and re-invoke
Reload the simulation log ONLY without needing to quit and re-invoke
These checkbuttons will allow you to select which thread to trace and
display in the Trace and State panels. Thread 0 (T0) is the default
selected thread. This is a tear-away menu.
Merge All: This selection allows you to merge all thread traces
together. Clicking on a trace line will display the state
for the particular thread selected.
Single steps the trace. Incremental changes are highlighted.
Quick means of going to first, last instrucion in trace window.
Choice of displaying the 'EXPECTED' Vs 'ACTUAL/DUT' values for logs
that have cosimulation enabled.
Chose to increase or decrease font sizes in the various panes.
Invoke additional debug tools
This panel displays the trace of the simulation for the selected
thread. Clicking on a trace line will cause the State panel to
display the architectural state after the execution of the seleceted
instruction for the selected thread.
If a symbol file is found (symbol.tbl), labels are inserted at the
correct positions in the trace.
Right-clicking on the panel will bring up search functions.
Shows the current instruction's offset from nearest (previous) label.
Shows the current instruction for which the state is being displayed.
This panel shows the architected register values at the completion of
the selected instruction.
Incremental changes for the instruction selected are highlighted.
Right-clicking on the panel will bring up search functions.
Hovering the cursor over some of the registers will show exploded
Gtrace will honor X resource attributes (typically specified in
~/.Xdefaults). Fonts, back/foreground colors etc may be secified
gtrace*font: -adobe-courier-medium-r-normal--14-120-75-75-m-70-iso8859-1
etc, and loaded immediately using xrdb -merge ...
Please report bugs/enhancement requests in Metrax.
- Save trace and state to file
- Show memory contents (when/where written..)
"\nINFO > Script to aid in tracing Arch state via VCS logfile.",
"\nINFO > The simulation must have delta state dumped at run time",
"\nINFO > A log file (and optionally the symbol table) must exist in ",
"\nINFO > the current directory or be specified as an argument\n\n",
"\nINFO > Usage $prog [options] " ,
"\nINFO > Options are :" ,
"\nINFO > -log <file> : use <file> as input instead of vcs.log",
"\nINFO > -s : expect to read sas.log instead of vcs",
"\nINFO > -t : non-gui trace to stdout",
"\nINFO > -m : Startup with all traces merged",
"\nINFO > -g : GATESIM: don't look for state-delta in vcs log file",
"\nINFO > -nodis : Skip disassembly if needing to disassemble",
"\nINFO > -usedis=file : Use the specifed existing file for disassembly",
"\nINFO > -x <value> : Limit reading upto time \@<value> (vcs.log only)",
"\nINFO > -c <n[,n]*> : Scan for specified virtual cores only",
&GetOptions
("log=s" => \
$logfile,
if ($saslog && $logfile eq "vcs.log") {$logfile = "sas.log"}
if (!$char && $ENV{DISPLAY
}) {
$char = 1; # Non Gui mode
# Figure out which files are around
if (!$gates && ! have_deltas
()) {
usage
( "\nERROR > Could not find a logfile with show_delta information.",
"\n Please run simulation with \"-vcs_run_args=+show_delta\"",
"\n OR \"-sas_run_args=-DPLI_DEBUG=2\" for sas deltas\"",
# Get list of restricted cores ..
foreach (split(/,/, $cores)) {
###############################################################################
# Boot Up .. Read all files .. {{{
if (-r
$symfile || -r
"$symfile.gz") {
# Do we need disassembly ?
slurp_disas
() if (! $nodisas);
if ($gates) {slurp_barelog
()}
elsif ($saslog) {slurp_saslog
()}
###############################################################################
if (!$char) { ## {{{ GUI Stuff
# Set up the main windows
my $main_w = new MainWindow
;
$main_w -> title
("gtrace :($ENV{PWD}) $logfile");
$main_w -> iconname
("gtrace: ($ENV{PWD} $logfile");
$main_w -> appname
('gtrace');
my $main_m = $main_w -> Menu
(-type
=> 'menubar', -bd
=> 1);
$main_w -> configure
(-menu
=> $main_m);
my $file_m = $main_m -> cascade
(-label
=> '~File', -tearoff
=> 0);
$file_m ->command(-label
=> 'Reload',
-command
=> sub {bootup
();
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
$status_t -> insert
("0.0", "Reloading.. ");
$trace_t->configure(-state=>'normal');
$trace_t->delete("0.0", 'end');
show_trace
($trace_t, $status_t, $addr_t, $tid);
$trace_t->configure(-state=>'disabled');
$state_t -> configure
(-state => 'normal');
$state_t->delete("0.0", 'end');
$state_t -> insert
("0.0", show_state
($tid,-1));
tagstate
($state_t, $balloon);
$state_t -> configure
(-state => 'disabled');
$status_t ->delete("0.0", 'end');
$status_t -> insert
("0.0", "Reloaded");
$status_t->configure(-state =>'disabled');
$file_m ->command(-label
=> 'Reload Log Only',
if ($gates) {slurp_barelog
()}
elsif ($saslog) {slurp_saslog
()}
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
$status_t -> insert
("0.0", "Reloading.. ");
$trace_t->configure(-state=>'normal');
$trace_t->delete("0.0", 'end');
show_trace
($trace_t, $status_t, $addr_t, $tid);
$trace_t->configure(-state=>'disabled');
$state_t -> configure
(-state => 'normal');
$state_t->delete("0.0", 'end');
$state_t -> insert
("0.0", show_state
($tid,-1));
tagstate
($state_t, $balloon);
$state_t -> configure
(-state => 'disabled');
$status_t ->delete("0.0", 'end');
$status_t -> insert
("0.0", "Reloaded");
$status_t->configure(-state =>'disabled');
$file_m ->command(-label
=> 'Save Current [Viewed] Trace ',
= $main_w->FileSelect(-directory
=>"./")->Show;
if (defined $tracefile) {
open (TF
, ">$tracefile") ||
warn "Could not open \"$tracefile\" for writing!, $!\n";
print TF
$trace_t->get("0.0",'end'), "\n";
$file_m ->command(-label
=> 'Quit', -command
=> sub {exit});
my $tid_m = $main_m -> cascade
(-label
=> '~Thread', -tearoff
=> 1);
$tid_m -> radiobutton
(-label
=> 'Merge All', -variable
=> \
$merge,
$trace_t->configure(-state =>'normal');
$trace_t ->delete ("0.0",'end');
show_trace
($trace_t, $status_t, $addr_t, $tid);
$trace_t->configure(-state=>'disabled');
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
tagstate
($state_t,$balloon);
$state_t->configure(-state=>'disabled');
foreach $cid (0 .. int(($numthreads-1)/$num_threads_per_core)) {
map {$anythd++ if ($state{$cid*$num_threads_per_core+$_})}
0..$num_threads_per_core-1;
my $cid_m = $tid_m -> cascade
(-label
=> 'C'.$cid, -tearoff
=> 1);
$temp = $cid*$num_threads_per_core+$_;
if (defined $trace{$temp}) {
$cid_m -> radiobutton
(-label
=> 'T'.$temp, -variable
=> \
$tid,
$trace_t->configure(-state =>'normal');
$trace_t ->delete ("0.0",'end');
show_trace
($trace_t, $status_t, $addr_t, $tid);
$trace_t->configure(-state=>'disabled');
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
my $step_m = $main_m -> command
(-label
=> '~Step' ,
-command
=> sub {my ($mtid, $instr) =
which_instr
($status_t->get ("0.0", "end"));
$instr = get_next_instr
($mtid, $instr);
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
show_state
($mtid, $instr));
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
->insert("0.0",$trace{$mtid}{$instr});
$status_t->configure(-state =>'disabled');
$addr_t->configure(-state =>'normal');
$addr_t ->delete("0.0", 'end');
->insert("0.0",$offset{$mtid}{$instr});
$addr_t->configure(-state =>'disabled');
$trace_t->tagRemove('curr', '0.0', 'end');
my $index = $trace_t->search($trace{$mtid}{$instr}, '0.0', 'end');
$trace_t->index("$index linestart"),
$trace_t->index("$index lineend"));
$trace_t->see($trace_t->index("$index linestart"));
my $goto_m = $main_m -> cascade
(-label
=> '~Goto', -tearoff
=> 1) ;
$goto_m -> command
(-label
=> 'First', -command
=> sub {
$trace_t->see($trace_t->index("0.0 linestart"));
$goto_m -> command
(-label
=> 'Last', -command
=> sub {
my $index = $trace_t->search($trace{$tid}{$last{$tid}}, '0.0','end');
$trace_t->see($trace_t->index("$index linestart"));
my $showtype_m = $main_m -> cascade
(-label
=> 'Show', -tearoff
=> 1) ;
$showtype_m -> radiobutton
(-label
=> 'Show Expected', -value
=> '0',
-variable
=> \
$statetype,
-command
=> sub { $main_w->Busy;
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
show_state
($tid,$current{$tid}));
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
$showtype_m -> radiobutton
(-label
=> 'Show Actual/DUT', -value
=> '1',
-variable
=> \
$statetype,
-command
=> sub { $main_w->Busy;
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
show_state
($tid,$current{$tid}));
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
## View Options (font etc)
my $viewtype_m = $main_m -> cascade
(-label
=> 'View', -tearoff
=> 0) ;
$viewtype_m -> command
(-label
=> 'Increase Font' ,
my %font = $trace_t -> fontActual
($state_t->cget(-font
));
$state_t ->configure(-font
=> [%font]);
$trace_t ->configure(-font
=> [%font]);
$addr_t ->configure(-font
=> [%font]);
$status_t ->configure(-font
=> [%font]);
$viewtype_m -> command
(-label
=> 'Decrease Font',
my %font = $trace_t -> fontActual
($state_t->cget(-font
));
$state_t ->configure(-font
=> [%font]);
$trace_t ->configure(-font
=> [%font]);
$addr_t ->configure(-font
=> [%font]);
$status_t ->configure(-font
=> [%font]);
my $tooltype_m = $main_m -> cascade
(-label
=> 'Tool', -tearoff
=> 0) ;
$tooltype_m -> command
(-label
=> 'Launch Regtool' ,
-command
=> sub {system("regtool &")}
$tooltype_m -> command
(-label
=> 'Launch Tlbtrace' ,
-command
=> sub {system("tlbtrace &")}
my $help_m = $main_m -> cascade
(-label
=> '~Help', -tearoff
=> 0) ;
$help_m -> command
(-label
=> 'Blurb', -command
=> sub {helptext
($main_w);});
my $trace_f = $main_w -> Frame
-> pack (-padx
=> '3m', -pady
=> '1m', -fill
=> 'both',
my $addr_f = $main_w ->Frame
-> pack (-padx
=> '3m', -pady
=> '1m', -fill
=> 'both',
my $status_f = $main_w ->Frame
-> pack (-padx
=> '3m', -pady
=> '1m', -fill
=> 'both',
my $state_f = $main_w ->Frame
-> pack (-padx
=> '3m', -pady
=> '1m', -fill
=> 'both',
$balloon = $main_w->Balloon(-balloonposition
=>'mouse');
$trace_t = $trace_f -> Text
(-height
=> '20', -width
=> '80',
$trace_t -> configure
(-height
=> '50');
$trace_t -> tagConfigure
('instr', -foreground
=> 'darkblue');
$trace_t -> tagConfigure
('curr', -foreground
=> 'darkgreen');
$trace_t -> tagConfigure
('hot', -foreground
=> 'red', -relief
=> "raised",
$trace_t -> tagBind
('instr', '<Button-1>',
sub {$main_w->Busy; my ($text) = @_;
$state_t->configure(-state =>'normal');
$state_t ->delete("0.0", 'end');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t -> insert
("0.0", show_state
(
$text->index("current linestart"),
$text->index("current lineend")))));
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
$status_t->configure(-state =>'normal');
$status_t->delete("0.0", 'end');
$status_t->insert("0.0", $text->get (
$text->index("current linestart"),
$text->index("current lineend")));
$status_t->configure(-state =>'disabled');
$addr_t->configure(-state =>'normal');
$addr_t ->delete("0.0", 'end');
->insert("0.0",$offset{$tid}{$instr});
$addr_t->configure(-state =>'disabled');
$text->tagRemove('curr', '0.0', 'end');
$text->index("current linestart"),
$text->index("current lineend"));
$text->see($text->index("current linestart"));
$trace_t -> tagBind
('instr', "<Enter>",
$last_hover = $text->index("current linestart");
$text->index("current linestart"),
$text->index("current lineend"));
$text->configure(-cursor
=> "hand2");
$trace_t -> tagBind
('instr', "<Leave>",
$text->index("current linestart"),
$text->index("current lineend"));
$text->configure(-cursor
=> "xterm");
$trace_t -> tagBind
('instr', "<Motion>",
my $newline = $text->index("current linestart");
if ($newline ne $last_hover) {
$text->tagRemove('hot', '1.0', 'end');
$text->index("current linestart"),
$text->index("current lineend"));
my $trace_sv = $trace_f -> Scrollbar
(-command
=> ['yview', $trace_t] );
$trace_t -> configure
(-yscrollcommand
=> ['set', $trace_sv]);
$trace_sv -> pack(-side
=> 'right', -fill
=> 'y', -expand
=> 0,
-padx
=> '0m', -pady
=> '0m');
$trace_t -> pack (-side
=> 'top', -padx
=> '1m', -pady
=> '0m',
-fill
=> "both", -expand
=> 1);
$addr_f -> Label
(-text
=> 'Current Label/Offset') -> pack (-side
=> 'left');
$addr_t = $addr_f -> Text
(-background
=> 'white', -height
=> '1', -width
=> '60');
$addr_t -> pack (-side
=> 'top', -padx
=> '1m', -pady
=> '0m', -fill
=>'y',
$addr_t -> insert
("0.0", $addr_blurb);
$addr_t->configure(-state=>'disabled');
$status_t = $status_f -> Text
(-background
=> 'white', -height
=> '1', -width
=> '85');
$status_t -> pack (-side
=> 'top', -padx
=> '1m', -pady
=> '0m', -fill
=>'y',
$status_t -> insert
("0.0", $status_blurb);
$status_t->configure(-state=>'disabled');
$trace_t->configure(-state=>'normal');
show_trace
($trace_t, $status_t, $addr_t, $tid);
$trace_t->configure(-state=>'disabled');
$state_t = $state_f -> Text
(-background
=> 'white', -height
=> '34', -width
=> '80');
$state_t -> tagConfigure
('regname', -foreground
=> 'darkblue',
$state_t -> tagConfigure
('delta', -foreground
=> 'red');
$state_t -> configure
(-height
=> '1', background
=> 'gray', -foreground
=> 'gray');
$state_t -> tagConfigure
('regname', -foreground
=> 'gray',
$balloon->attach($state_t, -msg
=>"No State Information Available!" );
my $state_sv = $state_f -> Scrollbar
(-command
=> ['yview', $state_t] );
$state_t -> configure
(-yscrollcommand
=> ['set', $state_sv]);
$state_sv -> pack(-side
=> 'right', -fill
=> 'y', -expand
=> 0,
-padx
=> '0m', -pady
=> '0m');
$state_t -> pack (-side
=> 'top', -padx
=> '1m', -pady
=> '0m', -fill
=>"both",
$state_t -> insert
("0.0", show_state
($tid,-1));
tagstate
($state_t, $balloon);
$state_t -> configure
(-state => 'disabled');
$trace_t -> bind('<4>' => sub {$_[0]->yview('scroll', -3, 'units')});
$trace_t -> bind('<5>' => sub {$_[0]->yview('scroll', +3, 'units')});
$state_t -> bind('<4>' => sub {$_[0]->yview('scroll', -3, 'units')});
$state_t -> bind('<5>' => sub {$_[0]->yview('scroll', +3, 'units')});
$state_m = $state_t -> menu
;
$search_m = $state_m->cascade(-label
=>'Find Delta', -state=>'disabled');
$search_m ->command(-label
=>'Previous', -command
=>
sub{$instr = previous_delta
($state_t);
if ($instr !~ /^[0-9]+$/o) {
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
->insert("0.0","\tNo Prev Delta Found for $instr");
$status_t->configure(-state =>'disabled');
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
show_state
($tid, $instr));
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
->insert("0.0",$trace{$tid}{$instr});
$status_t->configure(-state =>'disabled');
$addr_t->configure(-state =>'normal');
$addr_t ->delete("0.0", 'end');
->insert("0.0",$offset{$tid}{$instr});
$addr_t->configure(-state =>'disabled');
$trace_t->configure(-state =>'normal');
my $index = $trace_t->search($trace{$tid}{$instr}, '0.0', 'end');
$trace_t->tagRemove('curr', '0.0', 'end');
$trace_t->index("$index linestart"),
$trace_t->index("$index lineend"));
$trace_t->see($trace_t->index("$index linestart"));});
$search_m ->command(-label
=>'Next', -command
=>
sub{$instr = next_delta
($state_t);
if ($instr !~ /^[0-9]+$/o) {
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
->insert("0.0","\tNo Next Delta Found for $instr");
$status_t->configure(-state =>'disabled');
$state_t->configure(-state =>'normal');
$state_t ->tagRemove('delta', "1.0", 'end');
$state_t ->delete("0.0", 'end');
$state_t -> insert
("0.0",
show_state
($tid, $instr));
tagstate
($state_t, $balloon);
$state_t->configure(-state=>'disabled');
$status_t->configure(-state =>'normal');
$status_t ->delete("0.0", 'end');
->insert("0.0",$trace{$tid}{$instr});
$status_t->configure(-state =>'disabled');
$addr_t->configure(-state =>'normal');
$addr_t ->delete("0.0", 'end');
->insert("0.0",$offset{$tid}{$instr});
$addr_t->configure(-state =>'disabled');
$trace_t->configure(-state =>'normal');
my $index = $trace_t->search($trace{$tid}{$instr}, '0.0', 'end');
$trace_t->tagRemove('curr', '0.0', 'end');
$trace_t->index("$index linestart"),
$trace_t->index("$index lineend"));
$trace_t->see($trace_t->index("$index linestart"));});
$main_w -> Label
(-text
=> "($ENV{PWD}) $logfile") -> pack();
###############################################################################
# Initialize Non-Zero State for requested threads {{{
$state{$tid}{0}{"PC"} = "0000fffff0000020";
$state{$tid}{0}{"NPC"} = "0000fffff0000024";
$state{$tid}{0}{"CCR"} = "0000000000000000";
$state{$tid}{0}{"FPRS"} = "0000000000000004";
$state{$tid}{0}{"VER"} = "003e002410030607";
$state{$tid}{0}{"PSTATE"} = "0000000000000014";
$state{$tid}{0}{"HPSTATE"} = "0000000000000024";
$state{$tid}{0}{"TL"} = "0000000000000006";
$state{$tid}{0}{"TT6"} = "0000000000000001";
$state{$tid}{0}{"GL"} = "0000000000000003";
$state{$tid}{0}{"TICK"} = "8000000000000000";
###############################################################################
# Initialize trace structure for requested threads {{{
$state{$tid}{0}{$_} = "0000000000000000";
foreach my $win (0 .. $maxwin-1) {
$cwp{$tid}{$win}{0}{$_} = "0000000000000000";
foreach my $g (0 .. $maxgl-1) {
$gl{$tid}{$g}{0}{$_} = "0000000000000000";
###############################################################################
# Read in log file and update database .. {{{
my ($ttid, $mtid, $reg, $value);
my $fn = (-r
$logfile)?
$logfile :"gunzip -c $logfile |";
|| usage
( "ERROR > Cannot open Log file $logfile, $!\n");
print "INFO > Loading logfile \"$logfile\"..\n";
print "INFO > Restricted to reading log for core(s) $only_cores\n";
next unless ($line =~ /^\<T\d+\>/ || $line =~ /^Dumping\s+remaining/o
|| $line =~ /Reg did not change/o
|| $line =~ /^\s*\d+:\s+\w+\[\w+_top.*?\]:\s+@\d+\s+.*?\s+T\d+/o
|| $line =~ /^\s*\d+:\s+\S+:\s+@\d+\s+\T\d+\s+\w*[Pp]arked/o);
# If DUT did not change then last read item is in expect only ..
if ($line =~ /DUT Reg did not change/o) {
$expdelta{$ttid}{$instr}{$reg} = $temp{$ttid}{$reg};
delete $temp{$ttid}{$reg};
if ($line =~ /^Dumping remaining EXPECTED/o) {
$expect = 1; $actual = 0; next;
if ($line =~ /^Dumping remaining ACTUAL/o) {
$actual = 1; $expect = 0; next;
if ($line =~ /tb_top(\d+).*\s+T(\d+)/) {
my $act_tid = $2 + $1*$num_threads_per_node;
$line =~ s/ T\d+/ T$act_tid/;
next if ($line !~ /$only_cores/o);
if ($line =~ /^\<T(\d+)\>/o) {
foreach ($line =~ m/(\w+\s*=\s*\w+)/go) {
($reg,$value) = m/(\w+)\s*=\s*(\w+)/o;
$expdelta{$ttid}{$instr}{$reg} = $value;
$actdelta{$ttid}{$instr}{$reg} = $value;
$temp{$ttid}{$reg} = $value;
= $line =~ /^\s*\d+:\s+\w+\[\w+_top.*?\]:\s+.*?\s+T(\d+)/o) {
$line =~ s/.*\[\w+_top.*?\]:\s+@(\d+)/$1:/;
last if ($maxtime && $1 > $maxtime);
$line =~ s/(#\d+)*\s+T/ #$instr T/; # Add instr# if not present.
if (!exists ($state{$mtid}{0})) {
$numthreads = $mtid+1 if ($numthreads<=$mtid) ;
$tid = $mtid if ($mtid < $tid);
my ($va) = $line =~ m/T\d+\s+(\w+)/o;
my $sva = substr($va, -12); # Use 48 bits only
$line =~ s/\(unchecked.*?\)/$disas{$sva}/i;
$current{$mtid} = $instr;
$trace{$mtid}{$instr} = $line;
$fulltrace{$instr} = $line;
foreach (keys %{$temp{$ttid}}) {
$delta{$mtid}{$instr}{$_} = $temp{$ttid}{$_};
$expdelta{$mtid}{$instr}{$reg} =$expdelta{$ttid}{$instr}{$reg} ;
$actdelta{$mtid}{$instr}{$reg} =$actdelta{$ttid}{$instr}{$reg} ;
delete($expdelta{$ttid}{$instr}{$reg});
delete($actdelta{$ttid}{$instr}{$reg});
= $line =~ /^\s*\d+:\s+\S+:\s+@\d+\s+\T(\d+)\s+\w*[Pp]arked/o) {
$line =~ s/.*\[.*?\]:\s+@(\d+)/$1:/;
$instr = $instr -1 + 0.1 ;
$line =~ s/(#\d+)*\s+T/ #$instr T/; # Add instr# if not present.
$current{$mtid} = $instr;
$trace{$mtid}{$instr} = $line;
$fulltrace{$instr} = $line;
foreach (keys %{$temp{$ttid}}) {
$delta{$mtid}{$instr}{$_} = $temp{$ttid}{$_};
foreach (0.. $numthreads-1) {
$last{$_} = $current{$_};
###############################################################################
# Read in SAS log file and update database .. {{{
my ($prevtid, $mtid, $reg, $win, $value, $pc);
my $fn = (-r
$logfile)?
$logfile :"gunzip -c $logfile |";
|| usage
( "ERROR > Cannot open Log file $logfile, $!\n");
print "INFO > Loading logfile \"$logfile\"..\n";
foreach (split(/,/, $cores)) {
$only_cores .= "|^#\d+\s+T$_|STEP:\s+$_\s+";
$only_cores .= "|^T$_|STEP:\s+$_\s+";
print "INFO > Restricted to reading log for core(s) $cores\n";
my %temp; my $first = 1; my $sasline; my $saspcline;
$sasline = "^#\\d+\\s+T(\\d+)\\s+|STEP:\\s+(\\d+)";
$saspcline = "T(\\d+).*?\\s+<v:(\\w+)>";
$sasline = "^T(\\d+)\\s+|STEP:\\s+(\\d+)";
$saspcline = "^T(\\d+).*?PC=0x(\\w+)";
next unless ($line =~ /$sasline/);
next if ($line !~ /$only_cores/);
if ($line =~ /$saspcline/o) {
foreach (keys %{$temp{$mtid}}) {
$delta{$mtid}{$instr}{$_} = $temp{$mtid}{$_};
($mtid, $pc) = $line =~ m/$saspcline/o ;
if (!exists ($state{$mtid}{0})) {
$numthreads = $mtid+1 if ($numthreads<=$mtid) ;
$tid = $mtid if ($mtid < $tid);
$pc = sprintf "%012llx", hex($pc);
$line =~ s/^#(\d+)\s+(T\d+)\s+<(v:\w+>\s+<p:\w+>)\s+\[(.*?)\]\s+(.*)$/$1: #$1 $2 $pc [ 0x$4 ] $5/;
$line =~ s/^(T\d+)\s+ic=(\d+)\s+\((#\d+)\)\s+PC=0x(\w+)\s+(\[.*?\])\s+(.*)$/$2: $3 $1 $pc $5 $6/;
$current{$mtid} = $instr;
$trace{$mtid}{$instr} = $line;
$fulltrace{$instr} = $line;
if (($mtid) = $line =~ /STEP:\s+(\d+)\s+/) {
if (($reg,$value) = $line =~ /C\s+(\w+).*?\s+(\w+)/) {
if ($reg =~ /^[0-9]+$/) {
$temp{$mtid}{$reg} = $value;
$currwin{$mtid} = $value;
}elsif (($reg,$value) = $line =~ /F\s+(\d+)\s+(\w+)/) {
$temp{$mtid}{"f".$reg} = $value;
}elsif (($reg,$value) = $line =~ /G\s+\d\s+(\d+)\s+(\w+)/) {
$temp{$mtid}{"g".$reg} = $value;
}elsif (($win, $reg, $value) = $line=~ /W\s+(\d)\s+(\d+)\s+(\w+)/) {
$reg = getwinreg
($currwin{$mtid}, $win, $reg);
$temp{$mtid}{$reg} = $value;
foreach (0.. $numthreads-1) {
$last{$_} = $current{$_};
###############################################################################
# Get Regname for window registers {{{
my ($currwin, $win, $reg) = @_ ;
if ($reg >= 8 && $reg <= 15) {
$reg = "l" . ($reg - 16) ;
###############################################################################
# Find nearest symbol offset {{{
# Input va, Output symbol+offset
foreach (@sorted_symbols) {
last if (hex($va) < hex($_));
return (sprintf ("%s+0x%lx",
$symbols{$nearest_va}, hex($va)- hex($nearest_va)));
###############################################################################
# Show trace for specific thread {{{
# Inputs Text Widget, TID
# Outputs - trace formatted string
my ($trace_t, $status_t, $addr_t, $tid) = @_;
if (!$merge && !defined $trace{$tid}) {
$trace_t -> insert
('0.0', "\nNo Trace available for thread $tid");
%mytrace = %{$trace{$tid}};
foreach (sort {$a <=> $b} keys %mytrace) {
my $line = $mytrace{$_} . "\n";
($inst,$mtid, $va) = $line =~ /\d+:\s+#(\d+)\s+T(\d+)\s+v:(\w+)/o;
($inst,$mtid, $va) = $line =~ /\d+:\s+#(\d+)\s+T(\d+)\s+(\w+)/o;
if (defined ($symbols{$va})) {
$trace_t -> insert
('end', "\n$symbols{$va}: \n");
$last_label = $symbols{$va};
$trace_t -> insert
('end', $line, 'instr');
my $index = $trace_t->search($mytrace{$current{$tid}}, '0.0','end');
$trace_t->index("$index linestart"),
$trace_t->index("$index lineend"));
$trace_t->see($trace_t->index("$index linestart"));
$status_t->configure(-state =>'normal');
$status_t->delete("0.0", 'end');
$status_t->insert("0.0", $mytrace{$current{$tid}});
$status_t->configure(-state =>'disabled');
$addr_t->configure(-state =>'normal');
$addr_t ->delete("0.0", 'end');
$addr_t ->insert("0.0",$offset{$tid}{$current{$tid}});
$addr_t->configure(-state =>'disabled');
$trace_t->tagRemove('curr', '0.0', 'end');
$trace_t->see($trace_t->index("0.0 linestart"));
$status_t->configure(-state =>'normal');
$status_t->delete("0.0", 'end');
$status_t->insert("0.0", $status_blurb);
$status_t->configure(-state =>'disabled');
$addr_t->configure(-state =>'normal');
$addr_t ->delete("0.0", 'end');
$addr_t ->insert("0.0",$addr_blurb);
$addr_t->configure(-state =>'disabled');
###############################################################################
# Show full state for specific instruction {{{
# Outputs - State display listing -
print "\nINFO > Tracing State for T$tid to Instruction #$instr..\n"
my ($currwin, $currgl) = current_state
($tid, $instr);
print "INFO > State for Thread $tid ($vtime : $disas):\n" if ($debug);
$statelist .= " g[".hex($currgl)."] " .
" o[". hex($currwin). "] " .
" l[". hex($currwin). "] " .
" i[". hex($currwin). "] \n";
if (defined ($delta{$tid}{$instr}{"g".$_})) {
push (@delta_index, length($statelist),
length($gl{$tid}{hex($currgl)}{$instr}{"g".$_}));
$statelist .= sprintf "%16s ",
$gl{$tid}{hex($currgl)}{$instr}{"g".$_};
if (defined ($delta{$tid}{$instr}{"o".$_})) {
push (@delta_index, length($statelist),
length($cwp{$tid}{hex($currwin)}{$instr}{"o".$_}));
$statelist .= sprintf "%16s ",
$cwp{$tid}{hex($currwin)}{$instr}{"o".$_};
if (defined ($delta{$tid}{$instr}{"l".$_})) {
push (@delta_index, length($statelist),
length($cwp{$tid}{hex($currwin)}{$instr}{"l".$_}));
$statelist .= sprintf "%16s ",
$cwp{$tid}{hex($currwin)}{$instr}{"l".$_};
if (defined ($delta{$tid}{$instr}{"i".$_})) {
push (@delta_index, length($statelist),
length($cwp{$tid}{hex($currwin)}{$instr}{"i".$_}));
$statelist .= sprintf "%16s ",
$cwp{$tid}{hex($currwin)}{$instr}{"i".$_} ;
while ($i < scalar(@allregs)) {
$statelist .= sprintf " %16s %16s %16s %16s\n",
$allregs[$i], $allregs[$i+1], $allregs[$i+2], $allregs[$i+3] ;
if (defined ($delta{$tid}{$instr}{$allregs[$i]})) {
push (@delta_index, length($statelist)+3,
length($state{$tid}{$instr}{$allregs[$i]}));
} elsif ($allregs[$i] =~ /^f(\d+)/) {
if (defined($delta{$tid}{$instr}{"f".($1+1)})) {
push (@delta_index, length($statelist)+3,
length($state{$tid}{$instr}{$allregs[$i]}));
$statelist .= sprintf " %16s ",
$state{$tid}{$instr}{$allregs[$i]};
if (defined ($delta{$tid}{$instr}{$allregs[$i+1]})) {
push (@delta_index, length($statelist),
length($state{$tid}{$instr}{$allregs[$i+1]}));
} elsif ($allregs[$i+1] =~ /^f(\d+)/) {
if (defined($delta{$tid}{$instr}{"f".($1+1)})) {
push (@delta_index, length($statelist),
length($state{$tid}{$instr}{$allregs[$i+1]}));
$statelist .= sprintf "%16s ",
$state{$tid}{$instr}{$allregs[$i+1]};
if (defined ($delta{$tid}{$instr}{$allregs[$i+2]})) {
push (@delta_index, length($statelist),
length($state{$tid}{$instr}{$allregs[$i+2]}));
} elsif ($allregs[$i+2] =~ /^f(\d+)/) {
if (defined($delta{$tid}{$instr}{"f".($1+1)})) {
push (@delta_index, length($statelist),
length($state{$tid}{$instr}{$allregs[$i+2]}));
$statelist .= sprintf "%16s ",
$state{$tid}{$instr}{$allregs[$i+2]};
if (defined ($delta{$tid}{$instr}{$allregs[$i+3]})) {
push (@delta_index, length($statelist),
length($state{$tid}{$instr}{$allregs[$i+3]}));
} elsif ($allregs[$i+3] =~ /^f(\d+)/) {
if (defined($delta{$tid}{$instr}{"f".($1+1)})) {
push (@delta_index, length($statelist),
length($state{$tid}{$instr}{$allregs[$i+3]}));
$statelist .= sprintf "%16s ",
$state{$tid}{$instr}{$allregs[$i+3]};
###############################################################################
# Parse trace line and return instr, tid {{{
if ($line !~ m/^\s*\d+:\s*#(\d+)\s+T(\d+)/) {
my ($instr, $tid) = $line =~ /^\s*\d+:\s*#(\d+)\s+T(\d+)/;
###############################################################################
# Figure out if valid show_deltas file is present {{{
if (!-r
$logfile && !-r
"$logfile.gz") {
usage
( "\nERROR > Could not find file $logfile or $logfile.gz, $!");
my $cat = (-r
$logfile)?
"/bin/cat -s " : "/bin/gzcat";
chomp($line = `$cat $logfile* | head -6000 | /bin/grep 'Show Delta Enabled'`);
chomp($line = `$cat $logfile* | head -100 | /bin/grep 'STEP:'`);
###############################################################################
# Figure out if PA is displayed in file {{{
if (!-r
$logfile && !-r
"$logfile.gz") {
usage
( "\nERROR > Could not find file $logfile or $logfile.gz, $!");
my $cat = (-r
$logfile)?
"/bin/cat -s " : "/bin/gzcat";
chomp($line = `$cat $logfile* | head -6000 | /bin/grep ': Enabled PA display'`);
###############################################################################
# Figure out if sas checking is enabled {{{
if (!-r
$logfile && !-r
"$logfile.gz") {
usage
( "\nERROR > Could not find file $logfile or $logfile.gz, $!");
my $cat = (-r
$logfile)?
"/bin/cat -s " : "/bin/gzcat";
chomp(my $line = `$cat $logfile* | head -6000 | /bin/grep 'Nas Checking Disabled'`);
###############################################################################
my $fn = (-r
$symfile)?
$symfile :"gunzip -c $symfile |";
|| die "ERROR > Cannot open Symbols file $symfile, $!\n";
print "INFO > Loading Symbols \"$symfile\"..\n";
my ($label, $va) = $line =~ m/^(.*?)\s+(\w+)\s+/o;
$va = substr ($va, -12); # use 48 bits only
@sorted_symbols = sort {hex($a) <=> hex($b)} keys %symbols ;
print "INFO > Loaded & sorted $count symbols from $symfile..\n";
###############################################################################
if (! $usedis && ! -r
$diagexe && ! -r
"$diagexe.gz") {
print "INFO > No Disassembly, (\"$diagexe\" or \"$diagexe.gz\" not found) ..\n";
if (!-r
$diagexe && -r
"$diagexe.gz") {
`cp $diagexe.gz /tmp/$diagexe.$$.gz; gunzip /tmp/$diagexe.$$.gz`;
$diagexe = "/tmp/$diagexe.$$";
open (DIS
, "$dis_cmd $diagexe |")
|| die "ERROR > Cannot open \"$dis_cmd $diagexe\"for disassembly, $!\n";
print "INFO > Disassembling \"$diagexe\"..($dis_cmd)\n";
print "INFO > Using existing disassembly \"$usedis\"..\n";
open (DIS
, "$usedis") || die "ERROR> Cannot read sepcified disassembly file \"$usedis\" !\n";
next if ( $line !~ /^\s*(\w+):\s+(\w\w\s){4}\s+(.*?)$/);
my ($va,$temp,$dis) = $line =~ m/^\s*(\w+):\s+(\w\w\s){4}\s+(.*)$/o;
$va = substr ($va, -12); # use 48 bits only
$va = "0" x
(12-length($va)) . $va;
$have_disas = 1 if (scalar keys %disas);
unlink "$diagexe" if ($iscomp && -r
$diagexe);
###############################################################################
# Remove leading 0x0 .. {{{
###############################################################################
# Find Regnames and create tags {{{
# Scan text string for regnames
my ($state_t,$balloon) = @_;
my $statestring = $state_t->get('0.0', 'end');
my $len = 0; my $regex = '\b'.$_.'\b';
my $index = $state_t->search(-count
=>\
$len, -regex
, $regex, '0.0', 'end');
my ($line, $char) = $index =~ m/(\d+).(\d+)/o; $char += $len;
$state_t->tagAdd('regname', $index, $line.".".$char);
my $index = $state_t->search(-count
=>\
$len, -exact
, $_, '0.0', '2.0');
my ($line, $char) = $index =~ m/(\d+).(\d+)/o; $char += $len;
$state_t->tagAdd('regname', $index, $line.".".$char);
$state_t->tagBind('regname', "<Enter>",
$regstat=$text->get($text->index("current wordstart"),
$text->index("current wordend"));
if (defined($expandreg{$regstat})) {
$regstat = showbits
($regstat);
$balloon->attach($state_t, -msg
=>$regstat );
$text->menu()->entryconfigure('last', -state => 'disabled');
$state_t->tagBind('regname', "<Leave>",
sub { my ($text)=@_;$regstat="";
$balloon->detach($state_t);
$state_t->tagBind('regname', "<Button-3>",
$text->menu()->entryconfigure('last', -state => 'normal');
###############################################################################
# Expand state bits for registers {{{
= reverse(split(//, unpack("B*", pack("H16",$state{$tid}{$instr}{$regname}))));
foreach (reverse sort {$a<=>$b} keys %{$expandreg{$regname}}) {
my ($l, $h) = split(/:/,$_);
$regtext .= " ".$expandreg{$regname}{$_}." = ".join('',reverse(@regbits[$l..$h])). " |" ;
###############################################################################
# Tag Deltas in state window {{{
$state_t ->tagRemove('delta', "1.0", 'end');
return if (! scalar(@delta_index));
while (scalar(@delta_index)) {
my $st_d = shift (@delta_index);
my $en_d = $st_d + (shift (@delta_index));
$state_t->tagAdd('delta', "1.0 + $st_d chars", "1.0 + $en_d chars");
###############################################################################
# Get Next instruction {{{
foreach (sort {$a <=> $b} keys %{$trace{$tid}}) {
return ($_) if ($_ > $instr);
###############################################################################
# Get Prev instruction state {{{
foreach (reverse sort {$a <=> $b} keys %{$state{$tid}}) {
return ($_) if ($_ < $instr);
###############################################################################
# Compress state/win/gl hashes {{{
# to keep mem util low when in incr mode
sub compress_to_last_state
{
my @statelist = reverse sort {$a <=> $b} keys %{$state{$tid}};
foreach (@statelist[1..(scalar(@statelist)-1)]) {
delete ($state{$tid}{$_});
foreach my $win (0..$maxwin) {
my @winlist = reverse sort {$a <=> $b} keys %{$cwp{$tid}{$win}};
foreach (@winlist[1..(scalar(@winlist)-1)]) {
delete ($cwp{$tid}{$win}{$_});
foreach my $g (0..$maxgl) {
my @glist = reverse sort {$a <=> $b} keys %{$gl{$tid}{$g}};
foreach (@glist[1..(scalar(@glist)-1)]) {
delete ($gl{$tid}{$g}{$_});
###############################################################################
# Subroutine to show help text
# window with global help displayed..
my $help_w = $main -> Toplevel
;
$help_w -> title
('A Helping Hand');
my $help_t = $help_w -> Text
(-width
=> '80', -height
=> '20',
-> pack (-padx
=> '0m', -pady
=> '1m', -side
=> 'left',
my $help_s = $help_w -> Scrollbar
(-command
=> ['yview', $help_t] );
$help_t -> configure
(-yscrollcommand
=> ['set', $help_s]);
$help_s -> pack(-side
=> 'right', -fill
=> 'y');
$help_t -> insert
("0.0", $help);
$help_t -> configure
(-state => 'disabled');
$help_w -> Button
(-text
=> 'OK', -command
=> [$help_w, 'destroy'])
-> pack(-padx
=> '3m', -pady
=> '1m', -side
=> 'bottom');
###############################################################################
# Non GUI trace logging {{{
# Display sorted (instr#) to stdout.
# Keep current state for each thread - incrementally update
# Add deltas for instruction
# Determine %rd, and show %rd value if not in delta.
foreach my $currinstr (sort {$a <=> $b} keys %fulltrace) {
my ($currtid, $curraddr, $disas, $junk) ;
($currtid, $curraddr, $disas, $junk) = $fulltrace{$currinstr} =~
m/^\d+:.*#\d+\s+T(\d+)\s+(\w+)\s+(.*?)\s*(OK|FAIL)*$/;
($currtid, $curraddr, $disas, $junk) = $fulltrace{$currinstr} =~
m/^\d+:.*#\d+\s+T(\d+)\s+v:(\w+)\s+p:\w+\s+(.*?)\s*(OK|FAIL)*$/;
if ($have_symbols && defined ($symbols{$curraddr})) {
print "\n$symbols{$curraddr}:\n";
print " $fulltrace{$currinstr}\n";
if ($disas =~ /(\w+)\s+.*%(\w+)$/) {
if ($rd =~ /^[fd](\d+)$/) {
$frnum=$1; $rd =~ s/^d/f/;
if ($opcode =~ /^[f].*d$|^ldd$/) {
if (!(defined($delta{$currtid}{$currinstr}{$rd}) ||
defined($delta{$currtid}{$currinstr}{"\U$rd\E"}))) {
my ($win, $gl) = current_state
($currtid,$currinstr);
compress_to_last_state
($currtid);
if ($rd !~ /^[ilogf]\d+$/o) {
print "\t$rd = ", $state{$currtid}{$currinstr}{"\U$rd\E"};
} elsif ($rd =~ /^f(\d+)$/o) {
# Float state is stored in even reg as 64 bit (Even,Odd)..
if (($frnum%2)) { ## Odd reg
print "\t$rd = 00000000",
join('',(split(//,$state{$currtid}{$currinstr}{$freg}))[8..15]);
print "\t$rd = 00000000",
join('',(split(//,$state{$currtid}{$currinstr}{$freg}))[0..7]);
} elsif ($rd =~ /^g\d+$/o) {
print "\t$rd = ", $gl{$currtid}{$gl}{$currinstr}{$rd};
print "\t$rd = ", $cwp{$currtid}{$win}{$currinstr}{$rd};
} elsif (defined($delta{$currtid}{$currinstr}{$rd})) {
print "\t$rd = $delta{$currtid}{$currinstr}{$rd}";
} elsif (defined($delta{$currtid}{$currinstr}{"\U$rd\E"})) {
print "\t$rd = ",$delta{$currtid}{$currinstr}{"\U$rd\E"};
# For float doubles, print odd reg now (even is printed as rd)
if (!defined($delta{$currtid}{$currinstr}{$freg})) {
if (!defined($state{$currtid}{$currinstr}{$rd})) {
my ($win, $gl) = current_state
($currtid,$currinstr);
compress_to_last_state
($currtid);
print "\t$freg = 00000000",
join('',(split(//,$state{$currtid}{$currinstr}{$rd}))[8..15]);
print "\t$freg = ", $delta{$currtid}{$currinstr}{$freg};
foreach my $reg (reverse sort keys %{$delta{$currtid}{$currinstr}}) {
next if ($reg =~ /$freg/i);
print "\t$reg = $delta{$currtid}{$currinstr}{$reg}";
###############################################################################
# Incremental state update {{{
# Inputs : TID, current Instr#
# Ouputs : Returns Win, GL; Updates %state, %win, %cwp ..
# Assumes that state{thread}{instr} is valid for last state updated (or reset)
# Routine will scan all instructions between nearest previous instr and
# specified instruction and return state hash that can be inserted into state
if ($have_symbols && !defined $offset{$tid}{$instr}) {
$line = $trace{$tid}{$instr};
($va) = $line =~ /\d+:\s+#\d+\s+T\d+\s+v:(\w+)/o;
($va) = $line =~ /\d+:\s+#\d+\s+T\d+\s+(\w+)/o;
print "current_state: $tid $instr $va ($line)\n" if ($debug);
if (defined ($symbols{$va})) {
$offset{$tid}{$instr} = $symbols{$va};
$offset{$tid}{$instr} = get_symbol_offset
($va);
# If Statetype=actual, remove any expected from %delta and insert
# from actual if statetype has changed ..
if ($statetype && (defined ($actdelta{$tid}{$instr}) ||
defined ($expdelta{$tid}{$instr}))) {
foreach (keys %{$expdelta{$tid}{$instr}}) {
#print "Deleting $_ $delta{$tid}{$instr}{$_}\n";
delete($delta{$tid}{$instr}{$_});
foreach (keys %{$delta{$tid}{$instr}}) {
$expdelta{$tid}{$instr}{$_} = $delta{$tid}{$instr}{$_};
foreach (keys %{$actdelta{$tid}{$instr}}) {
$delta{$tid}{$instr}{$_} = $actdelta{$tid}{$instr}{$_};
#print "Restoring $_ $delta{$tid}{$instr}{$_}\n";
# If Statetype=expected, remove any actual from %delta and insert
# from expected if statetype has changed ..
} elsif (!$statetype && defined ($expdelta{$tid}{$instr})) {
foreach (keys %{$actdelta{$tid}{$instr}}) {
#print "Deleting $_ $delta{$tid}{$instr}{$_}\n";
delete($delta{$tid}{$instr}{$_});
foreach (keys %{$expdelta{$tid}{$instr}}) {
$delta{$tid}{$instr}{$_} = $expdelta{$tid}{$instr}{$_};
#print "Restoring $_ $delta{$tid}{$instr}{$_}\n";
# Find the nearest previous instr # for this thread
my $prev = get_prev_state
($tid, $instr);
if ($prev == "" || $prev < 0) {
$state{$tid}{$instr}{$_} = $state{$tid}{0}{$_};
foreach my $win (@windows) {
foreach (0 .. $maxwin-1) {
$cwp{$tid}{$_}{$instr}{$win} = $cwp{$tid}{$_}{0}{$win};
foreach my $g (@globals) {
foreach (0 .. $maxgl-1) {
$gl{$tid}{$_}{$instr}{$g} = $gl{$tid}{$_}{0}{$g};
# Starting from $prev state, update deltas until $instr
$state{$tid}{$instr}{$_} = $state{$tid}{$prev}{$_};
foreach my $win (@windows) {
foreach (0 .. $maxwin-1) {
$cwp{$tid}{$_}{$instr}{$win} = $cwp{$tid}{$_}{$prev}{$win};
foreach my $g (@globals) {
foreach (0 .. $maxgl-1) {
$gl{$tid}{$_}{$instr}{$g} = $gl{$tid}{$_}{$prev}{$g};
my $currwin = hex($state{$tid}{$prev}{"CWP"});
my $currgl = hex($state{$tid}{$prev}{"GL"});
# Scan deltas from $prev and update until $instr is reached ..
foreach $currinstr (sort {$a <=> $b} keys %{$trace{$tid}}) {
next if ($currinstr <= $prev);
last if ( $currinstr > $instr);
foreach $reg (sort keys %{$delta{$tid}{$currinstr}}) {
if ($reg =~ /^gl$/i) { # Change currgl
$state{$tid}{$instr}{$reg} = $delta{$tid}{$currinstr}{$reg};
$currgl = $delta{$tid}{$currinstr}{$reg};
} elsif ($reg =~ /^cwp$/i) { # Change currwin
$state{$tid}{$instr}{$reg} = $delta{$tid}{$currinstr}{$reg};
$currwin = $delta{$tid}{$currinstr}{$reg};
} elsif ($reg =~ /^([ilo])(\d+)/) { # Window regs
my ($wreg, $regnum) = ($1, $2);
$cwp{$tid}{hex($currwin)}{$instr}{$reg} =
$delta{$tid}{$currinstr}{$reg};
$cwp{$tid}{(hex($currwin)-1)%8}{$instr}{"o".$regnum} =
$delta{$tid}{$currinstr}{$reg};
$cwp{$tid}{(hex($currwin)+1)%8}{$instr}{"i".$regnum} =
$delta{$tid}{$currinstr}{$reg};
} elsif ($reg =~ /^g\d+/) { # Globals
$gl{$tid}{hex($currgl)}{$instr}{$reg} =
$delta{$tid}{$currinstr}{$reg};
} elsif ($reg =~ /^f(\d+)/) { # Floats are 32 bit [Even,Odd]
my $fereg = "f".($freg & 0xfe); #regnum
if ($saslog) { # sas stores 32 bits only ..
if (! ($freg%2)) { ## Even reg
$state{$tid}{$instr}{$fereg} =
$delta{$tid}{$currinstr}{$reg} .
substr($state{$tid}{$instr}{$fereg},8,8);
$state{$tid}{$instr}{$fereg} =
substr($state{$tid}{$instr}{$fereg},0,8) .
$delta{$tid}{$currinstr}{$reg};
if (! ($freg%2)) { ## Even reg
(split(//,$delta{$tid}{$currinstr}{$reg}))[8..15]);
$state{$tid}{$instr}{$fereg} = $value .
substr($state{$tid}{$instr}{$fereg},8,8);
(split(//,$delta{$tid}{$currinstr}{$reg}))[8..15]);
$state{$tid}{$instr}{$fereg} =
substr($state{$tid}{$instr}{$fereg},0,8) . $value;
$state{$tid}{$instr}{$reg} = $delta{$tid}{$currinstr}{$reg};
return (hex($currwin), hex($currgl));
###############################################################################
# search for previous delta for register under cursor {{{
my $regname = $state_t->get($state_t->index("current wordstart"),
$state_t->index("current wordend"));
foreach my $previnstr (reverse sort {$a<=>$b} keys %{$delta{$tid}}) {
if ($previnstr < $instr && defined ($delta{$tid}{$previnstr}{$regname})) {
###############################################################################
# search for next delta for register under cursor {{{
my $regname = $state_t->get($state_t->index("current wordstart"),
$state_t->index("current wordend"));
foreach my $nextinstr (sort {$a<=>$b} keys %{$delta{$tid}}) {
if ($nextinstr > $instr && defined ($delta{$tid}{$nextinstr}{$regname})) {
###############################################################################
###############################################################################
# Translate control register number to name {{{
if (!defined $regmap{32}) {
96 => "ECACHE_ERROR_ENABLE",
97 => "ASYNCHRONOUS_FAULT_STATUS",
98 => "ASYNCHRONOUS_FAULT_ADDRESS",
102=> "INTR_DISPATCH_STATUS",
136=> "CTXT_NZ_TSB_CFG0",
137=> "CTXT_NZ_TSB_CFG1",
138=> "CTXT_NZ_TSB_CFG2",
139=> "CTXT_NZ_TSB_CFG3",
return ($regmap{$regnum});
# Read in gates log file and update database .. {{{
my ($mtid, $reg, $value);
my $fn = (-r
$logfile)?
$logfile :"gunzip -c $logfile |";
|| usage
( "ERROR > Cannot open Log file $logfile, $!\n");
print "INFO > Loading logfile \"$logfile\"..\n";
print "INFO > Restricted to reading log for core(s) $only_cores\n";
next unless ($line =~ /^\s*\d+:\s+\w+\[\w+_top.*?\]:\s+.*?\s+T\d+/o);
next if ($line !~ /$only_cores/o);
= $line =~ /^\s*\d+:\s+\w+\[\w+_top.*?\]:\s+.*?\s+T(\d+)/o) {
$line =~ s/.*\[\w+_top.*?\]:\s+@(\d+)/$1:/o;
last if ($maxtime && $1 > $maxtime);
$line =~ s/(#\d+)*\s+T/ #$instr T/; # Add instr# if not present.
if (!exists ($state{$mtid}{0})) {
$numthreads = $mtid+1 if ($numthreads<=$mtid) ;
$tid = $mtid if ($mtid < $tid);
my ($va) = $line =~ m/T\d+\s+(\w+)/o;
my $sva = substr($va, -12); # Use 48 bits only
$line .= " " . $disas{$sva};
$current{$mtid} = $instr;
$trace{$mtid}{$instr} = $line;
$fulltrace{$instr} = $line;
foreach (0.. $numthreads-1) {
$last{$_} = $current{$_};