2009-10-28 20:41:52 +01:00
|
|
|
#!/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;
|
|
|
|
|
2010-04-27 08:56:47 +02:00
|
|
|
# the 'range' field is not useful in this instance, but used in the 'fields' version of this block to easily go
|
2009-10-28 20:41:52 +01:00
|
|
|
# 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;
|
2010-04-27 08:56:47 +02:00
|
|
|
$tmp .=
|
2009-10-28 20:41:52 +01:00
|
|
|
$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";
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|