Synthesizer support for synchronous begin-end blocks.

This commit is contained in:
steve 2002-10-21 01:42:08 +00:00
parent df5ae54ec7
commit 3d4593d4d5
3 changed files with 129 additions and 3 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: net_link.cc,v 1.11 2002/08/18 22:07:16 steve Exp $"
#ident "$Id: net_link.cc,v 1.12 2002/10/21 01:42:08 steve Exp $"
#endif
# include "config.h"
@ -484,8 +484,24 @@ bool NexusSet::contains(const NexusSet&that) const
return true;
}
bool NexusSet::intersect(const NexusSet&that) const
{
for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) {
unsigned where = bsearch_(that[idx]);
if (where == nitems_)
continue;
if (items_[where] == that[idx])
return true;
}
return false;
}
/*
* $Log: net_link.cc,v $
* Revision 1.12 2002/10/21 01:42:08 steve
* Synthesizer support for synchronous begin-end blocks.
*
* Revision 1.11 2002/08/18 22:07:16 steve
* Detect temporaries in sequential block synthesis.
*

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.265 2002/10/19 22:59:49 steve Exp $"
#ident "$Id: netlist.h,v 1.266 2002/10/21 01:42:08 steve Exp $"
#endif
/*
@ -297,6 +297,9 @@ class NexusSet {
// Return true if this set contains every nexus in that set.
bool contains(const NexusSet&that) const;
// Return true if this set contains any nexus in that set.
bool intersect(const NexusSet&that) const;
private:
Nexus**items_;
unsigned nitems_;
@ -1411,6 +1414,10 @@ class NetBlock : public NetProc {
bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
bool synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events);
// This version of emit_recurse scans all the statements of
// the begin-end block sequentially. It is typically of use
// for sequential blocks.
@ -3070,6 +3077,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.266 2002/10/21 01:42:08 steve
* Synthesizer support for synchronous begin-end blocks.
*
* Revision 1.265 2002/10/19 22:59:49 steve
* Redo the parameter vector support to allow
* parameter names in range expressions.

102
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.15 2002/10/20 19:19:37 steve Exp $"
#ident "$Id: synth2.cc,v 1.16 2002/10/21 01:42:09 steve Exp $"
#endif
# include "config.h"
@ -292,6 +292,103 @@ bool NetProcTop::synth_async(Design*des)
return flag;
}
/*
* This method is called when a block is encountered near the surface
* of a synchronous always statement. For example, this code will be
* invoked for input like this:
*
* always @(posedge clk...) begin
* <statement1>
* <statement2>
* ...
* end
*
* This needs to be split into a DFF bank for each statement, because
* the statements may each infer different reset and enable signals.
*/
bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events_in)
{
if (last_ == 0)
return true;
bool flag = true;
NetProc*cur = last_;
unsigned offset = 0;
do {
cur = cur->next_;
/* Create a temporary nex_map for the substatement. */
NexusSet tmp_set;
cur->nex_output(tmp_set);
NetNet*tmp_map = new NetNet(scope, "tmp1", NetNet::WIRE,
tmp_set.count());
for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1)
connect(tmp_set[idx], tmp_map->pin(idx));
/* Create also a temporary net_out to collect the
output. */
NetNet*tmp_out = new NetNet(scope, "tmp2", NetNet::WIRE,
tmp_set.count());
/* Create a new DFF to handle this part of the begin-end
block. Connect this NetFF to the associated pins of
the existing wide NetFF device. */
NetFF*ff2 = new NetFF(scope, scope->local_hsymbol().c_str(),
tmp_out->pin_count());
des->add_node(ff2);
for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) {
connect(ff->pin_Data(idx+offset), ff2->pin_Data(idx));
connect(ff->pin_Q(idx+offset), ff2->pin_Q(idx));
}
if (ff->pin_Aclr().is_linked())
connect(ff->pin_Aclr(), ff2->pin_Aclr());
if (ff->pin_Aset().is_linked())
connect(ff->pin_Aset(), ff2->pin_Aset());
if (ff->pin_Clock().is_linked())
connect(ff->pin_Clock(), ff2->pin_Clock());
if (ff->pin_Enable().is_linked())
connect(ff->pin_Enable(),ff2->pin_Enable());
/* Now go on with the synchronous synthesis for this
subset of the statement. */
bool ok_flag = cur->synth_sync(des, scope, ff2, tmp_map,
tmp_out, events_in);
flag = flag && ok_flag;
if (ok_flag == false)
continue;
/* Use the nex_map to link up the output from the
substatement to the output of the block as a whole. */
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
unsigned ptr = find_nexus_in_set(nex_map, tmp_set[idx]);
connect(nex_out->pin(ptr), tmp_out->pin(idx));
}
delete tmp_map;
delete tmp_out;
offset += ff2->width();
} while (cur != last_);
/* Done. The large NetFF is no longer needed, as it has been
taken up by the smaller NetFF devices. */
assert(offset == ff->width());
delete ff;
return flag;
}
/*
* 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
* asynchronous set/reset, depending on whether the pin of the
* expression is connected to an event, or not.
*/
bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events_in)
@ -558,6 +655,9 @@ void synth2(Design*des)
/*
* $Log: synth2.cc,v $
* Revision 1.16 2002/10/21 01:42:09 steve
* Synthesizer support for synchronous begin-end blocks.
*
* Revision 1.15 2002/10/20 19:19:37 steve
* Handle conditional error cases better.
*