#!/bin/perl # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # use strict; use File::Basename; my $PROGNAME = basename($0); my ($funcunit, $error); my @funcunits = (); my @errorrefs = (); my $codelinesin = 0; # number of input 'code' lines for an ereport type my $codeoutlen = 0; # number of output lines from sub state_code my $state = "initial"; sub usage() { print STDERR "Usage: $PROGNAME inputfile\n"; exit(2); } sub bail() { print STDERR "$PROGNAME: ", join(" ", @_), "\n"; exit(1); } sub parsebail() { print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n"; exit(1); } sub error_alloc() { my @a = (); push(@::errorrefs, \@a); return (\@a); } sub error_dup() { my ($drop) = @_; my $newref = &error_alloc(); my $zeroref = $::errorrefs[0]; my $n = $#$zeroref - $drop; @$newref = @$zeroref[0 .. $n]; } sub code_lines() { return ($::codelinesin++); } sub error_init() { &error_alloc(); $::codelinesin = 0; } sub error_reset() { @::errorrefs = (); $::codelinesin = 0; $::codeoutlen = 0; } sub errout() { my ($line) = @_; foreach my $ref (@::errorrefs) { push(@$ref, $line); } } sub errout_N() { my ($instance, $line) = @_; my $ref = @::errorrefs[$instance]; push(@$ref, $line); return 1; } sub print_errout() { foreach my $ref (@::errorrefs) { print @$ref; } } sub print_header() { print "#include \n"; print "#include \"ao_mca_disp.h\"\n\n"; } sub print_footer() { print 'const ao_error_disp_t *ao_error_disp[] = {' . "\n"; foreach my $name (@funcunits) { print "\t$name,\n"; } print "};\n"; } sub funcunit_begin() { my $arrnm = "ao_error_disp_" . $_[0]; print "static const ao_error_disp_t " . $arrnm . "[] = {\n"; @funcunits = (@funcunits, $arrnm); } sub funcunit_end() { print "\t{ NULL }\n};\n\n"; } sub error_begin() { my ($ereport_name) = @_; $ereport_name =~ tr/[a-z]./[A-Z]_/; my $flags_name = $ereport_name; $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/; &errout("\tFM_$ereport_name,\n\tFM_$flags_name,\n"); } sub error_end() { &errout("\t},\n\n"); &print_errout(); &error_reset(); } sub print_bits() { my $name = $_[0]; my @bits = @_[1..$#_]; my $out = ""; if (@bits == 0) { $out = "\t0,"; } elsif (@bits == 1) { $out = "\t$bits[0],"; } else { $out = "\t( " . join(" | ", @bits) . " ),"; } $out .= " /* $name */" if (defined $name); $out .= "\n"; return ($out); } sub field_burst() { my ($field, $valuesref, $name, $prefix) = @_; if ($field eq "-") { return (); } map { if (!defined ${$valuesref}{$_}) { &parsebail("unknown $name value `$_'"); } $_ = ${$valuesref}{$_}; tr/[a-z]/[A-Z]/; $prefix . "_" . $_; } split(/\//, $field); } sub bin2dec() { my $bin = $_[0]; my $dec = 0; foreach my $bit (split(//, $bin)) { $dec = $dec * 2 + ($bit eq "1" ? 1 : 0); } $dec; } sub state_funcunit() { my $val = $_[0]; if (defined $::funcunit) { &funcunit_end(); } $::funcunit = $val; undef $::error; &funcunit_begin($::funcunit); } sub state_desc() { my $desc = $_[0]; &error_init(); &errout("\t/* $desc */\n\t{\n"); } sub state_error() { $::error = $_[0]; &error_begin($::error); } sub state_mask_on() { @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); } sub state_mask_off() { my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); &errout(&print_bits("mask", @::mask_on, @mask_off)); &errout(&print_bits("mask_res", @::mask_on)); } sub state_code() { my ($ext, $type, $pp, $t, $r4, $addr, $ii, $ll, $tt) = split(/\s+/, $_[0]); my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 ); my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 ); my %r4_values = ( 'err' => 'err', 'rd' => 'rd', 'wr' => 'wr', 'drd' => 'drd', 'dwr' => 'dwr', 'ird' => 'ird', 'pf' => 'prefetch', 'ev' => 'evict', 'snp' => 'snoop', '-' => '-'); my %pp_values = ( 'src' => 'src', 'res' => 'res', 'obs' => 'obs', 'gen' => 'gen', '-' => '-' ); my %t_values = ( 0 => 1, 1 => 1, '-' => 1 ); my %ii_values = ( 'mem' => 'mem', 'io' => 'io', 'gen' => 'gen', '-' => '-' ); my $instance = &code_lines(); if ($instance > 0) { &error_dup($::codeoutlen); # dup info thus far } if (!defined $tt_values{$tt}) { &parsebail("unknown tt value `$tt'"); } if (!defined $ll_values{$ll}) { &parsebail("unknown ll value `$ll'"); } my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT"); my @pp = ($pp eq '-') ? () : &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT"); if (!defined $t_values{$t}) { &parsebail("unknown t value `$t'"); } my @ii = ($ii eq '-') ? () : &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT"); map { tr/[a-z]/[A-Z]/; } ($ii, $ll, $tt); if ($type eq "bus") { if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" || $ll eq "-" || $tt ne "-") { &parsebail("invalid members for bus code type"); } $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKBUS(" . "0, " . # pp "MCAX86_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " . "0, " . # r4 "0, " . # ii "MCAX86_ERRCODE_LL_$ll),\n"); } elsif ($type eq "mem") { if ($r4 eq "-" || $tt eq "-" || $ll eq "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { &parsebail("invalid members for mem code type"); } $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKMEM(" . "0, " . # r4 "MCAX86_ERRCODE_TT_$tt, " . "MCAX86_ERRCODE_LL_$ll),\n"); } elsif ($type eq "tlb") { if ($tt eq "-" || $ll eq "-" || $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { &parsebail("invalid members for tlb code type"); } $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKTLB(" . "MCAX86_ERRCODE_TT_$tt, " . "MCAX86_ERRCODE_LL_$ll),\n"); } else { &parsebail("unknown code type `$type'"); } $::codeoutlen += &errout_N($instance, "\t" . &bin2dec($ext) . ", /* ext code $ext */\n"); $::codeoutlen += &errout_N($instance, &print_bits("pp_bits", @pp)); $::codeoutlen += &errout_N($instance, &print_bits("ii_bits", @ii)); $::codeoutlen += &errout_N($instance, &print_bits("r4_bits", @r4)); my $valid_hi; my $valid_lo; if ($addr eq "none") { $valid_hi = $valid_lo = 0; } elsif ($addr =~ /<(\d+):(\d+)>/) { $valid_hi = $1; $valid_lo = $2; } else { &parsebail("invalid addr specification"); } $::codeoutlen += &errout_N($instance, "\t" . $valid_hi . ", /* addr valid hi */\n"); $::codeoutlen += &errout_N($instance, "\t" . $valid_lo . ", /* addr valid lo */\n"); } sub state_panic() { my @vals = split(/,\s*/, $_[0]); if ($#vals < 0) { &errout("\t0, /* panic_when */\n"); } else { @vals = map { tr/[a-z]/[A-Z]/; "AO_AED_PANIC_" . $_; } @vals; &errout(&print_bits("panic_when", @vals)); } } sub state_flags() { my @flags = split(/,\s*/, $_[0]); @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags; &errout(&print_bits("flags", @flags)); } sub state_errtype() { my @types = split(/,\s*/, $_[0]); @types = map { tr/[a-z]/[A-Z]/; "AO_AED_ET_" . $_; } @types; &errout(&print_bits("errtype", @types)); } my %stateparse = ( funcunit => [ \&state_funcunit, 'desc' ], desc => [ \&state_desc, 'error' ], error => [ \&state_error, 'mask on' ], 'mask on' => [ \&state_mask_on, 'mask off' ], 'mask off' => [ \&state_mask_off, 'code' ], code => [ \&state_code, 'code|panic' ], panic => [ \&state_panic, 'flags' ], flags => [ \&state_flags, 'errtype' ], errtype => [ \&state_errtype, 'initial' ] ); usage unless (@ARGV == 1); my $infile = $ARGV[0]; open(INFILE, "<$infile") || &bail("failed to open $infile: $!"); &print_header(); while () { chop; /^#/ && next; /^$/ && next; if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) { &parsebail("failed to parse"); } my ($keyword, $val) = ($1, $2); if ($state eq "initial") { if ($keyword eq "funcunit") { $state = "funcunit"; } elsif ($keyword eq "desc") { $state = "desc"; } else { &parsebail("unexpected keyword $keyword between " . "errors"); } } elsif ($state eq "desc") { if ($keyword eq "funcunit") { $state = "funcunit"; } } if (!($keyword =~ /$state/)) { &parsebail("keyword `$keyword' invalid here; expected " . "`$state'"); } $state = $keyword; # disambiguate between multiple legal states if (!defined $stateparse{$state}) { &parsebail("attempt to transition to invalid state `$state'"); } my ($handler, $next) = @{$stateparse{$state}}; &{$handler}($val); $state = $next; if ($state eq "initial") { &error_end(); } } close(INFILE); if ($state ne "initial" && $state ne "desc") { &bail("input file ended prematurely"); } if (defined $::funcunit) { &funcunit_end(); } else { &bail("no functional units defined"); } &print_footer;