Merge branch 'master' into verilog-ams
[sverilog.git] / net_link.cc
blob228add8c023902569aeb5cddd54fb20eea512d5d
1 /*
2 * Copyright (c) 2000-2008 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
20 # include "config.h"
22 # include <iostream>
24 # include "netlist.h"
25 # include <sstream>
26 # include <cstring>
27 # include <string>
28 # include <typeinfo>
29 #ifdef HAVE_MALLOC_H
30 # include <malloc.h>
31 #endif
33 void connect(Nexus*l, Link&r)
35 assert(l);
36 assert(r.nexus_);
38 if (l == r.nexus_)
39 return;
42 Nexus*tmp = r.nexus_;
43 while (Link*cur = tmp->list_) {
44 tmp->list_ = cur->next_;
45 cur->nexus_ = 0;
46 cur->next_ = 0;
47 l->relink(cur);
50 l->driven_ = Nexus::NO_GUESS;
52 assert(tmp->list_ == 0);
53 delete tmp;
56 void connect(Link&l, Link&r)
58 assert(&l != &r);
59 if (r.is_linked() && !l.is_linked())
60 connect(r.nexus_, l);
61 else
62 connect(l.nexus_, r);
65 Link::Link()
66 : dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx),
67 inst_(0), next_(0), nexus_(0)
69 (new Nexus()) -> relink(this);
72 Link::~Link()
74 assert(nexus_);
75 Nexus*tmp = nexus_;
76 nexus_->unlink(this);
77 if (tmp->list_ == 0)
78 delete tmp;
81 Nexus* Link::nexus()
83 return nexus_;
86 const Nexus* Link::nexus() const
88 return nexus_;
91 void Link::set_dir(DIR d)
93 dir_ = d;
96 Link::DIR Link::get_dir() const
98 return dir_;
101 void Link::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
103 nexus_->drivers_delays(rise, fall, decay);
106 void Link::drive0(Link::strength_t str)
108 drive0_ = str;
111 void Link::drive1(Link::strength_t str)
113 drive1_ = str;
116 Link::strength_t Link::drive0() const
118 return drive0_;
121 Link::strength_t Link::drive1() const
123 return drive1_;
126 void Link::set_init(verinum::V val)
128 init_ = val;
131 verinum::V Link::get_init() const
133 return init_;
137 void Link::cur_link(NetObj*&net, unsigned &pin)
139 net = node_;
140 pin = pin_;
143 void Link::cur_link(const NetObj*&net, unsigned &pin) const
145 net = node_;
146 pin = pin_;
149 void Link::unlink()
151 assert(nexus_);
152 if (! is_linked())
153 return;
155 nexus_->unlink(this);
156 (new Nexus()) -> relink(this);
159 bool Link::is_equal(const Link&that) const
161 return (node_ == that.node_) && (pin_ == that.pin_);
164 bool Link::is_linked() const
166 if (next_)
167 return true;
168 if (nexus_->first_nlink() != this)
169 return true;
171 return false;
174 bool Link::is_linked(const Link&that) const
176 return nexus_ == that.nexus_;
179 Link* Link::next_nlink()
181 return next_;
184 const Link* Link::next_nlink() const
186 return next_;
189 const NetObj*Link::get_obj() const
191 return node_;
194 NetObj*Link::get_obj()
196 return node_;
199 unsigned Link::get_pin() const
201 return pin_;
204 void Link::set_name(perm_string n, unsigned i)
206 name_ = n;
207 inst_ = i;
210 perm_string Link::get_name() const
212 return name_;
215 unsigned Link::get_inst() const
217 return inst_;
220 Nexus::Nexus()
222 name_ = 0;
223 list_ = 0;
224 driven_ = NO_GUESS;
225 t_cookie_ = 0;
228 Nexus::~Nexus()
230 assert(list_ == 0);
231 if (name_)
232 delete[]name_;
235 verinum::V Nexus::get_init() const
237 assert(list_);
238 for (Link*cur = list_ ; cur ; cur = cur->next_) {
239 if (cur->get_dir() == Link::OUTPUT)
240 return verinum::Vx;
242 if ((cur->get_dir() == Link::PASSIVE)
243 && (cur->get_init() != verinum::Vz))
244 return cur->get_init();
247 return verinum::Vz;
250 void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
252 for (Link*cur = list_ ; cur ; cur = cur->next_) {
253 if (cur->get_dir() != Link::OUTPUT)
254 continue;
256 NetObj*obj = cur->get_obj();
257 obj->rise_time(rise);
258 obj->fall_time(fall);
259 obj->decay_time(decay);
263 void Nexus::unlink(Link*that)
265 if (name_) {
266 delete[] name_;
267 name_ = 0;
270 /* If the link I'm removing was a driver for this nexus, then
271 cancel my guess of the driven value. */
272 if (that->get_dir() != Link::INPUT)
273 driven_ = NO_GUESS;
275 assert(that);
276 if (list_ == that) {
277 list_ = that->next_;
278 that->next_ = 0;
279 that->nexus_ = 0;
280 return;
283 Link*cur = list_;
284 while (cur->next_ != that) {
285 assert(cur->next_);
286 cur = cur->next_;
289 cur->next_ = that->next_;
290 that->nexus_ = 0;
291 that->next_ = 0;
294 void Nexus::relink(Link*that)
296 if (name_) {
297 delete[] name_;
298 name_ = 0;
301 /* If the link I'm adding is a driver for this nexus, then
302 cancel my guess of the driven value. */
303 if (that->get_dir() != Link::INPUT)
304 driven_ = NO_GUESS;
306 assert(that->nexus_ == 0);
307 assert(that->next_ == 0);
308 that->next_ = list_;
309 that->nexus_ = this;
310 list_ = that;
313 Link* Nexus::first_nlink()
315 return list_;
318 const Link* Nexus::first_nlink() const
320 return list_;
323 ivl_nexus_t Nexus::t_cookie() const
325 return t_cookie_;
328 ivl_nexus_t Nexus::t_cookie(ivl_nexus_t val)const
330 ivl_nexus_t tmp = t_cookie_;
331 t_cookie_ = val;
332 return tmp;
335 unsigned Nexus::vector_width() const
337 for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
338 const NetNet*sig = dynamic_cast<const NetNet*>(cur->get_obj());
339 if (sig == 0)
340 continue;
342 return sig->vector_width();
345 return 0;
348 NetNet* Nexus::pick_any_net()
350 for (Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
351 NetNet*sig = dynamic_cast<NetNet*>(cur->get_obj());
352 if (sig != 0)
353 return sig;
356 return 0;
359 const char* Nexus::name() const
361 if (name_)
362 return name_;
364 const NetNet*sig = 0;
365 unsigned pin = 0;
366 for (const Link*cur = first_nlink()
367 ; cur ; cur = cur->next_nlink()) {
369 const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
370 if (cursig == 0)
371 continue;
373 if (sig == 0) {
374 sig = cursig;
375 pin = cur->get_pin();
376 continue;
379 if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
380 continue;
382 if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
383 sig = cursig;
384 pin = cur->get_pin();
385 continue;
388 if (cursig->local_flag() && !sig->local_flag())
389 continue;
391 if (cursig->name() < sig->name())
392 continue;
394 sig = cursig;
395 pin = cur->get_pin();
398 if (sig == 0) {
399 const Link*lnk = first_nlink();
400 const NetObj*obj = lnk->get_obj();
401 pin = lnk->get_pin();
402 cerr << "internal error: No signal for nexus of " <<
403 obj->name() << " pin " << pin << "(" <<
404 lnk->get_name() << "<" << lnk->get_inst() << ">)"
405 " type=" << typeid(*obj).name() << "?" << endl;
408 assert(sig);
409 ostringstream tmp;
410 tmp << scope_path(sig->scope()) << "." << sig->name();
411 if (sig->pin_count() > 1)
412 tmp << "<" << pin << ">";
414 const string tmps = tmp.str();
415 name_ = new char[strlen(tmps.c_str()) + 1];
416 strcpy(name_, tmps.c_str());
417 return name_;
421 NexusSet::NexusSet()
423 items_ = 0;
424 nitems_ = 0;
427 NexusSet::~NexusSet()
429 if (nitems_ > 0) {
430 assert(items_ != 0);
431 free(items_);
432 } else {
433 assert(items_ == 0);
437 unsigned NexusSet::count() const
439 return nitems_;
442 void NexusSet::add(Nexus*that)
444 if (nitems_ == 0) {
445 assert(items_ == 0);
446 items_ = (Nexus**)malloc(sizeof(Nexus*));
447 items_[0] = that;
448 nitems_ = 1;
449 return;
452 unsigned ptr = bsearch_(that);
453 if (ptr < nitems_) {
454 assert(items_[ptr] == that);
455 return;
458 assert(ptr == nitems_);
460 items_ = (Nexus**)realloc(items_, (nitems_+1) * sizeof(Nexus*));
461 items_[ptr] = that;
462 nitems_ += 1;
465 void NexusSet::add(const NexusSet&that)
467 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1)
468 add(that.items_[idx]);
471 void NexusSet::rem(Nexus*that)
473 if (nitems_ == 0)
474 return;
476 unsigned ptr = bsearch_(that);
477 if (ptr >= nitems_)
478 return;
480 if (nitems_ == 1) {
481 free(items_);
482 items_ = 0;
483 nitems_ = 0;
484 return;
487 for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1)
488 items_[idx] = items_[idx+1];
490 items_ = (Nexus**)realloc(items_, (nitems_-1) * sizeof(Nexus*));
491 nitems_ -= 1;
494 void NexusSet::rem(const NexusSet&that)
496 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1)
497 rem(that.items_[idx]);
500 Nexus* NexusSet::operator[] (unsigned idx) const
502 assert(idx < nitems_);
503 return items_[idx];
506 unsigned NexusSet::bsearch_(Nexus*that) const
508 for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
509 if (items_[idx] == that)
510 return idx;
513 return nitems_;
516 bool NexusSet::contains(const NexusSet&that) const
518 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) {
519 unsigned where = bsearch_(that[idx]);
520 if (where == nitems_)
521 return false;
522 if (items_[where] != that[idx])
523 return false;
526 return true;
529 bool NexusSet::intersect(const NexusSet&that) const
531 for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) {
532 unsigned where = bsearch_(that[idx]);
533 if (where == nitems_)
534 continue;
535 if (items_[where] == that[idx])
536 return true;
539 return false;