blob: d0bb4c7b6ff74ac6532185d53695b243c5d1156d [file] [log] [blame]
Ward Vandewege3d83cff2009-10-28 19:41:52 +00001#!/usr/bin/perl -w
2
3my $NAME = $0;
4my $VERSION = '0.01';
5my $DATE = '2009-09-04';
6my $AUTHOR = "Ward Vandewege <ward\@jhvc.com>";
7my $COPYRIGHT = "2009";
8my $LICENSE = "GPL v3 - http://www.fsf.org/licenses/gpl.txt";
Paul Menzela8843de2017-06-05 12:33:23 +02009my $URL = "https://coreboot.org";
Ward Vandewege3d83cff2009-10-28 19:41:52 +000010
11my $DEBUG = 0;
12
13use strict;
14
15# Run the bkdg for k8 through pdftotext first (from the poppler package)
16
17my @registers = ();
18my $raw_register = '';
19
20my $name = '';
21my $description = '';
22my $step = 0;
23my $oldstep = 0;
24
25my $previous_res = 0;
26my $previous_start = 0;
27my $previous_stop = 0;
28my $strip_empties = 0;
29
30my $previous_bits = '';
31
32our %info;
33
34my %typos;
35
36$typos{'CkeDreStrength'} = 'CkeDrvStrength';
37
38while (<>) {
39 my $line = $_;
40 chomp($line);
41
42 foreach my $k (keys %typos) {
43 $line =~ s/$k/$typos{$k}/;
44 }
45
46 # Make sure we do not include headers in our output
47 if (($line =~ /^Chapter 4/) || ($line =~ /Chapter 4$/)) {
48 $oldstep = $step;
49 $step = 99;
50 next;
51 }
52 if ($step == 99) { # header
53 if ($line =~ /Processors$/) {
54 $step = $oldstep;
55 $strip_empties = 1;
56 }
57 next;
58 }
59
60 if ($strip_empties) {
61 # Headers are followed by two blank lines. Strip them.
62 if ($line =~ /^\s*$/) {
63 next;
64 } else {
65 $strip_empties = 0;
66 }
67 }
68
69
70 if (($step % 6 == 0) && ($line =~ /^\d+\.\d+\.\d+\s+(.*)$/)) {
71 $step = 1;
72 next;
73 }
74 if ($step == 1) {
75 $description = "$line\n";
76 $step = 2;
77 next;
78 }
79 #print STDERR "STEP: $step\n";
80 #print STDERR "$line\n";
81
82 if ((($step == 0) || ($step == 6) || ($step == 2)) && ($line =~ /^(.*)\s+Function\s+\d+:\s+Offset\s+..h$/)) {
83 $name = $1;
84 $name =~ s/ +$//;
85 $step = 3;
86 $description =~ s/\n+$//ms;
87
88 if ($previous_bits ne '') {
89 &finish_record($previous_bits);
90 $previous_bits = ''; # reset previous_bits (used in step 6)
91 }
92
93
94 next;
95 } elsif ($step == 2) {
96 $description .= "$line\n";
97 next;
98 }
99
100 if (($step == 3) && ($line =~ /^\s+Index (.+h)$/)) {
101 $raw_register= $1;
102 @registers = split(/,/,$raw_register);
103 for (my $i=0;$i<=$#registers;$i++) {
104 $registers[$i] =~ s/ //g;
105 $registers[$i] =~ s/h$//;
106 }
107 # OK, we have our register(s), so now we can print out the name and description lines.
108 print "\$info{'$registers[0]'}{'name'} = \"$name\";\n";
109 print "\$info{'$registers[0]'}{'description'} = \"$description\";\n";
110 $step = 4;
111 next;
112 }
113
114 if (($step == 4) && ($line =~ /^Bits\s+Mnemonic\s+Function\s+R\/W\s+Reset$/)) {
115 $step = 5;
116 next;
117 }
118
119 if (($step == 5) && (!($line =~ /^Field Descriptions$/))) {
120 $line =~ s/^ +//; # Strip leading spaces
121 my @f = split(/ +/,$line);
122
123 # skip blank lines
124 next if (!exists($f[0]));
125
126 # skip headers (they could be repeated if the table crosses a page boundary
127 next if ($f[0] eq 'Bits');
128
129 # Clean up funky field separator
130 if ($f[0] =~ /\d+.+\d+/) {
131 $f[0] =~ s/[^\d]+/-/g;
132 }
133
134 my ($start, $stop, $width) = (0,0,0);
135 if ($f[0] =~ /-/) {
136 $f[0] =~ s/^(\d+)[^\d]+(\d+)$/$1-$2/;
137 ($stop,$start) = ($1,$2);
138 $width = $stop-$start+1;
139 } else {
140 if ($f[0] =~ /^\d+$/) {
141 $start = $stop = $f[0];
142 $width = 1;
143 } else {
144 # continuation from previous line
145 $start = $stop = $width = 0;
146 }
147 }
148
149 # Some lines have only bit entries
150 if (($#f < 1) && ($f[0] =~ /^\d+(|\-\d+)/)) {
151 $f[4] = '';
152 $f[3] = '';
153 $f[2] = '';
154 $f[1] = '';
155 } elsif ($#f < 1) {
156 # Some lines are a continuation of the function field a line above
157 $f[4] = '';
158 $f[3] = '';
159 $f[2] = $f[0];
160 $f[1] = '';
161 $f[0] = '';
162 my $tmp = "\$info{'$registers[0]'}{'ranges'}{" . $previous_res . "}{'function'} .= \"" . $f[2] . "\";\n";
163 print &multiply($tmp,$previous_res,$previous_start,$previous_stop);
164 next;
165 }
166
167 # Some lines have only bit and reset entries
168 if ($#f < 2) {
169 $f[4] = $f[1];
170 $f[3] = '';
171 $f[2] = '';
172 $f[1] = '';
173 }
174
175 # Some lines have no mnemonic and no function
176 if ($#f < 3) {
177 $f[4] = $f[2];
178 $f[3] = $f[1];
179 $f[2] = '';
180 $f[1] = '';
181 }
182
183 # functions with 'reserved' mnemonic have no function
184 if ($f[1] =~ /^reserved$/i) {
185 $f[4] = $f[3];
186 $f[3] = $f[2];
187 $f[2] = '';
188 }
189
190 $previous_res = $f[0];
191 $previous_start = $start;
192 $previous_stop = $stop;
193
Stefan Reinauer14e22772010-04-27 06:56:47 +0000194 # the 'range' field is not useful in this instance, but used in the 'fields' version of this block to easily go
Ward Vandewege3d83cff2009-10-28 19:41:52 +0000195 # from a bit position to the corresponding range.
196 my $str = "
197\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'function'} = \"" . $f[2] . "\";
198\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'mnemonic'} = \"" . $f[1] . "\";
199\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'description'} = \"" . "\";
200\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'begin'} = $start;
201\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'end'} = $stop;
202\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'width'} = $width;
203\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'rw'} = \"" . $f[3] . "\";
204\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'reset'} = \"" . $f[4] . "\";
205\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'range'} = \"" . $f[0] . "\";
206";
207 my $output;
208
209 $output = &multiply($str,$f[0],$start,$stop);
210
211 # Load the data structure here, too
212 eval($output);
213
214 print $output . "\n\n";
215 } elsif (($step == 5) && ($line =~ /^Field Descriptions$/)) {
216 $step = 6;
217 next;
218 }
219
220 if ($step == 6) {
221 if ($line =~ /^(.*?)\((.*?)\).+Bit(s|) +(.*?)\. (.*)$/) {
222 my $bits = $4;
223 my $desc = $5;
224 $bits =~ s/[^\d]+/-/;
225
226 if ($previous_bits ne '') {
227 # We're done with a field description block
228 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'description'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} . "\";\n";
229 foreach my $k (keys %{$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}}) {
230 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'values'}{'$k'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$k} . "\";\n";
231 }
232 }
233
234 if (exists($info{$registers[0]}{'ranges'}{$bits})) {
235 print STDERR "match ($bits) on $line\n";
236 $info{$registers[0]}{'ranges'}{$bits}{'description'} = $desc . "\n";
237 $previous_bits = $bits;
238 }
239 } elsif ($previous_bits ne '') {
240 $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} .= $line . "\n";
241 if ($line =~ /([0-9a-f]+b|[0-9a-f]+h) = (.*)$/i) {
242 $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$1} = $2;
243 }
244 }
245 }
246
247}
248&finish_record($previous_bits);
249
250
251print "1;\n";
252
253sub multiply {
254 my $str = shift;
255 my $range = shift;
256 my $start = shift;
257 my $stop = shift;
258 my $output = '';
259 for (my $i=$start;$i<=$stop;$i++) {
260 my $tmp = $str;
261 $tmp =~ s/\{'$range'\}/{'$i'}/g;
262 $tmp =~ s/\{'ranges'\}/{'fields'}/g;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000263 $tmp .=
Ward Vandewege3d83cff2009-10-28 19:41:52 +0000264 $output .= $tmp;
265 }
266
267 #$output .= $str if (($stop - $start + 1) > 1);
268 $output .= $str;
269
270 return $output;
271}
272
273sub finish_record {
274 my $previous_bits = shift;
275 # We're done with a field description block
276 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'description'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} . "\";\n";
277 foreach my $k (keys %{$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}}) {
278 print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'values'}{'$k'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$k} . "\";\n";
279 }
280
281 # End of table. If this data applies to more than one register, print duplication lines.
282 for (my $i=1;$i<=$#registers;$i++) {
283 print "\$info{'$registers[$i]'} = \$info{'$registers[0]'};\n";
284 }
285
286}