Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perlmod / vlog,1.99
CommitLineData
86530b38
AT
1
2use strict;
3use IO::Handle;
4use Getopt::Long;
5
6sub update_regs;
7sub print_regs;
8sub error;
9sub b2h;
10sub format_time;
11
12$SIG{__WARN__} = sub {die $_[0]};
13
14# Initialize and defines all kinds of variables
15#----------------------------------------------
16$| = 1; # autoflush
17my(@gl); # global register level per thread
18my(@tl); # trap level per thread
19my(@cwp); # current window pointer per thread
20my($logfile); # what file to read
21
22# global, FP, integer, asi registers
23my(@gregs, @fpregs, @regs, @asi_reg);
24
25my($pc, $inst); # program counter, instructions
26my(%diag_code, %label); # disassembled diag code and labels
27my($time, $spc, $thr, $proc, $reg, $val, $win, $instr, $tmp);
28my(@instr_list); # instruction list
29my($PROG) = ($0=~ m%([^/]+)$%); # regreport real name
30
31my(%miss); # additional info - less important
32my(%notintlb); # additional info - less important
33
34my($i, $k);
35my $version = '1.NN';
36
37print "===============================================\n";
38print "=== OpenSPARC T1 Vlog Version $version ===\n";
39print "===============================================\n";
40
41my @Options = qw( debug sas mom h help ccx l2 dram cycles sort! perf);
42my %opt = ();
43$opt{debug} = 0;
44$opt{sas} = 0;
45$opt{mom} = 0;
46$opt{h} = 0;
47$opt{help} = 0;
48$opt{ccx} = 0;
49$opt{l2} = 0;
50$opt{dram} = 0;
51$opt{cycles} = 0;
52$opt{sort} = 1;
53$opt{perf} = 0;
54
55GetOptions(\%opt, @Options) or die "Error in arguments!\n";
56my($debug) = $opt{debug};
57my($sas) = $opt{sas};
58my($mom) = $opt{mom};
59my($ccx) = $opt{ccx};
60my($l2) = $opt{l2};
61my($dram) = $opt{dram};
62my($h) = $opt{h};
63my($help) = $opt{help};
64my($cycles) = $opt{cycles};
65my($sorti) = $opt{sort};
66my($perf) = $opt{perf};
67
68
69if($h || $help) {
70 print "===============================================\n";
71 print "=== Version $PROG ===\n";
72 print "Usage: vlog [logfilename|path_to_sim.log] [-debug -h -ccx -l2 -dram -cycles -[no]sort] [-perf] \n";
73 print "-ccx prints ccx related messages\n";
74 print "-l2 prints l2 related messages\n";
75 print "-dram prints dram related messages\n";
76 print "-h prints out this screen\n";
77 print "-debug is for script debug\n";
78 print " It will probably be obsoleted in the future \n";
79 print "-cycles prints the cycles and not the time \n";
80 print "-sort will sort sim.log according to time stamps first [default is on]\n";
81 print "-perf will print all kinds of performance data - I, D miss e.t.c.\n";
82 print "-mom Special mom sas.log file processing\n";
83 print "===============================================\n";
84 print "Examples:\n";
85 print "vlog -ccx -l2 -dram >! vlog.log\n";
86 print "vlog >! vlog.log\n";
87 print "vlog <my_path>/sim.log >! vlog.log\n";
88 print "===============================================\n";
89 exit 0;
90 }
91
92if($debug) { print "Debug mode on\n"; }
93if($sas) { print "sas mode\n"; }
94if($mom) { print "mom mode\n"; }
95if($sorti) { print "sort mode\n"; }
96if($perf) { print "perf mode\n"; }
97
98#==========================================
99# initialize register hashes.
100#==========================================
101for ($i = 0; $i < 32; $i++){
102 $tl[$i] = 5;
103 $gl[$i] = 3;
104 $cwp[$i] = 0;
105 $asi_reg[$i] = "x";
106 for ($k = 0; $k < 32; $k++){
107 $gregs[$i][$k] = "x";
108 }
109 $gregs[$i][0] = 0x0;
110 $gregs[$i][8] = 0x0;
111 $gregs[$i][16] = 0x0;
112 $gregs[$i][24] = 0x0;
113
114 for ($k = 0; $k < 64; $k++){
115 $fpregs[$i][$k] = "x";
116 }
117
118 for ($k = 0; $k < 256; $k++){
119 $regs[$i][$k] = "x";
120 }
121}
122
123
124#==========================================
125# figure out logfile to read
126#==========================================
127my $logfilename = $mom ? "sas.log" : "sim.log";
128
129if($#ARGV >= 0){
130
131 my @pathname = split '/' , $ARGV[0];
132 if($pathname[$#pathname] =~ /$logfilename/){
133 $#pathname--;
134 }
135 if(scalar(@pathname)){
136 chdir join '/', @pathname or die "cannot change dir\n";
137 print "changed dir to ";
138 }else{
139 print "current dir is ";
140 }
141 my $temp = `pwd`;
142 print "$temp\n";
143}
144
145$logfile= (-f $logfilename) ? $logfilename :
146 (-f "$logfilename.gz") ? "$logfilename.gz" :
147 &error("Logfile $logfilename or $logfilename.gz not found");
148
149
150print "\n===== Opening $logfile ======\n";
151#-------------------------------------
152# log file in N1 is unsorted mess.
153# sort it unless soritng is disabled.
154# sort by forking a sorting process.
155#-------------------------------------
156if($sorti && !$mom){
157 my $pid = open(VCS, "-|");
158 unless (defined $pid){die "cannot fork $!\n"}
159 if(!$pid){sorti();}
160}
161else{
162 if($logfile =~ /\.gz$/) {
163 open(VCS, "gunzip -c $logfile |") || die "cannot open gunzip -c $logfile";
164 }else{
165 open(VCS, "< $logfile") || die "cannot open $logfile";
166 }
167}
168
169#============================================================
170
171# get the labels inside the diag.s
172if((! -f "symbol.tbl") &&(-f "symbol.tbl.gz")){
173 system("gunzip symbol.tbl.gz");
174}
175
176if(! -f "symbol.tbl") {print "no symbol.tbl\n"; exit 0;}
177open(SYM , "symbol.tbl") || die " BAD BAD symbol.tbl opening";
178while(<SYM>){
179 chop;
180 s/\.\w+\.//g;
181 my @symline = split /\s+/;
182 if($#symline != 3){die "something is wrong with symbol.tbl\n";}
183
184 my $pc = truncate_len($symline[1]);
185 if(exists $label{$pc} and $label{$pc} eq 'main'){
186 next;
187 }
188 $label{$pc} = $symline[0];
189 print "label $label{$pc}, $pc\n" if($debug);
190}
191
192# disassemble the diag.
193#---------------------
194my(@diag_exe_files) = `ls diag*.exe*`;
195if(!(@diag_exe_files)){
196 print "Warning: No diag.\*exe files!!!\n";
197}
198else{
199 my($exe_file, $exe_file_gz);
200 foreach $exe_file (@diag_exe_files){
201 chop $exe_file;
202 $exe_file_gz = $exe_file . ".gz";
203 if(!(-e $exe_file) && (-e $exe_file_gz)){ system("gunzip $exe_file_gz"); }
204 print "Will extract instruction info from: $exe_file \n";
205
206 open(DIS, "g_objdump -m sparc:v9B -d $exe_file | ") || die "BAD objdump";
207 while(<DIS>){
208 s/^\s+//;
209 if(/^([a-f\d]+):\s+.. .. .. ..\s+(.*)$/) {
210 $pc = truncate_len($1);
211 $inst = $2;
212
213 $inst =~ s/\s*!.*$//;
214 if($inst =~ /\((\d+)\)/){ # convert from decimal to hex.
215 my $inst_left = $` . '(0x';
216 my $inst_cent = sprintf("%lx",$1);
217 my $inst_right = ')' . $';
218 my $asi_str = asi_mnem($inst_cent);
219 $inst = $inst_left . $inst_cent . ' ' . $asi_str . $inst_right;
220 }
221 $diag_code{$pc}= $inst;
222 }
223
224 } ### of while...
225 close(DIS);
226
227 } ### of foreach
228} # of if
229
230
231$| = 0; # autoflush
232#============================================================
233my $found_ctime = 0;
234my $pll_freq = 0;
235my $cmp_clk_divider = 0;
236my($ctime) = 0;
237
238# the main loop:
239#---------------
240while(<VCS>) {
241 chop;
242
243 s/-MATCH/-updated/g;
244
245 if(/MISMATCH/) { print ;print "\n"; next;}
246 elsif(/timeout/i) { print ;print "\n"; next;}
247 elsif(/error/i) { print ;print "\n"; next;}
248 elsif(/fail/i) { print ;print "\n"; next;}
249 elsif(/wrong/i) { print ;print "\n"; next;}
250 elsif(/good trap/i) { print ;print "\n"; next;}
251
252# some messing around needed to calculate the clock period.
253#----------------------------------------------------------
254 elsif(/cmp_clk period\s*=\s*(\d+)/){
255 $ctime = $1;
256 print "cycle time is $ctime\n";
257 die "Found clock period of 0!\n" unless $ctime;
258 $found_ctime = 1;
259 }
260 elsif(!$found_ctime && /cmp_clk divider\s*=\s*(\d+)/){
261 $cmp_clk_divider = $1;
262 print "cmp_clk_divider is $cmp_clk_divider\n";
263 }
264 elsif(!$found_ctime && /pll_clk frequency\s*=\s*(\d+)/i){
265 $pll_freq = $1;
266 print "pll_freq time is $pll_freq\n";
267 }
268 elsif(!$found_ctime && /Selected Core Clock Frequency\s(\d+)\s*MHz/){
269 if($pll_freq && $cmp_clk_divider){
270 my $pll_period;
271 my %pll_periods = ( # HACK! These are periods hardcoded from cmp_clk.v.
272 2000 => 250, # Hopefully, we're using a version of hte model that has the
273 2200 => 227, # "cmp_period" defined, so we don't have to use this.
274 2333 => 214,
275 2334 => 214,
276 2400 => 208,
277 2550 => 196,
278 2600 => 192,
279 2800 => 179,
280 default => 208,
281 );
282 $pll_period = exists $pll_periods{$pll_freq} ? $pll_periods{$pll_freq} : $pll_periods{default};
283 $ctime = $pll_period * 2 * $cmp_clk_divider;
284 print "Computed cycle_period from PLL ($pll_freq) and div ". "($cmp_clk_divider): $ctime\n";
285 } else {
286# Couldn't find anything but the frequency message. Use that.
287#------------------------------------------------------------
288 my $freq = $1;
289 $ctime = int(1 / $freq * 1000000);
290 print "Guessed at cycle_period from frequency ($freq): $ctime\n";
291 }
292 $found_ctime = 1;
293 }
294#=============================
295# example line:
296#567: [th02] <v:0x0000000000134000> < not in tlb >
297# this is not very important`. It was nice to the perofrmace
298# debuggers.
299#=============================
300 elsif(/th([\dabcdef]+)\]\s+\<v:0x(\w+)>.*not in tlb/i){
301 $spc = $1 / 4;
302 $thr = $1 % 4;
303 $val = truncate_len($2);
304 $notintlb{$spc}{$thr}{$val} = 1;
305 print "switch on tlb message $_\n" if($debug);
306 }
307# this is VERY IMPORTANT - the register updates:
308 elsif(/^(\d+):.*reg.updated\s*->\s*spc.(\d).\s*thread.(\d)/){
309 $time = format_time($1, $ctime, $cycles);
310 $spc = $2;
311 $thr = $3;
312 $proc = 4 * $spc + $thr;
313
314 if(/float_reg.updated.*reg#\((\w+)\).*val = (\w+)/){
315 $reg = "%" . $1;
316 $val = $2;
317
318 printf "%-10s: C%dT%d\t\tFPREG UPDATE <%s = %s>\n", $time, $spc, $thr, $reg, $val;
319 update_regs;
320
321 my @chars = split //, $val;
322 if($#chars > 7){
323 if($reg =~ /%[df](\d+)/){
324 my $newreg = $1 + 1;
325 $reg = "%f" . $newreg;
326 $val = substr $val, 8;
327 update_regs;
328 }
329 else{
330 die " $time: something is wrong with FP updates\n";
331 }
332 }
333 }
334 elsif(/window.(\w+).*reg#\((\w+)\).*val = (\w+)/){
335 $win = $1;
336 $reg = "%" . $2;
337 $val = $3;
338 printf "%-10s: C%dT%d\t\tREG UPDATE <%s = %s> in window %s\n", $time, $spc, $thr, $reg, $val, $win;
339 update_regs;
340 }
341 elsif(/asi_reg.updated.*window.(\w+).*val = 0*(\w+)/){
342 $asi_reg[$proc] = $2;
343 printf "%-10s: C%dT%d\t\tASI REG UPDATE <ASI = $2> in window %s\n", $time, $spc, $thr, $1;
344 }
345 elsif(/canrestore_reg.updated.*window.(\w+).*val = 0*(\w+)/){
346 printf "%-10s: C%dT%d\t\tCANRESTORE REG UPDATE <CANRESTORE = $2> in window %s\n", $time, $spc, $thr, $1;
347 }
348 elsif(/cansave_reg.updated.*window.(\w+).*val = 0*(\w+)/){
349 printf "%-10s: C%dT%d\t\tCANSAVE REG UPDATE <CANSAVE = $2> in window %s\n", $time, $spc, $thr, $1;
350 }
351 elsif(/ccr_reg.updated.*window.(\w+).*val = 0*(\w+)/){
352 printf "%-10s: C%dT%d\t\tCCR REG UPDATE <CCR = $2> in window %s\n", $time, $spc, $thr, $1;
353 }
354 elsif(/cleanwin_reg.updated.*window.(\w+).*val = 0*(\w+)/){
355 printf "%-10s: C%dT%d\t\tCLEANWIN REG UPDATE <CLEANWIN = $2> in window %s\n", $time, $spc, $thr, $1;
356 }
357 elsif(/cwp_reg.updated.*window.(\w+).*val = (\w+)/){
358 printf "%-10s: C%dT%d\t\tCWP REG UPDATE <CWP = %s> in window %s\n", $time, $spc, $thr, $2, $1;
359 $cwp[$proc] = $1;
360 }
361 elsif(/hpstate_reg.updated.*window.(\w+).*val = (\w+)/){
362 printf "%-10s: C%dT%d\t\tHPSTATE REG UPDATE <HPSTATE = %s> in window %s\n", $time, $spc, $thr, $2, $1;
363 }
364 elsif(/htba_reg.updated.*window.(\w+).*val = (\w+)/){
365 printf "%-10s: C%dT%d\t\tHTBA REG UPDATE <HTBA = %s> in window %s\n", $time, $spc, $thr, $2, $1;
366 }
367 elsif(/hstate2_reg.updated.*window.(\w+).*val = (\w+)/){
368 printf "%-10s: C%dT%d\t\tHSTATE2 REG UPDATE <HSTATE2 = %s> in window %s\n", $time, $spc, $thr, $2, $1;
369 }
370 elsif(/hstate3_reg.updated.*window.(\w+).*val = (\w+)/){
371 printf "%-10s: C%dT%d\t\tHSTATE3 REG UPDATE <HSTATE3 = %s> in window %s\n", $time, $spc, $thr, $2, $1;
372 }
373 elsif(/otherwin_reg.updated.*window.(\w+).*val = (\w+)/){
374 printf "%-10s: C%dT%d\t\tOTHERWIN REG UPDATE <OTHERWIN = %s> in window %s\n", $time, $spc, $thr, $2, $1;
375 }
376 elsif(/pil_reg.updated.*window.(\w+).*val = (\w+)/){
377 printf "%-10s: C%dT%d\t\tPIL REG UPDATE <PIL = %s> in window %s\n", $time, $spc, $thr, $2, $1;
378 }
379 elsif(/pstate_reg.updated.*window.(\w+).*val = (\w+)/){
380 printf "%-10s: C%dT%d\t\tPSTATE REG UPDATE <PSTATE = %s> in window %s\n", $time, $spc, $thr, $2, $1;
381 }
382 elsif(/tba_reg.updated.*window.(\w+).*val = (\w+)/){
383 printf "%-10s: C%dT%d\t\tTBA REG UPDATE <TBA = %s> in window %s\n", $time, $spc, $thr, $2, $1;
384 }
385 elsif(/tl_reg.updated.*window.(\w+).*val = (\w+)/){
386 $tl[$proc] = $2;
387 printf "%-10s: C%dT%d\t\tTL REG UPDATE <TL = %d>\n", $time, $spc, $thr, $tl[$proc];
388 }
389 elsif(/gl_reg.updated.*window.(\w+).*val = 0*(\w+)/){
390 $gl[$proc] = $2;
391 printf "%-10s: C%dT%d\t\tGL REG UPDATE <GL = $2>\n", $time, $spc, $thr;
392 }
393 elsif(/tstate1_reg.updated.*window.(\w+).*val = (\w+)/){
394 printf "%-10s: C%dT%d\t\tTSTATE1 REG UPDATE <TSTATE1 = %s> in window %s\n", $time, $spc, $thr, $2, $1;
395 }
396 elsif(/tstate2_reg.updated.*window.(\w+).*val = (\w+)/){
397 printf "%-10s: C%dT%d\t\tTSTATE2 REG UPDATE <TSTATE2 = %s> in window %s\n", $time, $spc, $thr, $2, $1;
398 }
399 elsif(/ttype1_reg.updated.*window.(\w+).*val = (\w+)/){
400 printf "%-10s: C%dT%d\t\tTTYPE1 REG UPDATE <TTYPE1 = %s> in window %s\n", $time, $spc, $thr, $2, $1;
401 }
402 elsif(/ttype2_reg.updated.*window.(\w+).*val = (\w+)/){
403 printf "%-10s: C%dT%d\t\tTTYPE2 REG UPDATE <TTYPE2 = %s> in window %s\n", $time, $spc, $thr, $2, $1;
404 }
405 elsif(/wstate_reg.updated.*window.(\w+).*val = (\w+)/){
406 printf "%-10s: C%dT%d\t\tWSTATE REG UPDATE <WSTATE = %s> in window %s\n", $time, $spc, $thr, $2, $1;
407 }
408 elsif(/hstick_cmpr_reg.updated.*window.(\w+).*val = (\w+)/){
409 printf "%-10s: C%dT%d\t\tHSTICK_CMPR REG UPDATE <TICK_CMPR = %s> in window %s\n", $time, $spc, $thr, $2, $1;
410 }
411 elsif(/stick_cmpr_reg.updated.*window.(\w+).*val = (\w+)/){
412 printf "%-10s: C%dT%d\t\tSTICK_CMPR REG UPDATE <TICK_CMPR = %s> in window %s\n", $time, $spc, $thr, $2, $1;
413 }
414 elsif(/tick_cmpr_reg.updated.*window.(\w+).*val = (\w+)/){
415 printf "%-10s: C%dT%d\t\tTICK_CMPR REG UPDATE <TICK_CMPR = %s> in window %s\n", $time, $spc, $thr, $2, $1;
416 }
417 elsif(/y_reg.updated.*window.(\w+).*val = (\w+)/){
418 printf "%-10s: C%dT%d\t\tY REG UPDATE <Y = %s> in window %s\n", $time, $spc, $thr, $2, $1;
419 }
420 else{
421 print "$_ - an undetected register\n" if ($debug);
422 }
423 }
424#================================
425# VERY IMPORTANT - PC extraction
426# the notintlb and miss info
427# is just nice to have.
428# everything else is crucial.
429#================================
430 elsif(!$sas && /info-perm/i){
431 if(/^.(\d+).info-perm\s+thread.([\dabcdef]+).\s+pc.(\w+)/i){
432 $time = format_time($1, $ctime, $cycles);
433 $proc = hex ($2);
434 $spc = int ($proc / 4);
435 $thr = $proc % 4 ;
436 $val = truncate_len($3);
437 }
438 else{
439 die "See this\n$_\nsomething is wrong with the PC extraction\n";
440 }
441
442 $instr = $diag_code{$val};
443 if($label{$val}){
444 printf "%-10s: C%dT%d ======================================\n", $time, $spc, $thr;
445 printf "%-10s: C%dT%d LABEL <%s>:\n", $time, $spc, $thr, $label{$val};
446 }
447
448 if($instr){
449 my($notintlb, $imiss, $dmiss, $short_val);
450 $val =~ /(\w{8})$/;
451 $short_val = $1;
452 if((exists $miss{I}{$spc}{$thr}{$short_val}) && ( $miss{I}{$spc}{$thr}{$short_val} == 1) && $perf){
453 $imiss = 'IMISS';
454 $miss{I}{$spc}{$thr}{$short_val} = 0;
455 }
456 else{
457 $imiss = '';
458 }
459
460 if((exists $miss{D}{$spc}{$thr}{$short_val}) && ( $miss{D}{$spc}{$thr}{$short_val} == 1) && $perf){
461 $dmiss = 'DMISS';
462 $miss{D}{$spc}{$thr}{$short_val} = 0;
463 }
464 else{
465 $dmiss = '';
466 }
467
468 if(exists $notintlb{$spc}{$thr}{$val} && $notintlb{$spc}{$thr}{$val} && $perf){
469 $notintlb = "not in tlb";
470 $notintlb{$spc}{$thr}{$val} = 0;
471 print "switch off tlb message $_\n" if($debug);
472 }
473 else{
474 $notintlb = '';
475 }
476 if($instr =~ /%asi/){
477 my $asi_str = asi_mnem($asi_reg[$proc]);
478 $instr =~ s/%asi/%asi ($asi_reg[$proc] $asi_str)/;
479 }
480
481 printf "%-10s: C%dT%d v%-12s \t%-30s $notintlb $imiss $dmiss\n", $time, $spc, $thr, $val, $instr;
482 $instr =~ s/[,\[\]]//g;
483 if($instr =~ /%fp\W|%sp\W|%fp$|%sp$/){
484 $instr =~ s/%fp/%i6/g;
485 $instr =~ s/%sp/%o6/g;
486 }
487
488 @instr_list = split /\s+/, $instr;
489 print_regs;
490 }
491 else{
492 printf "%-10s: C%dT%d v%-12s \tWARNING probably illegal instruction - could not translate\n", $time, $spc, $thr, $val;
493 }
494 }
495
496#====================================
497# also very important - SAS only runs
498#====================================
499 elsif($sas && /^\((\d+)\):sas>\s+\d+:\s+\[th([\dabcdef]+)\]\s+<v:0x(\w+)>\s+<p:0*(\w+)>\s(.*)/){
500 $time = format_time($1, $ctime, $cycles);
501 $proc = hex ($2);
502 $spc = $proc / 4;
503 $thr = $2 % 4;
504 $val = truncate_len($3);
505 my($pa) = $4;
506 $instr = $5;
507
508 if(exists $label{$val}){
509 printf "%-10s: C%dT%d ======================================\n", $time, $spc, $thr;
510 printf "%-10s: C%dT%d LABEL <%s>:\n", $time, $spc, $thr, $label{$val};
511 }
512
513 printf "%-10s: C%dT%d v%-12s \t%-30s \(pa=%-12s\)\n", $time, $spc, $thr, $val, $instr, $pa;
514 $instr =~ s/[,\[\]]//g;
515 @instr_list = split /\s+/, $instr;
516 print_regs;
517 }
518
519# example line:
520#@1101: 0000.pc=00000000000400ac inst[lstore] in switch stage /wo speculation, latency=0
521 elsif($mom && /^\@(\d+):\s+(\d+)\.pc=(\w+)\s+inst/){
522 $time = format_time($1, $ctime, $cycles);
523 my $proc = $2 + 0;
524 $spc = $proc / 4;
525 $thr = $proc % 4;
526 $val = truncate_len($3);
527
528 if(exists $diag_code{$val}){
529 $instr = $diag_code{$val};
530 }
531 else{
532 $instr = "Instruction not found";
533 }
534 if($label{$val}){
535 printf "%-10s: C%dT%d ======================================\n", $time, $spc, $thr;
536 printf "%-10s: C%dT%d LABEL <%s>:\n", $time, $spc, $thr, $label{$val};
537 }
538
539 printf "%-10s: C%dT%d v%-12s \t%-30s\n", $time, $spc, $thr, $val, $instr;
540 }
541
542
543#=============================
544# print CCX info.
545#=============================
546 elsif($ccx && (/^(\d+):Info cpu.(\d). cpx.*->\s*(\w+)/)) {
547 $time = format_time($1, $ctime, $cycles);
548 $spc = $2;
549 my($rawpkt) = $3;
550
551 my($pkt) = process_cpx_pkt($rawpkt);
552 print "debug cpx: $_\n" if($debug);
553 printf "%-10s: C${spc}T$pkt\n", $time;
554 next;
555 }
556 elsif(/^(\d+):Info cpu.(\d). pcx.*->\s*(\w+)/) {
557 $time = format_time($1, $ctime, $cycles);
558 $spc= $2;
559 my($rawpkt) = $3;
560
561 my($pkt) = process_pcx_pkt($rawpkt);
562 print "debug pcx: $_\n" if($debug);
563 if($ccx){
564 printf "%-10s: C$spc$pkt\n", $time;
565 }
566 if($pkt =~ /^T(\d).*([id])fill_req.*addr\s+\w*(\w{8})\s/i){
567 my $thr = $1;
568 my $iord = $2;
569 my $addr = $3;
570 $miss{$iord}{$spc}{$thr}{$addr} = 1;
571 print " setting $iord $spc $thr $addr miss \n" if($debug);
572 }
573
574 next;
575 }
576# l2 bank info
577#==============
578 elsif($l2 && /^(\d+):\s+(L2 bank.*)/) {
579 $time = format_time($1, $ctime, $cycles);
580 my $rawpkt = $2;
581 if($rawpkt =~ /core\s+(\d+),\s+thread\s+(\d+)/){
582 $spc = $1;
583 $thr = $2;
584 printf "%-10s: C${spc}T${thr}\t$rawpkt\n", $time;
585 }
586 else{
587 printf "%-10s: \t$rawpkt\n", $time;
588 }
589 next;
590 }
591# dram info
592 elsif($dram && /^(\d+):\s*(DRAM.*)/) {
593 $time = format_time($1, $ctime, $cycles);
594 my $rawpkt = $2;
595 printf "%-10s: $rawpkt\n", $time;
596 next;
597 }
598 elsif($dram && /^(\d+):\s*(L2_DRAM.*)/) {
599 $time = format_time($1, $ctime, $cycles);
600 my $rawpkt = $2;
601 printf "%-10s: $rawpkt\n", $time;
602 next;
603 }
604 elsif(/bad/i) { print "$_\n"; }
605} # while
606
607close(VCS);
608print "\nBye\n";
609
610#==========================
611
612sub error {
613 my($msg)= @_;
614 STDOUT->autoflush(1);
615 STDERR->autoflush(1);
616 print STDERR "ERR: $msg!\n";
617 exit(1);
618}
619
620#==========================
621# updates the register values
622# this is per thread.
623# I am modeling all registers per thread as one big flat
624# register file, index by register window number * N + register number
625# where N = 8 for globals and 16 for others
626#==========================
627sub update_regs {
628
629 my($reg_num);
630
631 if($reg =~ /%r(\d+)/){
632 if($1 < 8){ # global reg.
633 $reg_num = 8 *$win + $1;
634 $gregs[$proc][$reg_num] = $val;
635 print "C${spc}T${thr} debug updating global $reg to $gregs[$proc][$1] reg num = $reg_num\n" if($debug);
636 }
637 else{ # not a global reg.
638 $reg_num = $win*16 + 31 - $1;
639 $regs[$proc][$reg_num] = $val;
640 print "C${spc}T${thr} debug updating $reg to $regs[$proc][$reg_num] reg_num = $reg_num\n" if($debug);
641 }
642 }
643 elsif($reg =~ /%g(\d+)/){ # global reg
644 $reg_num = 8 * $win + $1;
645 $gregs[$proc][$reg_num] = $val;
646 print "C${spc}T${thr} debug updating $reg to $gregs[$proc][$reg_num] reg_num: $reg_num\n" if($debug);
647 }
648 elsif($reg =~ /%i(\d+)/){ # input reg
649 $reg_num = $win*16 + $1;
650 $regs[$proc][$reg_num] = $val;
651 print "C${spc}T${thr} debug updating $reg to $regs[$proc][$reg_num] reg_num: $reg_num\n" if($debug);
652 }
653 elsif($reg =~ /%l(\d+)/){ # local reg
654 $reg_num = $win*16 + 8 + $1;
655 $regs[$proc][$reg_num] = $val;
656 print "C${spc}T${thr} debug updating $reg to $regs[$proc][$reg_num] reg_num: $reg_num\n" if($debug);
657 }
658 elsif($reg =~ /%o(\d+)/){ # output reg
659 $reg_num = $win*16 + 16 + $1;
660 $regs[$proc][$reg_num] = $val;
661 print "C${spc}T${thr} debug updating $reg to $regs[$proc][$reg_num] reg_num: $reg_num\n" if($debug);
662 }
663 elsif($reg =~ /%f(\d+)/){ # FP reg.
664 $reg_num = $1;
665 $fpregs[$proc][$reg_num] = $val;
666 print "C${spc}T${thr} debug updating $reg to $fpregs[$proc][$reg_num] reg_num: $reg_num\n" if($debug);
667 }
668 elsif($reg =~ /%d(\d+)/){ # should not come here.
669 print "%d stuff, man, don't know what to do yet.\n";
670 exit 1;
671 }
672}
673
674#-----------------------------------------------------------------
675
676# prints the relevant registers for the instruction/PC which found it.
677sub print_regs{
678
679 my($needs_print) = 0;
680 my($e, $reg_num);
681
682 if($instr =~ /%(r|g|l|i|o|f|d)\d+/){
683 $needs_print = 1;
684 printf " C%dT%d\t\told reg values: ", $spc, $thr;
685 }
686 if($needs_print){
687 foreach $e (@instr_list){
688
689 if($e =~ /%r(\d+)/){
690 my $rnumh = $1;
691 if($rnumh < 8) { $e =~ s/%r/%g/; }
692 elsif(($rnumh >= 8) && ($rnumh < 16)) { $e =~ s/%r/%o/; }
693 elsif(($rnumh >= 16) && ($rnumh < 24)) { $e =~ s/%r/%l/; }
694 elsif(($rnumh >= 24) && ($rnumh < 32)) { $e =~ s/%r/%i/; }
695 else { die "something is wrong with register number $rnumh\n";}
696 }
697
698 if($e =~ /%g(\d+)/){
699 $reg_num = $gl[$proc] * 8 + $1;
700 printf "%s= %s ", $e, $gregs[$proc][$reg_num];
701 }
702 elsif($e =~ /%i(\d+)/){
703 $reg_num = $cwp[$proc]*16 + $1;
704 printf "%s= %s ", $e, $regs[$proc][$reg_num];
705 }
706 elsif($e =~ /%l(\d+)/){
707 $reg_num = $cwp[$proc]*16 + 8 + $1;
708 printf "%s= %s ", $e, $regs[$proc][$reg_num];
709 }
710 elsif($e =~ /%o(\d+)/){
711 $reg_num = $cwp[$proc]*16 + 16 + $1;
712 printf "%s= %s ", $e, $regs[$proc][$reg_num];
713 }
714 elsif($e =~ /%f(\d+)/){
715 $reg_num = $1;
716 printf "%s= %s ", $e, $fpregs[$proc][$reg_num];
717 }
718 elsif($e =~ /%d(\d+)/){
719 print "%d stuff, man, don't know what to do yet.\n";
720 exit 1;
721 }
722 }
723 print "\n";
724 }
725}
726
727
728#====================================================================
729# makes sense of the PCX packet
730#====================================================================
731sub process_pcx_pkt{
732
733my %ReqTyps =
734 (
735 '00000' => 'Dfill_Req',
736 '10000' => 'Ifill_Req',
737 '00001' => 'ST',
738 '00111' => 'STQ(1)',
739 '00010' => 'CAS(1)',
740 '00011' => 'CAS(2)',
741 '00110' => 'SWP_Ldstb',
742 '00100' => 'Stream_loads',
743 '00101' => 'Stream_store',
744 '01001' => 'Int',
745 '01010' => 'FP(1)',
746 '01011' => 'FP(2)',
747 '01100' => 'blank',
748 '01101' => 'Fwd_req',
749 '01110' => 'Fwd_reply'
750 );
751
752 my $rawpkt = shift @_;
753 my $vld = substr $rawpkt, 0, 1;
754 my $rawtype = substr $rawpkt, 1, 5;
755 my $nc = substr $rawpkt, 6, 1;
756 my $cpuid = substr $rawpkt, 7, 3;
757 my $thrid = substr $rawpkt, 10, 2;
758 my $inv = substr $rawpkt, 12, 1;
759 my $pf = substr $rawpkt, 13, 1;
760 my $binit = substr $rawpkt, 14, 1;
761 my $repl = substr $rawpkt, 15, 2;
762 my $size = substr $rawpkt, 17, 3;
763 my $rawaddr = substr $rawpkt, 20, 40;
764 my $rawdata = substr $rawpkt, 60, 64;
765
766 my $addr = b2h($rawaddr);
767 my $data = b2h($rawdata);
768
769 my $type = "illegal";
770 $type = $ReqTyps{$rawtype} if (defined $ReqTyps{$rawtype});
771
772 my $reqid = 'TX';
773 if ($thrid eq '00'){ $reqid = 'T0'; }
774 elsif($thrid eq '01'){ $reqid = 'T1'; }
775 elsif($thrid eq '10'){ $reqid = 'T2'; }
776 elsif($thrid eq '11'){ $reqid = 'T3'; }
777
778 my $pkt = "$reqid\tPCX: $type nc $nc cpuid $cpuid thrid $thrid inv $inv pf $pf binit $binit repl $repl size $size addr $addr data $data";
779 return $pkt;
780}
781#====================================================================
782# makes sense of the CPX packet
783#====================================================================
784sub process_cpx_pkt{
785
786my %RtnTyps =
787 (
788 '0000' => 'Dfill',
789 '0001' => 'Ifill',
790 '0010' => 'Strm_Load',
791 '0011' => 'Evict_Inv',
792 '0100' => 'Store_Ack',
793 '0101' => 'Flush',
794 '0110' => 'Strm_Store_Ack',
795 '0111' => 'Int',
796 '1000' => 'FP',
797 '1001' => 'blank',
798 '1010' => 'Fwd_req',
799 '1011' => 'Fwd_Reply',
800 '1100' => 'Err',
801 );
802
803 my $rawpkt = shift @_;
804 my $vld = substr $rawpkt, 0, 1;
805 my $rawtype = substr $rawpkt, 1, 4;
806 my $l2miss = substr $rawpkt, 5, 1;
807 my $err = substr $rawpkt, 6, 2;
808 my $nc = substr $rawpkt, 8, 1;
809 my $shared = substr $rawpkt, 9, 7;
810 my $thrbits = substr $rawpkt, 9, 2;
811 my $rsvd = substr $rawpkt, 16, 1;
812 my $rawdata = substr $rawpkt, 17, 128;
813
814 my $type = "illegal";
815 $type = $RtnTyps{$rawtype} if (defined $RtnTyps{$rawtype});
816
817 my $data = b2h($rawdata);
818
819 my $thread = 'x';
820 if($thrbits eq '00'){
821 $thread = '0';
822 }
823 elsif($thrbits eq '01'){
824 $thread = '1';
825 }
826 elsif($thrbits eq '10'){
827 $thread = '2';
828 }
829 elsif($thrbits eq '11'){
830 $thread = '3';
831 }
832
833
834 my $pkt = "$thread\t\tCPX: $type l2miss $l2miss err $err nc $nc shared $shared rsvd $rsvd data $data";
835 return $pkt;
836}
837#====================================================================
838# binary to hex.
839#====================================================================
840sub b2h{
841
842 my $in = shift @_;
843
844 if($in =~ /x/i){
845 return "xxxxxxxx";
846 }
847
848 my @inlist = split //, $in;
849
850 my ($res, $i, $digit, @num, $strres);
851
852 while (@inlist){
853 $res = 0;
854 $i = shift @inlist;
855 $res = 2 * $res + $i;
856 $i = shift @inlist;
857 $res = 2 * $res + $i;
858 $i = shift @inlist;
859 $res = 2 * $res + $i;
860 $i = shift @inlist;
861 $res = 2 * $res + $i;
862
863 $digit = sprintf "%lx", $res;
864 push @num, $digit;
865 }
866
867 $strres = join '', @num;
868
869 return $strres;
870
871}
872
873#====================================================================
874#truncate PC length from the MSB zeroes (or FF-s)
875#====================================================================
876sub truncate_len{
877
878 my $pc = $_[0];
879 my($length) = length($pc);
880 my($va_length) = 12;
881
882 if($length>$va_length){
883 $pc =~ /(.{$va_length})$/;
884 $pc = $1;
885 }
886 elsif($pc=~ /^f/i) {
887 $pc= 'f' x ($va_length-$length) . $pc;
888 }
889 else {
890 $pc= '0' x ($va_length-$length) . $pc;
891 }
892 print "pc= $pc\n" if($debug);
893 $pc;
894}
895
896#====================================================================
897
898#====================================================================
899# sorti: sorts the input file in a special way.
900# very simple - the RTL messages are ordered and the SAS
901# messages are ordered, so all we need is merge sorting.
902# Notes:
903#-------
904# disambiguate lines on the same timetick. - register updates,
905# and info-perm messages
906#====================================================================
907sub sorti{
908
909 if($logfile =~ /\.gz$/) {
910 open(VCSRAW1, "gunzip -c $logfile | egrep 'sas|MAT|trig' | ") || die "cannot open gunzip -c $logfile";
911 open(VCSRAW2, "gunzip -c $logfile | egrep -v 'sas|MAT|trig' | ") || die "cannot open gunzip -c $logfile";
912 }else{
913 open(VCSRAW1, "egrep 'sas|MAT|trig' $logfile | ") || die "cannot open $logfile";
914 open(VCSRAW2, "egrep -v 'sas|MAT|trig' $logfile | ") || die "cannot open $logfile";
915 }
916
917 my $curtime1 = 0;
918 my $curtime2 = 0;
919 my $gets1 = 1;
920 my $gets2 = 1;
921 my $s1line;
922 my $s2line;
923
924 while(1) {
925
926# get the vcsraw1
927#----------------
928 if($gets1){
929 $s1line = <VCSRAW1>;
930 if(!$s1line){
931 if($s2line){
932 print $s2line;
933 }
934 while(<VCSRAW2>){
935 print;
936 }
937 last;
938 }
939 else{
940 if($s1line =~ /^(\d+)\s*:.*(gl|tl|pstate)_reg-M/) {
941 $curtime1 = $1 + 3;
942 }elsif($s1line =~ /^(\d+)\s*:.*reg-M/) {
943 $curtime1 = $1 + 10;
944 }elsif($s1line =~ /^(\d+)\s*:/) {
945 $curtime1 = $1 + 0;
946 }elsif($s1line =~ /^\((\d+)\)\s*:/) {
947 $curtime1 = $1 + 0;
948 }
949 }
950 }
951
952# get the vcsraw2
953#----------------
954 if($gets2){
955 $s2line = <VCSRAW2>;
956 if(!$s2line){
957 if($s1line){
958 print $s1line;
959 }
960 while(<VCSRAW1>){
961 print;
962 }
963 last;
964 }
965 else{
966 if($s2line =~ /^\((\d+)\)Info-p/) {
967 $curtime2 = $1 + 5;
968 }elsif($s2line =~ /^(\d+)\s*:/) {
969 $curtime2 = $1 + 0;
970 }elsif($s2line =~ /^\((\d+)\)\s*:/) {
971 $curtime2 = $1 + 0;
972 }
973 }
974 }
975
976 if($curtime1 < $curtime2){
977 print $s1line;
978 $gets2 = 0;
979 $gets1 = 1;
980 }
981 else{
982 print $s2line;
983 $gets2 = 1;
984 $gets1 = 0;
985 }
986 }
987
988 close(VCSRAW1);
989 close(VCSRAW2);
990
991 exit;
992
993}
994
995#=======================================================
996# print ASI mnemonics to make debugging more pleasurable.
997#=======================================================
998sub asi_mnem{
999my %asis = (
1000"4", "ASI_NUCLEUS",
1001"c", "ASI_NUCLEUS_LITTLE",
1002"10", "ASI_AS_IF_USER_PRIMARY",
1003"11", "ASI_AS_IF_USER_SECONDARY",
1004"14", "ASI_REAL_MEM",
1005"15", "ASI_REAL_IO",
1006"16", "ASI_BLOCK_AS_IF_USER_PRIMARY",
1007"17", "ASI_BLOCK_AS_IF_USER_SECONDARY",
1008"18", "ASI_AS_IF_USER_PRIMARY_LITTLE",
1009"19", "ASI_AS_IF_USER_SECONDARY_LITTLE",
1010"1c", "ASI_REAL_MEM_LITTLE",
1011"1d", "ASI_REAL_IO_LITTLE",
1012"1e", "ASI_BLOCK_AS_IF_USER_P_LITTLE",
1013"1f", "ASI_BLOCK_AS_IF_USER_S_LITTLE",
1014"20", "ASI_SCRATCHPAD",
1015"21", "ASI_MMU",
1016"22", "ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_P",
1017"23", "ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_S",
1018"24", "ASI_QUAD_LDD",
1019"25", "ASI_QUEUE",
1020"26", "ASI_QUAD_LDD_REAL",
1021"27", "ASI_NUCLEUS_BLK_INIT_ST_QUAD_LDD",
1022"2a", "ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_P_LITTLE",
1023"2b", "ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_S_LITTLE",
1024"2c", "ASI_QUAD_LDD_LITTLE",
1025"2e", "ASI_QUAD_LDD_REAL_LITTLE",
1026"2f", "ASI_NUCLEUS_BLK_INIT_ST_QUAD_LDD_P_LITTLE",
1027"30", "UNDEFINED",
1028"31", "ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0",
1029"32", "ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1",
1030"33", "ASI_DMMU_CTXT_ZERO_CONFIG",
1031"35", "ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0",
1032"36", "ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1",
1033"37", "ASI_IMMU_CTXT_ZERO_CONFIG",
1034"38", "ASI_DTSB_TAG_TARGET",
1035"39", "ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0",
1036"3a", "ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1",
1037"3b", "ASI_DMMU_CTXT_NONZERO_CONFIG",
1038"3d", "ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0",
1039"3e", "ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1",
1040"3f", "ASI_IMMU_CTXT_NONZERO_CONFIG",
1041"40", "ASI_STREAM_MA",
1042"42", "ASI_SPARC_BIST_CONTROL_OR_INST_MASK_REG_OR_LSU_DIAG_REG",
1043"43", "ASI_ERROR_INJECT_REG",
1044"44", "ASI_STM_CTL_REG",
1045"45", "ASI_LSU_CTL_REG",
1046"46", "ASI_DCACHE_DATA",
1047"47", "ASI_DCACHE_TAG",
1048"48", "ASI_INTR_DISPATCH_STATUS_OBSOLETE",
1049"49", "ASI_INTR_RECEIVE_OBSOLETE",
1050"4a", "ASI_OBSOLETE",
1051"4b", "ASI_SPARC_ERROR_EN_REG",
1052"4c", "ASI_SPARC_ERROR_STAT_REG",
1053"4d", "ASI_SPARC_ERROR_ADDR_REG",
1054"4e", "ASI_ECACHE_TAG_DATA",
1055"4f", "ASI_HYP_SCRATCHPAD",
1056"50", "ASI_IMMU",
1057"51", "ASI_IMMU_TSB_8KB_PTR_REG",
1058"52", "ASI_IMMU_TSB_64KB_PTR_REG",
1059"54", "ASI_ITLB_DATA_IN_REG",
1060"55", "ASI_ITLB_DATA_ACCESS_REG",
1061"56", "ASI_ITLB_TAG_READ_REG",
1062"57", "ASI_IMMU_DEMAP",
1063"58", "ASI_DMMU",
1064"59", "ASI_DMMU_TSB_8KB_PTR_REG",
1065"5a", "ASI_DMMU_TSB_64KB_PTR_REG",
1066"5b", "ASI_DMMU_TSB_DIRECT_PTR_REG",
1067"5c", "ASI_DTLB_DATA_IN_REG",
1068"5d", "ASI_DTLB_DATA_ACCESS_REG",
1069"5e", "ASI_DTLB_TAG_READ_REG",
1070"5f", "ASI_DMMU_DEMAP",
1071"60", "ASI_TLB_INVALIDATE_ALL",
1072"66", "ASI_ICACHE_INSTR",
1073"67", "ASI_ICACHE_TAG",
1074"72", "ASI_SWVR_INTR_RECEIVE",
1075"73", "ASI_SWVR_UDB_INTR_W",
1076"74", "ASI_SWVR_UDB_INTR_R",
1077"80", "ASI_PRIMARY",
1078"81", "ASI_SECONDARY",
1079"82", "ASI_PRIMARY_NO_FAULT",
1080"83", "ASI_SECONDARY_NO_FAULT",
1081"88", "ASI_PRIMARY_LITTLE",
1082"89", "ASI_SECONDARY_LITTLE",
1083"8a", "ASI_PRIMARY_NOFAULT_LITTLE",
1084"8b", "ASI_SECONDARY_NOFAULT_LITTLE",
1085"e2", "ASI_BLK_INIT_ST_QUAD_LDD_P",
1086"e3", "ASI_BLK_INIT_ST_QUAD_LDD_S",
1087"ea", "ASI_BLK_INIT_ST_QUAD_LDD_P_LITTLE",
1088"eb", "ASI_BLK_INIT_ST_QUAD_LDD_S_LITTLE",
1089"f0", "ASI_BLK_P",
1090"f1", "ASI_BLK_S",
1091"f8", "ASI_BLK_P_LITTLE",
1092"f9", "ASI_BLK_S_LITTLE"
1093);
1094
1095my $mykey = $_[0];
1096
1097if(exists $asis{$mykey}){
1098 return $asis{$mykey};
1099}
1100else {
1101 return "";
1102}
1103
1104}
1105#============================================
1106
1107# print cycles or timeticks.
1108#============================================
1109sub format_time
1110{
1111 my $time = $_[0];
1112 my $ctime = $_[1];
1113 my $cycles = $_[2];
1114
1115 if($cycles){
1116 if($ctime){
1117 $time = int ($time /$ctime);
1118 $time = 'c' . $time;
1119 }
1120 else { die "something is wrong with ctime\n" }
1121 }
1122 $time;
1123}
1124
1125#============================================