Fix for assertion error when expanding macro.
[iverilog.git] / net_link.cc
bloba6275a68fb527b838e0ef5ce618b3820126312a8
1 /*
2 * Copyright (c) 2000 Stephen Williams (steve@icarus.com)
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: net_link.cc,v 1.21 2007/06/02 03:42:13 steve Exp $"
21 #endif
23 # include "config.h"
25 # include <iostream>
27 # include "netlist.h"
28 # include <sstream>
29 # include <string>
30 # include <typeinfo>
31 #ifdef HAVE_MALLOC_H
32 # include <malloc.h>
33 #endif
35 void connect(Nexus*l, Link&r)
37 assert(l);
38 assert(r.nexus_);
40 if (l == r.nexus_)
41 return;
44 Nexus*tmp = r.nexus_;
45 while (Link*cur = tmp->list_) {
46 tmp->list_ = cur->next_;
47 cur->nexus_ = 0;
48 cur->next_ = 0;
49 l->relink(cur);
52 l->driven_ = Nexus::NO_GUESS;
54 assert(tmp->list_ == 0);
55 delete tmp;
58 void connect(Link&l, Link&r)
60 assert(&l != &r);
61 if (r.is_linked() && !l.is_linked())
62 connect(r.nexus_, l);
63 else
64 connect(l.nexus_, r);
67 Link::Link()
68 : dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx),
69 inst_(0), next_(0), nexus_(0)
71 (new Nexus()) -> relink(this);
74 Link::~Link()
76 assert(nexus_);
77 Nexus*tmp = nexus_;
78 nexus_->unlink(this);
79 if (tmp->list_ == 0)
80 delete tmp;
83 Nexus* Link::nexus()
85 return nexus_;
88 const Nexus* Link::nexus() const
90 return nexus_;
93 void Link::set_dir(DIR d)
95 dir_ = d;
98 Link::DIR Link::get_dir() const
100 return dir_;
103 void Link::drive0(Link::strength_t str)
105 drive0_ = str;
108 void Link::drive1(Link::strength_t str)
110 drive1_ = str;
113 Link::strength_t Link::drive0() const
115 return drive0_;
118 Link::strength_t Link::drive1() const
120 return drive1_;
123 void Link::set_init(verinum::V val)
125 init_ = val;
128 verinum::V Link::get_init() const
130 return init_;
134 void Link::cur_link(NetObj*&net, unsigned &pin)
136 net = node_;
137 pin = pin_;
140 void Link::cur_link(const NetObj*&net, unsigned &pin) const
142 net = node_;
143 pin = pin_;
146 void Link::unlink()
148 assert(nexus_);
149 if (! is_linked())
150 return;
152 nexus_->unlink(this);
153 (new Nexus()) -> relink(this);
156 bool Link::is_equal(const Link&that) const
158 return (node_ == that.node_) && (pin_ == that.pin_);
161 bool Link::is_linked() const
163 if (next_)
164 return true;
165 if (nexus_->first_nlink() != this)
166 return true;
168 return false;
171 bool Link::is_linked(const Link&that) const
173 return nexus_ == that.nexus_;
176 Link* Link::next_nlink()
178 return next_;
181 const Link* Link::next_nlink() const
183 return next_;
186 const NetObj*Link::get_obj() const
188 return node_;
191 NetObj*Link::get_obj()
193 return node_;
196 unsigned Link::get_pin() const
198 return pin_;
201 void Link::set_name(perm_string n, unsigned i)
203 name_ = n;
204 inst_ = i;
207 perm_string Link::get_name() const
209 return name_;
212 unsigned Link::get_inst() const
214 return inst_;
217 Nexus::Nexus()
219 name_ = 0;
220 list_ = 0;
221 driven_ = NO_GUESS;
222 t_cookie_ = 0;
225 Nexus::~Nexus()
227 assert(list_ == 0);
228 if (name_)
229 delete[]name_;
232 verinum::V Nexus::get_init() const
234 assert(list_);
235 for (Link*cur = list_ ; cur ; cur = cur->next_) {
236 if (cur->get_dir() == Link::OUTPUT)
237 return verinum::Vx;
239 if ((cur->get_dir() == Link::PASSIVE)
240 && (cur->get_init() != verinum::Vz))
241 return cur->get_init();
244 return verinum::Vz;
247 void Nexus::unlink(Link*that)
249 if (name_) {
250 delete[] name_;
251 name_ = 0;
254 /* If the link I'm removing was a driver for this nexus, then
255 cancel my guess of the driven value. */
256 if (that->get_dir() != Link::INPUT)
257 driven_ = NO_GUESS;
259 assert(that);
260 if (list_ == that) {
261 list_ = that->next_;
262 that->next_ = 0;
263 that->nexus_ = 0;
264 return;
267 Link*cur = list_;
268 while (cur->next_ != that) {
269 assert(cur->next_);
270 cur = cur->next_;
273 cur->next_ = that->next_;
274 that->nexus_ = 0;
275 that->next_ = 0;
278 void Nexus::relink(Link*that)
280 if (name_) {
281 delete[] name_;
282 name_ = 0;
285 /* If the link I'm adding is a driver for this nexus, then
286 cancel my guess of the driven value. */
287 if (that->get_dir() != Link::INPUT)
288 driven_ = NO_GUESS;
290 assert(that->nexus_ == 0);
291 assert(that->next_ == 0);
292 that->next_ = list_;
293 that->nexus_ = this;
294 list_ = that;
297 Link* Nexus::first_nlink()
299 return list_;
302 const Link* Nexus::first_nlink() const
304 return list_;
307 ivl_nexus_t Nexus::t_cookie() const
309 return t_cookie_;
312 ivl_nexus_t Nexus::t_cookie(ivl_nexus_t val)const
314 ivl_nexus_t tmp = t_cookie_;
315 t_cookie_ = val;
316 return tmp;
319 unsigned Nexus::vector_width() const
321 for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
322 const NetNet*sig = dynamic_cast<const NetNet*>(cur->get_obj());
323 if (sig == 0)
324 continue;
326 return sig->vector_width();
329 return 0;
332 NetNet* Nexus::pick_any_net()
334 for (Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
335 NetNet*sig = dynamic_cast<NetNet*>(cur->get_obj());
336 if (sig != 0)
337 return sig;
340 return 0;
343 const char* Nexus::name() const
345 if (name_)
346 return name_;
348 const NetNet*sig = 0;
349 unsigned pin = 0;
350 for (const Link*cur = first_nlink()
351 ; cur ; cur = cur->next_nlink()) {
353 const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
354 if (cursig == 0)
355 continue;
357 if (sig == 0) {
358 sig = cursig;
359 pin = cur->get_pin();
360 continue;
363 if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
364 continue;
366 if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
367 sig = cursig;
368 pin = cur->get_pin();
369 continue;
372 if (cursig->local_flag() && !sig->local_flag())
373 continue;
375 if (cursig->name() < sig->name())
376 continue;
378 sig = cursig;
379 pin = cur->get_pin();
382 if (sig == 0) {
383 const Link*lnk = first_nlink();
384 const NetObj*obj = lnk->get_obj();
385 pin = lnk->get_pin();
386 cerr << "internal error: No signal for nexus of " <<
387 obj->name() << " pin " << pin << "(" <<
388 lnk->get_name() << "<" << lnk->get_inst() << ">)"
389 " type=" << typeid(*obj).name() << "?" << endl;
392 assert(sig);
393 ostringstream tmp;
394 tmp << scope_path(sig->scope()) << "." << sig->name();
395 if (sig->pin_count() > 1)
396 tmp << "<" << pin << ">";
398 const string tmps = tmp.str();
399 name_ = new char[strlen(tmps.c_str()) + 1];
400 strcpy(name_, tmps.c_str());
401 return name_;
405 NexusSet::NexusSet()
407 items_ = 0;
408 nitems_ = 0;
411 NexusSet::~NexusSet()
413 if (nitems_ > 0) {
414 assert(items_ != 0);
415 delete[] items_;
416 } else {
417 assert(items_ == 0);
421 unsigned NexusSet::count() const
423 return nitems_;
426 void NexusSet::add(Nexus*that)
428 if (nitems_ == 0) {
429 assert(items_ == 0);
430 items_ = (Nexus**)malloc(sizeof(Nexus*));
431 items_[0] = that;
432 nitems_ = 1;
433 return;
436 unsigned ptr = bsearch_(that);
437 if (ptr < nitems_) {
438 assert(items_[ptr] == that);
439 return;
442 assert(ptr == nitems_);
444 items_ = (Nexus**)realloc(items_, (nitems_+1) * sizeof(Nexus*));
445 items_[ptr] = that;
446 nitems_ += 1;
449 void NexusSet::add(const NexusSet&that)
451 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1)
452 add(that.items_[idx]);
455 void NexusSet::rem(Nexus*that)
457 if (nitems_ == 0)
458 return;
460 unsigned ptr = bsearch_(that);
461 if (ptr >= nitems_)
462 return;
464 if (nitems_ == 1) {
465 free(items_);
466 items_ = 0;
467 nitems_ = 0;
468 return;
471 for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1)
472 items_[idx] = items_[idx+1];
474 items_ = (Nexus**)realloc(items_, (nitems_-1) * sizeof(Nexus*));
475 nitems_ -= 1;
478 void NexusSet::rem(const NexusSet&that)
480 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1)
481 rem(that.items_[idx]);
484 Nexus* NexusSet::operator[] (unsigned idx) const
486 assert(idx < nitems_);
487 return items_[idx];
490 unsigned NexusSet::bsearch_(Nexus*that) const
492 for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
493 if (items_[idx] == that)
494 return idx;
497 return nitems_;
500 bool NexusSet::contains(const NexusSet&that) const
502 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) {
503 unsigned where = bsearch_(that[idx]);
504 if (where == nitems_)
505 return false;
506 if (items_[where] != that[idx])
507 return false;
510 return true;
513 bool NexusSet::intersect(const NexusSet&that) const
515 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) {
516 unsigned where = bsearch_(that[idx]);
517 if (where == nitems_)
518 continue;
519 if (items_[where] == that[idx])
520 return true;
523 return false;
527 * $Log: net_link.cc,v $
528 * Revision 1.21 2007/06/02 03:42:13 steve
529 * Properly evaluate scope path expressions.
531 * Revision 1.20 2007/03/26 18:17:50 steve
532 * Remove pretense of general use for t_cookie.
534 * Revision 1.19 2006/02/02 02:43:58 steve
535 * Allow part selects of memory words in l-values.
537 * Revision 1.18 2005/09/25 23:40:11 steve
538 * Simplify NexusSet set handling.
540 * Revision 1.17 2005/06/13 23:22:37 steve
541 * Fix compile errors.
543 * Revision 1.16 2005/04/24 23:44:02 steve
544 * Update DFF support to new data flow.
546 * Revision 1.15 2005/01/09 20:16:01 steve
547 * Use PartSelect/PV and VP to handle part selects through ports.
549 * Revision 1.14 2004/02/18 17:11:56 steve
550 * Use perm_strings for named langiage items.
552 * Revision 1.13 2003/01/14 21:16:18 steve
553 * Move strstream to ostringstream for compatibility.
555 * Revision 1.12 2002/10/21 01:42:08 steve
556 * Synthesizer support for synchronous begin-end blocks.
558 * Revision 1.11 2002/08/18 22:07:16 steve
559 * Detect temporaries in sequential block synthesis.
561 * Revision 1.10 2002/08/12 01:34:59 steve
562 * conditional ident string using autoconfig.
564 * Revision 1.9 2002/07/03 03:08:47 steve
565 * Clear drive cache on link or unlink.
567 * Revision 1.8 2002/06/30 02:21:31 steve
568 * Add structure for asynchronous logic synthesis.
570 * Revision 1.7 2002/06/24 01:49:39 steve
571 * Make link_drive_constant cache its results in
572 * the Nexus, to improve cprop performance.
574 * Revision 1.6 2002/04/21 04:59:08 steve
575 * Add support for conbinational events by finding
576 * the inputs to expressions and some statements.
577 * Get case and assignment statements working.
579 * Revision 1.5 2001/07/25 03:10:49 steve
580 * Create a config.h.in file to hold all the config
581 * junk, and support gcc 3.0. (Stephan Boettcher)
583 * Revision 1.4 2000/10/06 23:46:50 steve
584 * ivl_target updates, including more complete
585 * handling of ivl_nexus_t objects. Much reduced
586 * dependencies on pointers to netlist objects.
588 * Revision 1.3 2000/08/26 00:54:03 steve
589 * Get at gate information for ivl_target interface.
591 * Revision 1.2 2000/07/14 06:12:57 steve
592 * Move inital value handling from NetNet to Nexus
593 * objects. This allows better propogation of inital
594 * values.
596 * Clean up constant propagation a bit to account
597 * for regs that are not really values.
599 * Revision 1.1 2000/06/25 19:59:42 steve
600 * Redesign Links to include the Nexus class that
601 * carries properties of the connected set of links.