File Coverage

blib/lib/SystemC/Vregs/Bit.pm
Criterion Covered Total %
statement 165 255 64.7
branch 87 176 49.4
condition 23 52 44.2
subroutine 18 24 75.0
pod 2 17 11.7
total 295 524 56.3


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package SystemC::Vregs::Bit;
5 3     3   13 use SystemC::Vregs::Number;
  3         6  
  3         95  
6 3     3   2535 use Bit::Vector::Overload;
  3         39954  
  3         182  
7              
8 3     3   29 use strict;
  3         5  
  3         104  
9 3     3   15 use vars qw ($VERSION %Keywords);
  3         4  
  3         162  
10 3     3   14 use base qw (SystemC::Vregs::Subclass);
  3         6  
  3         8657  
11             $VERSION = '1.470';
12              
13             foreach my $kwd (qw( w dw fieldsZero fieldsReset
14             ))
15             { $Keywords{$kwd} = 1; }
16              
17             ######################################################################
18              
19             #Fields:
20             # {name} Field name (Subclass)
21             # {at} File/line number (Subclass)
22             # {pack} Parent SystemC::Vregs ref
23             # {typeref} Parent SystemC::Vregs::Type ref
24             # {desc} Description
25             # {bits} Textlist of bits
26             # {bitlist}[] Array of each bit being set
27             # {access} RW/R/W etc
28             # {overlaps} What fields can overlap
29             # {type} C++ type
30             # {rst} Reset value or 'x'
31             # {rst_val} {rst} as hex
32             # After check
33             # {cast_needed} True if C++ needs a cast to convert
34             # {bitarray}[bit]{...} Per bit info
35              
36             ######################################################################
37              
38             sub new {
39 24     24 1 29 my $class = shift;
40 24         89 my $self = $class->SUPER::new(overlaps=>'',
41             @_);
42 24 50       72 ($self->{typeref}) or die "%Error: No typeref,";
43             # Enter each bit into the table
44 24         89 $self->{typeref}{fields}{ $self->{name} } = $self;
45 24         56 return $self;
46             }
47              
48             sub DESTROY {
49 0     0   0 my $self = shift;
50 0 0       0 if ($self->{typeref}) {
51 0         0 delete $self->{typeref}{fields}{$self->{name}};
52             }
53             }
54 0     0 0 0 sub delete { $_[0]->DESTROY(); }
55             sub ignore {
56 0     0 0 0 my $self = shift;
57 0         0 return $self->{attributes}{Deleted};
58             }
59              
60             sub attribute_value {
61 0     0 0 0 my $self = shift;
62 0         0 my $attr = shift;
63 0 0       0 return $self->{attributes}{$attr} if defined $self->{attributes}{$attr};
64 0         0 return $self->{typeref}->attribute_value($attr);
65             }
66              
67             sub is_overlap_ok {
68 5     5 0 7 my $self = shift;
69 5         6 my $other = shift;
70             # Return true if these two bitrefs can overlap
71 5 50 33     24 return 1 if !$self || !$other;
72 5 50       20 return 1 if lc $self->{overlaps} eq "allowed";
73 5 50       20 return 1 if lc $other->{overlaps} eq "allowed";
74 5 50       17 return 1 if lc $self->{name} eq lc $other->{name};
75 5 50       25 return 1 if lc $self->{overlaps} eq lc $other->{name};
76 0 0       0 return 1 if lc $other->{overlaps} eq lc $self->{name};
77 0 0 0     0 return 1 if $self->ignore || $other->ignore;
78 0         0 return 0;
79             }
80              
81             sub check_desc {
82 24     24 0 32 my $self = shift;
83 24 100       105 $self->{overlaps} = $1 if ($self->{desc} =~ /\boverlaps\s+([a-zA-Z0-9_]+)/i);
84 24         87 $self->{desc} = $self->clean_sentence($self->{desc});
85 24 50       67 ($self->{desc}) or $self->warn("Empty description, please document it.\n");
86             }
87              
88             sub check_name {
89 24     24 0 30 my $self = shift;
90 24         43 my $field = $self->{name};
91 24         33 $field =~ s/^_//g;
92              
93 24 50       76 if ($self->{typeref}->attribute_value('allowunder')) {
94 0 0       0 ($field =~ /^[A-Z][A-Za-z0-9_]*$/)
95             or $self->warn ("Bit mnemonics must start with capitals and contain only alphanumerics or underscores.\n");
96             } else {
97 24 50       100 ($field =~ /^[A-Z][A-Za-z0-9]*$/)
98             or $self->warn ("Bit mnemonics must start with capitals and contain only alphanumerics.\n");
99             }
100 24         47 $self->{name} = $field;
101 24   33     89 my $lang = (SystemC::Vregs::Language::is_keyword(lc $field)
102             || ($Keywords{lc($field)} && "Vregs"));
103 24 50 33     77 if ($lang && (lc $lang ne "verilog")) {
104             # For now, we don't emit verilog structures, so don't burden the world
105 0         0 $self->warn ("Name matches a $lang language keyword: ", lc $field, "\n");
106             }
107             }
108              
109             sub compute_type {
110 24     24 0 32 my $self = shift;
111 24         36 my $field = $self->{type};
112 24 50 33     107 if (!defined $field || $field eq "") {
113 0 0       0 if ($self->{bits} =~ /:/) {
114 0 0       0 if ($self->{numbits} > 64) {
    0          
115 0         0 $field = 'uint'.$self->{numbits}.'_t';
116             # probably a compile error, let the user deal with it
117             } elsif ($self->{numbits} > 32) {
118 0         0 $field = 'uint64_t';
119             } else {
120 0         0 $field = 'uint32_t';
121             }
122             } else {
123 0         0 $field = 'bool';
124             }
125             }
126              
127 24 100       93 $self->{cast_needed}=1 if ($field !~ /^(bool|uint\d+_t)$/);
128             #use Data::Dumper; $Data::Dumper::Maxdepth=1; print Dumper($self);
129              
130 24         82 $self->{type} = $field;
131             }
132              
133             sub check_access {
134 24     24 0 26 my $bitref = shift;
135 24         49 my $field = $bitref->{access};
136              
137 24         31 my $l = "";
138 24 50       56 $l = "L" if ($field =~ s/L//g);
139 24 100 66     152 if ($field eq "R" || $field eq "RO" ) {
    100 66        
    50 33        
140 1         3 $field = "R"; # Read only, no side effects
141             } elsif ($field eq "RW" || $field eq "R/W") {
142 22         30 $field = "RW"; # Read/Write
143             } elsif ($field eq "W" || $field eq "WO") {
144 0         0 $field = "W"; # Write only
145             }
146 24         32 $field =~ s/V//g; # Volitile - for testing access only -- currently ignored
147 24         32 $field = $field . $l;
148              
149 24 50       184 if ($field !~ /$SystemC::Vregs::Bit_Access_Regexp/o) {
150 0         0 $bitref->warn ("Bit access must match ${SystemC::Vregs::Bit_Access_Regexp}: '$field'\n");
151 0         0 $field = 'RW';
152             }
153              
154 24         51 $bitref->{access} = $field;
155             }
156              
157             sub check_rst {
158 24     24 0 29 my $bitref = shift;
159 24         37 my $typeref = $bitref->{typeref};
160 24         36 my $field = $bitref->{rst};
161 24         30 $field =~ s/0X/0x/;
162 24 100 66     204 if ($field =~ /^0?x?[0-9a-f_]+$/i) {
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
163 6         9 $field =~ s/_//g;
164             } elsif ($field =~ /^FW-?0$/i) {
165 0         0 $field = "FW0";
166             } elsif ($field =~ /^0-?FW$/i) {
167 0         0 $field = "FW0";
168             } elsif ($field =~ /^FW-(\(.*\))$/i) {
169 0         0 $field = "FW$1";
170             } elsif ($field =~ /^x$/i || $field =~ /^N\/A$/i) {
171 16         28 $field = "X";
172             } elsif ($field =~ /^pin/i) {
173 0         0 $field = "X";
174             } elsif ($field =~ /^tbd$/i) {
175 0         0 print "-Info: $typeref->{name}_$bitref->{bitmnem} TBD reset field value, assuming not reset.\n";
176 0         0 $field = "X";
177             } elsif ($field eq 'true') {
178 0         0 $field = "1";
179             } elsif ($field eq 'false') {
180 0         0 $field = "0";
181             } elsif ($field =~ /^[A-Z0-9_]+$/) {
182 2 50       9 if (!$bitref->{type}) {
183 0         0 $bitref->warn ("Reset mnemonic, but no type: '$field'\n");
184             } else {
185 2         11 my $mnemref = $bitref->{pack}->find_enum($bitref->{type});
186 2 50       9 if ($mnemref) {
187 2 50       11 if (!$mnemref->find_value($field)) {
188 0         0 $bitref->warn("Field '$field' not found as member of enum '$bitref->{type}'\n");
189             }
190             }
191             #else We could check for a valid enum, but are they all in this document?
192             }
193             } else {
194 0         0 $bitref->warn ("Strange reset field definition: '$field'\n");
195 0         0 $field = "0";
196             }
197 24         59 $bitref->{rst} = $field;
198             }
199              
200             sub check_bits {
201 24     24 0 30 my $bitref = shift;
202 24         39 my $field = $bitref->{bits};
203              
204 24         38 $field =~ s/[ \t]+//g; $field = lc $field;
  24         35  
205 24         34 $field =~ s/,,+//g; $field =~ s/,$//;
  24         31  
206 24         32 $bitref->{bits} = $field;
207              
208 24 50 33     139 (defined $field && $field =~ /^[0-9wbdh]/) or $bitref->warn ("No bit range specified: '$field'\n");
209              
210             # Split w[15:0],w[21] into 15,14,13,...
211 24         49 $bitref->{bitlist} = [];
212 24         31 my $numbits=0;
213 24         65 foreach my $subfield (split ",","$field,") {
214 27 100       84 $subfield = "w0[${subfield}]" if $subfield !~ /\[/;
215 27         81 foreach my $busbit (Verilog::Language::split_bus ($subfield)) {
216 291         1870 my $bit;
217 291 50       1560 if ($busbit =~ /^(b(\d+))\[(\d+)\]$/) {
    50          
    50          
    0          
218 0         0 my $byte=$2; $bit=$3;
  0         0  
219 0 0       0 $bit += $byte*8 if $byte;
220             }
221             elsif ($busbit =~ /^(h(\d+))\[(\d+)\]$/) {
222 0         0 my $byte=$2; $bit=$3;
  0         0  
223 0 0       0 $bit += $byte*16 if $byte;
224             }
225             elsif ($busbit =~ /^(w(\d+)|)\[(\d+)\]$/) { # Default if no letter
226 291         438 my $word=$2; $bit=$3;
  291         361  
227 291 100       629 $bit += $word*32 if $word;
228             }
229             elsif ($busbit =~ /^(d(\d+))\[(\d+)\]$/) {
230 0         0 my $word=$2; $bit=$3;
  0         0  
231 0 0       0 $bit += $word*64 if $word;
232             }
233             else {
234 0         0 $bitref->warn ("Strange bits selection: '$field': $busbit\n");
235 0         0 return;
236             }
237 291         326 push @{$bitref->{bitlist}}, $bit;
  291         664  
238 291         492 $numbits++;
239             }
240             }
241 24 50       59 ($numbits) or $bitref->warn ("Register without bits\n");
242 24         54 $bitref->{numbits} = $numbits;
243             #print "bitdecode '$field'=> @{$bitref->{bitlist}}\n";
244              
245             # Encode bits back into extents and ranges
246 24         42 $bitref->{bitlist_range} = [];
247 24         49 $bitref->{bitlist_range_32} = [];
248 24         37 foreach my $thirtytwo (0 .. 1) {
249 48         54 my @blist;
250 48         52 my $msb = -1;
251 48         74 my $lastbit = -1;
252 48         65 my $tobit = $bitref->{numbits};
253 48         51 foreach my $bit (@{$bitref->{bitlist}}, -1) {
  48         93  
254 630 100 100     3677 if ($bit != $lastbit-1
      66        
      100        
255             || ($thirtytwo && (31==($bit % 32))) # Don't let a range span different 32 bit words
256             || $bit == -1
257             ) {
258 102 100       201 if ($msb>=0) {
259             #print " rangeadd $msb $lastbit $bit\n";
260 54         180 push @blist, [$msb, $lastbit, $msb-$lastbit+1, $tobit];
261             }
262 102         137 $msb = $bit;
263             }
264 630         654 $lastbit = $bit;
265 630         759 $tobit--;
266             }
267 48 100       117 $bitref->{bitlist_range_32} = \@blist if $thirtytwo;
268 48 100       188 $bitref->{bitlist_range} = \@blist if !$thirtytwo;
269             }
270             }
271              
272             ######################################################################
273              
274             sub dewildcard {
275 24     24 0 25 my $bitref = shift;
276 24 50       73 return if !$bitref->{expand};
277              
278 0 0       0 print "type_expand_field $bitref->{name}\n" if $SystemC::Vregs::Debug;
279 0         0 my $ityperef = $bitref->{pack}->find_type($bitref->{type});
280 0 0       0 if (!$ityperef) {
281 0         0 $bitref->warn("Can't find class $bitref->{type} for bit marked as 'Expand Class'\n");
282 0         0 return;
283             }
284              
285             # Copy the expanded type's fields directly into this class, minding the bit offsets
286 0         0 foreach my $ibitref (values %{$ityperef->{fields}}) {
  0         0  
287 0         0 my $newname = $bitref->{name}.$ibitref->{name};
288             # Compute what bit numbers the new structure gets
289 0         0 $bitref->check_bits; # So we get bistlist
290 0         0 $ibitref->check_bits; # So we get bistlist
291 0         0 my $bits="";
292 0         0 my $basebit = $bitref->{bitlist_range}[0][1];
293 0 0       0 defined $basebit or $bitref->warn("No starting bit specified for base structure\n");
294 0         0 foreach my $bitrange (@{$ibitref->{bitlist_range}}) {
  0         0  
295 0         0 my ($msb,$lsb,$nbits,$srcbit) = @{$bitrange};
  0         0  
296 0         0 $bits .= ($msb+$basebit).":".($lsb+$basebit).",";
297             }
298             #print "$newname $bitref->{bitlist_range}[0]\n" if $SystemC::Vregs::Debug;
299 0 0       0 print "$newname $basebit $bits\n" if $SystemC::Vregs::Debug;
300 0         0 my $overlaps = $ibitref->{overlaps};
301 0 0 0     0 $overlaps = ($bitref->{name}.$overlaps) if $overlaps && $overlaps ne "allowed";
302 0         0 my $newref = SystemC::Vregs::Bit->new
303 0         0 (%{$ibitref}, # Clone attributes, etc
304             pack=>$bitref->{pack},
305             name=>$newname,
306             typeref=>$bitref->{typeref},
307             expanded_super=>$bitref->{name},
308             expanded_sub=>$ibitref->{name},
309             bits=>$bits,
310             );
311 0 0       0 $newref->{desc} =~ s/(\boverlaps\s+)([a-zA-Z0-9_]+)/$1$overlaps/i if $overlaps;
312             #print "REG $newref->{name} ol $overlaps\n";
313              
314             # Cleanup the bitlist
315 0         0 $newref->check_bits;
316             }
317              
318             # Eliminate ourself
319 0         0 $bitref->delete();
320             }
321              
322             sub computes {
323 24     24 0 33 my $bitref = shift;
324             {
325 24         26 my $access = $bitref->{access};
  24         41  
326 24 50       77 $bitref->{access_last} = (($access =~ /L/) ? 1:0);
327 24 50       132 $bitref->{access_read} = (($access =~ /R/) ? 1:0);
328 24 50       67 $bitref->{access_read_side} = (($access =~ /R[^W]*S/) ? 1:0);
329 24 100       66 $bitref->{access_hardwired} = (($access =~ /H/) ? 1:0);
330 24 100       71 $bitref->{access_write} = (($access =~ /W/) ? 1:0);
331 24 50       121 $bitref->{access_write_side} = (($access =~ /(W[^R]*S|W1C)/) ? 1:0);
332 24 50       73 $bitref->{access_write_one} = (($access =~ /(W1)/) ? 1:0);
333             }
334              
335 24 50 33     71 $bitref->{fw_reset} = 1 if ($bitref->{rst} =~ /^FW/ && $bitref->{access} =~ /W/);
336 24         135 $bitref->{comment} = sprintf ("%5s %4s %3s: %s",
337             $bitref->{bits}, $bitref->{access}, $bitref->{rst}, $bitref->{desc});
338             }
339              
340             sub computes_type {
341             # Computes that associate a bit with a type
342             # These need to be done on any inherited types also
343 29     29 0 39 my $bitref = shift;
344 29 50       63 my $typeref = shift or die;
345              
346             # Access fields that affect the register itself
347 29 50       65 $typeref->{access_last} = 1 if $bitref->{access_last};
348 29 50       74 $typeref->{access_read} = 1 if $bitref->{access_read};
349 29 50       62 $typeref->{access_read_side} = 1 if $bitref->{access_read_side};
350 29 50       102 $typeref->{access_write_side} = 1 if $bitref->{access_write_side};
351              
352 29         50 my $bitsleft = $bitref->{numbits}-1;
353 29         66 foreach my $bit (@{$bitref->{bitlist}}) {
  29         55  
354             #print "Use $bit $bitref->{name}\n";
355              
356 393         528 my $prevuser = $typeref->{bitarray}[$bit];
357 393 100       754 if ($prevuser) {
358 5         10 $prevuser = $prevuser->{bitref};
359 5 50       17 if (!$bitref->is_overlap_ok($prevuser)) {
360 0         0 $bitref->warn ("Bit $bit defined twice in register ($bitref->{name} and $prevuser->{name})\n"
361             ."Perhaps you need a 'Overlaps $bitref->{name}.' in $prevuser->{name}'s description\n");
362             }
363             }
364              
365 393         388 my $rstvec = undef; # undef means unknown (x)
366 393         549 my $rst = $bitref->{rst};
367 393 100 66     1137 if ($rst eq "X" || $rst =~ /^FW/) {
    100          
    50          
    100          
    50          
368 314         341 $rstvec = undef;
369             } elsif ($rst eq "0") {
370 70         87 $rstvec = 0;
371 70         270 $bitref->{rst_val} = 0;
372             } elsif ($rst =~ /^0x[0-9a-f_]+$/i) {
373 0         0 $rst =~ s/_//g;
374 3     3   20 my $value = eval { no warnings 'portable'; hex $rst; };
  3         7  
  3         1626  
  0         0  
  0         0  
375 0         0 $bitref->{rst_val} = $value;
376 0 0       0 $rstvec = (($value & (1<<($bitsleft))) ? 1:0);
377             } elsif ($rst =~ /^[0-9_]+$/i) {
378 1         3 $rst =~ s/_//g;
379 1         8 my $value = $rst;
380 1         4 $bitref->{rst_val} = $value;
381 1 50       5 $rstvec = (($value & (1<<($bitsleft))) ? 1:0);
382             } elsif ($rst =~ /^[A-Z][A-Z0-9_]*$/) {
383 8         11 $rstvec = 0;
384 8         28 my $mnemref = $bitref->{pack}->find_enum($bitref->{type});
385 8 50       19 $mnemref or $bitref->warn("Enum '$bitref->{type}' not found\n");
386 8 50       26 if ($mnemref) {
387 8         20 my $vref = $mnemref->find_value($rst);
388 8 50       50 if (!$vref) {
389 0         0 $bitref->warn("Field '$rst' not found as member of enum '$bitref->{type}'\n");
390             }
391 8         19 $bitref->{rst_val} = $vref->{rst_val};
392 8 100       25 $rstvec = 1 if ($vref->{rst_val} & (1<<$bitsleft));
393             }
394             } else {
395 0         0 $bitref->warn ("Odd reset form: $rst\n");
396             }
397              
398             # Save info for every bit in the register
399 393         2326 $bitref->{bitarray}[$bit] = $typeref->{bitarray}[$bit]
400             = { bitref=>$bitref,
401             write => $bitref->{access_write},
402             read => $bitref->{access_read},
403             write_side => $bitref->{access_write_side},
404             read_side => $bitref->{access_read_side},
405             rstvec => $rstvec,
406             };
407 393         687 $bitsleft--;
408             } # each bit
409             }
410              
411             sub check {
412 24     24 1 33 my $self = shift;
413 24         54 $self->check_desc();
414 24         51 $self->check_name();
415 24         55 $self->check_access();
416 24         49 $self->check_rst();
417 24         50 $self->check_bits();
418             # Computes rely on check() being correct
419 24         61 $self->computes();
420 24         54 $self->compute_type();
421             }
422              
423             sub remove_if_mismatch {
424 0     0 0   my $self = shift;
425 0           my $test_cb = shift;
426 0 0         if ($test_cb->($self)) {
427 0           $self->delete;
428 0           return 1;
429             }
430 0           return undef;
431             }
432              
433             sub dump {
434 0     0 0   my $self = shift;
435 0   0       my $fh = shift || \*STDOUT;
436 0   0       my $indent = shift||" ";
437             }
438              
439             ######################################################################
440             #### Package return
441             1;
442             __END__