1#!/bin/perl 2# 3# CDDL HEADER START 4# 5# The contents of this file are subject to the terms of the 6# Common Development and Distribution License (the "License"). 7# You may not use this file except in compliance with the License. 8# 9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10# or http://www.opensolaris.org/os/licensing. 11# See the License for the specific language governing permissions 12# and limitations under the License. 13# 14# When distributing Covered Code, include this CDDL HEADER in each 15# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16# If applicable, add the following below this CDDL HEADER, with the 17# fields enclosed by brackets "[]" replaced with your own identifying 18# information: Portions Copyright [yyyy] [name of copyright owner] 19# 20# CDDL HEADER END 21# 22 23# 24# Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25# Use is subject to license terms. 26# 27# ident "%Z%%M% %I% %E% SMI" 28# 29 30use strict; 31use File::Basename; 32 33my $PROGNAME = basename($0); 34 35my ($funcunit, $error); 36my @funcunits = (); 37my @errorrefs = (); 38 39my $codelinesin = 0; # number of input 'code' lines for an ereport type 40my $codeoutlen = 0; # number of output lines from sub state_code 41 42my $state = "initial"; 43 44sub usage() { 45 print STDERR "Usage: $PROGNAME inputfile\n"; 46 exit(2); 47} 48 49sub bail() { 50 print STDERR "$PROGNAME: ", join(" ", @_), "\n"; 51 exit(1); 52} 53 54sub parsebail() { 55 print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n"; 56 exit(1); 57} 58 59sub error_alloc() { 60 my @a = (); 61 62 push(@::errorrefs, \@a); 63 return (\@a); 64} 65 66sub error_dup() { 67 my ($drop) = @_; 68 my $newref = &error_alloc(); 69 70 my $zeroref = $::errorrefs[0]; 71 72 my $n = $#$zeroref - $drop; 73 74 @$newref = @$zeroref[0 .. $n]; 75} 76 77sub code_lines() { 78 return ($::codelinesin++); 79} 80 81sub error_init() { 82 &error_alloc(); 83 $::codelinesin = 0; 84} 85 86sub error_reset() { 87 @::errorrefs = (); 88 $::codelinesin = 0; 89 $::codeoutlen = 0; 90} 91 92sub errout() { 93 my ($line) = @_; 94 95 foreach my $ref (@::errorrefs) { 96 push(@$ref, $line); 97 } 98} 99 100sub errout_N() { 101 my ($instance, $line) = @_; 102 my $ref = @::errorrefs[$instance]; 103 push(@$ref, $line); 104 return 1; 105} 106 107sub print_errout() { 108 foreach my $ref (@::errorrefs) { 109 print @$ref; 110 } 111} 112 113sub print_header() { 114 print "#include \"ao_mca_disp.h\"\n\n"; 115} 116 117sub print_footer() { 118 print 'const ao_error_disp_t *ao_error_disp[] = {' . "\n"; 119 120 foreach my $name (@funcunits) { 121 print "\t$name,\n"; 122 } 123 124 print "};\n"; 125} 126 127sub funcunit_begin() { 128 my $arrnm = "ao_error_disp_" . $_[0]; 129 print "static const ao_error_disp_t " . $arrnm . "[] = {\n"; 130 131 @funcunits = (@funcunits, $arrnm); 132} 133 134sub funcunit_end() { 135 print "\t{ NULL }\n};\n\n"; 136} 137 138sub error_begin() { 139 my ($ereport_name) = @_; 140 141 $ereport_name =~ tr/[a-z]./[A-Z]_/; 142 my $flags_name = $ereport_name; 143 $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/; 144 145 &errout("\tFM_$ereport_name,\n\tFM_$flags_name,\n"); 146} 147 148sub error_end() { 149 &errout("\t},\n\n"); 150 151 &print_errout(); 152 153 &error_reset(); 154} 155 156sub print_bits() { 157 my $name = $_[0]; 158 my @bits = @_[1..$#_]; 159 my $out = ""; 160 161 if (@bits == 0) { 162 $out = "\t0,"; 163 } elsif (@bits == 1) { 164 $out = "\t$bits[0],"; 165 } else { 166 $out = "\t( " . join(" | ", @bits) . " ),"; 167 } 168 169 $out .= " /* $name */" if (defined $name); 170 $out .= "\n"; 171 172 return ($out); 173} 174 175sub field_burst() { 176 my ($field, $valuesref, $name, $prefix) = @_; 177 178 if ($field eq "-") { 179 return (); 180 } 181 182 map { 183 if (!defined ${$valuesref}{$_}) { 184 &parsebail("unknown $name value `$_'"); 185 } 186 $_ = ${$valuesref}{$_}; 187 tr/[a-z]/[A-Z]/; 188 $prefix . "_" . $_; 189 } split(/\//, $field); 190} 191 192sub bin2dec() { 193 my $bin = $_[0]; 194 my $dec = 0; 195 196 foreach my $bit (split(//, $bin)) { 197 $dec = $dec * 2 + ($bit eq "1" ? 1 : 0); 198 } 199 200 $dec; 201} 202 203sub state_funcunit() { 204 my $val = $_[0]; 205 206 if (defined $::funcunit) { 207 &funcunit_end(); 208 } 209 210 $::funcunit = $val; 211 undef $::error; 212 &funcunit_begin($::funcunit); 213} 214 215sub state_desc() { 216 my $desc = $_[0]; 217 218 &error_init(); 219 220 &errout("\t/* $desc */\n\t{\n"); 221} 222 223sub state_error() { 224 $::error = $_[0]; 225 &error_begin($::error); 226} 227 228sub state_mask_on() { 229 @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); 230} 231 232sub state_mask_off() { 233 my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); 234 235 &errout(&print_bits("mask", @::mask_on, @mask_off)); 236 &errout(&print_bits("mask_res", @::mask_on)); 237} 238 239sub state_code() { 240 my ($ext, $type, $pp, $t, $r4, $addr, $ii, $ll, $tt) = 241 split(/\s+/, $_[0]); 242 243 my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 ); 244 my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 ); 245 246 my %r4_values = ( 247 gen => 'gen', 248 rd => 'rd', 249 wr => 'wr', 250 drd => 'drd', 251 dwr => 'dwr', 252 ird => 'ird', 253 pf => 'prefetch', 254 ev => 'evict', 255 snp => 'snoop', 256 '-' => '-'); 257 258 my %pp_values = ( 259 src => 'src', 260 rsp => 'rsp', 261 obs => 'obs', 262 gen => 'gen', 263 '-' => '-' ); 264 265 my %t_values = ( 0 => 1, 1 => 1, '-' => 1 ); 266 267 my %ii_values = ( 268 mem => 'mem', 269 io => 'io', 270 gen => 'gen', 271 '-' => '-' ); 272 273 my $instance = &code_lines(); 274 if ($instance > 0) { 275 &error_dup($::codeoutlen); # dup info thus far 276 } 277 278 if (!defined $tt_values{$tt}) { 279 &parsebail("unknown tt value `$tt'"); 280 } 281 282 if (!defined $ll_values{$ll}) { 283 &parsebail("unknown ll value `$ll'"); 284 } 285 286 my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT"); 287 288 my @pp = ($pp eq '-') ? () : 289 &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT"); 290 291 if (!defined $t_values{$t}) { 292 &parsebail("unknown t value `$t'"); 293 } 294 295 my @ii = ($ii eq '-') ? () : 296 &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT"); 297 298 map { 299 tr/[a-z]/[A-Z]/; 300 } ($ii, $ll, $tt); 301 302 if ($type eq "bus") { 303 if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" || 304 $ll eq "-" || 305 $tt ne "-") { 306 &parsebail("invalid members for bus code type"); 307 } 308 309 $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKBUS(" . 310 "0, " . # pp 311 "AMD_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " . 312 "0, " . # r4 313 "0, " . # ii 314 "AMD_ERRCODE_LL_$ll),\n"); 315 316 } elsif ($type eq "mem") { 317 if ($r4 eq "-" || $tt eq "-" || $ll eq "-" || 318 $pp ne "-" || $t ne "-" || $ii ne "-") { 319 &parsebail("invalid members for mem code type"); 320 } 321 322 $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKMEM(" . 323 "0, " . # r4 324 "AMD_ERRCODE_TT_$tt, " . 325 "AMD_ERRCODE_LL_$ll),\n"); 326 327 } elsif ($type eq "tlb") { 328 if ($tt eq "-" || $ll eq "-" || 329 $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { 330 &parsebail("invalid members for tlb code type"); 331 } 332 333 $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKTLB(" . 334 "AMD_ERRCODE_TT_$tt, " . 335 "AMD_ERRCODE_LL_$ll),\n"); 336 } else { 337 &parsebail("unknown code type `$type'"); 338 } 339 340 $::codeoutlen += &errout_N($instance, "\t" . &bin2dec($ext) . 341 ", /* ext code $ext */\n"); 342 343 $::codeoutlen += &errout_N($instance, &print_bits("pp_bits", @pp)); 344 $::codeoutlen += &errout_N($instance, &print_bits("ii_bits", @ii)); 345 $::codeoutlen += &errout_N($instance, &print_bits("r4_bits", @r4)); 346 347 my $valid_hi; 348 my $valid_lo; 349 350 if ($addr eq "none") { 351 $valid_hi = $valid_lo = 0; 352 } elsif ($addr =~ /<(\d+):(\d+)>/) { 353 $valid_hi = $1; 354 $valid_lo = $2; 355 } else { 356 &parsebail("invalid addr specification"); 357 } 358 $::codeoutlen += &errout_N($instance, "\t" . $valid_hi . 359 ", /* addr valid hi */\n"); 360 $::codeoutlen += &errout_N($instance, "\t" . $valid_lo . 361 ", /* addr valid lo */\n"); 362} 363 364sub state_panic() { 365 my @vals = split(/,\s*/, $_[0]); 366 367 if ($#vals < 0) { 368 &errout("\t0, /* panic_when */\n"); 369 } else { 370 @vals = map { tr/[a-z]/[A-Z]/; "AO_AED_PANIC_" . $_; } @vals; 371 &errout(&print_bits("panic_when", @vals)); 372 } 373} 374 375sub state_flags() { 376 my @flags = split(/,\s*/, $_[0]); 377 378 @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags; 379 380 &errout(&print_bits("flags", @flags)); 381} 382 383my %stateparse = ( 384 funcunit => [ \&state_funcunit, 'desc' ], 385 desc => [ \&state_desc, 'error' ], 386 error => [ \&state_error, 'mask on' ], 387 'mask on' => [ \&state_mask_on, 'mask off' ], 388 'mask off' => [ \&state_mask_off, 'code' ], 389 code => [ \&state_code, 'code|panic' ], 390 panic => [ \&state_panic, 'flags' ], 391 flags => [ \&state_flags, 'initial' ] 392); 393 394usage unless (@ARGV == 1); 395 396my $infile = $ARGV[0]; 397open(INFILE, "<$infile") || &bail("failed to open $infile: $!"); 398 399&print_header(); 400 401while (<INFILE>) { 402 chop; 403 404 /^#/ && next; 405 /^$/ && next; 406 407 if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) { 408 &parsebail("failed to parse"); 409 } 410 411 my ($keyword, $val) = ($1, $2); 412 413 if ($state eq "initial") { 414 if ($keyword eq "funcunit") { 415 $state = "funcunit"; 416 } elsif ($keyword eq "desc") { 417 $state = "desc"; 418 } else { 419 &parsebail("unexpected keyword $keyword between " . 420 "errors"); 421 } 422 423 } elsif ($state eq "desc") { 424 if ($keyword eq "funcunit") { 425 $state = "funcunit"; 426 } 427 } 428 429 if (!($keyword =~ /$state/)) { 430 &parsebail("keyword `$keyword' invalid here; expected " . 431 "`$state'"); 432 } 433 $state = $keyword; # disambiguate between multiple legal states 434 435 if (!defined $stateparse{$state}) { 436 &parsebail("attempt to transition to invalid state `$state'"); 437 } 438 439 my ($handler, $next) = @{$stateparse{$state}}; 440 441 &{$handler}($val); 442 443 $state = $next; 444 445 if ($state eq "initial") { 446 &error_end(); 447 } 448} 449 450close(INFILE); 451 452if ($state ne "initial" && $state ne "desc") { 453 &bail("input file ended prematurely"); 454} 455 456if (defined $::funcunit) { 457 &funcunit_end(); 458} else { 459 &bail("no functional units defined"); 460} 461 462&print_footer; 463