xref: /titanic_51/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl (revision 20c794b39650d115e17a15983b6b82e46238cf45)
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#
24*20c794b3Sgavinm# Copyright 2007 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 = ();
374156fc34Sgavinmmy @errorrefs = ();
384156fc34Sgavinm
394156fc34Sgavinmmy $codelinesin = 0;	# number of input 'code' lines for an ereport type
404156fc34Sgavinmmy $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
594156fc34Sgavinmsub error_alloc() {
604156fc34Sgavinm	my @a = ();
614156fc34Sgavinm
624156fc34Sgavinm	push(@::errorrefs, \@a);
634156fc34Sgavinm	return (\@a);
644156fc34Sgavinm}
654156fc34Sgavinm
664156fc34Sgavinmsub error_dup() {
674156fc34Sgavinm	my ($drop) = @_;
684156fc34Sgavinm	my $newref = &error_alloc();
694156fc34Sgavinm
704156fc34Sgavinm	my $zeroref = $::errorrefs[0];
714156fc34Sgavinm
724156fc34Sgavinm	my $n = $#$zeroref - $drop;
734156fc34Sgavinm
744156fc34Sgavinm	@$newref = @$zeroref[0 .. $n];
754156fc34Sgavinm}
764156fc34Sgavinm
774156fc34Sgavinmsub code_lines() {
784156fc34Sgavinm	return ($::codelinesin++);
794156fc34Sgavinm}
804156fc34Sgavinm
814156fc34Sgavinmsub error_init() {
824156fc34Sgavinm	&error_alloc();
834156fc34Sgavinm	$::codelinesin = 0;
844156fc34Sgavinm}
854156fc34Sgavinm
864156fc34Sgavinmsub error_reset() {
874156fc34Sgavinm	@::errorrefs = ();
884156fc34Sgavinm	$::codelinesin = 0;
894156fc34Sgavinm	$::codeoutlen = 0;
904156fc34Sgavinm}
914156fc34Sgavinm
924156fc34Sgavinmsub errout() {
934156fc34Sgavinm	my ($line) = @_;
944156fc34Sgavinm
954156fc34Sgavinm	foreach my $ref (@::errorrefs) {
964156fc34Sgavinm		push(@$ref, $line);
974156fc34Sgavinm	}
984156fc34Sgavinm}
994156fc34Sgavinm
1004156fc34Sgavinmsub errout_N() {
1014156fc34Sgavinm	my ($instance, $line) = @_;
1024156fc34Sgavinm	my $ref = @::errorrefs[$instance];
1034156fc34Sgavinm	push(@$ref, $line);
1044156fc34Sgavinm	return 1;
1054156fc34Sgavinm}
1064156fc34Sgavinm
1074156fc34Sgavinmsub print_errout() {
1084156fc34Sgavinm	foreach my $ref (@::errorrefs) {
1094156fc34Sgavinm		print @$ref;
1104156fc34Sgavinm	}
1114156fc34Sgavinm}
1124156fc34Sgavinm
1137aec1d6eScindisub print_header() {
114*20c794b3Sgavinm	print "#include <sys/mca_x86.h>\n";
1157aec1d6eScindi	print "#include \"ao_mca_disp.h\"\n\n";
1167aec1d6eScindi}
1177aec1d6eScindi
1187aec1d6eScindisub print_footer() {
1194156fc34Sgavinm	print 'const ao_error_disp_t *ao_error_disp[] = {' . "\n";
1207aec1d6eScindi
1217aec1d6eScindi	foreach my $name (@funcunits) {
1227aec1d6eScindi		print "\t$name,\n";
1237aec1d6eScindi	}
1247aec1d6eScindi
1257aec1d6eScindi	print "};\n";
1267aec1d6eScindi}
1277aec1d6eScindi
1287aec1d6eScindisub funcunit_begin() {
1297aec1d6eScindi	my $arrnm = "ao_error_disp_" . $_[0];
1307aec1d6eScindi	print "static const ao_error_disp_t " . $arrnm . "[] = {\n";
1317aec1d6eScindi
1327aec1d6eScindi	@funcunits = (@funcunits, $arrnm);
1337aec1d6eScindi}
1347aec1d6eScindi
1357aec1d6eScindisub funcunit_end() {
1364156fc34Sgavinm	print "\t{ NULL }\n};\n\n";
1377aec1d6eScindi}
1387aec1d6eScindi
1397aec1d6eScindisub error_begin() {
1407aec1d6eScindi	my ($ereport_name) = @_;
1417aec1d6eScindi
1427aec1d6eScindi	$ereport_name =~ tr/[a-z]./[A-Z]_/;
1437aec1d6eScindi	my $flags_name = $ereport_name;
1447aec1d6eScindi	$flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/;
1457aec1d6eScindi
1464156fc34Sgavinm	&errout("\tFM_$ereport_name,\n\tFM_$flags_name,\n");
1477aec1d6eScindi}
1487aec1d6eScindi
1497aec1d6eScindisub error_end() {
1504156fc34Sgavinm	&errout("\t},\n\n");
1514156fc34Sgavinm
1524156fc34Sgavinm	&print_errout();
1534156fc34Sgavinm
1544156fc34Sgavinm	&error_reset();
1557aec1d6eScindi}
1567aec1d6eScindi
1577aec1d6eScindisub print_bits() {
1587aec1d6eScindi	my $name = $_[0];
1597aec1d6eScindi	my @bits = @_[1..$#_];
1604156fc34Sgavinm	my $out = "";
1617aec1d6eScindi
1627aec1d6eScindi	if (@bits == 0) {
1634156fc34Sgavinm		$out = "\t0,";
1647aec1d6eScindi	} elsif (@bits == 1) {
1654156fc34Sgavinm		$out = "\t$bits[0],";
1667aec1d6eScindi	} else {
1674156fc34Sgavinm		$out = "\t( " . join(" | ", @bits) . " ),";
1687aec1d6eScindi	}
1697aec1d6eScindi
1704156fc34Sgavinm	$out .= " /* $name */" if (defined $name);
1714156fc34Sgavinm	$out .= "\n";
1724156fc34Sgavinm
1734156fc34Sgavinm	return ($out);
1747aec1d6eScindi}
1757aec1d6eScindi
1767aec1d6eScindisub field_burst() {
1777aec1d6eScindi	my ($field, $valuesref, $name, $prefix) = @_;
1787aec1d6eScindi
1797aec1d6eScindi	if ($field eq "-") {
1807aec1d6eScindi		return ();
1817aec1d6eScindi	}
1827aec1d6eScindi
1837aec1d6eScindi	map {
1847aec1d6eScindi		if (!defined ${$valuesref}{$_}) {
1857aec1d6eScindi			&parsebail("unknown $name value `$_'");
1867aec1d6eScindi		}
1877aec1d6eScindi		$_ = ${$valuesref}{$_};
1887aec1d6eScindi		tr/[a-z]/[A-Z]/;
1897aec1d6eScindi		$prefix . "_" . $_;
1907aec1d6eScindi	} split(/\//, $field);
1917aec1d6eScindi}
1927aec1d6eScindi
1937aec1d6eScindisub bin2dec() {
1947aec1d6eScindi	my $bin = $_[0];
1957aec1d6eScindi	my $dec = 0;
1967aec1d6eScindi
1977aec1d6eScindi	foreach my $bit (split(//, $bin)) {
1987aec1d6eScindi		$dec = $dec * 2 + ($bit eq "1" ? 1 : 0);
1997aec1d6eScindi	}
2007aec1d6eScindi
2017aec1d6eScindi	$dec;
2027aec1d6eScindi}
2037aec1d6eScindi
2047aec1d6eScindisub state_funcunit() {
2057aec1d6eScindi	my $val = $_[0];
2067aec1d6eScindi
2077aec1d6eScindi	if (defined $::funcunit) {
2087aec1d6eScindi		&funcunit_end();
2097aec1d6eScindi	}
2107aec1d6eScindi
2117aec1d6eScindi	$::funcunit = $val;
2127aec1d6eScindi	undef $::error;
2137aec1d6eScindi	&funcunit_begin($::funcunit);
2147aec1d6eScindi}
2157aec1d6eScindi
2167aec1d6eScindisub state_desc() {
2177aec1d6eScindi	my $desc = $_[0];
2187aec1d6eScindi
2194156fc34Sgavinm	&error_init();
2204156fc34Sgavinm
2214156fc34Sgavinm	&errout("\t/* $desc */\n\t{\n");
2227aec1d6eScindi}
2237aec1d6eScindi
2247aec1d6eScindisub state_error() {
2257aec1d6eScindi	$::error = $_[0];
2267aec1d6eScindi	&error_begin($::error);
2277aec1d6eScindi}
2287aec1d6eScindi
2297aec1d6eScindisub state_mask_on() {
2307aec1d6eScindi	@::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]);
2317aec1d6eScindi}
2327aec1d6eScindi
2337aec1d6eScindisub state_mask_off() {
2347aec1d6eScindi	my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]);
2357aec1d6eScindi
2364156fc34Sgavinm	&errout(&print_bits("mask", @::mask_on, @mask_off));
2374156fc34Sgavinm	&errout(&print_bits("mask_res", @::mask_on));
2387aec1d6eScindi}
2397aec1d6eScindi
2407aec1d6eScindisub state_code() {
2414156fc34Sgavinm	my ($ext, $type, $pp, $t, $r4, $addr, $ii, $ll, $tt) =
2424156fc34Sgavinm	    split(/\s+/, $_[0]);
2437aec1d6eScindi
2447aec1d6eScindi	my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 );
2457aec1d6eScindi	my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 );
2467aec1d6eScindi
2477aec1d6eScindi	my %r4_values = (
248*20c794b3Sgavinm		'err' => 'err',
249*20c794b3Sgavinm		'rd' => 'rd',
250*20c794b3Sgavinm		'wr' => 'wr',
251*20c794b3Sgavinm		'drd' => 'drd',
252*20c794b3Sgavinm		'dwr' => 'dwr',
253*20c794b3Sgavinm		'ird' => 'ird',
254*20c794b3Sgavinm		'pf' => 'prefetch',
255*20c794b3Sgavinm		'ev' => 'evict',
256*20c794b3Sgavinm		'snp' => 'snoop',
2577aec1d6eScindi	        '-' => '-');
2587aec1d6eScindi
2597aec1d6eScindi	my %pp_values = (
260*20c794b3Sgavinm		'src' => 'src',
261*20c794b3Sgavinm		'res' => 'res',
262*20c794b3Sgavinm		'obs' => 'obs',
263*20c794b3Sgavinm		'gen' => 'gen',
2647aec1d6eScindi		'-' => '-' );
2657aec1d6eScindi
2667aec1d6eScindi	my %t_values = ( 0 => 1, 1 => 1, '-' => 1 );
2677aec1d6eScindi
2687aec1d6eScindi	my %ii_values = (
269*20c794b3Sgavinm		'mem' => 'mem',
270*20c794b3Sgavinm		'io' => 'io',
271*20c794b3Sgavinm		'gen' => 'gen',
2727aec1d6eScindi		'-' => '-' );
2737aec1d6eScindi
2744156fc34Sgavinm	my $instance = &code_lines();
2754156fc34Sgavinm	if ($instance > 0) {
2764156fc34Sgavinm		&error_dup($::codeoutlen);	# dup info thus far
2774156fc34Sgavinm	}
2784156fc34Sgavinm
2797aec1d6eScindi	if (!defined $tt_values{$tt}) {
2807aec1d6eScindi		&parsebail("unknown tt value `$tt'");
2817aec1d6eScindi	}
2827aec1d6eScindi
2837aec1d6eScindi	if (!defined $ll_values{$ll}) {
2847aec1d6eScindi		&parsebail("unknown ll value `$ll'");
2857aec1d6eScindi	}
2867aec1d6eScindi
2877aec1d6eScindi	my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT");
2887aec1d6eScindi
2897aec1d6eScindi	my @pp = ($pp eq '-') ? () :
2907aec1d6eScindi	    &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT");
2917aec1d6eScindi
2927aec1d6eScindi	if (!defined $t_values{$t}) {
2937aec1d6eScindi		&parsebail("unknown t value `$t'");
2947aec1d6eScindi	}
2957aec1d6eScindi
2967aec1d6eScindi	my @ii = ($ii eq '-') ? () :
2977aec1d6eScindi	    &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT");
2987aec1d6eScindi
2997aec1d6eScindi	map {
3007aec1d6eScindi		tr/[a-z]/[A-Z]/;
3017aec1d6eScindi	} ($ii, $ll, $tt);
3027aec1d6eScindi
3037aec1d6eScindi	if ($type eq "bus") {
3047aec1d6eScindi		if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" ||
3057aec1d6eScindi		    $ll eq "-" ||
3067aec1d6eScindi		    $tt ne "-") {
3077aec1d6eScindi			&parsebail("invalid members for bus code type");
3087aec1d6eScindi		}
3097aec1d6eScindi
3104156fc34Sgavinm		$::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKBUS(" .
3117aec1d6eScindi		    "0, " . # pp
312*20c794b3Sgavinm		    "MCAX86_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " .
3137aec1d6eScindi		    "0, " . # r4
3147aec1d6eScindi		    "0, " . # ii
315*20c794b3Sgavinm		    "MCAX86_ERRCODE_LL_$ll),\n");
3167aec1d6eScindi
3177aec1d6eScindi	} elsif ($type eq "mem") {
3187aec1d6eScindi		if ($r4 eq "-" || $tt eq "-" || $ll eq "-" ||
3197aec1d6eScindi		    $pp ne "-" || $t ne "-" || $ii ne "-") {
3207aec1d6eScindi			&parsebail("invalid members for mem code type");
3217aec1d6eScindi		}
3227aec1d6eScindi
3234156fc34Sgavinm		$::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKMEM(" .
3247aec1d6eScindi		    "0, " . # r4
325*20c794b3Sgavinm		    "MCAX86_ERRCODE_TT_$tt, " .
326*20c794b3Sgavinm		    "MCAX86_ERRCODE_LL_$ll),\n");
3277aec1d6eScindi
3287aec1d6eScindi	} elsif ($type eq "tlb") {
3297aec1d6eScindi		if ($tt eq "-" || $ll eq "-" ||
3307aec1d6eScindi		    $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") {
3317aec1d6eScindi			&parsebail("invalid members for tlb code type");
3327aec1d6eScindi		}
3337aec1d6eScindi
3344156fc34Sgavinm		$::codeoutlen += &errout_N($instance, "\tAMD_ERRCODE_MKTLB(" .
335*20c794b3Sgavinm		    "MCAX86_ERRCODE_TT_$tt, " .
336*20c794b3Sgavinm		    "MCAX86_ERRCODE_LL_$ll),\n");
3377aec1d6eScindi	} else {
3387aec1d6eScindi		&parsebail("unknown code type `$type'");
3397aec1d6eScindi	}
3407aec1d6eScindi
3414156fc34Sgavinm	$::codeoutlen += &errout_N($instance, "\t" . &bin2dec($ext) .
3424156fc34Sgavinm	    ", /* ext code $ext */\n");
3437aec1d6eScindi
3444156fc34Sgavinm	$::codeoutlen += &errout_N($instance, &print_bits("pp_bits", @pp));
3454156fc34Sgavinm	$::codeoutlen += &errout_N($instance, &print_bits("ii_bits", @ii));
3464156fc34Sgavinm	$::codeoutlen += &errout_N($instance, &print_bits("r4_bits", @r4));
3474156fc34Sgavinm
3484156fc34Sgavinm	my $valid_hi;
3494156fc34Sgavinm	my $valid_lo;
3504156fc34Sgavinm
3514156fc34Sgavinm	if ($addr eq "none") {
3524156fc34Sgavinm		$valid_hi = $valid_lo = 0;
3534156fc34Sgavinm	} elsif ($addr =~ /<(\d+):(\d+)>/) {
3544156fc34Sgavinm		$valid_hi = $1;
3554156fc34Sgavinm		$valid_lo = $2;
3564156fc34Sgavinm	} else {
3574156fc34Sgavinm		&parsebail("invalid addr specification");
3584156fc34Sgavinm	}
3594156fc34Sgavinm	$::codeoutlen += &errout_N($instance, "\t" . $valid_hi .
3604156fc34Sgavinm	    ", /* addr valid hi */\n");
3614156fc34Sgavinm	$::codeoutlen += &errout_N($instance, "\t" . $valid_lo .
3624156fc34Sgavinm	    ", /* addr valid lo */\n");
3637aec1d6eScindi}
3647aec1d6eScindi
3657aec1d6eScindisub state_panic() {
366a307a255Sgavinm	my @vals = split(/,\s*/, $_[0]);
3677aec1d6eScindi
368a307a255Sgavinm	if ($#vals < 0) {
3694156fc34Sgavinm		&errout("\t0, /* panic_when */\n");
3707aec1d6eScindi	} else {
371a307a255Sgavinm		@vals = map { tr/[a-z]/[A-Z]/; "AO_AED_PANIC_" . $_; } @vals;
3724156fc34Sgavinm		&errout(&print_bits("panic_when", @vals));
3737aec1d6eScindi	}
3747aec1d6eScindi}
3757aec1d6eScindi
3767aec1d6eScindisub state_flags() {
3777aec1d6eScindi	my @flags = split(/,\s*/, $_[0]);
3787aec1d6eScindi
3797aec1d6eScindi	@flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags;
3807aec1d6eScindi
3814156fc34Sgavinm	&errout(&print_bits("flags", @flags));
3827aec1d6eScindi}
3837aec1d6eScindi
384*20c794b3Sgavinmsub state_errtype() {
385*20c794b3Sgavinm	my @types = split(/,\s*/, $_[0]);
386*20c794b3Sgavinm
387*20c794b3Sgavinm	@types = map { tr/[a-z]/[A-Z]/; "AO_AED_ET_" . $_; } @types;
388*20c794b3Sgavinm
389*20c794b3Sgavinm	&errout(&print_bits("errtype", @types));
390*20c794b3Sgavinm}
391*20c794b3Sgavinm
3927aec1d6eScindimy %stateparse = (
3934156fc34Sgavinm	funcunit	=> [ \&state_funcunit, 'desc' ],
3944156fc34Sgavinm	desc		=> [ \&state_desc, 'error' ],
3954156fc34Sgavinm	error		=> [ \&state_error, 'mask on' ],
3964156fc34Sgavinm	'mask on'	=> [ \&state_mask_on, 'mask off' ],
3974156fc34Sgavinm	'mask off'	=> [ \&state_mask_off, 'code' ],
3984156fc34Sgavinm	code		=> [ \&state_code, 'code|panic' ],
3994156fc34Sgavinm	panic		=> [ \&state_panic, 'flags' ],
400*20c794b3Sgavinm	flags		=> [ \&state_flags, 'errtype' ],
401*20c794b3Sgavinm	errtype		=> [ \&state_errtype, 'initial' ]
4027aec1d6eScindi);
4037aec1d6eScindi
4047aec1d6eScindiusage unless (@ARGV == 1);
4057aec1d6eScindi
4067aec1d6eScindimy $infile = $ARGV[0];
4077aec1d6eScindiopen(INFILE, "<$infile") || &bail("failed to open $infile: $!");
4087aec1d6eScindi
4097aec1d6eScindi&print_header();
4107aec1d6eScindi
4117aec1d6eScindiwhile (<INFILE>) {
4127aec1d6eScindi	chop;
4137aec1d6eScindi
4147aec1d6eScindi	/^#/ && next;
4157aec1d6eScindi	/^$/ && next;
4167aec1d6eScindi
4177aec1d6eScindi	if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) {
4187aec1d6eScindi		&parsebail("failed to parse");
4197aec1d6eScindi	}
4207aec1d6eScindi
4217aec1d6eScindi	my ($keyword, $val) = ($1, $2);
4227aec1d6eScindi
4237aec1d6eScindi	if ($state eq "initial") {
4247aec1d6eScindi		if ($keyword eq "funcunit") {
4257aec1d6eScindi			$state = "funcunit";
4267aec1d6eScindi		} elsif ($keyword eq "desc") {
4277aec1d6eScindi			$state = "desc";
4287aec1d6eScindi		} else {
4297aec1d6eScindi			&parsebail("unexpected keyword $keyword between " .
4307aec1d6eScindi			    "errors");
4317aec1d6eScindi		}
4327aec1d6eScindi
4337aec1d6eScindi	} elsif ($state eq "desc") {
4347aec1d6eScindi		if ($keyword eq "funcunit") {
4357aec1d6eScindi			$state = "funcunit";
4367aec1d6eScindi		}
4377aec1d6eScindi	}
4387aec1d6eScindi
4394156fc34Sgavinm	if (!($keyword =~ /$state/)) {
4404156fc34Sgavinm		&parsebail("keyword `$keyword' invalid here; expected " .
4414156fc34Sgavinm		    "`$state'");
4427aec1d6eScindi	}
4434156fc34Sgavinm	$state = $keyword;	# disambiguate between multiple legal states
4447aec1d6eScindi
4457aec1d6eScindi	if (!defined $stateparse{$state}) {
4467aec1d6eScindi		&parsebail("attempt to transition to invalid state `$state'");
4477aec1d6eScindi	}
4487aec1d6eScindi
4497aec1d6eScindi	my ($handler, $next) = @{$stateparse{$state}};
4507aec1d6eScindi
4517aec1d6eScindi	&{$handler}($val);
4527aec1d6eScindi
4537aec1d6eScindi	$state = $next;
4547aec1d6eScindi
4557aec1d6eScindi	if ($state eq "initial") {
4567aec1d6eScindi		&error_end();
4577aec1d6eScindi	}
4587aec1d6eScindi}
4597aec1d6eScindi
4607aec1d6eScindiclose(INFILE);
4617aec1d6eScindi
4627aec1d6eScindiif ($state ne "initial" && $state ne "desc") {
4637aec1d6eScindi	&bail("input file ended prematurely");
4647aec1d6eScindi}
4657aec1d6eScindi
4667aec1d6eScindiif (defined $::funcunit) {
4677aec1d6eScindi	&funcunit_end();
4687aec1d6eScindi} else {
4697aec1d6eScindi	&bail("no functional units defined");
4707aec1d6eScindi}
4717aec1d6eScindi
4727aec1d6eScindi&print_footer;
473