File Coverage

blib/lib/SystemC/Vregs/Enum.pm
Criterion Covered Total %
statement 103 164 62.8
branch 21 60 35.0
condition 6 28 21.4
subroutine 21 31 67.7
pod 2 10 20.0
total 153 293 52.2


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package SystemC::Vregs::Enum;
5 3     3   15 use SystemC::Vregs::Number;
  3         4  
  3         127  
6 3     3   1378 use SystemC::Vregs::Subclass;
  3         7  
  3         96  
7 3     3   3290 use Verilog::Language; # For value parsing
  3         15842  
  3         136  
8              
9 3     3   25 use strict;
  3         16  
  3         101  
10 3     3   16 use vars qw ($VERSION);
  3         5  
  3         129  
11 3     3   13 use base qw (SystemC::Vregs::Subclass);
  3         6  
  3         363  
12              
13             $VERSION = '1.470';
14              
15             ######################################################################
16             ######################################################################
17             ######################################################################
18             ######################################################################
19             #### SystemC::Vregs::Enum
20              
21             package SystemC::Vregs::Enum;
22 3     3   14 use strict;
  3         5  
  3         2301  
23              
24             #Fields: name, at, pack, fields
25              
26             sub new {
27 2     2 1 5 my $class = shift;
28 2         8 my $self = {@_};
29 2         5 bless $self, $class;
30 2 50       12 $self->{pack} or die; # Should have been passed as parameter
31 2         7 $self->{pack}{enums}{$self->{name}} = $self;
32 2         7 return $self;
33             }
34              
35             sub delete {
36 0     0 0 0 my $self = shift;
37 0         0 $self->{deleted} = 1; # So can see in any dangling refs.
38 0 0       0 if ($self->{pack}) {
39 0         0 delete $self->{pack}{enums}{$self->{name}};
40             }
41             }
42              
43             sub find_value {
44 10     10 0 12 my $self = shift;
45 10         13 my $name = shift;
46 10         34 return $self->{fields}{$name};
47             }
48              
49             sub attribute_value {
50 27     27 0 42 my $self = shift;
51 27         34 my $attr = shift;
52 27 50       72 return $self->{attributes}{$attr} if defined $self->{attributes}{$attr};
53 27 50       77 return $self->{pack}{attributes}{$attr} if defined $self->{pack}{attributes}{$attr};
54 27         74 return undef;
55             }
56              
57             #======
58              
59             sub check_name {
60 4     4 0 5 my $self = shift;
61 4         8 my $field = $self->{name};
62 4 50       9 if ($self->attribute_value('allowlc')) {
63 0 0       0 if ($field !~ /^[a-zA-Z][a-zA-Z0-9_]*$/) {
64 0         0 return $self->warn ("Enum names must match [alpha][alphanumerics_]'\n: $field");
65             }
66             } else {
67 4 50       17 if ($field !~ /^[A-Z][a-zA-Z0-9_]*$/) {
68 0         0 return $self->warn ("Enum names must match [capitals][alphanumerics_]'\n: $field");
69             }
70             }
71             # Because the enum is always capitalized, we don't add the 'lc' here.
72 4   33     15 my $lang = (SystemC::Vregs::Language::is_keyword($field)
73             || SystemC::Vregs::Language::is_keyword(uc $field));
74 4 50       14 if ($lang) {
75 0         0 $self->warn ("Name matches a $lang language keyword: ", lc $field, "\n");
76             }
77             }
78              
79             sub check {
80 4     4 1 5 my $self = shift;
81             #print ::Dumper($enumref);
82 4         17 $self->check_name();
83 4         5 foreach my $fieldref (values %{$self->{fields}}) {
  4         14  
84 15         31 $fieldref->check();
85             }
86 4 50       18 $self->{bits} or $self->warn ("Enum has no entries");
87             }
88              
89             sub remove_if_mismatch {
90 0     0 0 0 my $self = shift;
91 0         0 my $test_cb = shift;
92 0         0 my $rm=0; my $cnt=0;
  0         0  
93 0         0 foreach my $fieldref (values %{$self->{fields}}) {
  0         0  
94 0 0       0 $rm++ if $fieldref->remove_if_mismatch($test_cb);
95 0         0 $cnt++;
96             }
97 0 0 0     0 if ($test_cb->($self) || ($rm && $rm == $cnt)) {
      0        
98 0         0 $self->delete;
99             }
100             }
101              
102             sub fields_sorted {
103 6     6 0 8 my $typeref = shift;
104 76 50       174 return (sort {$a->{rst_val} <=> $b->{rst_val}
  6         27  
105             || $a->{name} cmp $b->{name} }
106 6         9 (values %{$typeref->{fields}}));
107             }
108              
109             sub fields_first_name {
110 0     0 0 0 my $self = shift;
111 0         0 my @fields = $self->fields_sorted;
112 0 0       0 if ($fields[0]) {
113 0         0 return $fields[0]->name;
114             } else {
115 0         0 return undef;
116             }
117             }
118              
119             sub dump {
120 0     0 0 0 my $self = shift;
121 0   0     0 my $fh = shift || \*STDOUT;
122 0   0     0 my $indent = shift||" ";
123 0         0 print $fh +($indent,"Enum: ",$self->{name},
124             "\n");
125 0         0 foreach my $fieldref ($self->fields_sorted) {
126 0         0 $fieldref->dump($fh,$indent." ");
127             }
128             }
129              
130             ######################################################################
131             ######################################################################
132             ######################################################################
133             ######################################################################
134             #### SystemC::Vregs::Enum::Value
135              
136             package SystemC::Vregs::Enum::Value;
137 3     3   17 use strict;
  3         4  
  3         88  
138 3     3   14 use base qw (SystemC::Vregs::Subclass);
  3         6  
  3         3301  
139              
140             # Fields: name, at, class
141 0     0   0 sub name { return $_[0]->{name}; }
142              
143             sub new {
144 15     15   20 my $class = shift;
145 15         54 my $self = $class->SUPER::new(@_);
146 15 50       42 $self->{class} or die; # Should have been passed as parameter
147 15         45 $self->{class}{fields}{$self->{name}} = $self;
148 15         30 return $self;
149             }
150              
151             sub delete {
152 0     0   0 my $self = shift;
153 0         0 $self->{deleted} = 1; # So can see in any dangling refs.
154 0 0       0 if ($self->{class}) {
155 0         0 delete $self->{class}{fields}{$self->{name}};
156             }
157             }
158              
159             sub attributes {
160 0     0   0 my $self = shift;
161 0         0 my $attr = shift;
162 0         0 my $value = shift;
163 0 0       0 $self->{attributes}{$attr} = $value if $value;
164 0         0 return $self->{attributes}{$attr};
165             }
166              
167             sub attribute_value {
168 0     0   0 my $self = shift;
169 0         0 my $attr = shift;
170 0 0       0 return $self->{attributes}{$attr} if defined $self->{attributes}{$attr};
171 0         0 return $self->{class}->attribute_value($attr);
172             }
173              
174             sub clean_desc {
175 23     23   23 my $self = shift;
176 23         70 $self->{desc} = $self->clean_sentence($self->{desc});
177             }
178              
179             sub clean_rst {
180 23     23   25 my $self = shift;
181 23         35 my $field = $self->{rst};
182              
183 23         59 my $bits = Verilog::Language::number_bits ($field);
184 23 50       211 if (!$bits) { return $self->warn ("Number of bits in constant not specified: $field\n"); }
  0         0  
185 23         47 $self->{bits} = $bits;
186 23         54 my $val = Verilog::Language::number_value ($field);
187 23 50       361 if (!defined $val) { return $self->warn ("Value of constant unparsable: $field\n"); }
  0         0  
188 23         81 $self->{rst_val} = $val;
189              
190 23 50 66     130 if (defined $self->{class}{bits}
191             && ($self->{class}{bits} != $bits)) {
192 0         0 return $self->warn ("Enum value doesn't match register width: $field != "
193             .$self->{class}{bits}."\n");
194             }
195 23         41 $self->{class}{bits} = $bits;
196              
197 23 50 33     192 if ($bits && $bits<32 && ($self->{rst_val}||0) >= (1<<$bits)) {
      50        
      33        
198 0         0 $self->warn ("Enum value wider than width: ".$self->{rst}." > width "
199             .$self->{class}{bits}."\n");
200             }
201             }
202              
203             sub check_name {
204 23     23   26 my $self = shift;
205 23         41 my $field = $self->{name};
206 23         46 my $class = $self->{class};
207              
208 23 50       168 if ($class->attribute_value('allowlc')) {
209 0 0       0 if ($field !~ /^[a-zA-Z][a-zA-Z0-9_]*$/) {
210 0         0 return $self->warn ("Enum field names must match [capital][alphanumerics_]: $field\n");
211             }
212             } else {
213 23 50       100 if ($field !~ /^[A-Z][A-Z0-9_]*$/) {
214 0         0 return $self->warn ("Enum field names must match [capital][capitalnumerics_]: $field\n");
215             }
216             }
217             }
218              
219             sub expand_subenums {
220 23     23   26 my $self = shift;
221 23 100       81 if ($self->{desc} =~ /^(.*)ENUM:(\S+)(.*)/) {
222 2         6 my $prefix = $1; my $subname = $2; my $postfix = $3;
  2         3  
  2         12  
223 2 50       7 print "Expand Subenum '$prefix' '$subname' '$postfix'\n" if $SystemC::Vregs::Debug;
224 2         10 my $suberef = $self->{pack}->find_enum($subname);
225 2 50       6 if (!$suberef) {
226 0         0 $self->warn("Enum references sub-enum which isn't found: $subname\n");
227             } else {
228 2         7 $suberef->check();
229 2         4 $self->{omit_description} = 1;
230 2         13 foreach my $subfieldref ($suberef->fields_sorted) {
231 8 50       18 print " FIELD ADD ".$subfieldref->{name}."\n" if $SystemC::Vregs::Debug;
232 8         22 my $rst = $self->{bits}."'d".($self->{rst_val} + $subfieldref->{rst_val});
233 8         50 my $valref = new SystemC::Vregs::Enum::Value
234             (pack => $self->{pack},
235             name => $self->{name}."_".$subfieldref->{name},
236             class => $self->{class},
237             rst => $rst,
238             desc => $prefix . $subfieldref->{desc} . $postfix,
239             omit_from_vregs_file => 1, # Else we'll add it every time we rebuild
240             );
241             # Clone attributes too; higher ones first, so lower ones can override
242 8         28 $valref->copy_attributes_from($subfieldref); # Overrides whole enum attrs, so do first
243 8         23 $valref->copy_attributes_from($self);
244 8         17 $valref->check;
245             }
246             }
247             }
248             }
249              
250             sub check {
251 23     23   29 my $self = shift;
252 23         43 $self->clean_desc();
253 23         52 $self->clean_rst();
254 23         45 $self->check_name();
255 23         52 $self->expand_subenums();
256 23 50       75 ($self->{desc}) or $self->warn("Empty description, please document it.\n");
257             }
258              
259             sub remove_if_mismatch {
260 0     0     my $self = shift;
261 0           my $test_cb = shift;
262 0 0         if ($test_cb->($self)) {
263 0           $self->delete;
264 0           return 1;
265             }
266 0           return undef;
267             }
268              
269             sub dump {
270 0     0     my $self = shift;
271 0   0       my $fh = shift || \*STDOUT;
272 0   0       my $indent = shift||" ";
273 0           print $fh +($indent,"Value: ",$self->{name},
274             "\n");
275             }
276              
277             ######################################################################
278             #### Package return
279             1;
280             __END__