coreboot-kgpe-d16/util/amdtools/parse-bkdg.pl
Stefan Reinauer 14e2277962 Since some people disapprove of white space cleanups mixed in regular commits
while others dislike them being extra commits, let's clean them up once and
for all for the existing code. If it's ugly, let it only be ugly once :-)

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Stefan Reinauer <stepan@coresystems.de>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5507 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2010-04-27 06:56:47 +00:00

286 lines
8.3 KiB
Perl
Executable file

#!/usr/bin/perl -w
my $NAME = $0;
my $VERSION = '0.01';
my $DATE = '2009-09-04';
my $AUTHOR = "Ward Vandewege <ward\@jhvc.com>";
my $COPYRIGHT = "2009";
my $LICENSE = "GPL v3 - http://www.fsf.org/licenses/gpl.txt";
my $URL = "http://coreboot.org";
my $DEBUG = 0;
use strict;
# Run the bkdg for k8 through pdftotext first (from the poppler package)
my @registers = ();
my $raw_register = '';
my $name = '';
my $description = '';
my $step = 0;
my $oldstep = 0;
my $previous_res = 0;
my $previous_start = 0;
my $previous_stop = 0;
my $strip_empties = 0;
my $previous_bits = '';
our %info;
my %typos;
$typos{'CkeDreStrength'} = 'CkeDrvStrength';
while (<>) {
my $line = $_;
chomp($line);
foreach my $k (keys %typos) {
$line =~ s/$k/$typos{$k}/;
}
# Make sure we do not include headers in our output
if (($line =~ /^Chapter 4/) || ($line =~ /Chapter 4$/)) {
$oldstep = $step;
$step = 99;
next;
}
if ($step == 99) { # header
if ($line =~ /Processors$/) {
$step = $oldstep;
$strip_empties = 1;
}
next;
}
if ($strip_empties) {
# Headers are followed by two blank lines. Strip them.
if ($line =~ /^\s*$/) {
next;
} else {
$strip_empties = 0;
}
}
if (($step % 6 == 0) && ($line =~ /^\d+\.\d+\.\d+\s+(.*)$/)) {
$step = 1;
next;
}
if ($step == 1) {
$description = "$line\n";
$step = 2;
next;
}
#print STDERR "STEP: $step\n";
#print STDERR "$line\n";
if ((($step == 0) || ($step == 6) || ($step == 2)) && ($line =~ /^(.*)\s+Function\s+\d+:\s+Offset\s+..h$/)) {
$name = $1;
$name =~ s/ +$//;
$step = 3;
$description =~ s/\n+$//ms;
if ($previous_bits ne '') {
&finish_record($previous_bits);
$previous_bits = ''; # reset previous_bits (used in step 6)
}
next;
} elsif ($step == 2) {
$description .= "$line\n";
next;
}
if (($step == 3) && ($line =~ /^\s+Index (.+h)$/)) {
$raw_register= $1;
@registers = split(/,/,$raw_register);
for (my $i=0;$i<=$#registers;$i++) {
$registers[$i] =~ s/ //g;
$registers[$i] =~ s/h$//;
}
# OK, we have our register(s), so now we can print out the name and description lines.
print "\$info{'$registers[0]'}{'name'} = \"$name\";\n";
print "\$info{'$registers[0]'}{'description'} = \"$description\";\n";
$step = 4;
next;
}
if (($step == 4) && ($line =~ /^Bits\s+Mnemonic\s+Function\s+R\/W\s+Reset$/)) {
$step = 5;
next;
}
if (($step == 5) && (!($line =~ /^Field Descriptions$/))) {
$line =~ s/^ +//; # Strip leading spaces
my @f = split(/ +/,$line);
# skip blank lines
next if (!exists($f[0]));
# skip headers (they could be repeated if the table crosses a page boundary
next if ($f[0] eq 'Bits');
# Clean up funky field separator
if ($f[0] =~ /\d+.+\d+/) {
$f[0] =~ s/[^\d]+/-/g;
}
my ($start, $stop, $width) = (0,0,0);
if ($f[0] =~ /-/) {
$f[0] =~ s/^(\d+)[^\d]+(\d+)$/$1-$2/;
($stop,$start) = ($1,$2);
$width = $stop-$start+1;
} else {
if ($f[0] =~ /^\d+$/) {
$start = $stop = $f[0];
$width = 1;
} else {
# continuation from previous line
$start = $stop = $width = 0;
}
}
# Some lines have only bit entries
if (($#f < 1) && ($f[0] =~ /^\d+(|\-\d+)/)) {
$f[4] = '';
$f[3] = '';
$f[2] = '';
$f[1] = '';
} elsif ($#f < 1) {
# Some lines are a continuation of the function field a line above
$f[4] = '';
$f[3] = '';
$f[2] = $f[0];
$f[1] = '';
$f[0] = '';
my $tmp = "\$info{'$registers[0]'}{'ranges'}{" . $previous_res . "}{'function'} .= \"" . $f[2] . "\";\n";
print &multiply($tmp,$previous_res,$previous_start,$previous_stop);
next;
}
# Some lines have only bit and reset entries
if ($#f < 2) {
$f[4] = $f[1];
$f[3] = '';
$f[2] = '';
$f[1] = '';
}
# Some lines have no mnemonic and no function
if ($#f < 3) {
$f[4] = $f[2];
$f[3] = $f[1];
$f[2] = '';
$f[1] = '';
}
# functions with 'reserved' mnemonic have no function
if ($f[1] =~ /^reserved$/i) {
$f[4] = $f[3];
$f[3] = $f[2];
$f[2] = '';
}
$previous_res = $f[0];
$previous_start = $start;
$previous_stop = $stop;
# the 'range' field is not useful in this instance, but used in the 'fields' version of this block to easily go
# from a bit position to the corresponding range.
my $str = "
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'function'} = \"" . $f[2] . "\";
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'mnemonic'} = \"" . $f[1] . "\";
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'description'} = \"" . "\";
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'begin'} = $start;
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'end'} = $stop;
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'width'} = $width;
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'rw'} = \"" . $f[3] . "\";
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'reset'} = \"" . $f[4] . "\";
\$info{'$registers[0]'}{'ranges'}{'" . $f[0] . "'}{'range'} = \"" . $f[0] . "\";
";
my $output;
$output = &multiply($str,$f[0],$start,$stop);
# Load the data structure here, too
eval($output);
print $output . "\n\n";
} elsif (($step == 5) && ($line =~ /^Field Descriptions$/)) {
$step = 6;
next;
}
if ($step == 6) {
if ($line =~ /^(.*?)\((.*?)\).+Bit(s|) +(.*?)\. (.*)$/) {
my $bits = $4;
my $desc = $5;
$bits =~ s/[^\d]+/-/;
if ($previous_bits ne '') {
# We're done with a field description block
print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'description'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} . "\";\n";
foreach my $k (keys %{$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}}) {
print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'values'}{'$k'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$k} . "\";\n";
}
}
if (exists($info{$registers[0]}{'ranges'}{$bits})) {
print STDERR "match ($bits) on $line\n";
$info{$registers[0]}{'ranges'}{$bits}{'description'} = $desc . "\n";
$previous_bits = $bits;
}
} elsif ($previous_bits ne '') {
$info{$registers[0]}{'ranges'}{$previous_bits}{'description'} .= $line . "\n";
if ($line =~ /([0-9a-f]+b|[0-9a-f]+h) = (.*)$/i) {
$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$1} = $2;
}
}
}
}
&finish_record($previous_bits);
print "1;\n";
sub multiply {
my $str = shift;
my $range = shift;
my $start = shift;
my $stop = shift;
my $output = '';
for (my $i=$start;$i<=$stop;$i++) {
my $tmp = $str;
$tmp =~ s/\{'$range'\}/{'$i'}/g;
$tmp =~ s/\{'ranges'\}/{'fields'}/g;
$tmp .=
$output .= $tmp;
}
#$output .= $str if (($stop - $start + 1) > 1);
$output .= $str;
return $output;
}
sub finish_record {
my $previous_bits = shift;
# We're done with a field description block
print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'description'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'description'} . "\";\n";
foreach my $k (keys %{$info{$registers[0]}{'ranges'}{$previous_bits}{'values'}}) {
print "\$info{'$registers[0]'}{'ranges'}{'$previous_bits'}{'values'}{'$k'} = \"" . $info{$registers[0]}{'ranges'}{$previous_bits}{'values'}{$k} . "\";\n";
}
# End of table. If this data applies to more than one register, print duplication lines.
for (my $i=1;$i<=$#registers;$i++) {
print "\$info{'$registers[$i]'} = \$info{'$registers[0]'};\n";
}
}