mb/ibm/sbp1: Update PCIe SBDF in comment
[coreboot2.git] / util / amdtools / parse-bkdg.pl
blob31f3873436d65cf0eeae6a550753d44f20264fd5
1 #!/usr/bin/env perl
3 my $NAME = $0;
4 my $VERSION = '0.01';
5 my $DATE = '2009-09-04';
6 my $AUTHOR = "Ward Vandewege <ward\@jhvc.com>";
7 my $COPYRIGHT = "2009";
8 my $LICENSE = "GPL v3 - http://www.fsf.org/licenses/gpl.txt";
9 my $URL = "https://coreboot.org";
11 my $DEBUG = 0;
13 use strict;
14 use warnings;
16 # Run the bkdg for k8 through pdftotext first (from the poppler package)
18 my @registers = ();
19 my $raw_register = '';
21 my $name = '';
22 my $description = '';
23 my $step = 0;
24 my $oldstep = 0;
26 my $previous_res = 0;
27 my $previous_start = 0;
28 my $previous_stop = 0;
29 my $strip_empties = 0;
31 my $previous_bits = '';
33 our %info;
35 my %typos;
37 $typos{'CkeDreStrength'} = 'CkeDrvStrength';
39 while (<>) {
40 my $line = $_;
41 chomp($line);
43 foreach my $k (keys %typos) {
44 $line =~ s/$k/$typos{$k}/;
47 # Make sure we do not include headers in our output
48 if (($line =~ /^Chapter 4/) || ($line =~ /Chapter 4$/)) {
49 $oldstep = $step;
50 $step = 99;
51 next;
53 if ($step == 99) { # header
54 if ($line =~ /Processors$/) {
55 $step = $oldstep;
56 $strip_empties = 1;
58 next;
61 if ($strip_empties) {
62 # Headers are followed by two blank lines. Strip them.
63 if ($line =~ /^\s*$/) {
64 next;
65 } else {
66 $strip_empties = 0;
71 if (($step % 6 == 0) && ($line =~ /^\d+\.\d+\.\d+\s+(.*)$/)) {
72 $step = 1;
73 next;
75 if ($step == 1) {
76 $description = "$line\n";
77 $step = 2;
78 next;
80 #print STDERR "STEP: $step\n";
81 #print STDERR "$line\n";
83 if ((($step == 0) || ($step == 6) || ($step == 2)) && ($line =~ /^(.*)\s+Function\s+\d+:\s+Offset\s+..h$/)) {
84 $name = $1;
85 $name =~ s/ +$//;
86 $step = 3;
87 $description =~ s/\n+$//ms;
89 if ($previous_bits ne '') {
90 &finish_record($previous_bits);
91 $previous_bits = ''; # reset previous_bits (used in step 6)
95 next;
96 } elsif ($step == 2) {
97 $description .= "$line\n";
98 next;
101 if (($step == 3) && ($line =~ /^\s+Index (.+h)$/)) {
102 $raw_register= $1;
103 @registers = split(/,/,$raw_register);
104 for (my $i=0;$i<=$#registers;$i++) {
105 $registers[$i] =~ s/ //g;
106 $registers[$i] =~ s/h$//;
108 # OK, we have our register(s), so now we can print out the name and description lines.
109 print "\$info{'$registers[0]'}{'name'} = \"$name\";\n";
110 print "\$info{'$registers[0]'}{'description'} = \"$description\";\n";
111 $step = 4;
112 next;
115 if (($step == 4) && ($line =~ /^Bits\s+Mnemonic\s+Function\s+R\/W\s+Reset$/)) {
116 $step = 5;
117 next;
120 if (($step == 5) && (!($line =~ /^Field Descriptions$/))) {
121 $line =~ s/^ +//; # Strip leading spaces
122 my @f = split(/ +/,$line);
124 # skip blank lines
125 next if (!exists($f[0]));
127 # skip headers (they could be repeated if the table crosses a page boundary
128 next if ($f[0] eq 'Bits');
130 # Clean up funky field separator
131 if ($f[0] =~ /\d+.+\d+/) {
132 $f[0] =~ s/[^\d]+/-/g;
135 my ($start, $stop, $width) = (0,0,0);
136 if ($f[0] =~ /-/) {
137 $f[0] =~ s/^(\d+)[^\d]+(\d+)$/$1-$2/;
138 ($stop,$start) = ($1,$2);
139 $width = $stop-$start+1;
140 } else {
141 if ($f[0] =~ /^\d+$/) {
142 $start = $stop = $f[0];
143 $width = 1;
144 } else {
145 # continuation from previous line
146 $start = $stop = $width = 0;
150 # Some lines have only bit entries
151 if (($#f < 1) && ($f[0] =~ /^\d+(|\-\d+)/)) {
152 $f[4] = '';
153 $f[3] = '';
154 $f[2] = '';
155 $f[1] = '';
156 } elsif ($#f < 1) {
157 # Some lines are a continuation of the function field a line above
158 $f[4] = '';
159 $f[3] = '';
160 $f[2] = $f[0];
161 $f[1] = '';
162 $f[0] = '';
163 my $tmp = "\$info{'$registers[0]'}{'ranges'}{" . $previous_res . "}{'function'} .= \"" . $f[2] . "\";\n";
164 print &multiply($tmp,$previous_res,$previous_start,$previous_stop);
165 next;
168 # Some lines have only bit and reset entries
169 if ($#f < 2) {
170 $f[4] = $f[1];
171 $f[3] = '';
172 $f[2] = '';
173 $f[1] = '';
176 # Some lines have no mnemonic and no function
177 if ($#f < 3) {
178 $f[4] = $f[2];
179 $f[3] = $f[1];
180 $f[2] = '';
181 $f[1] = '';
184 # functions with 'reserved' mnemonic have no function
185 if ($f[1] =~ /^reserved$/i) {
186 $f[4] = $f[3];
187 $f[3] = $f[2];
188 $f[2] = '';
191 $previous_res = $f[0];
192 $previous_start = $start;
193 $previous_stop = $stop;
195 # the 'range' field is not useful in this instance, but used in the 'fields' version of this block to easily go
196 # from a bit position to the corresponding range.
197 my $str = "
198 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'function'} = \"" . $f[2] . "\";
199 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'mnemonic'} = \"" . $f[1] . "\";
200 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'description'} = \"" . "\";
201 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'begin'} = $start;
202 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'end'} = $stop;
203 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'width'} = $width;
204 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'rw'} = \"" . $f[3] . "\";
205 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'reset'} = \"" . $f[4] . "\";
206 \$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'range'} = \"" . $f[0] . "\";
208 my $output;
210 $output = &multiply($str,$f[0],$start,$stop);
212 # Load the data structure here, too
213 eval($output);
215 print $output . "\n\n";
216 } elsif (($step == 5) && ($line =~ /^Field Descriptions$/)) {
217 $step = 6;
218 next;
221 if ($step == 6) {
222 if ($line =~ /^(.*?)\((.*?)\).+Bit(s|) +(.*?)\. (.*)$/) {
223 my $bits = $4;
224 my $desc = $5;
225 $bits =~ s/[^\d]+/-/;
227 if ($previous_bits ne '') {
228 # We're done with a field description block
229 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'description'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} . "\";\n";
230 foreach my $k (keys %{$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}}) {
231 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'values'}{'$k'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$k} . "\";\n";
235 if (exists($info{$registers[0]}{'ranges'}{$bits})) {
236 print STDERR "match ($bits) on $line\n";
237 $info{$registers[0]}{'ranges'}{$bits}{'description'} = $desc . "\n";
238 $previous_bits = $bits;
240 } elsif ($previous_bits ne '') {
241 $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} .= $line . "\n";
242 if ($line =~ /([0-9a-f]+b|[0-9a-f]+h) = (.*)$/i) {
243 $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$1} = $2;
249 &finish_record($previous_bits);
252 print "1;\n";
254 sub multiply {
255 my $str = shift;
256 my $range = shift;
257 my $start = shift;
258 my $stop = shift;
259 my $output = '';
260 for (my $i=$start;$i<=$stop;$i++) {
261 my $tmp = $str;
262 $tmp =~ s/\{'$range'\}/{'$i'}/g;
263 $tmp =~ s/\{'ranges'\}/{'fields'}/g;
264 $tmp .=
265 $output .= $tmp;
268 #$output .= $str if (($stop - $start + 1) > 1);
269 $output .= $str;
271 return $output;
274 sub finish_record {
275 my $previous_bits = shift;
276 # We're done with a field description block
277 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'description'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} . "\";\n";
278 foreach my $k (keys %{$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}}) {
279 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'values'}{'$k'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$k} . "\";\n";
282 # End of table. If this data applies to more than one register, print duplication lines.
283 for (my $i=1;$i<=$#registers;$i++) {
284 print "\$info{'$registers[$i]'} = \$info{'$registers[0]'};\n";