File Coverage

blib/lib/SystemC/Vregs/Register.pm
Criterion Covered Total %
statement 96 144 66.6
branch 22 66 33.3
condition 3 23 13.0
subroutine 14 18 77.7
pod 2 12 16.6
total 137 263 52.0


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package SystemC::Vregs::Register;
5 3     3   17 use SystemC::Vregs::Number;
  3         5  
  3         130  
6 3     3   1535 use SystemC::Vregs::Type;
  3         7  
  3         81  
7 3     3   17 use Bit::Vector::Overload;
  3         5  
  3         101  
8              
9 3     3   12 use strict;
  3         6  
  3         81  
10 3     3   15 use vars qw ($VERSION);
  3         4  
  3         104  
11 3     3   13 use base qw (SystemC::Vregs::Subclass);
  3         6  
  3         6159  
12             $VERSION = '1.470';
13              
14             # Fields:
15             # {name} Field name (Subclass)
16             # {nor_name} Name w/o leading R_
17             # {at} File/line number (Subclass)
18             # {pack} Parent SystemC::Vregs ref
19             # {typeref} Owning SystemC::Vregs::Type ref
20             # {addrtext}
21             # {addr} Beginning SystemC::Vregs::Addr
22             # {addr_end} Ending SystemC::Vregs::Addr (exclusive < end).
23             # {spacingtext}
24             # {range} Range text
25             # {range_high} SystemC::Vregs::Addr
26             # {range_low} SystemC::Vregs::Addr
27             # {range_ents} Number of range entries, SystemC::Vregs::Addr
28              
29             ######################################################################
30             # Accessors
31              
32             sub new {
33 3 50   3 1 5 my $class = shift; $class = ref $class if ref $class;
  3         15  
34 3         17 my $self = $class->SUPER::new(@_);
35 3 50       14 $self->{pack} or die; # Should have been passed as parameter
36 3         10 $self->{pack}{regs}{$self->{name}} = $self;
37 3         7 return $self;
38             }
39              
40             sub delete {
41 0     0 0 0 my $self = shift;
42 0 0       0 $self->{pack} or die;
43 0         0 $self->{deleted} = 1; # So can see in any dangling refs.
44 0         0 delete $self->{pack}{regs}{$self->{name}};
45             }
46              
47             sub attribute_value {
48 0     0 0 0 my $self = shift;
49 0         0 my $attr = shift;
50 0 0       0 return $self->{attributes}{$attr} if defined $self->{attributes}{$attr};
51 0         0 return $self->{typeref}->attribute_value($attr);
52             }
53              
54             ######################################################################
55              
56             sub dewildcard {
57 3     3 0 4 my $self = shift;
58             #print ::Dumper($self);
59 3 50 50     18 return if (($self->{name}||"") !~ /\*/);
60 0         0 my $inh = $self->{typeref}->inherits();
61 0 0       0 print "Reg Wildcard $self->{name} $inh\n" if $SystemC::Vregs::Debug;
62 0         0 (my $regexp = $inh) =~ s/[*]/\.\*/g;
63              
64             #(my $defbase = $inh) =~ s/[*]/Base/g;
65             #(my $defname = $defbase) =~ s/^R_//g;
66             #my $defref = new SystemC::Vregs::Define::Value
67             # (pack => $self->{pack},
68             # name => "RA_".$defname,
69             # rst => $self->{addrtext},
70             # desc => "Base address from wildcarded register range",
71             # );
72              
73 0         0 my $gotone;
74 0         0 foreach my $matchref ($self->{pack}->find_reg_regexp("^$regexp")) {
75 0         0 $gotone = 1;
76 0         0 my $newname = SystemC::Vregs::three_way_replace
77             ($self->{name}, $inh, $matchref->{name});
78 0 0       0 my $typeref = $self->{pack}->find_type($newname) or die;
79 0         0 my $addr = $self->{addrtext} ."|". $matchref->{addrtext};
80 0 0       0 print " Wildcarded $matchref->{name} to $newname\n" if $SystemC::Vregs::Debug;
81 0         0 my $newref = $self->new (name=>$newname,
82             pack=>$self->{pack},
83             addrtext => $addr,
84             spacingtext => $matchref->{spacingtext},
85             range => $matchref->{range},
86             typeref => $typeref,
87             );
88 0         0 $newref->copy_attributes_from($matchref);
89 0         0 $newref->copy_attributes_from($self);
90             }
91 0 0       0 $gotone or $self->warn ("No types matching wildcarded type: ",$self->inherits(),"\n");
92 0         0 $self->delete();
93             }
94              
95             ######################################################################
96              
97             sub check_name {
98 3     3 0 4 my $regref = shift;
99 3         8 my $field = $regref->{name};
100 3 50       16 ($field =~ /^R_[A-Z][a-zA-Z0-9]*$/)
101             or $regref->warn ("Register mnemonics must match R_[capitals][alphanumerics]\n");
102 3 50       11 ($field =~ /cnfg[0-9]+$/i) and $regref->warn ("Abbreviate CNFG (Configuration) as Cfg\n"); #Dan Lussier'ism
103 3         17 ($regref->{nor_name} = $field) =~ s/^[RC]_//;
104             }
105              
106             sub check_addrtext {
107 3     3 0 5 my $regref = shift;
108 3         5 my $addrtext = $regref->{addrtext};
109 3         6 $addrtext =~ s/\s+$//;
110              
111 3         4 my $inher_min;
112 3 50       9 if ($addrtext =~ s/\s*[|]\s*\b(R_[0-9a-zA-Z_]+)\b//) {
113 0         0 my $orin_name = $1;
114 0         0 my $orin_ref = $regref->{pack}->find_reg($orin_name);
115 0 0       0 if (!$orin_ref) {
116 0         0 $regref->warn ("Address contains | of unknown register: $addrtext\n");
117             } else {
118 0         0 my $text = $orin_ref->{addrtext};
119 0         0 $text =~ s/-.*//;
120 0         0 $inher_min = $regref->{pack}->addr_text_to_vec($text);
121 0 0       0 defined $inher_min or $orin_ref->warn("Can't parse address text: $text\n");
122             }
123             }
124              
125 3 50       10 if ($addrtext =~ s/^.*(0x[0-9a-f_]+)\s*-\s*(0x[0-9a-f_]+)\s*[|]\s*//i) {
126 0         0 my $mintext = $1; my $maxtext = $2;
  0         0  
127 0         0 $inher_min = $regref->{pack}->addr_text_to_vec($mintext);
128 0         0 $regref->{addr_end_wildcard} = $regref->{pack}->addr_text_to_vec($maxtext);
129             }
130 3 50       9 ($addrtext !~ /[|]/) or $regref->warn ("Address cannot contain |'s, or needs complete range: ", $addrtext,"\n");
131              
132 3         5 my $endtext = "";
133 3 50       10 if ($addrtext =~ s/^(0x[0-9a-f_]+)\s*-\s*(0x[0-9a-f_]+)$/$1/i) {
134 0         0 $endtext = $2;
135 0         0 $regref->{addr_end_user} = $regref->{pack}->addr_text_to_vec($endtext);
136             }
137              
138 3 50       14 ($addrtext =~ /^0x[0-9a-f_]+$/i)
139             or $regref->warn ("Strange address format '$addrtext'\n");
140              
141 3         10 $regref->{addr} = $regref->{pack}->addr_text_to_vec($addrtext);
142 3 50       10 if ($inher_min) {
143 0         0 $regref->{addr}->add( $regref->{addr}, $inher_min, 0);
144 0 0       0 $regref->{addr_end_user}->add( $regref->{addr_end_user}, $inher_min, 0) if $regref->{addr_end_user};
145             }
146             }
147              
148             sub check_range_spacing {
149 3     3 0 5 my $regref = shift;
150              
151 3         7 my $range = $regref->{range};
152 3 50       9 if (!defined $regref->{spacing}) {
153 3         12 $regref->{spacing} = $regref->{pack}->addr_text_to_vec($regref->{spacingtext});
154 3 50       10 (defined $regref->{spacing}) or $regref->warn ("Strange spacing value $regref->{spacingtext}\n");
155             }
156              
157 3         6 my $spacing = $regref->{spacing};
158 3 100       7 if ($range) {
159 2 50       11 $range =~ /^\[([^\]:]+):([^\]:]+)\]$/
160             or $regref->warn ("Strange range $range\n");
161 2         5 my $htext = $1; my $ltext = $2;
  2         4  
162 2         7 $regref->{range_high} = $regref->{pack}->addr_text_to_vec($htext);
163 2         7 $regref->{range_low} = $regref->{pack}->addr_text_to_vec($ltext);
164 2 50       6 (defined $regref->{range_high}) or $regref->warn ("Can't parse $htext in range $range\n");
165 2 50       7 (defined $regref->{range_low}) or $regref->warn ("Can't parse $htext in range $range\n");
166 2 50       123 ($regref->{range_low} < $regref->{range_high}) or $regref->warn ("Register range specified in the wrong order. Use regname[high:low] instead.\n");
167 2 50       73 ($spacing->Lexicompare($regref->{pack}->addr_const_vec($regref->{typeref}->numbytes)) >= 0)
168             or $regref->warn ("Strange address spacing $spacing\n");
169             }
170             else { # No range
171 1 50       6 ($spacing->equal($regref->{pack}->addr_const_vec(0)))
172             or $regref->warn ("Address spacing set to $spacing, but no range specified\n");
173 1         13 $regref->{range_low}
174             = $regref->{range_high}
175             = $regref->{pack}->addr_const_vec(0);
176             }
177 3         13 $regref->{range_ents} = $regref->{pack}->addr_const_vec(1);
178 3         23 $regref->{range_ents}->add( $regref->{range_high}, $regref->{range_ents}, 0);
179 3         13 $regref->{range_ents}->subtract ($regref->{range_ents}, $regref->{range_low}, 0);
180 3         9 $regref->{range_high_p1} = $regref->{pack}->addr_const_vec(1);
181 3         18 $regref->{range_high_p1}->add( $regref->{range_high_p1}, $regref->{range_high}, 0);
182             }
183              
184             sub check {
185 3     3 1 5 my $regref = shift;
186             #print ::Dumper($regref);
187 3         11 $regref->check_name();
188 3         11 $regref->check_addrtext();
189 3         42 $regref->check_range_spacing();
190             # Computes after all checks
191 3         8 $regref->computes();
192 3         8 $regref->check_end();
193             }
194              
195             sub remove_if_mismatch {
196 0     0 0 0 my $self = shift;
197 0         0 my $test_cb = shift;
198 0 0 0     0 if (($self->{typeref} && $self->{typeref}{deleted})
      0        
199             || $test_cb->($self)) {
200 0         0 $self->delete;
201             }
202             }
203              
204             sub computes {
205 3     3 0 4 my $regref = shift;
206             # Computes rely on check() being correct
207             {
208             # addr_end = addr + 4 + ((spacing * (ents - 1)))
209 3         4 my $inc = $regref->{pack}->addr_const_vec(1);
  3         8  
210 3         12 $inc->subtract($regref->{range_ents}, $inc, 0);
211 3         21 $inc->Multiply($regref->{spacing}, $inc);
212 3         12 $regref->{ent_size} = $regref->{pack}->addr_const_vec($regref->{typeref}->numbytes)->Clone();
213 3         24 $inc->add($inc, $regref->{ent_size}, 0);
214 3         12 $inc->add($regref->{addr}, $inc, 0);
215 3         21 $regref->{addr_end} = $inc->Clone();
216             }
217             {
218             # addr_end_inclusive = addr + ((spacing * (ents - 1)))
219 3         7 my $inc = $regref->{pack}->addr_const_vec(1);
  3         9  
220 3         16 $inc->subtract($regref->{range_ents}, $inc, 0);
221 3         13 $inc->Multiply($regref->{spacing}, $inc);
222 3         19 $inc->add($regref->{addr}, $inc, 0);
223 3         13 $regref->{addr_end_inclusive} = $inc->Clone();
224             # If register is of size 4 spacing 8, allow either XXXX_XXX0 or XXXX_XXX3.
225 3         11 $inc->add($regref->{addr_end_inclusive}, $regref->{ent_size}, 0);
226 3         10 $inc->subtract($inc, $regref->{pack}->addr_const_vec(1), 0);
227 3         17 $regref->{addr_end_inclusive_alt} = $inc->Clone();
228             # Or XXXX_XXXF
229 3         14 $inc->add($regref->{addr_end_inclusive}, $regref->{spacing}, 0);
230 3         8 $inc->subtract($inc, $regref->{pack}->addr_const_vec(1), 0);
231 3         23 $regref->{addr_end_inclusive_alt2} = $inc->Clone();
232             }
233             #print "-A $regref->{addr} AE $regref->{addr_end} SP $regref->{spacing} EC $regref->{addr_end_inclusive}\n";
234             }
235              
236             sub check_end {
237 3     3 0 5 my $regref = shift;
238 3 50       8 if ($regref->{addr_end_wildcard}) {
239 0 0       0 ($regref->{addr_end}->Lexicompare($regref->{addr_end_wildcard}) < 0)
240             or $regref->warn ("Register exceeds upper boundary in declaration: ",
241             $regref->{addr},"-",$regref->{addr_end}," > ", $regref->{addr_end_wildcard}, "\n");
242             } else {
243 3 0 33     19 (!$regref->{addr_end_user}
      33        
      0        
244             || $regref->{addr_end_user}->equal($regref->{addr_end_inclusive})
245             || $regref->{addr_end_user}->equal($regref->{addr_end_inclusive_alt})
246             || $regref->{addr_end_user}->equal($regref->{addr_end_inclusive_alt2}))
247             or $regref->warn ("Ending address specified as '$regref->{addrtext}' does not match calculated end $regref->{addr_end_inclusive} or $regref->{addr_end_inclusive_alt}.\n");
248             }
249             }
250              
251             sub dump {
252 0     0 0   my $self = shift;
253 0   0       my $fh = shift || \*STDOUT;
254 0   0       my $indent = shift||" ";
255 0   0       print $fh +($indent,"Reg: ",$self->{name},
256             " addr:",$self->{addrtext}||'',
257             "\n");
258             }
259              
260             ######################################################################
261             #### Package return
262             1;
263             __END__