synthesis of NetCondit handles partial resets.

This commit is contained in:
steve 2006-06-23 03:49:46 +00:00
parent 101810df21
commit 08dbe801c1
2 changed files with 228 additions and 76 deletions

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.h,v 1.321.2.18 2006/06/14 03:02:54 steve Exp $" #ident "$Id: netlist.h,v 1.321.2.19 2006/06/23 03:49:46 steve Exp $"
#endif #endif
/* /*
@ -1861,6 +1861,13 @@ class NetCondit : public NetProc {
virtual int match_proc(struct proc_match_t*); virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
private:
int connect_set_clr_range_( struct sync_accounting_cell*nex_ff,
unsigned bits, NetNet*rst,
const verinum&val);
int connect_enable_range_(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
unsigned bits, NetNet*ce);
private: private:
NetExpr* expr_; NetExpr* expr_;
NetProc*if_; NetProc*if_;
@ -3529,6 +3536,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/* /*
* $Log: netlist.h,v $ * $Log: netlist.h,v $
* Revision 1.321.2.19 2006/06/23 03:49:46 steve
* synthesis of NetCondit handles partial resets.
*
* Revision 1.321.2.18 2006/06/14 03:02:54 steve * Revision 1.321.2.18 2006/06/14 03:02:54 steve
* synthesis for NetEBitSel. * synthesis for NetEBitSel.
* *

288
synth2.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #ifdef HAVE_CVS_IDENT
#ident "$Id: synth2.cc,v 1.39.2.35 2006/06/07 03:17:39 steve Exp $" #ident "$Id: synth2.cc,v 1.39.2.36 2006/06/23 03:49:47 steve Exp $"
#endif #endif
# include "config.h" # include "config.h"
@ -1440,6 +1440,116 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
return flag; return flag;
} }
static bool test_ff_set_clr(struct sync_accounting_cell*nex_ff, unsigned bits)
{
for (unsigned idx = 0 ; idx < bits ; idx += 1) {
NetFF*ff = nex_ff[idx].ff;
if (ff->pin_Sset().is_linked())
return true;
if (ff->pin_Sclr().is_linked())
return true;
}
return false;
}
int NetCondit::connect_set_clr_range_(struct sync_accounting_cell*nex_ff,
unsigned bits, NetNet*rst,
const verinum&val)
{
/* Oops, this is not a constant, presumably because the case
is not fully connected. In this case, we need to fall back
on more general synthesis. */
if (! val.is_defined()) {
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Give up on set/clr synthesis, since "
<< "r-value = " << val << endl;
return -1;
}
assert(val.is_defined());
unsigned base = 0;
unsigned wid = nex_ff[0].ff->width();
while (base < bits) {
NetFF*ff = nex_ff[base].ff;
assert(base+wid <= bits);
verinum tmp(0UL, wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
assert(nex_ff[base+idx].ff == ff);
tmp.set(idx, val.get(base+idx));
}
if (tmp.is_zero()) {
connect(ff->pin_Sclr(), rst->pin(0));
} else {
connect(ff->pin_Sset(), rst->pin(0));
ff->sset_value(tmp);
}
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Create a synchronous set for "
<< ff->width() << " bit ff." << endl;
base += wid;
}
return 0;
}
int NetCondit::connect_enable_range_(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
unsigned bits, NetNet*ce)
{
unsigned base = 0;
unsigned wid = nex_ff[0].ff->width();
while (base < bits) {
NetFF*ff = nex_ff[base].ff;
assert(base+wid <= bits);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
assert(nex_ff[base+idx].ff == ff);
}
/* Watch out for the special case that there is already
a CE connected to this FF. This can be caused by code
like this:
if (a) if (b) <statement>;
In this case, we are working on the inner IF, so we
AND the a and b expressions to make a new CE. */
if (ff->pin_Enable().is_linked()) {
NetLogic*ce_and = new NetLogic(scope,
scope->local_symbol(), 3,
NetLogic::AND);
des->add_node(ce_and);
connect(ff->pin_Enable(), ce_and->pin(1));
connect(ce->pin(0), ce_and->pin(2));
ff->pin_Enable().unlink();
connect(ff->pin_Enable(), ce_and->pin(0));
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
tmp->local_flag(true);
connect(ff->pin_Enable(), tmp->pin(0));
} else {
connect(ff->pin_Enable(), ce->pin(0));
}
base += wid;
}
return 0;
}
/* /*
* This method handles the case where I find a conditional near the * This method handles the case where I find a conditional near the
* surface of a synchronous thread. This conditional can be a CE or an * surface of a synchronous thread. This conditional can be a CE or an
@ -1451,12 +1561,6 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
NetNet*nex_map, NetNet*nex_out, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events_in) const svector<NetEvProbe*>&events_in)
{ {
for (unsigned idx = 1 ; idx < nex_out->pin_count() ; idx += 1) {
assert(nex_ff[0].ff == nex_ff[idx].ff);
}
NetFF*ff = nex_ff[0].ff;
/* First try to turn the condition expression into an /* First try to turn the condition expression into an
asynchronous set/reset. If the condition expression has asynchronous set/reset. If the condition expression has
inputs that are included in the sensitivity list, then it inputs that are included in the sensitivity list, then it
@ -1466,6 +1570,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
assert(expr_input); assert(expr_input);
for (unsigned idx = 0 ; idx < events_in.count() ; idx += 1) { for (unsigned idx = 0 ; idx < events_in.count() ; idx += 1) {
NetEvProbe*ev = events_in[idx]; NetEvProbe*ev = events_in[idx];
NexusSet pin_set; NexusSet pin_set;
pin_set.add(ev->pin(0).nexus()); pin_set.add(ev->pin(0).nexus());
@ -1500,6 +1605,13 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
NetNet*rst = expr_->synthesize(des); NetNet*rst = expr_->synthesize(des);
assert(rst->pin_count() == 1); assert(rst->pin_count() == 1);
/* WARNING: This case relies on the ff vector being a
single NetFF. */
for (unsigned bit = 1 ; bit < nex_out->pin_count() ; bit += 1) {
assert(nex_ff[0].ff == nex_ff[bit].ff);
}
NetFF*ff = nex_ff[0].ff;
/* XXXX I really should find a way to check that the /* XXXX I really should find a way to check that the
edge used on the reset input is correct. This would edge used on the reset input is correct. This would
involve interpreting the exression that is fed by the involve interpreting the exression that is fed by the
@ -1516,26 +1628,93 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
bool flag = if_->synth_async_noaccum(des, scope, true, nex_ff, bool flag = if_->synth_async_noaccum(des, scope, true, nex_ff,
nex_map, asig); nex_map, asig);
assert(asig->pin_count() == ff->width()); assert(asig->pin_count() == nex_map->pin_count());
/* Collect the set/reset value into a verinum. If /* Collect the set/reset value into a verinum. If
this turns out to be entirely 0 values, then this turns out to be entirely 0 values, then
use the Aclr input. Otherwise, use the Aset use the Aclr input. Otherwise, use the Aset
input and save the set value. */ input and save the set value. */
verinum tmp (verinum::V0, ff->width()); verinum tmp (verinum::V0, ff->width());
unsigned count_z = 0;
unsigned count_x = 0;
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) { for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
assert(asig->pin(bit).nexus()->drivers_constant()); assert(asig->pin(bit).nexus()->drivers_constant());
tmp.set(bit, asig->pin(bit).nexus()->driven_value()); verinum::V val = asig->pin(bit).nexus()->driven_value();
tmp.set(bit, val);
switch (val) {
case verinum::V0:
case verinum::V1:
break;
case verinum::Vz:
count_z += 1;
break;
case verinum::Vx:
count_x += 1;
break;
}
} }
if (!tmp.is_defined()) { if (count_x > 0) {
cerr << get_line() << ": internal error: " cerr << get_line() << ": internal error: "
<< "True clause returns constant 'bx/'bz values" << "True clause returns constant 'bx values"
<< " which are not plausible for set/reset." << endl; << " which are not plausible for set/reset." << endl;
cerr << get_line() << ": : "
<< "XXXX val = " << tmp << endl;
return false; return false;
} }
if (count_z > 0) {
#if 0
cerr << get_line() << ": internal error: "
<< "True clause returns constant 'bz values"
<< " which are not plausible for set/reset." << endl;
cerr << get_line() << ": : "
<< "XXXX val = " << tmp << endl;
return false;
#endif
assert(count_z < ff->width());
/* Some bits are not reset by this input. To make
this work, split the current ff into a pair of
FF, one connected to the reset, and the other
not. */
NetFF*ff1 = new NetFF(scope, ff->name(),
ff->width() - count_z);
NetFF*ffz = new NetFF(scope, scope->local_symbol(),
count_z);
des->add_node(ff1);
des->add_node(ffz);
connect(ff->pin_Clock(), ff1->pin_Clock());
connect(ff->pin_Clock(), ffz->pin_Clock());
verinum tmp1(0UL, ff1->width());
unsigned bit1 = 0;
unsigned bitz = 0;
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
if (tmp.get(bit) == verinum::Vz) {
connect(ffz->pin_Q(bitz), ff->pin_Q(bit));
connect(ffz->pin_Data(bitz), ff->pin_Data(bit));
nex_ff[bit].ff = ffz;
nex_ff[bit].pin = bitz;
bitz += 1;
} else {
connect(ff1->pin_Q(bit1), ff->pin_Q(bit));
connect(ff1->pin_Data(bit1), ff->pin_Data(bit));
nex_ff[bit].ff = ff1;
nex_ff[bit].pin = bit1;
tmp1.set(bit1, tmp.get(bit));
bit1 += 1;
}
}
delete ff;
ff = ff1;
tmp = tmp1;
}
assert(tmp.is_defined()); assert(tmp.is_defined());
if (tmp.is_zero()) { if (tmp.is_zero()) {
connect(ff->pin_Aclr(), rst->pin(0)); connect(ff->pin_Aclr(), rst->pin(0));
@ -1601,8 +1780,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
if ((a_set->count() == 0) if ((a_set->count() == 0)
&& if_ && else_ && if_ && else_
&& !ff->pin_Sset().is_linked() && !test_ff_set_clr(nex_ff, nex_map->pin_count())) {
&& !ff->pin_Sclr().is_linked()) {
NetNet*rst = expr_->synthesize(des); NetNet*rst = expr_->synthesize(des);
assert(rst->pin_count() == 1); assert(rst->pin_count() == 1);
@ -1619,49 +1797,26 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
/* This path leads nowhere */ /* This path leads nowhere */
delete asig; delete asig;
} else do { } else do {
assert(asig->pin_count() == ff->width()); assert(asig->pin_count() == nex_map->pin_count());
unsigned nbits = nex_map->pin_count();
/* Collect the set/reset value into a verinum. If /* Collect the set/reset value into a verinum. If
this turns out to be entirely 0 values, then this turns out to be entirely 0 values, then
use the Sclr input. Otherwise, use the Aset use the Sclr input. Otherwise, use the Aset
input and save the set value. */ input and save the set value. */
verinum tmp (verinum::V0, ff->width()); verinum tmp (verinum::V0, nbits);
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) { for (unsigned bit = 0; bit< nbits; bit += 1) {
assert(asig->pin(bit).nexus()->drivers_constant()); assert(asig->pin(bit).nexus()->drivers_constant());
tmp.set(bit, asig->pin(bit).nexus()->driven_value()); tmp.set(bit, asig->pin(bit).nexus()->driven_value());
} }
/* Oops, this is not a constant, presumably if (connect_set_clr_range_(nex_ff, nbits, rst, tmp) < 0) {
because the case is not fully connected. In
this case, we need to fall back on more general
synthesis. */
if (! tmp.is_defined()) {
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Give up on set/clr synthesis, since "
<< "r-value = " << tmp << endl;
delete asig; delete asig;
break; break;
} }
assert(tmp.is_defined());
if (tmp.is_zero()) {
connect(ff->pin_Sclr(), rst->pin(0));
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Create a synchronous clr (set=0) for "
<< ff->width() << " bit ff." << endl;
} else {
connect(ff->pin_Sset(), rst->pin(0));
ff->sset_value(tmp);
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Create a synchronous set for "
<< ff->width() << " bit ff." << endl;
}
delete a_set; delete a_set;
@ -1702,36 +1857,10 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
The expr_ expression has already been synthesized to the ce The expr_ expression has already been synthesized to the ce
net, so we connect it here to the FF. What's left is to net, so we connect it here to the FF. What's left is to
synthesize the substatement as a combinational synthesize the substatement as a combinational
statement. statement. */
Watch out for the special case that there is already a CE unsigned nbits = nex_map->pin_count();
connected to this FF. This can be caused by code like this: connect_enable_range_(des, scope, nex_ff, nbits, ce);
if (a) if (b) <statement>;
In this case, we are working on the inner IF, so we AND the
a and b expressions to make a new CE. */
if (ff->pin_Enable().is_linked()) {
NetLogic*ce_and = new NetLogic(scope,
scope->local_symbol(), 3,
NetLogic::AND);
des->add_node(ce_and);
connect(ff->pin_Enable(), ce_and->pin(1));
connect(ce->pin(0), ce_and->pin(2));
ff->pin_Enable().unlink();
connect(ff->pin_Enable(), ce_and->pin(0));
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
tmp->local_flag(true);
connect(ff->pin_Enable(), tmp->pin(0));
} else {
connect(ff->pin_Enable(), ce->pin(0));
}
bool flag = if_->synth_sync(des, scope, bool flag = if_->synth_sync(des, scope,
nex_ff, nex_map, nex_out, nex_ff, nex_map, nex_out,
@ -1802,10 +1931,20 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
return false; return false;
} }
NetFF*ff = nex_ff[0].ff; unsigned base = 0;
while (base < nex_map->pin_count()) {
unsigned wid = nex_ff[base].ff->width();
assert((base + wid) <= nex_map->pin_count());
NetFF*ff = nex_ff[base].ff;
connect(ff->pin_Clock(), pclk->pin(0)); connect(ff->pin_Clock(), pclk->pin(0));
if (pclk->edge() == NetEvProbe::NEGEDGE) if (pclk->edge() == NetEvProbe::NEGEDGE)
ff->attribute(perm_string::literal("ivl:clock_polarity"), verinum("INVERT")); ff->attribute(perm_string::literal("ivl:clock_polarity"),
verinum("INVERT"));
base += wid;
}
assert(base == nex_map->pin_count());
/* Synthesize the input to the DFF. */ /* Synthesize the input to the DFF. */
bool flag = statement_->synth_sync(des, scope, nex_ff, bool flag = statement_->synth_sync(des, scope, nex_ff,
@ -1957,6 +2096,9 @@ void synth2(Design*des)
/* /*
* $Log: synth2.cc,v $ * $Log: synth2.cc,v $
* Revision 1.39.2.36 2006/06/23 03:49:47 steve
* synthesis of NetCondit handles partial resets.
*
* Revision 1.39.2.35 2006/06/07 03:17:39 steve * Revision 1.39.2.35 2006/06/07 03:17:39 steve
* Fix partial use of NetMux in sync condit statements. * Fix partial use of NetMux in sync condit statements.
* *