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