Avoid creating Nexus objects until they are really needed.

By not creating Nexus objects until necessary, we avoid creating a
lot of spurious objects. In fact, it is true that almost every
link that is created and connected to another link will create a
spurious Nexus object without this patch.
This commit is contained in:
Stephen Williams 2009-01-07 22:07:08 -08:00
parent 2353f91693
commit a2aff77ca2
7 changed files with 59 additions and 24 deletions

View File

@ -215,7 +215,10 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
o << " (";
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
o << pin(idx-1).nexus()->get_init();
if (const Nexus*tmp = pin(idx-1).nexus())
o << tmp->get_init();
else
o << ".";
o << ")" << endl;
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {

View File

@ -29,6 +29,9 @@
#define _END_DECL
#endif
#ifndef __GNUC__
# define __attribute__(x)
#endif
_BEGIN_DECL
@ -173,7 +176,7 @@ typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_switch_s *ivl_switch_t;
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
typedef struct ivl_memory_s *ivl_memory_t; //XXXX __attribute__((deprecated));
typedef struct ivl_statement_s*ivl_statement_t;
/*
@ -1414,7 +1417,7 @@ extern ivl_signal_t ivl_lval_sig(ivl_lval_t net);
* width. The compiler will insure this is so.
*/
extern const char* ivl_nexus_name(ivl_nexus_t net);
extern const char* ivl_nexus_name(ivl_nexus_t net) __attribute__((deprecated));
extern unsigned ivl_nexus_ptrs(ivl_nexus_t net);
extern ivl_nexus_ptr_t ivl_nexus_ptr(ivl_nexus_t net, unsigned idx);

View File

@ -33,11 +33,16 @@
void connect(Nexus*l, Link&r)
{
assert(l);
assert(r.nexus_);
if (l == r.nexus_)
return;
// Special case: The "r" link is connected to nothing. The
// connect becomes trivially easy.
if (r.nexus_ == 0) {
l->relink(&r);
return;
}
Nexus*tmp = r.nexus_;
while (Link*cur = tmp->list_) {
@ -56,30 +61,36 @@ void connect(Nexus*l, Link&r)
void connect(Link&l, Link&r)
{
assert(&l != &r);
if (r.is_linked() && !l.is_linked())
connect(r.nexus_, l);
else
if (l.nexus_ != 0) {
connect(l.nexus_, r);
} else if (r.nexus_ != 0) {
connect(r.nexus_, l);
} else {
Nexus*tmp = new Nexus;
connect(tmp, l);
connect(tmp, r);
}
}
Link::Link()
: dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx),
next_(0), nexus_(0)
{
(new Nexus()) -> relink(this);
}
Link::~Link()
{
assert(nexus_);
Nexus*tmp = nexus_;
nexus_->unlink(this);
if (tmp->list_ == 0)
delete tmp;
if (Nexus*tmp = nexus_) {
nexus_->unlink(this);
if (tmp->list_ == 0)
delete tmp;
}
}
Nexus* Link::nexus()
{
if (nexus_ == 0)
(new Nexus()) ->relink(this);
return nexus_;
}
@ -158,7 +169,6 @@ void Link::unlink()
return;
nexus_->unlink(this);
(new Nexus()) -> relink(this);
}
bool Link::is_equal(const Link&that) const
@ -168,6 +178,8 @@ bool Link::is_equal(const Link&that) const
bool Link::is_linked() const
{
if (nexus_ == 0)
return false;
if (next_)
return true;
if (nexus_->first_nlink() != this)
@ -178,6 +190,8 @@ bool Link::is_linked() const
bool Link::is_linked(const Link&that) const
{
if (nexus_ == 0)
return false;
return nexus_ == that.nexus_;
}
@ -489,6 +503,7 @@ unsigned NexusSet::count() const
void NexusSet::add(Nexus*that)
{
assert(that);
if (nitems_ == 0) {
assert(items_ == 0);
items_ = (Nexus**)malloc(sizeof(Nexus*));
@ -518,6 +533,7 @@ void NexusSet::add(const NexusSet&that)
void NexusSet::rem(Nexus*that)
{
assert(that);
if (nitems_ == 0)
return;

View File

@ -290,6 +290,9 @@ class Link {
verinum::V init_ : 2;
private:
// The Nexus uses these to maintain a single linked list of
// Link objects. If this link is not connected to anything,
// then these pointers are nil.
Link *next_;
Nexus*nexus_;

View File

@ -1354,7 +1354,9 @@ extern "C" const char* ivl_nexus_name(ivl_nexus_t net)
{
assert(net);
if (net->name_ == 0) {
net->name_ = api_strings.add(net->nexus_->name());
char tmp[2 * sizeof(net) + 5];
snprintf(tmp, sizeof tmp, "n%p", net);
net->name_ = api_strings.add(tmp);
}
return net->name_;
}

View File

@ -1429,16 +1429,15 @@ void dll_target::udp(const NetUDP*net)
obj->npins_ = net->pin_count();
obj->pins_ = new ivl_nexus_t[obj->npins_];
for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
const Nexus*nex = net->pin(idx).nexus();
/* Skip unconnected input pins. These will take on HiZ
values by the code generators. */
if (nex->t_cookie() == 0) {
if (! net->pin(idx).is_linked()) {
obj->pins_[idx] = 0;
continue;
}
assert(nex->t_cookie());
const Nexus*nex = net->pin(idx).nexus();
ivl_assert(*net, nex && nex->t_cookie());
obj->pins_[idx] = nex->t_cookie();
nexus_log_add(obj->pins_[idx], obj, idx);
}
@ -2566,8 +2565,19 @@ void dll_target::signal(const NetNet*net)
for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
const Nexus*nex = net->pin(idx).nexus();
ivl_assert(*net, nex);
if (nex->t_cookie()) {
if (nex == 0) {
// Special case: This pin is connected to
// nothing. This can happen, for example, if the
// variable is only used in behavioral
// code. Create a stub nexus.
ivl_nexus_t tmp = nexus_sig_make(obj, idx);
tmp->nexus_ = nex;
tmp->name_ = 0;
if (obj->array_words > 1)
obj->pins[idx] = tmp;
else
obj->pin = tmp;
} else if (nex->t_cookie()) {
if (obj->array_words > 1) {
obj->pins[idx] = nex->t_cookie();
nexus_sig_add(obj->pins[idx], obj, idx);
@ -2585,7 +2595,6 @@ void dll_target::signal(const NetNet*net)
else
obj->pin = tmp;
}
ivl_assert(*net, net->pin(idx).nexus()->t_cookie());
}
}

View File

@ -466,8 +466,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
}
fprintf(stderr, "internal error: no input to nexus %s\n",
ivl_nexus_name(nex));
fprintf(stderr, "internal error: no input to nexus.\n");
assert(0);
return strdup("C<z>");
}