line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# This file is part of the Perlilog project. |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Copyright (C) 2003, Eli Billauer |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
7
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
8
|
|
|
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or |
9
|
|
|
|
|
|
|
# (at your option) any later version. |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
12
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
13
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14
|
|
|
|
|
|
|
# GNU General Public License for more details. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
17
|
|
|
|
|
|
|
# along with this program; if not, write to the Free Software |
18
|
|
|
|
|
|
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
# A copy of the license can be found in a file named "licence.txt", at the |
21
|
|
|
|
|
|
|
# root directory of this project. |
22
|
|
|
|
|
|
|
# |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
${__PACKAGE__.'::errorcrawl'}='system'; |
25
|
|
|
|
|
|
|
sub who { |
26
|
0
|
|
|
0
|
|
0
|
return "The Global Object"; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub new { |
30
|
1
|
|
|
1
|
|
1
|
my $this = shift; |
31
|
1
|
|
|
|
|
6
|
my $self = $this->SUPER::new(@_); |
32
|
|
|
|
|
|
|
|
33
|
1
|
|
|
|
|
3
|
my $name = $self->get('name'); |
34
|
1
|
50
|
|
|
|
3
|
puke("The \'global\' class can generate an object only with the name \'globalobject\'". |
35
|
|
|
|
|
|
|
" and not \'$name\'\n") unless ($name eq 'globalobject'); |
36
|
|
|
|
|
|
|
|
37
|
1
|
|
|
|
|
2
|
return $self; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub complete { |
41
|
0
|
|
|
0
|
|
|
my $self = shift; |
42
|
0
|
|
|
|
|
|
my $dir=$self->get('filesdir'); |
43
|
0
|
0
|
|
|
|
|
blow("The \'filesdir\' property was not set for ".$self->who()."\n") |
44
|
|
|
|
|
|
|
unless ($dir); |
45
|
0
|
0
|
|
|
|
|
mkdir $dir, 0777 unless -e $dir; |
46
|
0
|
0
|
|
|
|
|
opendir(DIR,$dir) || blow("Failed to open $dir as a directory\n"); |
47
|
0
|
|
|
|
|
|
my @A=readdir(DIR); |
48
|
0
|
|
|
|
|
|
closedir(DIR); |
49
|
0
|
|
|
|
|
|
foreach (grep /[^.]/, @A) { |
50
|
0
|
|
|
|
|
|
unlink "$dir/$_"; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# NOTE: execute does not allow extra methods or objects to be |
55
|
|
|
|
|
|
|
# added once started. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub execute { |
58
|
0
|
|
|
0
|
|
|
my $global = shift; # We're the global object, aren't we? |
59
|
0
|
0
|
|
|
|
|
puke("The execute method was not run from the global object\n") |
60
|
|
|
|
|
|
|
unless ($global == $global->globalobj()); |
61
|
0
|
|
|
|
|
|
my $system = $global -> get('system'); |
62
|
0
|
|
|
|
|
|
my @methods = $system -> get('methods'); |
63
|
0
|
|
|
|
|
|
my @objects = ($global -> get('beginobjects'), |
64
|
|
|
|
|
|
|
$global -> get('objects'), |
65
|
|
|
|
|
|
|
$global -> get('endobjects')); |
66
|
0
|
|
|
|
|
|
my ($method, $object); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Note that the global object sneaks in first here |
69
|
0
|
|
|
|
|
|
@methods = grep { defined } @methods; |
|
0
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
|
@objects = grep { defined } ($global, @objects); |
|
0
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
0
|
|
|
|
|
|
foreach $method (@methods) { |
73
|
0
|
|
|
|
|
|
foreach $object (@objects) { |
74
|
0
|
|
|
|
|
|
$object->$method(); |
75
|
|
|
|
|
|
|
} |
76
|
0
|
0
|
|
|
|
|
last if ($Perlilog::wrongflag); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub constreset { |
81
|
0
|
|
|
0
|
|
|
my ($self, $ID, $type) = @_; |
82
|
|
|
|
|
|
|
wrong ("Reset of unknown type \'$type\'") |
83
|
0
|
0
|
|
|
|
|
unless grep {$type eq $_} qw(sync negsync async negasync); |
|
0
|
|
|
|
|
|
|
84
|
0
|
0
|
|
|
|
|
wrong ("Unproper ID \'$ID\' given for reset signal\n") |
85
|
|
|
|
|
|
|
unless (defined $Perlilog::VARS[$ID]); |
86
|
|
|
|
|
|
|
# $self is global object! |
87
|
0
|
|
|
|
|
|
$self->const('reset_type', $type); |
88
|
0
|
|
|
|
|
|
$self->const('reset_ID', $ID); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub instantiate { |
92
|
0
|
|
|
0
|
|
|
my $self = shift; |
93
|
0
|
|
|
|
|
|
$self->SUPER::instantiate(@_); |
94
|
0
|
|
|
|
|
|
my ($i, $ID, $drive, $obj, $var, $type, $parent); |
95
|
0
|
|
|
|
|
|
my ($from, $start, $to, $next, $f, $t, $toname); |
96
|
0
|
|
|
|
|
|
my ($fv, $tv, $dim, $nv, $nID, $tmp, $wf, $hashref); |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
|
my %eqvars; |
99
|
0
|
|
|
|
|
|
my @eq; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Type conversion hashes |
102
|
0
|
|
|
|
|
|
my %toin=('input' => 'input', |
103
|
|
|
|
|
|
|
'wire' => 'input', |
104
|
|
|
|
|
|
|
'inout' => 'inout', |
105
|
|
|
|
|
|
|
'output'=> 'inout'); |
106
|
0
|
|
|
|
|
|
my %toout=('output' => 'output', |
107
|
|
|
|
|
|
|
'reg' => 'outreg', |
108
|
|
|
|
|
|
|
'outreg' => 'outreg', |
109
|
|
|
|
|
|
|
'wire' => 'output', |
110
|
|
|
|
|
|
|
'inout' => 'inout', |
111
|
|
|
|
|
|
|
'input' => 'inout'); |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# We begin with triggering off tree studies. |
114
|
0
|
|
|
|
|
|
foreach $i (values %Perlilog::objects) { |
115
|
0
|
0
|
|
|
|
|
next unless (defined $i->get('inshash')); # Only Verilog objects... |
116
|
0
|
0
|
|
|
|
|
next if (ref $i->get('parent')); # Only "root" objects... |
117
|
0
|
|
|
|
|
|
$i->treestudy; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Now we collapse the EQVARS list to the minimal number |
121
|
|
|
|
|
|
|
# of distinct lists. Note that the hash keys are the |
122
|
|
|
|
|
|
|
# string representation of the reference, and only |
123
|
|
|
|
|
|
|
# functions as a unique representation of the reference. |
124
|
|
|
|
|
|
|
# The value points to the index in EQVARS, which makes |
125
|
|
|
|
|
|
|
# is possible to retrieve the EQVARS list again. |
126
|
|
|
|
|
|
|
# We loop in reverse order, so that the value will represent |
127
|
|
|
|
|
|
|
# the variable in the cluster that was defined earliest. |
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
my $imax = $#Perlilog::EQVARS; |
130
|
0
|
|
|
|
|
|
for ($i=$imax; $i>=0; $i--) { |
131
|
0
|
0
|
|
|
|
|
next unless (ref $Perlilog::EQVARS[$i]); |
132
|
0
|
|
|
|
|
|
$eqvars{$Perlilog::EQVARS[$i]}=$i; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my @in; |
136
|
|
|
|
|
|
|
my @out; |
137
|
0
|
|
|
|
|
|
my @zout; |
138
|
0
|
|
|
|
|
|
my %where; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# This little subroutine will help up make nice error messages. |
141
|
|
|
|
|
|
|
# Note that it runs in the current scope. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
my $s = sub { |
144
|
0
|
|
|
0
|
|
|
my $r = "These are the variables involved:\n"; |
145
|
0
|
0
|
|
|
|
|
if (@out) { |
146
|
0
|
|
|
|
|
|
$r.="Driving variables:\n"; |
147
|
0
|
|
|
|
|
|
foreach (@out) |
148
|
0
|
|
|
|
|
|
{ $r.=" Variable ".$self->varwho($_)."\n"; } |
149
|
|
|
|
|
|
|
} |
150
|
0
|
0
|
|
|
|
|
if (@zout) { |
151
|
0
|
|
|
|
|
|
$r.="Weakly driving variables:\n"; |
152
|
0
|
|
|
|
|
|
foreach (@zout) |
153
|
0
|
|
|
|
|
|
{ $r.=" Variable ".$self->varwho($_)."\n"; } |
154
|
|
|
|
|
|
|
} |
155
|
0
|
0
|
|
|
|
|
if (@in) { |
156
|
0
|
|
|
|
|
|
$r.="Driven variables:\n"; |
157
|
0
|
|
|
|
|
|
foreach (@in) |
158
|
0
|
|
|
|
|
|
{ $r.=" Variable ".$self->varwho($_)."\n"; } |
159
|
|
|
|
|
|
|
} |
160
|
0
|
|
|
|
|
|
return $r; |
161
|
0
|
|
|
|
|
|
}; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# This is the main loop. Each $i is a variable cluster that |
164
|
|
|
|
|
|
|
# needs to be interconnected. |
165
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
foreach $i (sort values %eqvars) { |
167
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
my @ids=@{$Perlilog::EQVARS[$i]}; # Get a local copy. The original may change |
|
0
|
|
|
|
|
|
|
169
|
0
|
0
|
|
|
|
|
next unless ($#ids>0); # No hassle with unconnected variables |
170
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
|
@in=(); @out=(); @zout=(); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
%where=(); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# We now distribute the variables to the respective lists. We |
175
|
|
|
|
|
|
|
# also set up the %where hash that tells us the names of the |
176
|
|
|
|
|
|
|
# variables in the objects, if they exist. Again, the keys |
177
|
|
|
|
|
|
|
# are not real references but string representations, but it's |
178
|
|
|
|
|
|
|
# good enough for looking up. |
179
|
|
|
|
|
|
|
IDLOOP: |
180
|
0
|
|
|
|
|
|
foreach $ID (sort @ids) { |
181
|
0
|
|
|
|
|
|
($obj, $var) = @{$Perlilog::VARS[$ID]}; |
|
0
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
$drive = $obj->get(['vars', $var, 'drive']); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# If $where{$obj} is already defined, it means we have two |
185
|
|
|
|
|
|
|
# equal variables in the same module. This is handled quite |
186
|
|
|
|
|
|
|
# gracefully as long as they don't happen to be both zouts. |
187
|
|
|
|
|
|
|
# For the case when they are both zouts, by make a nonstrength- |
188
|
|
|
|
|
|
|
# reducing transistor connecting, as would an inout connection, |
189
|
|
|
|
|
|
|
# and don't deal with the new variable any more. |
190
|
|
|
|
|
|
|
|
191
|
0
|
0
|
|
|
|
|
if (defined $where{$obj}) { |
192
|
0
|
0
|
|
|
|
|
if ($drive eq 'zout') { |
193
|
0
|
0
|
|
|
|
|
if ($obj->get(['vars', $where{$obj}, 'drive']) eq 'zout') { |
194
|
|
|
|
|
|
|
# Horrors! Two zouts in the same module! |
195
|
0
|
|
|
|
|
|
my $tranins = $obj->suggestins('PL_tran'); |
196
|
0
|
|
|
|
|
|
$obj->addins($tranins, 'detached'); |
197
|
|
|
|
|
|
|
wrong("Failed to handle bidirectional variable \'".$var."\' in ".$obj->who. |
198
|
|
|
|
|
|
|
" because the Verilog is static\n") |
199
|
0
|
0
|
|
|
|
|
unless ($obj->append(" tran $tranins ($var, ".$where{$obj}.");\n")); |
200
|
0
|
|
|
|
|
|
next IDLOOP; # Don't register this variable. It's already handled |
201
|
|
|
|
|
|
|
} else { |
202
|
|
|
|
|
|
|
# The existing variable wasn't a zout, but we'll set $where{$obj} to this |
203
|
|
|
|
|
|
|
# variable, so we won't miss a zout clash in the future... |
204
|
0
|
|
|
|
|
|
$where{$obj} = $var; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
# Note that we do nothing if this is not a zout case. We let the previously |
208
|
|
|
|
|
|
|
# registered variable persist. |
209
|
|
|
|
|
|
|
} else { |
210
|
0
|
|
|
|
|
|
$where{$obj} = $var; # This is just the normal case. A first-timer |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
# We put the variable in the right list, according to "drive" |
214
|
|
|
|
|
|
|
|
215
|
0
|
0
|
|
|
|
|
if ($drive eq 'in') { push @in, $ID; } |
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
elsif ($drive eq 'out') { push @out, $ID; } |
217
|
0
|
|
|
|
|
|
elsif ($drive eq 'zout') { push @zout, $ID; } |
218
|
|
|
|
|
|
|
elsif ($drive eq 'via') { |
219
|
0
|
|
|
|
|
|
wrong("Variable ".$self->varwho($ID). |
220
|
|
|
|
|
|
|
" was of drive-type \'via\' (System error?)\n"); |
221
|
|
|
|
|
|
|
} else { |
222
|
0
|
|
|
|
|
|
wrong("Variable ".$self->varwho($ID). |
223
|
|
|
|
|
|
|
" is of unknown drive-type \'$drive\'\n"); |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Now we complain if things aren't so good... |
228
|
0
|
0
|
0
|
|
|
|
if (($#out<0) && ($#zout<0)) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
wrong("No driving variable in cluster\n".&$s); |
230
|
|
|
|
|
|
|
} elsif ($#out>0) { |
231
|
0
|
|
|
|
|
|
wrong("More than one exclusively driving variable in cluster\n".&$s); |
232
|
|
|
|
|
|
|
} elsif (($#out==0) && ($#zout>=0)) { |
233
|
0
|
|
|
|
|
|
wrong("Exclusiveness of driving variable was offended by weakly driven variables\n".&$s); |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# Now we draw lines from every driving variable to every |
237
|
|
|
|
|
|
|
# driven variable. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
FLOOP: # The "from" loop -- driving variables |
240
|
0
|
|
|
|
|
|
foreach $f ((sort @out), (sort @zout)) { |
241
|
0
|
|
|
|
|
|
($start, $fv) = @{$Perlilog::VARS[$f]}; |
|
0
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
TLOOP: # The "to" loop -- driven variables |
243
|
0
|
|
|
|
|
|
foreach $t ((sort @in), (sort @zout)) { |
244
|
0
|
0
|
|
|
|
|
next TLOOP if ($t == $f); |
245
|
0
|
|
|
|
|
|
($to, $tv) = @{$Perlilog::VARS[$t]}; |
|
0
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
|
$from = $start; |
247
|
0
|
|
|
|
|
|
$toname = $to->get('name'); |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# If we happen to start and end at the same object, |
250
|
|
|
|
|
|
|
# why hassle? Just make an internal assignment. But |
251
|
|
|
|
|
|
|
# alas, the current object may not allow its Verilog |
252
|
|
|
|
|
|
|
# content to change, in which case append() fails. |
253
|
|
|
|
|
|
|
# In that case we simply go on, which will cause |
254
|
|
|
|
|
|
|
# a walk-up to the parent and back (good). |
255
|
|
|
|
|
|
|
next TLOOP |
256
|
0
|
0
|
0
|
|
|
|
if (($start == $to) && |
257
|
|
|
|
|
|
|
($start->append(" assign $tv = $fv;\n"))); |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# OK, now we come to SLOOP: The walking around loop. |
260
|
|
|
|
|
|
|
# We travel our way to $to. treestudy() earlier |
261
|
|
|
|
|
|
|
# promised to take us there, so we trust it and |
262
|
|
|
|
|
|
|
# run the loop until we reach the place. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
SLOOP: |
265
|
0
|
|
|
|
|
|
while (1) { |
266
|
|
|
|
|
|
|
# We fetch the next object to walk to |
267
|
0
|
|
|
|
|
|
$next = ${$from->get('treepath')}{$toname}; |
|
0
|
|
|
|
|
|
|
268
|
0
|
0
|
|
|
|
|
unless (ref $next) { |
269
|
0
|
|
|
|
|
|
wrong("No path found between variables ".$self->varwho($f). |
270
|
|
|
|
|
|
|
" and ".$self->varwho($t)."\n"); |
271
|
0
|
|
|
|
|
|
next TLOOP; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Now the world splits in two: Either we went from child |
275
|
|
|
|
|
|
|
# to parent, or the opposite way. Anyhow, this takes |
276
|
|
|
|
|
|
|
# opposite treatment, since we always create the inputs and |
277
|
|
|
|
|
|
|
# outputs on the child, whereas the parent gets a "wire" at |
278
|
|
|
|
|
|
|
# most. |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
|
$parent = $next->get('parent'); |
281
|
0
|
0
|
0
|
|
|
|
if (defined ($parent) && ($parent == $from)) { |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# This is the parent to child walk part: |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# Get the variable name an $next's object. If we happen to |
286
|
|
|
|
|
|
|
# have reached our destination, take $tv. This is because |
287
|
|
|
|
|
|
|
# if there are two input variables in the same object, |
288
|
|
|
|
|
|
|
# only one will be represented in $where{$next} |
289
|
|
|
|
|
|
|
|
290
|
0
|
0
|
|
|
|
|
$nv = ($next==$to) ? $tv : $where{$next}; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# If $nv is not defined, it means that object currently |
293
|
|
|
|
|
|
|
# has no access to the variable. We create a via. |
294
|
0
|
0
|
|
|
|
|
unless (defined $nv) { |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# Now we want to set the name nicely. If the current object |
297
|
|
|
|
|
|
|
# has the 'viasource' (list) property set, we scan through the objects |
298
|
|
|
|
|
|
|
# from which we may borrow the name. Only non-via variables |
299
|
|
|
|
|
|
|
# may donate names. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
VIALOOP1: |
302
|
0
|
|
|
|
|
|
foreach my $source ($next->get('viasource')) { |
303
|
0
|
0
|
0
|
|
|
|
if ((defined $where{$source}) && |
304
|
|
|
|
|
|
|
($source->get(['vars',$where{$source},'drive']) ne 'via')) { |
305
|
0
|
|
|
|
|
|
$nv = $next->suggestvar($where{$source}); # This is a good source! |
306
|
0
|
|
|
|
|
|
last VIALOOP1; # No more search! |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
0
|
0
|
|
|
|
|
$nv = $next->suggestvar($fv.'_via') # Make _via |
311
|
|
|
|
|
|
|
unless (defined $nv); |
312
|
|
|
|
|
|
|
|
313
|
0
|
|
|
|
|
|
$nID = $next->addvar($nv, 'wire', 'via'); |
314
|
0
|
|
|
|
|
|
$next->attach($f, $nID); # This will also get the 'dim' property right |
315
|
0
|
|
|
|
|
|
$where{$next}=$nv; # Register it, so we won't do this again |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Now we change the variable's type if needed. |
319
|
0
|
|
|
|
|
|
$tmp = $toin{$next->get(['vars',$nv,'type'])}; |
320
|
0
|
0
|
|
|
|
|
blow("Expected a variable convertable to input/inout, got ". |
321
|
|
|
|
|
|
|
"variable \'$nv\' of type \'".$next->get(['vars',$nv,'type'])."\' on ". |
322
|
|
|
|
|
|
|
$next->who."\n") |
323
|
|
|
|
|
|
|
unless (defined $tmp); |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# We can't change variable types of static objects. Be sure. |
326
|
|
|
|
|
|
|
|
327
|
0
|
0
|
|
|
|
|
if ($next->get('static')) { |
328
|
0
|
0
|
|
|
|
|
wrong("Attempted to change the variable type of $nv to $tmp in ". |
329
|
|
|
|
|
|
|
$next->who()." but it is a static Verilog object\n") |
330
|
|
|
|
|
|
|
unless ($next->get(['vars',$nv,'type']) eq $tmp) |
331
|
|
|
|
|
|
|
} else { |
332
|
0
|
|
|
|
|
|
$next->set(['vars',$nv,'type'], $tmp); |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# And finally, we register the connection in 'inshash'. We are not |
336
|
|
|
|
|
|
|
# worried about if the entry is already set, because it will always |
337
|
|
|
|
|
|
|
# be set to the same value, $where{$from} |
338
|
|
|
|
|
|
|
|
339
|
0
|
|
|
|
|
|
$hashref = $next->get('inshash'); |
340
|
0
|
|
|
|
|
|
${$hashref}{$nv}=$where{$from}; |
|
0
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
} else { |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# This is the child to parent walk part: (quite similar) |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# Get the variable name an $next's object. If we happen to |
347
|
|
|
|
|
|
|
# have reached our destination, take $tv. This is because |
348
|
|
|
|
|
|
|
# if there are two input variables in the same object, |
349
|
|
|
|
|
|
|
# only one will be represented in $where{$next} |
350
|
|
|
|
|
|
|
|
351
|
0
|
0
|
|
|
|
|
$nv = ($next==$to) ? $tv : $where{$next}; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# If $nv is not defined, it means that object currently |
354
|
|
|
|
|
|
|
# has no access to the variable. We create a via. |
355
|
0
|
0
|
|
|
|
|
unless (defined $nv) { |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Now we want to set the name nicely. If the current object |
358
|
|
|
|
|
|
|
# has the 'viasource' (list) property set, we scan through the objects |
359
|
|
|
|
|
|
|
# from which we may borrow the name. Only non-via variables |
360
|
|
|
|
|
|
|
# may donate names. |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
VIALOOP2: |
363
|
0
|
|
|
|
|
|
foreach my $source ($next->get('viasource')) { |
364
|
0
|
0
|
0
|
|
|
|
if ((defined $where{$source}) && |
365
|
|
|
|
|
|
|
($source->get(['vars',$where{$source},'drive']) ne 'via')) { |
366
|
0
|
|
|
|
|
|
$nv = $next->suggestvar($where{$source}); # This is a good source! |
367
|
0
|
|
|
|
|
|
last VIALOOP2; # No more search! |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
0
|
0
|
|
|
|
|
$nv = $next->suggestvar($fv.'_via') # Make _via |
372
|
|
|
|
|
|
|
unless (defined $nv); |
373
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
|
$nID = $next->addvar($nv, 'wire', 'via'); |
375
|
0
|
|
|
|
|
|
$next->attach($f, $nID); # This will also get the 'dim' property right |
376
|
0
|
|
|
|
|
|
$where{$next}=$nv; # Register it, so we won't do this again |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# Now we change the variable's type if needed. |
380
|
0
|
|
|
|
|
|
$wf = $where{$from}; # We use it a lot here, so... |
381
|
0
|
|
|
|
|
|
$tmp = $toout{$from->get(['vars',$wf,'type'])}; |
382
|
0
|
0
|
|
|
|
|
blow("Expected a variable convertable to output/inout, got ". |
383
|
|
|
|
|
|
|
"variable \'$wf\' of type \'".$from->get(['vars',$wf,'type'])."\' on ". |
384
|
|
|
|
|
|
|
$from->who."\n") |
385
|
|
|
|
|
|
|
unless (defined $tmp); |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# We can't change variable types of static objects. Be sure. |
388
|
|
|
|
|
|
|
|
389
|
0
|
0
|
|
|
|
|
if ($from->get('static')) { |
390
|
0
|
0
|
|
|
|
|
wrong("Attempted to change the variable type of $wf to $tmp in ". |
391
|
|
|
|
|
|
|
$from->who()." but it is a static Verilog object\n") |
392
|
|
|
|
|
|
|
unless ($from->get(['vars',$wf,'type']) eq $tmp) |
393
|
|
|
|
|
|
|
} else { |
394
|
0
|
|
|
|
|
|
$from->set(['vars',$wf,'type'], $tmp); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# And finally, we register the connection in 'inshash'. If the entry |
398
|
|
|
|
|
|
|
# is already initialized, then we've already connected that variable. |
399
|
|
|
|
|
|
|
# We use an assign instead. Note that this won't work with zouts. |
400
|
0
|
|
|
|
|
|
$hashref = $from->get('inshash'); |
401
|
0
|
|
|
|
|
|
$tmp = ${$hashref}{$wf}; |
|
0
|
|
|
|
|
|
|
402
|
0
|
0
|
0
|
|
|
|
if ((defined $tmp) && ($tmp ne $nv)) { |
403
|
0
|
|
|
|
|
|
$next->append(" assign $nv = $tmp;\n"); |
404
|
|
|
|
|
|
|
} else { |
405
|
0
|
|
|
|
|
|
${$hashref}{$wf}=$nv; |
|
0
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# Now it's time to see if we're finished. That is, have we |
410
|
|
|
|
|
|
|
# reached our destination? |
411
|
|
|
|
|
|
|
|
412
|
0
|
0
|
|
|
|
|
last SLOOP if ($next == $to); |
413
|
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
$from = $next; # This is the actual walking |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
} |