xref: /illumos-gate/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl (revision 60a3f738d56f92ae8b80e4b62a2331c6e1f2311f)
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 = ();
37
38my $state = "initial";
39
40sub usage() {
41	print STDERR "Usage: $PROGNAME inputfile\n";
42	exit(2);
43}
44
45sub bail() {
46	print STDERR "$PROGNAME: ", join(" ", @_), "\n";
47	exit(1);
48}
49
50sub parsebail() {
51	print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n";
52	exit(1);
53}
54
55sub print_header() {
56	print "#include \"ao_mca_disp.h\"\n\n";
57}
58
59sub print_footer() {
60	print "const ao_error_disp_t *ao_error_disp[] = {\n";
61
62	foreach my $name (@funcunits) {
63		print "\t$name,\n";
64	}
65
66	print "};\n";
67}
68
69sub funcunit_begin() {
70	my $arrnm = "ao_error_disp_" . $_[0];
71	print "static const ao_error_disp_t " . $arrnm . "[] = {\n";
72
73	@funcunits = (@funcunits, $arrnm);
74}
75
76sub funcunit_end() {
77	print "\tNULL\n};\n\n";
78}
79
80sub error_begin() {
81	my ($ereport_name) = @_;
82
83	$ereport_name =~ tr/[a-z]./[A-Z]_/;
84	my $flags_name = $ereport_name;
85	$flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/;
86
87	print "\tFM_$ereport_name,\n\tFM_$flags_name,\n";
88}
89
90sub error_end() {
91	print "\t},\n\n";
92}
93
94sub print_bits() {
95	my $name = $_[0];
96	my @bits = @_[1..$#_];
97
98	if (@bits == 0) {
99		print "\t0,";
100	} elsif (@bits == 1) {
101		print "\t$bits[0],";
102	} else {
103		print "\t( ", join(" | ", @bits), " ),";
104	}
105
106	print " /* $name */" if (defined $name);
107	print "\n";
108}
109
110sub field_burst() {
111	my ($field, $valuesref, $name, $prefix) = @_;
112
113	if ($field eq "-") {
114		return ();
115	}
116
117	map {
118		if (!defined ${$valuesref}{$_}) {
119			&parsebail("unknown $name value `$_'");
120		}
121		$_ = ${$valuesref}{$_};
122		tr/[a-z]/[A-Z]/;
123		$prefix . "_" . $_;
124	} split(/\//, $field);
125}
126
127sub bin2dec() {
128	my $bin = $_[0];
129	my $dec = 0;
130
131	foreach my $bit (split(//, $bin)) {
132		$dec = $dec * 2 + ($bit eq "1" ? 1 : 0);
133	}
134
135	$dec;
136}
137
138sub state_funcunit() {
139	my $val = $_[0];
140
141	if (defined $::funcunit) {
142		&funcunit_end();
143	}
144
145	$::funcunit = $val;
146	undef $::error;
147	&funcunit_begin($::funcunit);
148}
149
150sub state_desc() {
151	my $desc = $_[0];
152
153	print "\t/* $desc */\n\t{\n";
154}
155
156sub state_error() {
157	$::error = $_[0];
158	&error_begin($::error);
159}
160
161sub state_mask_on() {
162	@::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]);
163}
164
165sub state_mask_off() {
166	my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]);
167
168	&print_bits("mask", @::mask_on, @mask_off);
169	&print_bits("mask_res", @::mask_on);
170}
171
172sub state_code() {
173	my ($ext, $type, $pp, $t, $r4, $ii, $ll, $tt) = split(/\s+/, $_[0]);
174
175	my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 );
176	my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 );
177
178	my %r4_values = (
179		gen => 'gen',
180		rd => 'rd',
181		wr => 'wr',
182		drd => 'drd',
183		dwr => 'dwr',
184		ird => 'ird',
185		pf => 'prefetch',
186		ev => 'evict',
187		snp => 'snoop',
188	        '-' => '-');
189
190	my %pp_values = (
191		src => 'src',
192		rsp => 'rsp',
193		obs => 'obs',
194		gen => 'gen',
195		'-' => '-' );
196
197	my %t_values = ( 0 => 1, 1 => 1, '-' => 1 );
198
199	my %ii_values = (
200		mem => 'mem',
201		io => 'io',
202		gen => 'gen',
203		'-' => '-' );
204
205	if (!defined $tt_values{$tt}) {
206		&parsebail("unknown tt value `$tt'");
207	}
208
209	if (!defined $ll_values{$ll}) {
210		&parsebail("unknown ll value `$ll'");
211	}
212
213	my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT");
214
215	my @pp = ($pp eq '-') ? () :
216	    &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT");
217
218	if (!defined $t_values{$t}) {
219		&parsebail("unknown t value `$t'");
220	}
221
222	my @ii = ($ii eq '-') ? () :
223	    &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT");
224
225	map {
226		tr/[a-z]/[A-Z]/;
227	} ($ii, $ll, $tt);
228
229	if ($type eq "bus") {
230		if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" ||
231		    $ll eq "-" ||
232		    $tt ne "-") {
233			&parsebail("invalid members for bus code type");
234		}
235
236		print "\tAMD_ERRCODE_MKBUS(" .
237		    "0, " . # pp
238		    "AMD_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " .
239		    "0, " . # r4
240		    "0, " . # ii
241		    "AMD_ERRCODE_LL_$ll),\n";
242
243	} elsif ($type eq "mem") {
244		if ($r4 eq "-" || $tt eq "-" || $ll eq "-" ||
245		    $pp ne "-" || $t ne "-" || $ii ne "-") {
246			&parsebail("invalid members for mem code type");
247		}
248
249		print "\tAMD_ERRCODE_MKMEM(" .
250		    "0, " . # r4
251		    "AMD_ERRCODE_TT_$tt, " .
252		    "AMD_ERRCODE_LL_$ll),\n";
253
254	} elsif ($type eq "tlb") {
255		if ($tt eq "-" || $ll eq "-" ||
256		    $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") {
257			&parsebail("invalid members for tlb code type");
258		}
259
260		print "\tAMD_ERRCODE_MKTLB(" .
261		    "AMD_ERRCODE_TT_$tt, " .
262		    "AMD_ERRCODE_LL_$ll),\n";
263	} else {
264		&parsebail("unknown code type `$type'");
265	}
266
267	print "\t" . &bin2dec($ext) . ", /* ext code $ext */\n";
268
269	&print_bits("pp_bits", @pp);
270	&print_bits("ii_bits", @ii);
271	&print_bits("r4_bits", @r4);
272}
273
274sub state_panic() {
275	my @vals = split(/,\s*/, $_[0]);
276
277	if ($#vals < 0) {
278		print "\t0, /* panic_when */\n";
279	} else {
280		@vals = map { tr/[a-z]/[A-Z]/; "AO_AED_PANIC_" . $_; } @vals;
281		&print_bits("panic_when", @vals);
282	}
283}
284
285sub state_flags() {
286	my @flags = split(/,\s*/, $_[0]);
287
288	@flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags;
289
290	&print_bits("flags", @flags);
291}
292
293my %stateparse = (
294	funcunit	=> [ \&state_funcunit, "desc" ],
295	desc		=> [ \&state_desc, "error" ],
296	error		=> [ \&state_error, "mask on" ],
297	'mask on'	=> [ \&state_mask_on, "mask off" ],
298	'mask off'	=> [ \&state_mask_off, "code" ],
299	code		=> [ \&state_code, "panic" ],
300	panic		=> [ \&state_panic, "flags" ],
301	flags		=> [ \&state_flags, "initial" ]
302);
303
304usage unless (@ARGV == 1);
305
306my $infile = $ARGV[0];
307open(INFILE, "<$infile") || &bail("failed to open $infile: $!");
308
309&print_header();
310
311while (<INFILE>) {
312	chop;
313
314	/^#/ && next;
315	/^$/ && next;
316
317	if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) {
318		&parsebail("failed to parse");
319	}
320
321	my ($keyword, $val) = ($1, $2);
322
323	if ($state eq "initial") {
324		if ($keyword eq "funcunit") {
325			$state = "funcunit";
326		} elsif ($keyword eq "desc") {
327			$state = "desc";
328		} else {
329			&parsebail("unexpected keyword $keyword between " .
330			    "errors");
331		}
332
333	} elsif ($state eq "desc") {
334		if ($keyword eq "funcunit") {
335			$state = "funcunit";
336		}
337	}
338
339	if ($keyword ne $state) {
340		&parsebail("keyword `$keyword' invalid here; expected `$state'");
341	}
342
343	if (!defined $stateparse{$state}) {
344		&parsebail("attempt to transition to invalid state `$state'");
345	}
346
347	my ($handler, $next) = @{$stateparse{$state}};
348
349	&{$handler}($val);
350
351	$state = $next;
352
353	if ($state eq "initial") {
354		&error_end();
355	}
356}
357
358close(INFILE);
359
360if ($state ne "initial" && $state ne "desc") {
361	&bail("input file ended prematurely");
362}
363
364if (defined $::funcunit) {
365	&funcunit_end();
366} else {
367	&bail("no functional units defined");
368}
369
370&print_footer;
371