17aec1d6eScindi#!/bin/perl 27aec1d6eScindi# 37aec1d6eScindi# CDDL HEADER START 47aec1d6eScindi# 57aec1d6eScindi# The contents of this file are subject to the terms of the 6a307a255Sgavinm# Common Development and Distribution License (the "License"). 7a307a255Sgavinm# You may not use this file except in compliance with the License. 87aec1d6eScindi# 97aec1d6eScindi# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107aec1d6eScindi# or http://www.opensolaris.org/os/licensing. 117aec1d6eScindi# See the License for the specific language governing permissions 127aec1d6eScindi# and limitations under the License. 137aec1d6eScindi# 147aec1d6eScindi# When distributing Covered Code, include this CDDL HEADER in each 157aec1d6eScindi# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167aec1d6eScindi# If applicable, add the following below this CDDL HEADER, with the 177aec1d6eScindi# fields enclosed by brackets "[]" replaced with your own identifying 187aec1d6eScindi# information: Portions Copyright [yyyy] [name of copyright owner] 197aec1d6eScindi# 207aec1d6eScindi# CDDL HEADER END 217aec1d6eScindi# 227aec1d6eScindi 237aec1d6eScindi# 247aec1d6eScindi# Copyright 2006 Sun Microsystems, Inc. All rights reserved. 257aec1d6eScindi# Use is subject to license terms. 267aec1d6eScindi# 277aec1d6eScindi# ident "%Z%%M% %I% %E% SMI" 287aec1d6eScindi# 297aec1d6eScindi 307aec1d6eScindiuse strict; 317aec1d6eScindiuse File::Basename; 327aec1d6eScindi 337aec1d6eScindimy $PROGNAME = basename($0); 347aec1d6eScindi 357aec1d6eScindimy ($funcunit, $error); 367aec1d6eScindimy @funcunits = (); 37*4156fc34Sgavinmmy @errorrefs = (); 38*4156fc34Sgavinm 39*4156fc34Sgavinmmy $codelinesin = 0; # number of input 'code' lines for an ereport type 40*4156fc34Sgavinmmy $codeoutlen = 0; # number of output lines from sub state_code 417aec1d6eScindi 427aec1d6eScindimy $state = "initial"; 437aec1d6eScindi 447aec1d6eScindisub usage() { 457aec1d6eScindi print STDERR "Usage: $PROGNAME inputfile\n"; 467aec1d6eScindi exit(2); 477aec1d6eScindi} 487aec1d6eScindi 497aec1d6eScindisub bail() { 507aec1d6eScindi print STDERR "$PROGNAME: ", join(" ", @_), "\n"; 517aec1d6eScindi exit(1); 527aec1d6eScindi} 537aec1d6eScindi 547aec1d6eScindisub parsebail() { 557aec1d6eScindi print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n"; 567aec1d6eScindi exit(1); 577aec1d6eScindi} 587aec1d6eScindi 59*4156fc34Sgavinmsub error_alloc() { 60*4156fc34Sgavinm my @a = (); 61*4156fc34Sgavinm 62*4156fc34Sgavinm push(@::errorrefs, \@a); 63*4156fc34Sgavinm return (\@a); 64*4156fc34Sgavinm} 65*4156fc34Sgavinm 66*4156fc34Sgavinmsub error_dup() { 67*4156fc34Sgavinm my ($drop) = @_; 68*4156fc34Sgavinm my $newref = &error_alloc(); 69*4156fc34Sgavinm 70*4156fc34Sgavinm my $zeroref = $::errorrefs[0]; 71*4156fc34Sgavinm 72*4156fc34Sgavinm my $n = $#$zeroref - $drop; 73*4156fc34Sgavinm 74*4156fc34Sgavinm @$newref = @$zeroref[0 .. $n]; 75*4156fc34Sgavinm} 76*4156fc34Sgavinm 77*4156fc34Sgavinmsub code_lines() { 78*4156fc34Sgavinm return ($::codelinesin++); 79*4156fc34Sgavinm} 80*4156fc34Sgavinm 81*4156fc34Sgavinmsub error_init() { 82*4156fc34Sgavinm &error_alloc(); 83*4156fc34Sgavinm $::codelinesin = 0; 84*4156fc34Sgavinm} 85*4156fc34Sgavinm 86*4156fc34Sgavinmsub error_reset() { 87*4156fc34Sgavinm @::errorrefs = (); 88*4156fc34Sgavinm $::codelinesin = 0; 89*4156fc34Sgavinm $::codeoutlen = 0; 90*4156fc34Sgavinm} 91*4156fc34Sgavinm 92*4156fc34Sgavinmsub errout() { 93*4156fc34Sgavinm my ($line) = @_; 94*4156fc34Sgavinm 95*4156fc34Sgavinm foreach my $ref (@::errorrefs) { 96*4156fc34Sgavinm push(@$ref, $line); 97*4156fc34Sgavinm } 98*4156fc34Sgavinm} 99*4156fc34Sgavinm 100*4156fc34Sgavinmsub errout_N() { 101*4156fc34Sgavinm my ($instance, $line) = @_; 102*4156fc34Sgavinm my $ref = @::errorrefs[$instance]; 103*4156fc34Sgavinm push(@$ref, $line); 104*4156fc34Sgavinm return 1; 105*4156fc34Sgavinm} 106*4156fc34Sgavinm 107*4156fc34Sgavinmsub print_errout() { 108*4156fc34Sgavinm foreach my $ref (@::errorrefs) { 109*4156fc34Sgavinm print @$ref; 110*4156fc34Sgavinm } 111*4156fc34Sgavinm} 112*4156fc34Sgavinm 1137aec1d6eScindisub print_header() { 1147aec1d6eScindi print "#include \"ao_mca_disp.h\"\n\n"; 1157aec1d6eScindi} 1167aec1d6eScindi 1177aec1d6eScindisub print_footer() { 118*4156fc34Sgavinm print 'const ao_error_disp_t *ao_error_disp[] = {' . "\n"; 1197aec1d6eScindi 1207aec1d6eScindi foreach my $name (@funcunits) { 1217aec1d6eScindi print "\t$name,\n"; 1227aec1d6eScindi } 1237aec1d6eScindi 1247aec1d6eScindi print "};\n"; 1257aec1d6eScindi} 1267aec1d6eScindi 1277aec1d6eScindisub funcunit_begin() { 1287aec1d6eScindi my $arrnm = "ao_error_disp_" . $_[0]; 1297aec1d6eScindi print "static const ao_error_disp_t " . $arrnm . "[] = {\n"; 1307aec1d6eScindi 1317aec1d6eScindi @funcunits = (@funcunits, $arrnm); 1327aec1d6eScindi} 1337aec1d6eScindi 1347aec1d6eScindisub funcunit_end() { 135*4156fc34Sgavinm print "\t{ NULL }\n};\n\n"; 1367aec1d6eScindi} 1377aec1d6eScindi 1387aec1d6eScindisub error_begin() { 1397aec1d6eScindi my ($ereport_name) = @_; 1407aec1d6eScindi 1417aec1d6eScindi $ereport_name =~ tr/[a-z]./[A-Z]_/; 1427aec1d6eScindi my $flags_name = $ereport_name; 1437aec1d6eScindi $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/; 1447aec1d6eScindi 145*4156fc34Sgavinm &errout("\tFM_$ereport_name,\n\tFM_$flags_name,\n"); 1467aec1d6eScindi} 1477aec1d6eScindi 1487aec1d6eScindisub error_end() { 149*4156fc34Sgavinm &errout("\t},\n\n"); 150*4156fc34Sgavinm 151*4156fc34Sgavinm &print_errout(); 152*4156fc34Sgavinm 153*4156fc34Sgavinm &error_reset(); 1547aec1d6eScindi} 1557aec1d6eScindi 1567aec1d6eScindisub print_bits() { 1577aec1d6eScindi my $name = $_[0]; 1587aec1d6eScindi my @bits = @_[1..$#_]; 159*4156fc34Sgavinm my $out = ""; 1607aec1d6eScindi 1617aec1d6eScindi if (@bits == 0) { 162*4156fc34Sgavinm $out = "\t0,"; 1637aec1d6eScindi } elsif (@bits == 1) { 164*4156fc34Sgavinm $out = "\t$bits[0],"; 1657aec1d6eScindi } else { 166*4156fc34Sgavinm $out = "\t( " . join(" | ", @bits) . " ),"; 1677aec1d6eScindi } 1687aec1d6eScindi 169*4156fc34Sgavinm $out .= " /* $name */" if (defined $name); 170*4156fc34Sgavinm $out .= "\n"; 171*4156fc34Sgavinm 172*4156fc34Sgavinm return ($out); 1737aec1d6eScindi} 1747aec1d6eScindi 1757aec1d6eScindisub field_burst() { 1767aec1d6eScindi my ($field, $valuesref, $name, $prefix) = @_; 1777aec1d6eScindi 1787aec1d6eScindi if ($field eq "-") { 1797aec1d6eScindi return (); 1807aec1d6eScindi } 1817aec1d6eScindi 1827aec1d6eScindi map { 1837aec1d6eScindi if (!defined ${$valuesref}{$_}) { 1847aec1d6eScindi &parsebail("unknown $name value `$_'"); 1857aec1d6eScindi } 1867aec1d6eScindi $_ = ${$valuesref}{$_}; 1877aec1d6eScindi tr/[a-z]/[A-Z]/; 1887aec1d6eScindi $prefix . "_" . $_; 1897aec1d6eScindi } split(/\//, $field); 1907aec1d6eScindi} 1917aec1d6eScindi 1927aec1d6eScindisub bin2dec() { 1937aec1d6eScindi my $bin = $_[0]; 1947aec1d6eScindi my $dec = 0; 1957aec1d6eScindi 1967aec1d6eScindi foreach my $bit (split(//, $bin)) { 1977aec1d6eScindi $dec = $dec * 2 + ($bit eq "1" ? 1 : 0); 1987aec1d6eScindi } 1997aec1d6eScindi 2007aec1d6eScindi $dec; 2017aec1d6eScindi} 2027aec1d6eScindi 2037aec1d6eScindisub state_funcunit() { 2047aec1d6eScindi my $val = $_[0]; 2057aec1d6eScindi 2067aec1d6eScindi if (defined $::funcunit) { 2077aec1d6eScindi &funcunit_end(); 2087aec1d6eScindi } 2097aec1d6eScindi 2107aec1d6eScindi $::funcunit = $val; 2117aec1d6eScindi undef $::error; 2127aec1d6eScindi &funcunit_begin($::funcunit); 2137aec1d6eScindi} 2147aec1d6eScindi 2157aec1d6eScindisub state_desc() { 2167aec1d6eScindi my $desc = $_[0]; 2177aec1d6eScindi 218*4156fc34Sgavinm &error_init(); 219*4156fc34Sgavinm 220*4156fc34Sgavinm &errout("\t/* $desc */\n\t{\n"); 2217aec1d6eScindi} 2227aec1d6eScindi 2237aec1d6eScindisub state_error() { 2247aec1d6eScindi $::error = $_[0]; 2257aec1d6eScindi &error_begin($::error); 2267aec1d6eScindi} 2277aec1d6eScindi 2287aec1d6eScindisub state_mask_on() { 2297aec1d6eScindi @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); 2307aec1d6eScindi} 2317aec1d6eScindi 2327aec1d6eScindisub state_mask_off() { 2337aec1d6eScindi my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); 2347aec1d6eScindi 235*4156fc34Sgavinm &errout(&print_bits("mask", @::mask_on, @mask_off)); 236*4156fc34Sgavinm &errout(&print_bits("mask_res", @::mask_on)); 2377aec1d6eScindi} 2387aec1d6eScindi 2397aec1d6eScindisub state_code() { 240*4156fc34Sgavinm my ($ext, $type, $pp, $t, $r4, $addr, $ii, $ll, $tt) = 241*4156fc34Sgavinm split(/\s+/, $_[0]); 2427aec1d6eScindi 2437aec1d6eScindi my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 ); 2447aec1d6eScindi my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 ); 2457aec1d6eScindi 2467aec1d6eScindi my %r4_values = ( 2477aec1d6eScindi gen => 'gen', 2487aec1d6eScindi rd => 'rd', 2497aec1d6eScindi wr => 'wr', 2507aec1d6eScindi drd => 'drd', 2517aec1d6eScindi dwr => 'dwr', 2527aec1d6eScindi ird => 'ird', 2537aec1d6eScindi pf => 'prefetch', 2547aec1d6eScindi ev => 'evict', 2557aec1d6eScindi snp => 'snoop', 2567aec1d6eScindi '-' => '-'); 2577aec1d6eScindi 2587aec1d6eScindi my %pp_values = ( 2597aec1d6eScindi src => 'src', 2607aec1d6eScindi rsp => 'rsp', 2617aec1d6eScindi obs => 'obs', 2627aec1d6eScindi gen => 'gen', 2637aec1d6eScindi '-' => '-' ); 2647aec1d6eScindi 2657aec1d6eScindi my %t_values = ( 0 => 1, 1 => 1, '-' => 1 ); 2667aec1d6eScindi 2677aec1d6eScindi my %ii_values = ( 2687aec1d6eScindi mem => 'mem', 2697aec1d6eScindi io => 'io', 2707aec1d6eScindi gen => 'gen', 2717aec1d6eScindi '-' => '-' ); 2727aec1d6eScindi 273*4156fc34Sgavinm my $instance = &code_lines(); 274*4156fc34Sgavinm if ($instance > 0) { 275*4156fc34Sgavinm &error_dup($::codeoutlen); # dup info thus far 276*4156fc34Sgavinm } 277*4156fc34Sgavinm 2787aec1d6eScindi if (!defined $tt_values{$tt}) { 2797aec1d6eScindi &parsebail("unknown tt value `$tt'"); 2807aec1d6eScindi } 2817aec1d6eScindi 2827aec1d6eScindi if (!defined $ll_values{$ll}) { 2837aec1d6eScindi &parsebail("unknown ll value `$ll'"); 2847aec1d6eScindi } 2857aec1d6eScindi 2867aec1d6eScindi my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT"); 2877aec1d6eScindi 2887aec1d6eScindi my @pp = ($pp eq '-') ? () : 2897aec1d6eScindi &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT"); 2907aec1d6eScindi 2917aec1d6eScindi if (!defined $t_values{$t}) { 2927aec1d6eScindi &parsebail("unknown t value `$t'"); 2937aec1d6eScindi } 2947aec1d6eScindi 2957aec1d6eScindi my @ii = ($ii eq '-') ? () : 2967aec1d6eScindi &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT"); 2977aec1d6eScindi 2987aec1d6eScindi map { 2997aec1d6eScindi tr/[a-z]/[A-Z]/; 3007aec1d6eScindi } ($ii, $ll, $tt); 3017aec1d6eScindi 3027aec1d6eScindi if ($type eq "bus") { 3037aec1d6eScindi if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" || 3047aec1d6eScindi $ll eq "-" || 3057aec1d6eScindi $tt ne "-") { 3067aec1d6eScindi &parsebail("invalid members for bus code type"); 3077aec1d6eScindi } 3087aec1d6eScindi 309*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKBUS(" . 3107aec1d6eScindi "0, " . # pp 3117aec1d6eScindi "AMD_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " . 3127aec1d6eScindi "0, " . # r4 3137aec1d6eScindi "0, " . # ii 314*4156fc34Sgavinm "AMD_ERRCODE_LL_$ll),\n"); 3157aec1d6eScindi 3167aec1d6eScindi } elsif ($type eq "mem") { 3177aec1d6eScindi if ($r4 eq "-" || $tt eq "-" || $ll eq "-" || 3187aec1d6eScindi $pp ne "-" || $t ne "-" || $ii ne "-") { 3197aec1d6eScindi &parsebail("invalid members for mem code type"); 3207aec1d6eScindi } 3217aec1d6eScindi 322*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKMEM(" . 3237aec1d6eScindi "0, " . # r4 3247aec1d6eScindi "AMD_ERRCODE_TT_$tt, " . 325*4156fc34Sgavinm "AMD_ERRCODE_LL_$ll),\n"); 3267aec1d6eScindi 3277aec1d6eScindi } elsif ($type eq "tlb") { 3287aec1d6eScindi if ($tt eq "-" || $ll eq "-" || 3297aec1d6eScindi $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { 3307aec1d6eScindi &parsebail("invalid members for tlb code type"); 3317aec1d6eScindi } 3327aec1d6eScindi 333*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKTLB(" . 3347aec1d6eScindi "AMD_ERRCODE_TT_$tt, " . 335*4156fc34Sgavinm "AMD_ERRCODE_LL_$ll),\n"); 3367aec1d6eScindi } else { 3377aec1d6eScindi &parsebail("unknown code type `$type'"); 3387aec1d6eScindi } 3397aec1d6eScindi 340*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, "\t" . &bin2dec($ext) . 341*4156fc34Sgavinm ", /* ext code $ext */\n"); 3427aec1d6eScindi 343*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, &print_bits("pp_bits", @pp)); 344*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, &print_bits("ii_bits", @ii)); 345*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, &print_bits("r4_bits", @r4)); 346*4156fc34Sgavinm 347*4156fc34Sgavinm my $valid_hi; 348*4156fc34Sgavinm my $valid_lo; 349*4156fc34Sgavinm 350*4156fc34Sgavinm if ($addr eq "none") { 351*4156fc34Sgavinm $valid_hi = $valid_lo = 0; 352*4156fc34Sgavinm } elsif ($addr =~ /<(\d+):(\d+)>/) { 353*4156fc34Sgavinm $valid_hi = $1; 354*4156fc34Sgavinm $valid_lo = $2; 355*4156fc34Sgavinm } else { 356*4156fc34Sgavinm &parsebail("invalid addr specification"); 357*4156fc34Sgavinm } 358*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, "\t" . $valid_hi . 359*4156fc34Sgavinm ", /* addr valid hi */\n"); 360*4156fc34Sgavinm $::codeoutlen += &errout_N($instance, "\t" . $valid_lo . 361*4156fc34Sgavinm ", /* addr valid lo */\n"); 3627aec1d6eScindi} 3637aec1d6eScindi 3647aec1d6eScindisub state_panic() { 365a307a255Sgavinm my @vals = split(/,\s*/, $_[0]); 3667aec1d6eScindi 367a307a255Sgavinm if ($#vals < 0) { 368*4156fc34Sgavinm &errout("\t0, /* panic_when */\n"); 3697aec1d6eScindi } else { 370a307a255Sgavinm @vals = map { tr/[a-z]/[A-Z]/; "AO_AED_PANIC_" . $_; } @vals; 371*4156fc34Sgavinm &errout(&print_bits("panic_when", @vals)); 3727aec1d6eScindi } 3737aec1d6eScindi} 3747aec1d6eScindi 3757aec1d6eScindisub state_flags() { 3767aec1d6eScindi my @flags = split(/,\s*/, $_[0]); 3777aec1d6eScindi 3787aec1d6eScindi @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags; 3797aec1d6eScindi 380*4156fc34Sgavinm &errout(&print_bits("flags", @flags)); 3817aec1d6eScindi} 3827aec1d6eScindi 3837aec1d6eScindimy %stateparse = ( 384*4156fc34Sgavinm funcunit => [ \&state_funcunit, 'desc' ], 385*4156fc34Sgavinm desc => [ \&state_desc, 'error' ], 386*4156fc34Sgavinm error => [ \&state_error, 'mask on' ], 387*4156fc34Sgavinm 'mask on' => [ \&state_mask_on, 'mask off' ], 388*4156fc34Sgavinm 'mask off' => [ \&state_mask_off, 'code' ], 389*4156fc34Sgavinm code => [ \&state_code, 'code|panic' ], 390*4156fc34Sgavinm panic => [ \&state_panic, 'flags' ], 391*4156fc34Sgavinm flags => [ \&state_flags, 'initial' ] 3927aec1d6eScindi); 3937aec1d6eScindi 3947aec1d6eScindiusage unless (@ARGV == 1); 3957aec1d6eScindi 3967aec1d6eScindimy $infile = $ARGV[0]; 3977aec1d6eScindiopen(INFILE, "<$infile") || &bail("failed to open $infile: $!"); 3987aec1d6eScindi 3997aec1d6eScindi&print_header(); 4007aec1d6eScindi 4017aec1d6eScindiwhile (<INFILE>) { 4027aec1d6eScindi chop; 4037aec1d6eScindi 4047aec1d6eScindi /^#/ && next; 4057aec1d6eScindi /^$/ && next; 4067aec1d6eScindi 4077aec1d6eScindi if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) { 4087aec1d6eScindi &parsebail("failed to parse"); 4097aec1d6eScindi } 4107aec1d6eScindi 4117aec1d6eScindi my ($keyword, $val) = ($1, $2); 4127aec1d6eScindi 4137aec1d6eScindi if ($state eq "initial") { 4147aec1d6eScindi if ($keyword eq "funcunit") { 4157aec1d6eScindi $state = "funcunit"; 4167aec1d6eScindi } elsif ($keyword eq "desc") { 4177aec1d6eScindi $state = "desc"; 4187aec1d6eScindi } else { 4197aec1d6eScindi &parsebail("unexpected keyword $keyword between " . 4207aec1d6eScindi "errors"); 4217aec1d6eScindi } 4227aec1d6eScindi 4237aec1d6eScindi } elsif ($state eq "desc") { 4247aec1d6eScindi if ($keyword eq "funcunit") { 4257aec1d6eScindi $state = "funcunit"; 4267aec1d6eScindi } 4277aec1d6eScindi } 4287aec1d6eScindi 429*4156fc34Sgavinm if (!($keyword =~ /$state/)) { 430*4156fc34Sgavinm &parsebail("keyword `$keyword' invalid here; expected " . 431*4156fc34Sgavinm "`$state'"); 4327aec1d6eScindi } 433*4156fc34Sgavinm $state = $keyword; # disambiguate between multiple legal states 4347aec1d6eScindi 4357aec1d6eScindi if (!defined $stateparse{$state}) { 4367aec1d6eScindi &parsebail("attempt to transition to invalid state `$state'"); 4377aec1d6eScindi } 4387aec1d6eScindi 4397aec1d6eScindi my ($handler, $next) = @{$stateparse{$state}}; 4407aec1d6eScindi 4417aec1d6eScindi &{$handler}($val); 4427aec1d6eScindi 4437aec1d6eScindi $state = $next; 4447aec1d6eScindi 4457aec1d6eScindi if ($state eq "initial") { 4467aec1d6eScindi &error_end(); 4477aec1d6eScindi } 4487aec1d6eScindi} 4497aec1d6eScindi 4507aec1d6eScindiclose(INFILE); 4517aec1d6eScindi 4527aec1d6eScindiif ($state ne "initial" && $state ne "desc") { 4537aec1d6eScindi &bail("input file ended prematurely"); 4547aec1d6eScindi} 4557aec1d6eScindi 4567aec1d6eScindiif (defined $::funcunit) { 4577aec1d6eScindi &funcunit_end(); 4587aec1d6eScindi} else { 4597aec1d6eScindi &bail("no functional units defined"); 4607aec1d6eScindi} 4617aec1d6eScindi 4627aec1d6eScindi&print_footer; 463