From 08dbe801c1894f720f45b64c7efb8f5040f0a4eb Mon Sep 17 00:00:00 2001 From: steve Date: Fri, 23 Jun 2006 03:49:46 +0000 Subject: [PATCH] synthesis of NetCondit handles partial resets. --- netlist.h | 12 ++- synth2.cc | 292 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 228 insertions(+), 76 deletions(-) diff --git a/netlist.h b/netlist.h index 56e8746ad..4e6c840cc 100644 --- a/netlist.h +++ b/netlist.h @@ -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. * diff --git a/synth2.cc b/synth2.cc index aae076d6a..2c53c6b79 100644 --- a/synth2.cc +++ b/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.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) ; + + 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&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) ; - - 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. *