| 1 | |
| 2 | use strict; |
| 3 | use IO::Handle; |
| 4 | use Getopt::Long; |
| 5 | |
| 6 | sub update_regs; |
| 7 | sub print_regs; |
| 8 | sub error; |
| 9 | sub b2h; |
| 10 | sub format_time; |
| 11 | |
| 12 | $SIG{__WARN__} = sub {die $_[0]}; |
| 13 | |
| 14 | # Initialize and defines all kinds of variables |
| 15 | #---------------------------------------------- |
| 16 | $| = 1; # autoflush |
| 17 | my(@gl); # global register level per thread |
| 18 | my(@tl); # trap level per thread |
| 19 | my(@cwp); # current window pointer per thread |
| 20 | my($logfile); # what file to read |
| 21 | |
| 22 | # global, FP, integer, asi registers |
| 23 | my(@gregs, @fpregs, @regs, @asi_reg); |
| 24 | |
| 25 | my($pc, $inst); # program counter, instructions |
| 26 | my(%diag_code, %label); # disassembled diag code and labels |
| 27 | my($time, $spc, $thr, $proc, $reg, $val, $win, $instr, $tmp); |
| 28 | my(@instr_list); # instruction list |
| 29 | my($PROG) = ($0=~ m%([^/]+)$%); # regreport real name |
| 30 | |
| 31 | my(%miss); # additional info - less important |
| 32 | my(%notintlb); # additional info - less important |
| 33 | |
| 34 | my($i, $k); |
| 35 | my $version = '1.NN'; |
| 36 | |
| 37 | print "===============================================\n"; |
| 38 | print "=== OpenSPARC T1 Vlog Version $version ===\n"; |
| 39 | print "===============================================\n"; |
| 40 | |
| 41 | my @Options = qw( debug sas mom h help ccx l2 dram cycles sort! perf); |
| 42 | my %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 | |
| 55 | GetOptions(\%opt, @Options) or die "Error in arguments!\n"; |
| 56 | my($debug) = $opt{debug}; |
| 57 | my($sas) = $opt{sas}; |
| 58 | my($mom) = $opt{mom}; |
| 59 | my($ccx) = $opt{ccx}; |
| 60 | my($l2) = $opt{l2}; |
| 61 | my($dram) = $opt{dram}; |
| 62 | my($h) = $opt{h}; |
| 63 | my($help) = $opt{help}; |
| 64 | my($cycles) = $opt{cycles}; |
| 65 | my($sorti) = $opt{sort}; |
| 66 | my($perf) = $opt{perf}; |
| 67 | |
| 68 | |
| 69 | if($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 | |
| 92 | if($debug) { print "Debug mode on\n"; } |
| 93 | if($sas) { print "sas mode\n"; } |
| 94 | if($mom) { print "mom mode\n"; } |
| 95 | if($sorti) { print "sort mode\n"; } |
| 96 | if($perf) { print "perf mode\n"; } |
| 97 | |
| 98 | #========================================== |
| 99 | # initialize register hashes. |
| 100 | #========================================== |
| 101 | for ($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 | #========================================== |
| 127 | my $logfilename = $mom ? "sas.log" : "sim.log"; |
| 128 | |
| 129 | if($#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 | |
| 150 | print "\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 | #------------------------------------- |
| 156 | if($sorti && !$mom){ |
| 157 | my $pid = open(VCS, "-|"); |
| 158 | unless (defined $pid){die "cannot fork $!\n"} |
| 159 | if(!$pid){sorti();} |
| 160 | } |
| 161 | else{ |
| 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 |
| 172 | if((! -f "symbol.tbl") &&(-f "symbol.tbl.gz")){ |
| 173 | system("gunzip symbol.tbl.gz"); |
| 174 | } |
| 175 | |
| 176 | if(! -f "symbol.tbl") {print "no symbol.tbl\n"; exit 0;} |
| 177 | open(SYM , "symbol.tbl") || die " BAD BAD symbol.tbl opening"; |
| 178 | while(<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 | #--------------------- |
| 194 | my(@diag_exe_files) = `ls diag*.exe*`; |
| 195 | if(!(@diag_exe_files)){ |
| 196 | print "Warning: No diag.\*exe files!!!\n"; |
| 197 | } |
| 198 | else{ |
| 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 | #============================================================ |
| 233 | my $found_ctime = 0; |
| 234 | my $pll_freq = 0; |
| 235 | my $cmp_clk_divider = 0; |
| 236 | my($ctime) = 0; |
| 237 | |
| 238 | # the main loop: |
| 239 | #--------------- |
| 240 | while(<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 | |
| 607 | close(VCS); |
| 608 | print "\nBye\n"; |
| 609 | |
| 610 | #========================== |
| 611 | |
| 612 | sub 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 | #========================== |
| 627 | sub 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. |
| 677 | sub 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 | #==================================================================== |
| 731 | sub process_pcx_pkt{ |
| 732 | |
| 733 | my %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 | #==================================================================== |
| 784 | sub process_cpx_pkt{ |
| 785 | |
| 786 | my %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 | #==================================================================== |
| 840 | sub 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 | #==================================================================== |
| 876 | sub 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 | #==================================================================== |
| 907 | sub 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 | #======================================================= |
| 998 | sub asi_mnem{ |
| 999 | my %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 | |
| 1095 | my $mykey = $_[0]; |
| 1096 | |
| 1097 | if(exists $asis{$mykey}){ |
| 1098 | return $asis{$mykey}; |
| 1099 | } |
| 1100 | else { |
| 1101 | return ""; |
| 1102 | } |
| 1103 | |
| 1104 | } |
| 1105 | #============================================ |
| 1106 | |
| 1107 | # print cycles or timeticks. |
| 1108 | #============================================ |
| 1109 | sub 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 | #============================================ |