Improved nexus management performance.
This commit is contained in:
parent
930cd598a0
commit
a0ec981c50
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: expr_synth.cc,v 1.59.2.8 2006/06/15 01:57:26 steve Exp $"
|
||||
#ident "$Id: expr_synth.cc,v 1.59.2.9 2006/08/08 02:17:48 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -742,6 +742,9 @@ NetNet* NetEMemory::synthesize(Design*des)
|
|||
connect(mux->pin_Data(idx, wrd), explode->pin(bit));
|
||||
}
|
||||
|
||||
if (debug_synth)
|
||||
cerr << get_line() << ": debug: synthesis done." << endl;
|
||||
|
||||
} else {
|
||||
cerr << get_line() << ": internal error: Synthesize memory "
|
||||
<< "expression that is not exploded?" << endl;
|
||||
|
|
@ -1003,6 +1006,9 @@ NetNet* NetESignal::synthesize(Design*des)
|
|||
|
||||
/*
|
||||
* $Log: expr_synth.cc,v $
|
||||
* Revision 1.59.2.9 2006/08/08 02:17:48 steve
|
||||
* Improved nexus management performance.
|
||||
*
|
||||
* Revision 1.59.2.8 2006/06/15 01:57:26 steve
|
||||
* Handle simple memory addressing in expression synthesis.
|
||||
*
|
||||
|
|
|
|||
101
net_link.cc
101
net_link.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: net_link.cc,v 1.14.2.3 2006/07/23 19:42:33 steve Exp $"
|
||||
#ident "$Id: net_link.cc,v 1.14.2.4 2006/08/08 02:17:48 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -40,8 +40,8 @@ void connect(Nexus*l, Link&r)
|
|||
if (l == r.nexus_)
|
||||
return;
|
||||
|
||||
|
||||
Nexus*tmp = r.nexus_;
|
||||
|
||||
while (Link*cur = tmp->list_) {
|
||||
tmp->list_ = cur->next_;
|
||||
cur->nexus_ = 0;
|
||||
|
|
@ -49,9 +49,6 @@ void connect(Nexus*l, Link&r)
|
|||
l->relink(cur);
|
||||
}
|
||||
|
||||
l->driven_ = Nexus::NO_GUESS;
|
||||
|
||||
assert(tmp->list_ == 0);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +57,8 @@ void connect(Link&l, Link&r)
|
|||
assert(&l != &r);
|
||||
if (r.is_linked() && !l.is_linked())
|
||||
connect(r.nexus_, l);
|
||||
else if (r.nexus_->list_len_ > l.nexus_->list_len_)
|
||||
connect(r.nexus_, l);
|
||||
else
|
||||
connect(l.nexus_, r);
|
||||
}
|
||||
|
|
@ -218,6 +217,7 @@ Nexus::Nexus()
|
|||
{
|
||||
name_ = 0;
|
||||
list_ = 0;
|
||||
list_len_ = 0;
|
||||
driven_ = NO_GUESS;
|
||||
t_cookie_ = 0;
|
||||
}
|
||||
|
|
@ -269,10 +269,12 @@ void Nexus::unlink(Link*that)
|
|||
driven_ = NO_GUESS;
|
||||
|
||||
assert(that);
|
||||
assert(that->nexus_ == this);
|
||||
if (list_ == that) {
|
||||
list_ = that->next_;
|
||||
that->next_ = 0;
|
||||
that->nexus_ = 0;
|
||||
list_len_ -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -285,6 +287,7 @@ void Nexus::unlink(Link*that)
|
|||
cur->next_ = that->next_;
|
||||
that->nexus_ = 0;
|
||||
that->next_ = 0;
|
||||
list_len_ -= 1;
|
||||
}
|
||||
|
||||
void Nexus::relink(Link*that)
|
||||
|
|
@ -304,6 +307,7 @@ void Nexus::relink(Link*that)
|
|||
that->next_ = list_;
|
||||
that->nexus_ = this;
|
||||
list_ = that;
|
||||
list_len_ += 1;
|
||||
}
|
||||
|
||||
Link* Nexus::first_nlink()
|
||||
|
|
@ -393,6 +397,7 @@ const char* Nexus::name() const
|
|||
NexusSet::NexusSet()
|
||||
{
|
||||
items_ = 0;
|
||||
index_ = 0;
|
||||
nitems_ = 0;
|
||||
}
|
||||
|
||||
|
|
@ -401,8 +406,11 @@ NexusSet::~NexusSet()
|
|||
if (nitems_ > 0) {
|
||||
assert(items_ != 0);
|
||||
delete[] items_;
|
||||
assert(index_ != 0);
|
||||
delete[] index_;
|
||||
} else {
|
||||
assert(items_ == 0);
|
||||
assert(index_ == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -411,26 +419,44 @@ unsigned NexusSet::count() const
|
|||
return nitems_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the Nexus to the nexus set at the *end* of the array. This
|
||||
* preserves order, which is used in a few cases by the
|
||||
* synthesizer. But for efficiency, also create a sorted index.
|
||||
*/
|
||||
void NexusSet::add(Nexus*that)
|
||||
{
|
||||
/* Handle the special case that the set is empty. */
|
||||
if (nitems_ == 0) {
|
||||
assert(items_ == 0);
|
||||
assert(index_ == 0);
|
||||
items_ = (Nexus**)malloc(sizeof(Nexus*));
|
||||
items_[0] = that;
|
||||
index_ = (unsigned*)malloc(sizeof(unsigned));
|
||||
index_[0] = 0;
|
||||
nitems_ = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned ptr = bsearch_(that);
|
||||
if (ptr < nitems_) {
|
||||
assert(items_[ptr] == that);
|
||||
if (ptr < nitems_ && items_[index_[ptr]] == that) {
|
||||
assert(items_[index_[ptr]] == that);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(ptr == nitems_);
|
||||
items_ = (Nexus**) realloc(items_, (nitems_+1) * sizeof(Nexus*));
|
||||
index_ = (unsigned*)realloc(index_, (nitems_+1) * sizeof(unsigned));
|
||||
|
||||
items_[nitems_] = that;
|
||||
|
||||
unsigned dest = nitems_;
|
||||
for (unsigned idx = ptr ; idx < nitems_ ; idx += 1) {
|
||||
unsigned tmp = index_[idx];
|
||||
index_[idx] = dest;
|
||||
dest = tmp;
|
||||
}
|
||||
index_[nitems_] = dest;
|
||||
|
||||
items_ = (Nexus**)realloc(items_, (nitems_+1) * sizeof(Nexus*));
|
||||
items_[ptr] = that;
|
||||
nitems_ += 1;
|
||||
}
|
||||
|
||||
|
|
@ -446,20 +472,31 @@ void NexusSet::rem(Nexus*that)
|
|||
return;
|
||||
|
||||
unsigned ptr = bsearch_(that);
|
||||
if (ptr >= nitems_)
|
||||
if (ptr >= nitems_ || items_[index_[ptr]] != that)
|
||||
return;
|
||||
|
||||
if (nitems_ == 1) {
|
||||
free(items_);
|
||||
free(index_);
|
||||
items_ = 0;
|
||||
index_ = 0;
|
||||
nitems_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1)
|
||||
unsigned index_ptr = index_[ptr];
|
||||
for (unsigned idx = index_ptr ; idx < (nitems_-1) ; idx += 1)
|
||||
items_[idx] = items_[idx+1];
|
||||
|
||||
items_ = (Nexus**)realloc(items_, (nitems_-1) * sizeof(Nexus*));
|
||||
for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1)
|
||||
index_[idx] = index_[idx+1];
|
||||
|
||||
for (unsigned idx = 0 ; idx < (nitems_-1) ; idx += 1)
|
||||
if (index_[idx] > index_ptr)
|
||||
index_[idx] -= 1;
|
||||
|
||||
items_ = (Nexus**) realloc(items_, (nitems_-1) * sizeof(Nexus*));
|
||||
index_ = (unsigned*)realloc(index_, (nitems_-1) * sizeof(unsigned));
|
||||
nitems_ -= 1;
|
||||
}
|
||||
|
||||
|
|
@ -475,14 +512,37 @@ Nexus* NexusSet::operator[] (unsigned idx) const
|
|||
return items_[idx];
|
||||
}
|
||||
|
||||
/*
|
||||
* This method uses binary search to locate the item in the list of
|
||||
* nexus pointers. If the item is in the set, then this method returns
|
||||
* the index where it exists in the *index* array. If the item is not
|
||||
* in the set, the index points to where in the array the item should go.
|
||||
*/
|
||||
unsigned NexusSet::bsearch_(Nexus*that) const
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
|
||||
if (items_[idx] == that)
|
||||
return idx;
|
||||
|
||||
unsigned low = 0, hig = nitems_;
|
||||
|
||||
while (low < hig) {
|
||||
unsigned mid = (low + hig) / 2;
|
||||
if (mid == hig) mid -= 1;
|
||||
assert(mid >= low);
|
||||
assert(mid < hig);
|
||||
|
||||
if (items_[index_[mid]] == that) {
|
||||
return mid;
|
||||
|
||||
} else if (items_[index_[mid]] > that) {
|
||||
hig = mid;
|
||||
|
||||
} else {
|
||||
low = mid+1;
|
||||
}
|
||||
}
|
||||
|
||||
return nitems_;
|
||||
assert(low == hig);
|
||||
assert(low == nitems_ || items_[index_[low]] >= that);
|
||||
return low;
|
||||
}
|
||||
|
||||
bool NexusSet::contains(const NexusSet&that) const
|
||||
|
|
@ -491,7 +551,7 @@ bool NexusSet::contains(const NexusSet&that) const
|
|||
unsigned where = bsearch_(that[idx]);
|
||||
if (where == nitems_)
|
||||
return false;
|
||||
if (items_[where] != that[idx])
|
||||
if (items_[index_[where]] != that[idx])
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -504,7 +564,7 @@ bool NexusSet::intersect(const NexusSet&that) const
|
|||
unsigned where = bsearch_(that[idx]);
|
||||
if (where == nitems_)
|
||||
continue;
|
||||
if (items_[where] == that[idx])
|
||||
if (items_[index_[where]] == that[idx])
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -513,6 +573,9 @@ bool NexusSet::intersect(const NexusSet&that) const
|
|||
|
||||
/*
|
||||
* $Log: net_link.cc,v $
|
||||
* Revision 1.14.2.4 2006/08/08 02:17:48 steve
|
||||
* Improved nexus management performance.
|
||||
*
|
||||
* Revision 1.14.2.3 2006/07/23 19:42:33 steve
|
||||
* Handle statement output override better in blocks.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: net_nex_output.cc,v 1.11.2.7 2006/06/02 23:42:48 steve Exp $"
|
||||
#ident "$Id: net_nex_output.cc,v 1.11.2.8 2006/08/08 02:17:48 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -115,7 +115,6 @@ void NetBlock::nex_output(NexusSet&out)
|
|||
return;
|
||||
|
||||
NetProc*cur = last_->next_;
|
||||
NexusSet accum;
|
||||
do {
|
||||
cur->nex_output(out);
|
||||
cur = cur->next_;
|
||||
|
|
@ -168,6 +167,9 @@ void NetWhile::nex_output(NexusSet&out)
|
|||
|
||||
/*
|
||||
* $Log: net_nex_output.cc,v $
|
||||
* Revision 1.11.2.8 2006/08/08 02:17:48 steve
|
||||
* Improved nexus management performance.
|
||||
*
|
||||
* Revision 1.11.2.7 2006/06/02 23:42:48 steve
|
||||
* Compilation warnings.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: netlist.h,v 1.321.2.21 2006/07/23 19:42:33 steve Exp $"
|
||||
#ident "$Id: netlist.h,v 1.321.2.22 2006/08/08 02:17:48 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -281,6 +281,7 @@ class Nexus {
|
|||
|
||||
private:
|
||||
Link*list_;
|
||||
int list_len_;
|
||||
void unlink(Link*);
|
||||
void relink(Link*);
|
||||
|
||||
|
|
@ -321,6 +322,7 @@ class NexusSet {
|
|||
|
||||
private:
|
||||
Nexus**items_;
|
||||
unsigned*index_;
|
||||
unsigned nitems_;
|
||||
|
||||
unsigned bsearch_(Nexus*that) const;
|
||||
|
|
@ -3540,6 +3542,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
|||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.321.2.22 2006/08/08 02:17:48 steve
|
||||
* Improved nexus management performance.
|
||||
*
|
||||
* Revision 1.321.2.21 2006/07/23 19:42:33 steve
|
||||
* Handle statement output override better in blocks.
|
||||
*
|
||||
|
|
|
|||
296
synth2.cc
296
synth2.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: synth2.cc,v 1.39.2.40 2006/07/23 19:42:34 steve Exp $"
|
||||
#ident "$Id: synth2.cc,v 1.39.2.41 2006/08/08 02:17:49 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -71,7 +71,7 @@ bool NetProc::synth_sync(Design*des, NetScope*scope,
|
|||
{
|
||||
return synth_async_noaccum(des, scope, true, nex_ff, nex_map, nex_out);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned find_nexus_in_set(const NetNet*nset, const Nexus*nex)
|
||||
{
|
||||
unsigned idx = 0;
|
||||
|
|
@ -81,6 +81,48 @@ static unsigned find_nexus_in_set(const NetNet*nset, const Nexus*nex)
|
|||
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
struct nexus_map_t {
|
||||
const Nexus*nex;
|
||||
int idx;
|
||||
};
|
||||
static int ncp_compare(const void*p1, const void*p2)
|
||||
{
|
||||
const Nexus*a1 = ((const struct nexus_map_t*)p1) -> nex;
|
||||
const Nexus*a2 = ((const struct nexus_map_t*)p2) -> nex;
|
||||
if (a1 < a2)
|
||||
return -1;
|
||||
if (a1 > a2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nexus_map_t*make_nexus_index(const NetNet*nset)
|
||||
{
|
||||
struct nexus_map_t*table = new struct nexus_map_t[nset->pin_count()];
|
||||
for (unsigned idx = 0 ; idx < nset->pin_count() ; idx += 1) {
|
||||
table[idx].nex = nset->pin(idx).nexus();
|
||||
table[idx].idx = idx;
|
||||
}
|
||||
qsort(table, nset->pin_count(), sizeof(struct nexus_map_t), ncp_compare);
|
||||
return table;
|
||||
}
|
||||
|
||||
static int map_nexus_in_index(struct nexus_map_t*table, size_t ntable,
|
||||
const Nexus*nex)
|
||||
{
|
||||
struct nexus_map_t key;
|
||||
key.nex = nex;
|
||||
struct nexus_map_t*res = (struct nexus_map_t*)
|
||||
bsearch(&key, table, ntable,
|
||||
sizeof(struct nexus_map_t), ncp_compare);
|
||||
|
||||
if (res == 0)
|
||||
return -1;
|
||||
|
||||
assert(res->nex == nex);
|
||||
return res->idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Async synthesis of assignments is done by synthesizing the rvalue
|
||||
|
|
@ -191,13 +233,20 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
connect(nex_ff[0].ff->pin_Q(off), dq->pin_Data(idx));
|
||||
}
|
||||
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0; idx < lsig->pin_count(); idx += 1) {
|
||||
unsigned off = cur->get_loff()+idx;
|
||||
unsigned ptr = find_nexus_in_set(nex_map, lsig->pin(off).nexus());
|
||||
assert(ptr < nex_out->pin_count());
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
lsig->pin(off).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(nex_out->pin(ptr), dq->pin_Q(idx));
|
||||
}
|
||||
|
||||
delete[]nex_map_idx;
|
||||
|
||||
/* The r-value (1 bit) connects to the WriteData
|
||||
input of the demux. */
|
||||
connect(dq->pin_WriteData(0), rsig->pin(roff));
|
||||
|
|
@ -214,11 +263,16 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
/* Bind the outputs that we do make to the nex_out. Use the
|
||||
nex_map to map the l-value bit position to the nex_out bit
|
||||
position. */
|
||||
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
|
||||
unsigned off = cur->get_loff()+idx;
|
||||
unsigned ptr = find_nexus_in_set(nex_map, lsig->pin(off).nexus());
|
||||
|
||||
assert(ptr <= nex_map->pin_count());
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
lsig->pin(off).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(nex_out->pin(ptr), rsig->pin(roff+idx));
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +304,11 @@ bool NetAssignBase::synth_async_mem_sync_(Design*des, NetScope*scope,
|
|||
NetMemory*lmem = cur->mem();
|
||||
assert(lmem);
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Start synthesis of assign "
|
||||
"to memory " << lmem->name() << "." << endl;
|
||||
}
|
||||
|
||||
NetNet*msig = lmem->explode_to_reg();
|
||||
cur->incr_mem_lref();
|
||||
|
||||
|
|
@ -266,14 +325,21 @@ bool NetAssignBase::synth_async_mem_sync_(Design*des, NetScope*scope,
|
|||
return false;
|
||||
}
|
||||
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
unsigned adr = lmem->index_to_address(adr_s) * lmem->width();
|
||||
for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
|
||||
unsigned off = adr+idx;
|
||||
unsigned ptr = find_nexus_in_set(nex_map, msig->pin(off).nexus());
|
||||
assert(ptr <= nex_map->pin_count());
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
msig->pin(off).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(nex_out->pin(ptr), rsig->pin(roff+idx));
|
||||
}
|
||||
|
||||
delete[]nex_map_idx;
|
||||
|
||||
cur->turn_sig_to_wire_on_release();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -292,13 +358,20 @@ bool NetAssignBase::synth_async_mem_sync_(Design*des, NetScope*scope,
|
|||
for (unsigned idx = 0; idx < adr->pin_count() ; idx += 1)
|
||||
connect(dq->pin_Address(idx), adr->pin(idx));
|
||||
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0; idx < msig->pin_count(); idx += 1) {
|
||||
unsigned off = idx;
|
||||
unsigned ptr = find_nexus_in_set(nex_map, msig->pin(off).nexus());
|
||||
assert(ptr <= nex_map->pin_count());
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
msig->pin(off).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(nex_out->pin(ptr), dq->pin_Q(idx));
|
||||
}
|
||||
|
||||
delete[]nex_map_idx;
|
||||
|
||||
for (unsigned idx = 0 ; idx < msig->pin_count(); idx += 1)
|
||||
connect(dq->pin_Data(idx), nex_map->pin(roff+idx));
|
||||
|
||||
|
|
@ -308,6 +381,11 @@ bool NetAssignBase::synth_async_mem_sync_(Design*des, NetScope*scope,
|
|||
roff += cur->lwidth();
|
||||
cur->turn_sig_to_wire_on_release();
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Finish synthesis of assign "
|
||||
"to memory " << lmem->name() << "." << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -367,12 +445,20 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
handle default cases specially. We will delete this
|
||||
temporary map as soon as the synth_async is done. */
|
||||
new_accum = new NetNet(scope, tmp3, NetNet::WIRE, tmp_set.count());
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < tmp_set.count() ; idx += 1) {
|
||||
unsigned ptr = find_nexus_in_set(nex_map, tmp_set[idx]);
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
tmp_set[idx]);
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
if (accum_out->pin(ptr).is_linked())
|
||||
connect(new_accum->pin(idx), accum_out->pin(ptr));
|
||||
}
|
||||
|
||||
delete [] nex_map_idx;
|
||||
|
||||
bool ok_flag = cur->synth_async(des, scope, sync_flag, nex_ff,
|
||||
tmp_map, tmp_out, new_accum);
|
||||
flag = flag && ok_flag;
|
||||
|
|
@ -395,20 +481,29 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
new_accum->local_flag(true);
|
||||
|
||||
/* Use the nex_map to link up the output from the
|
||||
substatement to the output of the block as a whole. */
|
||||
substatement to the output of the block as a
|
||||
whole. */
|
||||
|
||||
nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
|
||||
unsigned ptr = find_nexus_in_set(nex_map, tmp_map->pin(idx).nexus());
|
||||
if (ptr >= nex_map->pin_count()) {
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
tmp_map->pin(idx).nexus());
|
||||
if (tmp < 0) {
|
||||
cerr << cur->get_line() << ": internal error: "
|
||||
<< "Nexus isn't in nex_map?! idx=" << idx
|
||||
<< " map width = " << nex_map->pin_count()
|
||||
<< " tmp_map count = " << tmp_map->pin_count()
|
||||
<< endl;
|
||||
}
|
||||
assert(ptr < new_accum->pin_count());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(new_accum->pin(ptr), tmp_out->pin(idx));
|
||||
}
|
||||
|
||||
delete[]nex_map_idx;
|
||||
|
||||
delete tmp_map;
|
||||
delete tmp_out;
|
||||
|
||||
|
|
@ -1272,6 +1367,11 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope,
|
|||
/* There is no memory address, so resort to async
|
||||
assignments. */
|
||||
if (demux == 0) {
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Looks like simple assign "
|
||||
<< "to a synchronous vector." << endl;
|
||||
}
|
||||
|
||||
/* Synthesize the input to the DFF. */
|
||||
return synth_async_noaccum(des, scope, true, nex_ff,
|
||||
nex_map, nex_out);
|
||||
|
|
@ -1287,6 +1387,11 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope,
|
|||
assign to a constant bit. We don't need a demux in that
|
||||
case. */
|
||||
if (demux->mem() && dynamic_cast<NetEConst*>(demux->bmux())) {
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Looks like an assign "
|
||||
<< "to a fixed memory word." << endl;
|
||||
}
|
||||
|
||||
NetMemory*lmem = demux->mem();
|
||||
NetNet*msig = lmem->explode_to_reg();
|
||||
demux->incr_mem_lref();
|
||||
|
|
@ -1295,16 +1400,29 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope,
|
|||
long adr = ae->value().as_long();
|
||||
adr = lmem->index_to_address(adr) * lmem->width();
|
||||
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < demux->lwidth() ; idx += 1) {
|
||||
unsigned off = adr+idx;
|
||||
unsigned ptr = find_nexus_in_set(nex_map, msig->pin(off).nexus());
|
||||
assert(ptr <= nex_map->pin_count());
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
msig->pin(off).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(nex_out->pin(ptr), rsig->pin(idx));
|
||||
}
|
||||
|
||||
delete[]nex_map_idx;
|
||||
|
||||
lval_->turn_sig_to_wire_on_release();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Looks like an assign "
|
||||
<< "to an addressed memory word." << endl;
|
||||
}
|
||||
|
||||
/* We also need the address (now known to be non-constant)
|
||||
synthesized and connected to a decoder. */
|
||||
NetNet*adr = demux->bmux()->synthesize(des);
|
||||
|
|
@ -1326,6 +1444,11 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope,
|
|||
lval_->incr_mem_lref();
|
||||
}
|
||||
lval_->turn_sig_to_wire_on_release();
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Synchronous assign done." << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1352,6 +1475,10 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
if (last_ == 0)
|
||||
return true;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Start synthesis of block" << endl;
|
||||
}
|
||||
|
||||
/* Assert that this region still represents a single DFF. */
|
||||
for (unsigned idx = 1 ; idx < nex_out->pin_count() ; idx += 1) {
|
||||
assert(nex_ff[0].ff == nex_ff[idx].ff);
|
||||
|
|
@ -1374,6 +1501,12 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
do {
|
||||
cur = cur->next_;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Collect information for statement at "
|
||||
<< cur->get_line() << endl;
|
||||
}
|
||||
|
||||
/* Create a temporary nex_map for the substatement. */
|
||||
NexusSet tmp_set;
|
||||
cur->nex_output(tmp_set);
|
||||
|
|
@ -1406,11 +1539,22 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
struct sync_accounting_cell*tmp_ff
|
||||
= new struct sync_accounting_cell[ff2->width()];
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Map pins for statement at "
|
||||
<< cur->get_line() << endl;
|
||||
}
|
||||
|
||||
verinum aset_value2 (verinum::V1, ff2->width());
|
||||
verinum sset_value2 (verinum::V1, ff2->width());
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) {
|
||||
unsigned ptr = find_nexus_in_set(nex_map,
|
||||
tmp_map->pin(idx).nexus());
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
tmp_map->pin(idx).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
|
||||
/* Copy the asynch set bit to the new device. */
|
||||
if (ptr < tmp_aset.len())
|
||||
|
|
@ -1429,6 +1573,14 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
tmp_ff[idx].proc = cur;
|
||||
}
|
||||
|
||||
delete[]nex_map_idx;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Propagate FF controls for statement at "
|
||||
<< cur->get_line() << endl;
|
||||
}
|
||||
|
||||
/* PUll the non-sliced inputs (clock, set, reset, etc)
|
||||
forward to the new FF we are building. */
|
||||
if (ff->pin_Aclr().is_linked())
|
||||
|
|
@ -1475,6 +1627,12 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Start substatement synthesis at "
|
||||
<< cur->get_line() << endl;
|
||||
}
|
||||
|
||||
/* Now go on with the synchronous synthesis for this
|
||||
statement of the block. The tmp_map is the output
|
||||
nexa that we expect, and the tmp_out is where we want
|
||||
|
|
@ -1488,16 +1646,27 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
if (ok_flag == false)
|
||||
continue;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Bind block substatement to ff bits." << endl;
|
||||
}
|
||||
/* Use the nex_map to link up the output from the
|
||||
substatement to the output of the block as a
|
||||
whole. It is occasionally possible to have outputs
|
||||
beyond the input set, for example when the l-value of
|
||||
an assignment is smaller then the r-value. */
|
||||
|
||||
nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
|
||||
ff2 = tmp_ff[idx].ff;
|
||||
unsigned ff2_pin = tmp_ff[idx].pin;
|
||||
unsigned ptr = find_nexus_in_set(nex_map,
|
||||
tmp_map->pin(idx).nexus());
|
||||
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
tmp_map->pin(idx).nexus());
|
||||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
|
||||
if (ptr >= nex_out->pin_count())
|
||||
continue;
|
||||
|
|
@ -1536,6 +1705,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
}
|
||||
delete[]nex_map_idx;
|
||||
|
||||
delete tmp_map;
|
||||
delete tmp_out;
|
||||
|
|
@ -1552,6 +1722,11 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
delete ff;
|
||||
ff = 0;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Check block synthesis for completelness. " << endl;
|
||||
}
|
||||
|
||||
/* Run through the pin accounting one more time to make sure
|
||||
the data inputs are all connected. */
|
||||
for (unsigned idx = 0 ; idx < block_width ; idx += 1) {
|
||||
|
|
@ -1582,6 +1757,10 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Finish synthesis of block" << endl;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
|
@ -1706,6 +1885,11 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
NetNet*nex_map, NetNet*nex_out,
|
||||
const svector<NetEvProbe*>&events_in)
|
||||
{
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Start sync synthesis of conditional" << endl;
|
||||
}
|
||||
|
||||
/* First try to turn the condition expression into an
|
||||
asynchronous set/reset. If the condition expression has
|
||||
inputs that are included in the sensitivity list, then it
|
||||
|
|
@ -1899,11 +2083,20 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
nex_ff, nex_map,
|
||||
nex_out, events_tmp);
|
||||
|
||||
if (debug_synth)
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "End synthesis of conditional" << endl;
|
||||
return flag;
|
||||
}
|
||||
|
||||
delete expr_input;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Condit expression input not sensitive, "
|
||||
<< "so must be synchronous. " << endl;
|
||||
}
|
||||
|
||||
/* Detect the case that this is a *synchronous* set/reset. It
|
||||
is not asyncronous because we know the condition is not
|
||||
included in the sensitivity list, but if the if_ case is
|
||||
|
|
@ -1970,6 +2163,10 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
nex_ff, nex_map, nex_out,
|
||||
svector<NetEvProbe*>(0))
|
||||
&& flag;
|
||||
|
||||
if (debug_synth)
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "End synthesis of conditional" << endl;
|
||||
return flag;
|
||||
} while (0);
|
||||
}
|
||||
|
|
@ -1983,14 +2180,30 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
/* If this is an if/then/else, then it is likely a
|
||||
combinational if, and I should synthesize it that way. */
|
||||
if (if_ && else_) {
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Condit expression looks like a synchronous mux."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
bool flag =synth_async_noaccum(des, scope, true, nex_ff,
|
||||
nex_map, nex_out);
|
||||
|
||||
if (debug_synth)
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "End synthesis of conditional" << endl;
|
||||
return flag;
|
||||
}
|
||||
|
||||
assert(if_);
|
||||
assert(!else_);
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Condit expression looks like a synchronous enable. "
|
||||
<< endl;
|
||||
}
|
||||
|
||||
/* Synthesize the enable expression. */
|
||||
NetNet*ce = expr_->synthesize(des);
|
||||
assert(ce->pin_count() == 1);
|
||||
|
|
@ -2007,10 +2220,20 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|||
unsigned nbits = nex_map->pin_count();
|
||||
connect_enable_range_(des, scope, nex_ff, nbits, ce);
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Condit expression make input that is sync enabled."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
bool flag = if_->synth_sync(des, scope,
|
||||
nex_ff, nex_map, nex_out,
|
||||
events_in);
|
||||
|
||||
|
||||
if (debug_synth)
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "End synthesis of conditional" << endl;
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
|
@ -2019,7 +2242,6 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
NetNet*nex_map, NetNet*nex_out,
|
||||
const svector<NetEvProbe*>&events_in)
|
||||
{
|
||||
DEBUG_SYNTH2_ENTRY("NetEvWait")
|
||||
if (events_in.count() > 0) {
|
||||
cerr << get_line() << ": error: Events are unaccounted"
|
||||
<< " for in process synthesis. (evw)" << endl;
|
||||
|
|
@ -2028,6 +2250,11 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
|
||||
assert(events_in.count() == 0);
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Start synthesis of event wait statement."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
/* This can't be other then one unless there are named events,
|
||||
which I cannot synthesize. */
|
||||
assert(nevents_ == 1);
|
||||
|
|
@ -2072,7 +2299,6 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
cerr << get_line() << ": : Perhaps the clock"
|
||||
<< " is read by a statement or expression?" << endl;
|
||||
des->errors += 1;
|
||||
DEBUG_SYNTH2_EXIT("NetEvWait",false)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2095,7 +2321,11 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
bool flag = statement_->synth_sync(des, scope, nex_ff,
|
||||
nex_map, nex_out, events);
|
||||
|
||||
DEBUG_SYNTH2_EXIT("NetEvWait",flag)
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Finished synthesis of event wait statement."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
|
@ -2112,9 +2342,18 @@ bool NetWhile::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
|
||||
bool NetProcTop::synth_sync(Design*des)
|
||||
{
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Start synthesis of process." << endl;
|
||||
}
|
||||
|
||||
NexusSet nex_set;
|
||||
statement_->nex_output(nex_set);
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Process seems to have "
|
||||
<< nex_set.count() << " output bits." << endl;
|
||||
}
|
||||
|
||||
NetFF*ff = new NetFF(scope(), scope()->local_symbol(),
|
||||
nex_set.count());
|
||||
des->add_node(ff);
|
||||
|
|
@ -2159,6 +2398,10 @@ bool NetProcTop::synth_sync(Design*des)
|
|||
delete nex_q;
|
||||
delete[]nex_ff;
|
||||
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Finished synthesis of process." << endl;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
|
@ -2241,6 +2484,9 @@ void synth2(Design*des)
|
|||
|
||||
/*
|
||||
* $Log: synth2.cc,v $
|
||||
* Revision 1.39.2.41 2006/08/08 02:17:49 steve
|
||||
* Improved nexus management performance.
|
||||
*
|
||||
* Revision 1.39.2.40 2006/07/23 19:42:34 steve
|
||||
* Handle statement output override better in blocks.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue