File Coverage

blib/lib/SystemC/Vregs/Input/HTML.pm
Criterion Covered Total %
statement 12 261 4.6
branch 0 166 0.0
condition 0 79 0.0
subroutine 4 13 30.7
pod 2 7 28.5
total 18 526 3.4


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package SystemC::Vregs::Input::HTML;
5 3     3   14 use Carp;
  3         5  
  3         161  
6 3     3   13 use strict;
  3         6  
  3         78  
7              
8 3     3   1267 use SystemC::Vregs::Input::TableExtract;
  3         10  
  3         32  
9 3     3   156 use vars qw($VERSION $Debug);
  3         4  
  3         11360  
10              
11             $VERSION = '1.470';
12              
13             ######################################################################
14             # CONSTRUCTOR
15              
16             sub new {
17 0     0 1   my $class = shift;
18 0           my $self = {@_};
19 0           bless $self, $class;
20 0           return $self;
21             }
22              
23             ######################################################################
24             # Reading
25              
26             sub read {
27 0     0 1   my $self = shift;
28 0           my %params = (#filename =>
29             #pack =>
30             @_);
31 0 0         my $pack = $params{pack} or croak "%Error: No pack=> parameter passed,";
32 0           $self->{pack} = $pack;
33             # Dump headers for class name based accessors
34              
35 0           my $te = new SystemC::Vregs::Input::TableExtract(depth=>0, );
36 0           $te->{_vregs_inp} = $self;
37 0           $te->parse_file($params{filename});
38             }
39              
40             ######################################################################
41             # Callbacks from table extract
42              
43             sub new_item {
44 0     0 0   my $self = $_[0];
45 0           my $bittableref = $_[1];
46 0           my $flagref = $_[2]; # Hash of {heading} = value_of_heading
47             #Create a new register/class/enum, called from the html parser
48 0 0         print "new_item:",::Dumper(\$flagref, $bittableref) if $SystemC::Vregs::Input::TableExtract::Debug;
49              
50 0 0         if ($flagref->{Register}) {
    0          
    0          
    0          
    0          
51 0           new_register (@_);
52             } elsif ($flagref->{Class}) {
53 0           new_register (@_);
54             } elsif ($flagref->{Enum}) {
55 0           new_enum (@_);
56             } elsif (defined $flagref->{Defines}) { # Name not required, so defined.
57 0           new_define (@_);
58             } elsif ($flagref->{Package}) {
59 0           new_package (@_);
60             }
61             }
62              
63             sub new_package {
64 0     0 0   my $self = shift;
65 0           my $bittableref = shift; my @bittable = @{$bittableref};
  0            
  0            
66 0           my $flagref = shift; # Hash of {heading} = value_of_heading
67             # Create a new package
68 0           my $pack = $self->{pack};
69              
70 0 0         ($flagref->{Package}) or die;
71 0 0         (!$self->{_got_package_decl}) or return $pack->warn($flagref, "Multiple Package attribute sections, previous at $self->{_got_package_decl}.\n");
72              
73 0   0       my $attr = $flagref->{Attributes}||"";
74 0 0         print "PACK ATTR $attr\n" if $Debug;
75 0           $pack->attributes_parse($attr);
76 0           $self->{_got_package_decl} = $flagref->{at};
77             }
78              
79             sub new_define {
80 0     0 0   my $self = shift;
81 0           my $bittableref = shift; my @bittable = @{$bittableref};
  0            
  0            
82 0           my $flagref = shift; # Hash of {heading} = value_of_heading
83             # Create a new enumeration
84 0 0         return if $#bittable<0; # Empty list of defines
85 0           my $pack = $self->{pack};
86              
87             #print ::Dumper(\$flagref, $bittableref);
88 0 0         (defined $flagref->{Defines}) or die;
89 0   0       $flagref->{Defines} ||= "";
90 0           my $defname = _cleanup_column($flagref->{Defines});
91 0 0 0       $defname .= "_" if $defname ne "" && $defname !~ /_$/;
92 0 0         $defname = "" if $defname eq "_";
93              
94 0   0       my $whole_table_attr = $flagref->{Attributes}||"";
95              
96 0           my ($const_col, $mnem_col, $def_col)
97             = $self->_choose_columns ($flagref,
98             [qw(Constant Mnemonic Definition)],
99             [qw(Product)],
100             $bittable[0]);
101 0 0         defined $const_col or return $pack->warn ($flagref, "Define table is missing column headed 'Constant'\n");
102 0 0         defined $mnem_col or return $pack->warn ($flagref, "Define table is missing column headed 'Mnemonic'\n");
103 0 0         defined $def_col or return $pack->warn ($flagref, "Define table is missing column headed 'Definition'\n");
104              
105 0           foreach my $row (@bittable) {
106 0 0         print " Row:\n" if $Debug;
107 0           foreach my $col (@$row) {
108 0 0         print " Ent:$col\n" if $Debug;
109 0 0         if (!defined $col) {
110 0           $pack->warn ($flagref, "Column ".($col+1)." is empty\n");
111             }
112             }
113 0 0         next if $row eq $bittable[0]; # Ignore header
114              
115 0           my $val_mnem = $row->[$mnem_col];
116 0           my $desc = $row->[$def_col];
117              
118             # Skip blank/reserved values
119 0 0 0       next if ($val_mnem eq "" && ($desc eq "" || $desc =~ /^reserved/i));
      0        
120              
121             # Check for empty field
122 0           my $defref = new SystemC::Vregs::Define::Value
123             (pack => $pack,
124             name => $defname . $val_mnem,
125             rst => $row->[$const_col],
126             desc => $desc,
127             at => $flagref->{at},
128             is_manual => 1,
129             );
130              
131             # Take special user defined fields and add to table
132 0           for (my $colnum=0; $colnum<=$#{$bittable[0]}; $colnum++) {
  0            
133 0           my $col = $bittable[0][$colnum];
134 0           $col =~ s/\s+//;
135 0 0         if ($col =~ /^\s*\(([a-zA-Z_0-9]+)\)\s*$/) {
136 0           my $var = $1;
137 0   0       my $val = _cleanup_column($row->[$colnum]||"");
138 0 0         $defref->{attributes}{$var} = $val if $val =~ /^([][a-zA-Z._:0-9+]+)$/;
139             }
140             }
141 0           $defref->attributes_parse($whole_table_attr);
142             }
143             }
144              
145             sub new_enum {
146 0     0 0   my $self = shift;
147 0           my $bittableref = shift; my @bittable = @{$bittableref};
  0            
  0            
148 0           my $flagref = shift; # Hash of {heading} = value_of_heading
149             # Create a new enumeration
150 0           my $pack = $self->{pack};
151              
152 0 0         ($flagref->{Enum}) or die;
153 0           my $classname = _cleanup_column($flagref->{Enum});
154              
155 0           my ($const_col, $mnem_col, $def_col)
156             = $self->_choose_columns ($flagref,
157             [qw(Constant Mnemonic Definition)],
158             [qw(Product)],
159             $bittable[0]);
160 0 0         defined $const_col or return $pack->warn ($flagref, "Enum table is missing column headed 'Constant'\n");
161 0 0         defined $mnem_col or return $pack->warn ($flagref, "Enum table is missing column headed 'Mnemonic'\n");
162 0 0         defined $def_col or return $pack->warn ($flagref, "Enum table is missing column headed 'Definition'\n");
163              
164 0           my $classref = new SystemC::Vregs::Enum
165             (pack => $pack,
166             name => $classname,
167             at => $flagref->{at},
168             );
169              
170 0   0       my $attr = $flagref->{Attributes}||"";
171 0           while ($attr =~ s/-(\w+)//) {
172 0           $classref->{attributes}{$1} = 1;
173             }
174 0 0         ($attr =~ /^\s*$/) or $pack->warn($flagref, "Strange attributes $attr\n");
175              
176 0           foreach my $row (@bittable) {
177 0 0         print " Row:\n" if $Debug;
178 0           foreach my $col (@$row) {
179 0 0         print " Ent:$col\n" if $Debug;
180 0 0         if (!defined $col) {
181 0           $pack->warn ($flagref, "Column ".($col+1)." is empty\n");
182             }
183             }
184 0 0         next if $row eq $bittable[0]; # Ignore header
185              
186 0           my $val_mnem = _cleanup_column($row->[$mnem_col]);
187 0           my $desc = _cleanup_column($row->[$def_col]);
188              
189             # Skip blank/reserved values
190 0 0 0       next if ($val_mnem eq "" && ($desc eq "" || $desc =~ /^reserved/i));
      0        
191              
192             # Check for empty field
193 0           my $valref = new SystemC::Vregs::Enum::Value
194             (pack => $pack,
195             name => $val_mnem,
196             class => $classref,
197             rst => _cleanup_column($row->[$const_col]),
198             desc => $desc,
199             at => $flagref->{at},
200             );
201              
202              
203             # Take special user defined fields and add to table
204 0           for (my $colnum=0; $colnum<=$#{$bittable[0]}; $colnum++) {
  0            
205 0           my $col = $bittable[0][$colnum];
206 0           $col =~ s/\s+//;
207 0 0         if ($col =~ /^\s*\(([a-zA-Z_0-9]+)\)\s*$/) {
208 0           my $var = $1;
209 0   0       my $val = _cleanup_column($row->[$colnum]||"");
210 0 0         $valref->{attributes}{$var} = $val if $val =~ /^([][a-zA-Z._:0-9+]+)$/;
211             }
212             }
213             }
214             }
215              
216             sub new_register {
217 0     0 0   my $self = shift;
218 0           my $bittableref = shift; my @bittable = @{$bittableref};
  0            
  0            
219 0           my $flagref = shift; # Hash of {heading} = value_of_heading
220             # Create a new register
221 0           my $pack = $self->{pack};
222              
223 0   0       my $classname = _cleanup_column($flagref->{Register} || $flagref->{Class});
224 0 0         (defined $classname) or die;
225              
226             #print "new_register!\n",::Dumper(\$flagref,\@bittable);
227              
228 0           my $range = "";
229 0 0         $range = $1 if ($classname =~ s/(\[[^\]]+])//);
230 0           $classname =~ s/\s+$//;
231              
232 0   0       my $is_register = ($flagref->{Register} || $flagref->{Address});
233              
234 0           my $inherits = "";
235 0 0         if ($classname =~ s/\s*:\s*(\S+)$//) {
236 0           $inherits = $1;
237             }
238              
239 0   0       my $attr = $flagref->{Attributes}||"";
240 0 0         return if $attr =~ /noimplementation/;
241              
242 0           my $typeref = new SystemC::Vregs::Type
243             (pack => $pack,
244             name => $classname,
245             at => $flagref->{at},
246             is_register => $is_register, # Ok, perhaps I should have made a superclass
247             );
248 0           $typeref->inherits($inherits);
249              
250             # See also $typeref->{attributes}{lcfirst}, below.
251 0           while ($attr =~ s/-([a-zA-Z_0-9]+)\s*=?\s*([a-zA-Z._0-9+]+)?//) {
252 0 0         $typeref->{attributes}{$1} = (defined $2 ? $2 : 1);
253             }
254 0 0         ($attr =~ /^\s*$/) or $pack->warn($flagref, "Strange attributes $attr\n");
255              
256 0 0         if ($is_register) {
257             # Declare a register
258 0 0         ($classname =~ /^[R]_/) or return $pack->warn($flagref, "Strange mnemonic name, doesn't begin with R_");
259              
260 0           my $addr = $flagref->{Address}; # Don't _cleanup_column, as we have (Add 0x) text
261 0           my $spacingtext = 0;
262 0 0         $spacingtext = $pack->{data_bytes} if $range;
263 0 0         if (!$addr) {
264 0           $pack->warn ($flagref, "No 'Address' Heading Found\n");
265 0           return;
266             }
267 0           $addr =~ s/[()]//g;
268 0           $addr =~ s/\s*plus\s*base\s*address\s*//;
269 0           $addr =~ s/\s*per\s+entry//g;
270 0 0         if ($addr =~ s/\s*Add\s*(0x[a-f0-9_]+)\s*//i) {
271 0           $spacingtext = $1;
272             }
273              
274 0           my $regref = new SystemC::Vregs::Register
275             (pack => $pack,
276             typeref => $typeref,
277             name => $classname,
278             at => $flagref->{at},
279             addrtext => $addr,
280             spacingtext => $spacingtext,
281             range => $range,
282             );
283             }
284              
285 0 0 0       if (defined $bittable[0] || !$inherits) {
286 0           my ($bit_col, $mnem_col, $type_col, $def_col,
287             $acc_col, $rst_col,
288             $const_col,
289             $size_col)
290             = $self->_choose_columns ($flagref,
291             [qw(Bit Mnemonic Type Definition),
292             qw(Access Reset), # Register decls
293             qw(Constant), # Class declarations
294             qw(Size), # Ignored Optionals
295             ],
296             [qw(Product)],
297             $bittable[0]);
298 0   0       $rst_col ||= $const_col;
299 0 0         defined $bit_col or return $pack->warn ($flagref, "Table is missing column headed 'Bit'\n");
300 0 0         defined $mnem_col or return $pack->warn ($flagref, "Table is missing column headed 'Mnemonic'\n");
301 0 0         defined $def_col or return $pack->warn ($flagref, "Table is missing column headed 'Definition'\n");
302 0 0         if ($is_register) {
303 0 0         defined $rst_col or return $pack->warn ($flagref, "Table is missing column headed 'Reset'\n");
304 0 0         defined $acc_col or return $pack->warn ($flagref, "Table is missing column headed 'Access'\n");
305             }
306              
307             # Table by table, allow the field mnemonics to be either 'fooFlag'
308             # (per our Coding Conventions) or 'FooFlag' (as in a Vregs ASCII file).
309              
310 0           my $allMnems_LCFirst = (@bittable > 1);
311 0           foreach my $row (@bittable) {
312 0 0         next if $row eq $bittable[0]; # Ignore header
313 0 0         my $bit_mnem = $row->[$mnem_col] or next;
314 0           my $c1 = substr($bit_mnem, 0, 1);
315 0 0 0       if ($c1 ge 'A' && $c1 le 'Z') { $allMnems_LCFirst = 0; }
  0            
316             }
317 0 0         if ($allMnems_LCFirst) {
318 0 0         print " Upcasing first letter of mnemonics.\n" if $Debug;
319 0           foreach my $row (@bittable) {
320 0 0         next if $row eq $bittable[0]; # Ignore header
321 0 0         my $bit_mnem = $row->[$mnem_col] or next;
322 0           $row->[$mnem_col] = ucfirst $bit_mnem;
323             }
324 0           $typeref->{attributes}{lcfirst} = 1;
325             }
326              
327 0           foreach my $row (@bittable) {
328 0 0         print " Row:\n" if $Debug;
329 0           foreach my $col (@$row) {
330 0 0         print " Ent:$col\n" if $Debug;
331 0 0         if (!defined $col) {
332 0           $pack->warn ($flagref, "Column ".($col+1)." is empty\n");
333             }
334             }
335 0 0         next if $row eq $bittable[0]; # Ignore header
336              
337             # Check for empty field
338 0           my $bit_mnem = $row->[$mnem_col];
339 0           $bit_mnem =~ s/^_//;
340 0           my $desc = $row->[$def_col];
341              
342 0           my $overlaps = "";
343 0 0         $overlaps = $1 if ($desc =~ /\boverlaps\s+([a-zA-Z0-9_]+)/i);
344              
345             # Skip empty fields
346 0 0 0       if (($bit_mnem eq "" || $bit_mnem eq '-')
      0        
      0        
347             && ($desc eq "" || $desc =~ /Reserved/ || $desc=~/Hardwired/
348             || $desc =~ /^(\/\/|\#)/)) { # Allow //Comment or #Comment
349 0           next;
350             }
351 0 0 0       if ((!defined $bit_col || $row->[$bit_col] eq "")
      0        
      0        
      0        
      0        
352             && (!defined $mnem_col || $row->[$mnem_col] eq "")
353             && (!defined $rst_col || $row->[$rst_col] eq "")
354             ) {
355 0           next; # All blank lines (excl comment) are fine.
356             }
357              
358 0 0         my $rst = _cleanup_column(defined $rst_col ? $row->[$rst_col] : "");
359 0 0 0       $rst = 'X' if ($rst eq "" && !$is_register);
360              
361 0   0       my $type = _cleanup_column(defined $type_col && $row->[$type_col]);
362              
363 0 0         my $acc = _cleanup_column(defined $acc_col ? $row->[$acc_col] : 'RW');
364              
365 0 0         (!$typeref->{fields}{$bit_mnem}) or
366             $pack->warn ($typeref->{fields}{$bit_mnem}, "Field defined twice in spec\n");
367 0 0 0       my $bitref = new SystemC::Vregs::Bit
368             (pack => $pack,
369             name => $bit_mnem,
370             typeref => $typeref,
371             bits => $row->[$bit_col],
372             access => $acc,
373             overlaps => $overlaps,
374             rst => $rst,
375             desc => $row->[$def_col],
376             type => $type,
377             expand => ($type && $desc =~ /expand class/i)?1:undef,
378             at => $flagref->{at},
379             );
380              
381             # Take special user defined fields and add to table
382 0           for (my $colnum=0; $colnum<=$#{$bittable[0]}; $colnum++) {
  0            
383 0           my $col = $bittable[0][$colnum];
384 0           $col =~ s/\s+//;
385 0 0         if ($col =~ /^\s*\(([a-zA-Z_0-9]+)\)\s*$/) {
386 0           my $var = $1;
387 0   0       my $val = _cleanup_column($row->[$colnum]||"");
388 0 0         $bitref->{attributes}{$var} = $val if $val =~ /^([][a-zA-Z._:0-9+]+)$/;
389             }
390             }
391             }
392             }
393             }
394              
395             ######################################################################
396             #### Parsing
397              
398             sub _choose_columns {
399 0     0     my $self = shift;
400 0           my $flagref = shift;
401 0           my $fieldref = shift;
402 0           my $attrfieldref = shift;
403 0           my $headref = shift;
404             # Look for the columns with the given headings. Require them to exist.
405              
406 0           my @collist;
407 0           my @colused = ();
408 0           my @colheads;
409             # The list is short, so this is faster than forming a hash.
410             # If things get wide, this may change
411 0           for (my $h=0; $h<=$#{$headref}; $h++) {
  0            
412 0           $colheads[$h] = $headref->[$h];
413 0           $colheads[$h] =~ s/\s*\(.*\)\s*//; # Ignore comments in the header
414 0 0         $colused[$h] = 1 if $colheads[$h] eq "";
415             }
416 0           headchk:
417 0           foreach my $fld (@{$fieldref}) {
418 0           for (my $h=0; $h<=$#{$headref}; $h++) {
  0            
419 0 0         if ($fld eq $colheads[$h]) {
420 0           push @collist, $h;
421 0           $colused[$h] = 1;
422 0           next headchk;
423             }
424             }
425 0           push @collist, undef;
426             }
427 0           foreach my $fld (@{$attrfieldref}) {
  0            
428 0           for (my $h=0; $h<=$#{$headref}; $h++) {
  0            
429 0 0         if ($fld eq $colheads[$h]) {
430             # Convert to a attribute
431 0           $headref->[$h] = "(".$headref->[$h].")";
432 0           $colused[$h] = 1;
433             }
434             }
435             }
436              
437 0           my $ncol = 0;
438 0           for (my $h=0; $h<=$#{$headref}; $h++) {
  0            
439 0 0         $ncol = $h+1 if !$colused[$h];
440             }
441              
442 0 0         if ($ncol) {
443 0           SystemC::Vregs::Subclass::warn ($flagref, "Column ".($ncol-1)." found with unknown header.\n");
444 0           print "Desired column headers: '",join("' '",@{$fieldref}),"'\n";
  0            
445 0           print "Found column headers: '",join("' '",@{$headref}),"'\n";
  0            
446 0 0         print "Defined:("; foreach (@collist) { print (((defined $_)?$_:'-'),' '); }
  0            
  0            
447 0           print ")\n";
448 0 0         print "Used: ("; foreach (@colused) { print ((($_)?'Y':'-'),' '); }
  0            
  0            
449 0           print ")\n";
450             }
451              
452 0           return (@collist);
453             }
454              
455             sub _cleanup_column {
456 0     0     my $text = shift;
457 0 0         return undef if !defined $text;
458 0           while ($text =~ s/\s*\([^\(\)]*\)//) {} # Strip (comment) Leave trailing space "foo (bar) x" becomes "foo x"
459 0           $text =~ s/\s+$//;
460 0           $text =~ s/^\s+//;
461 0           return $text;
462             }
463              
464             ######################################################################
465             ######################################################################
466             #### Package return
467             1;
468             __END__