1 /*
2 * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
3 *
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 # include "config.h"
21
22 # include "netlist.h"
23 # include "netmisc.h"
24 # include "ivl_assert.h"
25
26 /*
27 * Scan the link for drivers. If there are only constant drivers, then
28 * the nexus has a known constant value.
29 */
drivers_constant() const30 bool Nexus::drivers_constant() const
31 {
32 if (driven_ == VAR)
33 return false;
34 if (driven_ != NO_GUESS)
35 return true;
36
37 unsigned constant_drivers = 0;
38 for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
39
40 /* A target of a procedural assign or force statement
41 can't be treated as constant. */
42 const NetNet*sig = dynamic_cast<const NetNet*>(cur->get_obj());
43 if (sig && (sig->peek_lref() > 0)) {
44 driven_ = VAR;
45 return false;
46 }
47
48 /* If we are connected to a tran, there may be a driver
49 on the other side of the tran. We could try checking
50 for this, but for now, be pessimistic. */
51 if (dynamic_cast<const NetTran*>(cur->get_obj())) {
52 driven_ = VAR;
53 return false;
54 }
55
56 Link::DIR cur_dir = cur->get_dir();
57 if (cur_dir == Link::INPUT)
58 continue;
59
60 /* If this is an input or inout port of a root module,
61 then this is probably not a constant value. I
62 certainly don't know what the value is, anyhow. This
63 can happen in cases like this:
64
65 module main(sig);
66 input sig;
67 endmodule
68
69 If main is a root module (it has no parent) then sig
70 is not constant because it connects to an unspecified
71 outside world. */
72
73 if (cur_dir == Link::PASSIVE) {
74 if (sig == 0 || sig->scope()->parent() != 0)
75 continue;
76
77 if (sig->port_type() == NetNet::NOT_A_PORT)
78 continue;
79
80 if (sig->port_type() == NetNet::POUTPUT)
81 continue;
82
83 driven_ = VAR;
84 return false;
85 }
86
87 /* If there is an implicit pullup/pulldown on a net,
88 count it as a constant driver. */
89 if (sig)
90 switch (sig->type()) {
91 case NetNet::SUPPLY0:
92 case NetNet::TRI0:
93 constant_drivers += 1;
94 driven_ = V0;
95 continue;
96 case NetNet::SUPPLY1:
97 case NetNet::TRI1:
98 constant_drivers += 1;
99 driven_ = V1;
100 continue;
101 default:
102 break;
103 }
104
105 const NetSubstitute*ps = dynamic_cast<const NetSubstitute*>(cur->get_obj());
106 if (ps) {
107 if (ps->pin(1).nexus()->drivers_constant() &&
108 ps->pin(2).nexus()->drivers_constant() ) {
109 constant_drivers += 1;
110 continue;
111 }
112 driven_ = VAR;
113 return false;
114 }
115
116 if (! dynamic_cast<const NetConst*>(cur->get_obj())) {
117 driven_ = VAR;
118 return false;
119 }
120
121 constant_drivers += 1;
122 }
123
124 /* If there is more than one constant driver for this nexus, we
125 would need to resolve the constant value, taking into account
126 the drive strengths. This is a lot of work for something that
127 will rarely occur, so for now leave the resolution to be done
128 at run time. */
129 if (constant_drivers > 1) {
130 driven_ = VAR;
131 return false;
132 }
133
134 return true;
135 }
136
driven_value() const137 verinum::V Nexus::driven_value() const
138 {
139 switch (driven_) {
140 case V0:
141 return verinum::V0;
142 case V1:
143 return verinum::V1;
144 case Vx:
145 return verinum::Vx;
146 case Vz:
147 return verinum::Vz;
148 case VAR:
149 assert(0);
150 break;
151 case NO_GUESS:
152 break;
153 }
154
155 const Link*cur = list_;
156
157 verinum::V val = verinum::Vz;
158
159 for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
160
161 const NetConst*obj;
162 const NetNet*sig;
163 if ((obj = dynamic_cast<const NetConst*>(cur->get_obj()))) {
164 // Multiple drivers are not currently supported.
165 ivl_assert(*obj, val == verinum::Vz);
166 val = obj->value(cur->get_pin());
167
168 } else if ((sig = dynamic_cast<const NetNet*>(cur->get_obj()))) {
169
170 // If we find an implicit pullup or pulldown on a
171 // net, this is a good guess for the driven value,
172 // but keep looking for other drivers.
173 if ((sig->type() == NetNet::SUPPLY0) ||
174 (sig->type() == NetNet::TRI0)) {
175 // Multiple drivers are not currently supported.
176 ivl_assert(*sig, val == verinum::Vz);
177 val = verinum::V0;
178 }
179 if ((sig->type() == NetNet::SUPPLY1) ||
180 (sig->type() == NetNet::TRI1)) {
181 // Multiple drivers are not currently supported.
182 ivl_assert(*sig, val == verinum::Vz);
183 val = verinum::V1;
184 }
185 }
186 }
187
188 /* Cache the result. */
189 switch (val) {
190 case verinum::V0:
191 driven_ = V0;
192 break;
193 case verinum::V1:
194 driven_ = V1;
195 break;
196 case verinum::Vx:
197 driven_ = Vx;
198 break;
199 case verinum::Vz:
200 driven_ = Vz;
201 break;
202 }
203
204 return val;
205 }
206
207
driven_vector() const208 verinum Nexus::driven_vector() const
209 {
210 const Link*cur = list_;
211
212 verinum val;
213 verinum pval;
214 unsigned width = 0;
215
216 for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
217
218 const NetSubstitute*ps;
219 const NetConst*obj;
220 const NetNet*sig;
221 if ((obj = dynamic_cast<const NetConst*>(cur->get_obj()))) {
222 // Multiple drivers are not currently supported.
223 ivl_assert(*obj, val.len() == 0);
224 ivl_assert(*obj, cur->get_pin() == 0);
225 val = obj->value();
226 width = val.len();
227
228 } else if ((ps = dynamic_cast<const NetSubstitute*>(cur->get_obj()))) {
229 if (cur->get_pin() != 0)
230 continue;
231
232 // Multiple drivers are not currently supported.
233 ivl_assert(*ps, val.len() == 0);
234 val = ps->pin(1).nexus()->driven_vector();
235 pval = ps->pin(2).nexus()->driven_vector();
236 for (unsigned idx = 0; idx < pval.len(); idx += 1)
237 val.set(ps->base() + idx, pval.get(idx));
238 width = val.len();
239
240 } else if ((sig = dynamic_cast<const NetNet*>(cur->get_obj()))) {
241
242 width = sig->vector_width();
243
244 // If we find an implicit pullup or pulldown on a
245 // net, this is a good guess for the driven value,
246 // but keep looking for other drivers.
247 if ((sig->type() == NetNet::SUPPLY0) ||
248 (sig->type() == NetNet::TRI0)) {
249 // Multiple drivers are not currently supported.
250 ivl_assert(*sig, val.len() == 0);
251 val = verinum(verinum::V0, width);
252 }
253 if ((sig->type() == NetNet::SUPPLY1) ||
254 (sig->type() == NetNet::TRI1)) {
255 // Multiple drivers are not currently supported.
256 ivl_assert(*sig, val.len() == 0);
257 val = verinum(verinum::V1, width);
258 }
259 }
260 }
261
262 // If we have a width but not a value, this must be an undriven net.
263 if (val.len() != width)
264 val = verinum(verinum::Vz, width);
265
266 return val;
267 }
268
269 /*
270 * Calculate a vector that represent all the bits of the vector, with
271 * each driven bit set to true, otherwise false.
272 */
driven_mask(void) const273 vector<bool> Nexus::driven_mask(void) const
274 {
275 vector<bool> mask (vector_width());
276
277 for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
278
279 Link::DIR link_dir = cur->get_dir();
280 if (link_dir==Link::PASSIVE)
281 continue;
282 if (link_dir==Link::INPUT)
283 continue;
284
285 const NetPins*obj = cur->get_obj();
286
287 // If the link is to a variable (REG or INTEGER) then
288 // the variable is driving all the bits. We have our
289 // complete answer, mark all the bits as driven and
290 // finish. Otherwise, we are not going to get new
291 // information from this node, move on.
292 if (const NetNet*sig = dynamic_cast<const NetNet*> (obj)) {
293 NetNet::Type sig_type = sig->type();
294 if (sig_type==NetNet::INTEGER || sig_type==NetNet::REG) {
295 for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
296 mask[idx] = true;
297 return mask;
298 }
299 continue;
300 }
301
302 const NetPartSelect*obj_ps = dynamic_cast<const NetPartSelect*>(obj);
303 if(obj_ps) {
304 if (obj_ps->dir()==NetPartSelect::VP) {
305 if(cur->get_pin() != 0)
306 continue;
307 for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
308 mask[idx] = true;
309 return mask;
310 } else {
311 if (cur->get_pin() != 1)
312 continue;
313 }
314 for (unsigned idx = 0 ; idx < obj_ps->width() ; idx += 1) {
315 size_t bit = idx + obj_ps->base();
316 ivl_assert(*obj, bit < mask.size());
317 mask[bit] = true;
318 }
319 continue;
320 }
321
322 for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
323 mask[idx] = true;
324 return mask;
325 }
326
327 return mask;
328 }
329