Improved nexus management performance.

This commit is contained in:
steve 2006-08-08 02:17:48 +00:00
parent 930cd598a0
commit a0ec981c50
5 changed files with 370 additions and 48 deletions

View File

@ -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.
*

View File

@ -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.
*

View File

@ -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.
*

View File

@ -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
View File

@ -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.
*