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
*/
#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
/*
@ -1861,6 +1861,13 @@ class NetCondit : public NetProc {
virtual int match_proc(struct proc_match_t*);
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:
NetExpr* expr_;
NetProc*if_;
@ -3529,6 +3536,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $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
* synthesis for NetEBitSel.
*

292
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.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
# include "config.h"
@ -1440,6 +1440,116 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
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
* 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,
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
asynchronous set/reset. If the condition expression has
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);
for (unsigned idx = 0 ; idx < events_in.count() ; idx += 1) {
NetEvProbe*ev = events_in[idx];
NexusSet pin_set;
pin_set.add(ev->pin(0).nexus());
@ -1500,6 +1605,13 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
NetNet*rst = expr_->synthesize(des);
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
edge used on the reset input is correct. This would
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,
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
this turns out to be entirely 0 values, then
use the Aclr input. Otherwise, use the Aset
input and save the set value. */
verinum tmp (verinum::V0, ff->width());
unsigned count_z = 0;
unsigned count_x = 0;
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
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: "
<< "True clause returns constant 'bx/'bz values"
<< "True clause returns constant 'bx values"
<< " which are not plausible for set/reset." << endl;
cerr << get_line() << ": : "
<< "XXXX val = " << tmp << endl;
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());
if (tmp.is_zero()) {
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_ && else_
&& !ff->pin_Sset().is_linked()
&& !ff->pin_Sclr().is_linked()) {
&& !test_ff_set_clr(nex_ff, nex_map->pin_count())) {
NetNet*rst = expr_->synthesize(des);
assert(rst->pin_count() == 1);
@ -1619,49 +1797,26 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
/* This path leads nowhere */
delete asig;
} 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
this turns out to be entirely 0 values, then
use the Sclr input. Otherwise, use the Aset
input and save the set value. */
verinum tmp (verinum::V0, ff->width());
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
verinum tmp (verinum::V0, nbits);
for (unsigned bit = 0; bit< nbits; bit += 1) {
assert(asig->pin(bit).nexus()->drivers_constant());
tmp.set(bit, asig->pin(bit).nexus()->driven_value());
}
/* 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 (! tmp.is_defined()) {
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Give up on set/clr synthesis, since "
<< "r-value = " << tmp << endl;
if (connect_set_clr_range_(nex_ff, nbits, rst, tmp) < 0) {
delete asig;
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;
@ -1702,36 +1857,10 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
The expr_ expression has already been synthesized to the ce
net, so we connect it here to the FF. What's left is to
synthesize the substatement as a combinational
statement.
statement. */
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));
}
unsigned nbits = nex_map->pin_count();
connect_enable_range_(des, scope, nex_ff, nbits, ce);
bool flag = if_->synth_sync(des, scope,
nex_ff, nex_map, nex_out,
@ -1802,10 +1931,20 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
return false;
}
NetFF*ff = nex_ff[0].ff;
connect(ff->pin_Clock(), pclk->pin(0));
if (pclk->edge() == NetEvProbe::NEGEDGE)
ff->attribute(perm_string::literal("ivl:clock_polarity"), verinum("INVERT"));
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));
if (pclk->edge() == NetEvProbe::NEGEDGE)
ff->attribute(perm_string::literal("ivl:clock_polarity"),
verinum("INVERT"));
base += wid;
}
assert(base == nex_map->pin_count());
/* Synthesize the input to the DFF. */
bool flag = statement_->synth_sync(des, scope, nex_ff,
@ -1957,6 +2096,9 @@ void synth2(Design*des)
/*
* $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
* Fix partial use of NetMux in sync condit statements.
*