Support Latch synthesis (Alan Feldstein)
This commit is contained in:
parent
8c04d669f9
commit
d16dd26660
|
|
@ -16,7 +16,7 @@
|
|||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.169.2.6 2007/03/23 23:26:51 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.169.2.7 2007/05/30 17:48:53 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
|
@ -114,7 +114,7 @@ O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
|||
elab_lval.o elab_net.o elab_anet.o elab_pexpr.o elab_scope.o \
|
||||
elab_sig.o emit.o eval.o eval_attrib.o \
|
||||
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
load_module.o netlist.o netmisc.o net_assign.o \
|
||||
load_module.o netlist.o NetLatch.o netmisc.o net_assign.o \
|
||||
net_design.o net_event.o net_expr.o net_force.o net_func.o \
|
||||
net_link.o net_modulo.o net_nex_input.o net_nex_output.o \
|
||||
net_proc.o net_scope.o net_udp.o net_variable.o pad_to_width.o \
|
||||
|
|
@ -164,7 +164,7 @@ dep:
|
|||
mkdir dep
|
||||
|
||||
%.o: %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o $(DEBUGFLAGS)
|
||||
mv $*.d dep/$*.d
|
||||
|
||||
|
||||
|
|
@ -231,7 +231,6 @@ $(bindir)/iverilog-vpi: ./iverilog-vpi
|
|||
|
||||
$(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
|
||||
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(libdir)/ivl/ivl@EXEEXT@
|
||||
$(STRIP) $(strip_dynamic) $(libdir)/ivl/ivl@EXEEXT@
|
||||
|
||||
$(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(libdir)/ivl/xnf-s.conf
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// NetLatch.cc
|
||||
// Author: Alan M. Feldstein
|
||||
// Class NetLatch member-function definitions
|
||||
|
||||
#include "NetLatch.h" // NetLatch class definition
|
||||
|
||||
// constructor
|
||||
NetLatch::NetLatch( NetScope *scope, perm_string name, unsigned width )
|
||||
// explicitly call base-class constructor
|
||||
: NetNode( scope, name, 2U * width + 1U )
|
||||
{
|
||||
} // end NetLatch constructor
|
||||
|
||||
Link &NetLatch::pin_Data( unsigned w )
|
||||
{
|
||||
unsigned pn = 1 + 2 * w;
|
||||
assert( pn < pin_count() );
|
||||
return pin( pn );
|
||||
} // end function pin_Data
|
||||
|
||||
Link &NetLatch::pin_Q( unsigned w )
|
||||
{
|
||||
unsigned pn = 2 + 2 * w;
|
||||
assert( pn < pin_count() );
|
||||
return pin( pn );
|
||||
} // end function pin_Q
|
||||
|
||||
Link &NetLatch::pin_Gate()
|
||||
{
|
||||
return pin( 0 );
|
||||
} // end function pin_Q
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// NetLatch.h
|
||||
// Author: Alan M. Feldstein
|
||||
// This class represents an LPM_LATCH device. In Verilog, storage components of this type can be inferred.
|
||||
// The pinout is assigned like so:
|
||||
// 0 -- Gate
|
||||
//
|
||||
// 1 -- Data[0]
|
||||
// 2 -- Q[0]
|
||||
// ...
|
||||
#ifndef NETLATCH_H
|
||||
#define NETLATCH_H
|
||||
|
||||
#include "netlist.h" // NetNode, NetScope, Link class definitions
|
||||
#include "StringHeap.h" // perm_string class definition
|
||||
|
||||
class NetLatch : public NetNode
|
||||
{
|
||||
public:
|
||||
NetLatch( NetScope *, perm_string, unsigned );
|
||||
|
||||
Link &pin_Data( unsigned );
|
||||
Link &pin_Q( unsigned );
|
||||
Link &pin_Gate();
|
||||
|
||||
const Link &pin_Data( unsigned ) const;
|
||||
const Link &pin_Q( unsigned ) const;
|
||||
const Link &pin_Gate() const;
|
||||
}; // end class NetLatch
|
||||
|
||||
#endif
|
||||
7
async.cc
7
async.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: async.cc,v 1.7.2.1 2006/05/21 21:58:46 steve Exp $"
|
||||
#ident "$Id: async.cc,v 1.7.2.2 2007/05/30 17:48:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -89,7 +89,7 @@ bool NetProc::is_asynchronous()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NetProcTop::is_asynchronous()
|
||||
bool NetProcTop::is_asynchronous() const
|
||||
{
|
||||
if (type_ == NetProcTop::KINITIAL)
|
||||
return false;
|
||||
|
|
@ -99,6 +99,9 @@ bool NetProcTop::is_asynchronous()
|
|||
|
||||
/*
|
||||
* $Log: async.cc,v $
|
||||
* Revision 1.7.2.2 2007/05/30 17:48:53 steve
|
||||
* Support Latch synthesis (Alan Feldstein)
|
||||
*
|
||||
* Revision 1.7.2.1 2006/05/21 21:58:46 steve
|
||||
* NetESignal input is only selected bits.
|
||||
*
|
||||
|
|
|
|||
34
netlist.h
34
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.24 2006/11/26 01:54:05 steve Exp $"
|
||||
#ident "$Id: netlist.h,v 1.321.2.25 2007/05/30 17:48:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -97,7 +97,6 @@ struct sync_accounting_cell {
|
|||
*/
|
||||
class NetObj : public Attrib, public virtual LineInfo {
|
||||
|
||||
public:
|
||||
public:
|
||||
// The name of the object must be a permallocated string. A
|
||||
// lex_strings string, for example.
|
||||
|
|
@ -1486,7 +1485,7 @@ class NetProc : public virtual LineInfo, public Attrib {
|
|||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
NetNet*accum_in);
|
||||
NetNet*accum_in, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
|
||||
// Synthesize synchronous logic, and return true. The nex_out
|
||||
// is where outputs are actually connected, and the nex_map
|
||||
|
|
@ -1631,10 +1630,10 @@ class NetAssignBase : public NetProc {
|
|||
// accounts for any grouping of NetAssign_ objects that might happen.
|
||||
unsigned lwidth() const;
|
||||
|
||||
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
NetNet*accum_in);
|
||||
NetNet*accum_in, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
|
|
@ -1709,9 +1708,9 @@ class NetBlock : public NetProc {
|
|||
|
||||
|
||||
// synthesize as asynchronous logic, and return true.
|
||||
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
|
|
@ -1766,9 +1765,9 @@ class NetCase : public NetProc {
|
|||
virtual NexusSet* nex_input();
|
||||
virtual void nex_output(NexusSet&out);
|
||||
|
||||
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
|
@ -1854,9 +1853,9 @@ class NetCondit : public NetProc {
|
|||
virtual void nex_output(NexusSet&o);
|
||||
|
||||
bool is_asynchronous();
|
||||
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum);
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
|
||||
bool synth_sync(Design*des, NetScope*scope,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
|
|
@ -2091,7 +2090,7 @@ class NetEvWait : public NetProc {
|
|||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
NetNet*accum_in);
|
||||
NetNet*accum_in, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
|
||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
|
|
@ -2493,9 +2492,9 @@ class NetWhile : public NetProc {
|
|||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in, bool latch_inferred = false, NetNet *gsig = 0);
|
||||
|
||||
private:
|
||||
NetExpr* cond_;
|
||||
|
|
@ -2524,14 +2523,14 @@ class NetProcTop : public LineInfo, public Attrib {
|
|||
const NetScope*scope() const;
|
||||
|
||||
/* Return true if this process represents combinational logic. */
|
||||
bool is_asynchronous();
|
||||
bool is_asynchronous() const;
|
||||
|
||||
/* Create asynchronous logic from this thread and return true,
|
||||
or return false if that cannot be done. */
|
||||
bool synth_async(Design*des);
|
||||
|
||||
/* Return true if this process represents synchronous logic. */
|
||||
bool is_synchronous();
|
||||
bool is_synchronous() const;
|
||||
|
||||
/* Create synchronous logic from this thread and return true,
|
||||
or return false if that cannot be done. */
|
||||
|
|
@ -3546,6 +3545,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
|||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.321.2.25 2007/05/30 17:48:53 steve
|
||||
* Support Latch synthesis (Alan Feldstein)
|
||||
*
|
||||
* Revision 1.321.2.24 2006/11/26 01:54:05 steve
|
||||
* Add synthesis of user defined functions.
|
||||
*
|
||||
|
|
|
|||
7
sync.cc
7
sync.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sync.cc,v 1.3 2002/09/24 00:58:35 steve Exp $"
|
||||
#ident "$Id: sync.cc,v 1.3.2.1 2007/05/30 17:48:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -57,7 +57,7 @@ bool NetEvWait::is_synchronous()
|
|||
return true; //statement_->is_asynchronous();
|
||||
}
|
||||
|
||||
bool NetProcTop::is_synchronous()
|
||||
bool NetProcTop::is_synchronous() const
|
||||
{
|
||||
if (type_ == NetProcTop::KINITIAL)
|
||||
return false;
|
||||
|
|
@ -67,6 +67,9 @@ bool NetProcTop::is_synchronous()
|
|||
|
||||
/*
|
||||
* $Log: sync.cc,v $
|
||||
* Revision 1.3.2.1 2007/05/30 17:48:54 steve
|
||||
* Support Latch synthesis (Alan Feldstein)
|
||||
*
|
||||
* Revision 1.3 2002/09/24 00:58:35 steve
|
||||
* More detailed check of process edge events.
|
||||
*
|
||||
|
|
|
|||
526
synth2.cc
526
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.47 2006/11/11 23:10:20 steve Exp $"
|
||||
#ident "$Id: synth2.cc,v 1.39.2.48 2007/05/30 17:48:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -25,7 +25,12 @@
|
|||
# include "functor.h"
|
||||
# include "netlist.h"
|
||||
# include "compiler.h"
|
||||
# include <assert.h>
|
||||
#include <cassert>
|
||||
#include "NetLatch.h"
|
||||
#include <climits>
|
||||
|
||||
#include <new> // standard operator new
|
||||
using std::bad_alloc;
|
||||
|
||||
static int debug_synth2=0;
|
||||
|
||||
|
|
@ -59,7 +64,7 @@ bool NetProc::synth_async_noaccum(Design*des, NetScope*scope, bool sync_flag,
|
|||
bool NetProc::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
NetNet*accum_in)
|
||||
NetNet*accum_in, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -138,7 +143,7 @@ static int map_nexus_in_index(struct nexus_map_t*table, size_t ntable,
|
|||
bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
NetNet*accum_in)
|
||||
NetNet*accum_in, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
NetNet*rsig = rval_->synthesize(des);
|
||||
if (rsig == 0) {
|
||||
|
|
@ -180,6 +185,12 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (cur->bmux() && !sync_flag) {
|
||||
cerr << get_line() << ": error: Assign to bit select "
|
||||
<< "Not possible in asynchronous logic." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
NetNet*lsig = cur->sig();
|
||||
if (!lsig) {
|
||||
|
|
@ -191,25 +202,64 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (cur->bmux() && !sync_flag) {
|
||||
cerr << get_line() << ": error: Assign to bit select "
|
||||
<< "Not possible in asynchronous logic." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
if ( latch_inferred )
|
||||
{
|
||||
// By this point any bmux() has been dealt with. Panic if that is not so.
|
||||
assert( !cur->bmux() );
|
||||
|
||||
/* Handle the special case that this is a decoded
|
||||
enable. generate a demux for the device, with the
|
||||
WriteData connected to the r-value and the Data
|
||||
vector connected to the feedback. */
|
||||
if (cur->bmux() != 0) {
|
||||
// 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 );
|
||||
|
||||
assert( cur->sig()->msb() - cur->sig()->lsb() >= 0L &&
|
||||
static_cast< unsigned long >( cur->sig()->msb() - cur->sig()->lsb() ) <= static_cast< unsigned long >( UINT_MAX ) - 1UL );
|
||||
|
||||
try
|
||||
{
|
||||
NetLatch *const latchPtr = new NetLatch( scope, cur->sig()->name(), static_cast< unsigned >( cur->sig()->msb() - cur->sig()->lsb() ) + 1U );
|
||||
latchPtr->set_line( *this );
|
||||
|
||||
for ( unsigned idx = 0U; idx < cur->lwidth(); idx += 1U )
|
||||
{
|
||||
unsigned off = cur->get_loff() + idx;
|
||||
int tmp = map_nexus_in_index( nex_map_idx, nex_map->pin_count(), lsig->pin( off ).nexus() );
|
||||
assert( tmp >= 0 );
|
||||
unsigned ptr = static_cast< unsigned >( tmp );
|
||||
connect( latchPtr->pin_Data( idx ), rsig->pin( roff + idx ) );
|
||||
connect( nex_out->pin( ptr ), latchPtr->pin_Q( idx ) );
|
||||
connect( latchPtr->pin_Gate(), gsig->pin( 0 ) );
|
||||
}
|
||||
|
||||
des->add_node( latchPtr );
|
||||
delete latchPtr;
|
||||
}
|
||||
|
||||
catch ( bad_alloc &memoryAllocationException )
|
||||
{
|
||||
cerr << "Exception occurred: " << memoryAllocationException.what() << endl;
|
||||
cerr << get_line() << ": error: NetAssignBase::synth_async on failure to create latch at lval ";
|
||||
dump_lval( cerr );
|
||||
cerr << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Handle the special case that this is a decoded
|
||||
enable. generate a demux for the device, with the
|
||||
WriteData connected to the r-value and the Data
|
||||
vector connected to the feedback. */
|
||||
if (cur->bmux() != 0) {
|
||||
assert(sync_flag);
|
||||
|
||||
NetNet*adr = cur->bmux()->synthesize(des);
|
||||
|
||||
/* Create a NetEemux wide enough to connect to all
|
||||
the bits of the lvalue signal (generally more
|
||||
then the bits of lwidth). */
|
||||
/* Create a NetEemux wide enough to connect to all
|
||||
the bits of the lvalue signal (generally more
|
||||
then the bits of lwidth). */
|
||||
NetDemux*dq = new NetDemux(scope, scope->local_symbol(),
|
||||
lsig->pin_count(),
|
||||
adr->pin_count(),
|
||||
|
|
@ -217,56 +267,56 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
des->add_node(dq);
|
||||
dq->set_line(*this);
|
||||
|
||||
/* The bmux expression connects to the address of
|
||||
the Demux device. */
|
||||
/* The bmux expression connects to the address of
|
||||
the Demux device. */
|
||||
for (unsigned idx = 0; idx < adr->pin_count() ; idx += 1)
|
||||
connect(dq->pin_Address(idx), adr->pin(idx));
|
||||
connect(dq->pin_Address(idx), adr->pin(idx));
|
||||
|
||||
assert(cur->lwidth() == 1);
|
||||
|
||||
/* Cycle the associated FF Data and Q through the
|
||||
demux to make synchronous "latches" that the
|
||||
Demux modifies. */
|
||||
/* Cycle the associated FF Data and Q through the
|
||||
demux to make synchronous "latches" that the
|
||||
Demux modifies. */
|
||||
assert(nex_ff[0].ff->width() >= lsig->pin_count());
|
||||
for (unsigned idx = 0; idx < lsig->pin_count(); idx += 1) {
|
||||
unsigned off = cur->get_loff()+idx;
|
||||
connect(nex_ff[0].ff->pin_Q(off), dq->pin_Data(idx));
|
||||
unsigned off = cur->get_loff()+idx;
|
||||
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;
|
||||
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));
|
||||
unsigned off = cur->get_loff()+idx;
|
||||
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. */
|
||||
/* The r-value (1 bit) connects to the WriteData
|
||||
input of the demux. */
|
||||
connect(dq->pin_WriteData(0), rsig->pin(roff));
|
||||
|
||||
roff += cur->lwidth();
|
||||
cur->turn_sig_to_wire_on_release();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* By this point ant bmux() has been dealt with. Panic
|
||||
if that is not so. */
|
||||
assert(! cur->bmux());
|
||||
/* By this point ant bmux() has been dealt with. Panic
|
||||
if that is not so. */
|
||||
assert(! cur->bmux());
|
||||
|
||||
/* 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. */
|
||||
/* 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);
|
||||
struct nexus_map_t*nex_map_idx = make_nexus_index(nex_map);
|
||||
|
||||
for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
|
||||
for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
|
||||
unsigned off = cur->get_loff()+idx;
|
||||
int tmp = map_nexus_in_index(nex_map_idx,
|
||||
nex_map->pin_count(),
|
||||
|
|
@ -274,15 +324,17 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
assert(tmp >= 0);
|
||||
unsigned ptr = tmp;
|
||||
connect(nex_out->pin(ptr), rsig->pin(roff+idx));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
roff += cur->lwidth();
|
||||
|
||||
/* This lval_ represents a reg that is a WIRE in the
|
||||
synthesized results. This function signals the destructor
|
||||
to change the REG that this l-value refers to into a
|
||||
WIRE. It is done then, at the last minute, so that pending
|
||||
synthesis can continue to work with it as a WIRE. */
|
||||
/* This lval_ represents a reg that is a WIRE in the
|
||||
synthesized results. This function signals the destructor
|
||||
to change the REG that this l-value refers to into a
|
||||
WIRE. It is done then, at the last minute, so that pending
|
||||
synthesis can continue to work with it as a WIRE. */
|
||||
cur->turn_sig_to_wire_on_release();
|
||||
}
|
||||
|
||||
|
|
@ -397,7 +449,7 @@ bool NetAssignBase::synth_async_mem_sync_(Design*des, NetScope*scope,
|
|||
*/
|
||||
bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in)
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
if (last_ == 0) {
|
||||
return true;
|
||||
|
|
@ -568,7 +620,7 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
|
||||
bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum)
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
unsigned cur;
|
||||
|
||||
|
|
@ -1036,7 +1088,7 @@ bool NetCase::synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
|
|||
bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out,
|
||||
NetNet*accum)
|
||||
NetNet*accum, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
/* Detect the special case that this is a nul-effect (for
|
||||
synthesis) statement. This happens, for example, for code
|
||||
|
|
@ -1074,49 +1126,63 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
// At least one of the clauses must have contents. */
|
||||
assert(if_ != 0 || else_ != 0);
|
||||
|
||||
// This is the beginning of where it will be decided whether or not a latch is inferred.
|
||||
// We prefer that latch_inferred be a local variable rather than a function parameter.
|
||||
// It must be a function parameter to match the signature of the function that we are overriding in the base class, the result of a chain reaction caused by adding that
|
||||
// parameter to NetAssignBase::synth_async (to give that function awareness of what we are recognizing here).
|
||||
// Of course, the parameter and the local variable could have been given distinct names.
|
||||
// Instead, we simply assert that the following code governs.
|
||||
// In other words, the parameter value coming into this function does not override the value (false) that would be the initial value of a local variable here.
|
||||
// Probably the incoming parameter got this value from the default argument, but it is not essential to prove that.
|
||||
assert( latch_inferred == false );
|
||||
|
||||
/* If there is no default_sig, and if this is a fully
|
||||
asynchronous process (nex_map is not a synchronous output)
|
||||
then both clases *must* be present.
|
||||
then, if !(both clauses are present), a latch is inferred.
|
||||
|
||||
If either clause is missing, and the output is synchronous,
|
||||
then the code below can take as the input the output from
|
||||
the DFF without worry for asynchronous cycles. */
|
||||
if (default_sig == 0 && ! sync_flag) {
|
||||
if (if_ == 0) {
|
||||
cerr << get_line() << ": error: Asynchronous if statement"
|
||||
<< " is missing the if clause." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
latch_inferred = true;
|
||||
}
|
||||
|
||||
if (else_ == 0) {
|
||||
cerr << get_line() << ": error: Asynchronous if statement"
|
||||
<< " is missing the else clause." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
latch_inferred = true;
|
||||
}
|
||||
}
|
||||
|
||||
NetNet*asig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, nex_map->pin_count());
|
||||
bool asigIsLatchOutput = false;
|
||||
asig->local_flag(true);
|
||||
|
||||
if (if_ == 0) {
|
||||
/* If the if clause is missing, then take the clause to
|
||||
be an assignment from the defaults input. If there is
|
||||
no defaults input, then take the input to be from the
|
||||
no defaults input and a latch is not inferred, then take the input to be from the
|
||||
output. */
|
||||
if (default_sig) {
|
||||
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
||||
connect(asig->pin(idx), default_sig->pin(idx));
|
||||
} else {
|
||||
if ( latch_inferred )
|
||||
{
|
||||
delete asig ;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( sync_flag );
|
||||
|
||||
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
||||
connect(asig->pin(idx), nex_map->pin(idx));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
bool flag = if_->synth_async(des, scope, sync_flag, nex_ff,
|
||||
nex_map, asig, accum);
|
||||
nex_map, asig, accum, latch_inferred, ssig);
|
||||
if (!flag) {
|
||||
delete asig;
|
||||
cerr << get_line() << ": error: Asynchronous if statement"
|
||||
|
|
@ -1124,10 +1190,12 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
asigIsLatchOutput = latch_inferred;
|
||||
}
|
||||
|
||||
NetNet*bsig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, nex_map->pin_count());
|
||||
bool bsigIsLatchOutput = false;
|
||||
bsig->local_flag(true);
|
||||
|
||||
if (else_ == 0) {
|
||||
|
|
@ -1135,12 +1203,21 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
||||
connect(bsig->pin(idx), default_sig->pin(idx));
|
||||
} else {
|
||||
if ( latch_inferred )
|
||||
{
|
||||
delete bsig;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( sync_flag );
|
||||
|
||||
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
||||
connect(bsig->pin(idx), nex_map->pin(idx));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool flag = else_->synth_async(des, scope, sync_flag, nex_ff,
|
||||
nex_map, bsig, accum);
|
||||
nex_map, bsig, accum, latch_inferred, ssig);
|
||||
if (!flag) {
|
||||
delete asig;
|
||||
delete bsig;
|
||||
|
|
@ -1149,183 +1226,217 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
bsigIsLatchOutput = latch_inferred;
|
||||
}
|
||||
|
||||
unsigned mux_width = 0;
|
||||
if ( latch_inferred )
|
||||
{
|
||||
// The value of a pointer that refers to deallocated storage is indeterminate, so I can't examine asig and bsig to determine which one hasn't been deallocated.
|
||||
assert ( ( asigIsLatchOutput || bsigIsLatchOutput ) && !( asigIsLatchOutput && bsigIsLatchOutput ) ); // logical exclusive OR
|
||||
|
||||
if ( asigIsLatchOutput )
|
||||
{
|
||||
asig->set_line( *this );
|
||||
|
||||
for ( unsigned idx = 0U; idx < nex_out->pin_count(); idx += 1U )
|
||||
{
|
||||
connect( nex_out->pin( idx ), asig->pin( idx ) );
|
||||
}
|
||||
|
||||
}
|
||||
else // bsigIsLatchOutput
|
||||
{
|
||||
bsig->set_line( *this );
|
||||
|
||||
for ( unsigned idx = 0U; idx < nex_out->pin_count(); idx += 1U )
|
||||
{
|
||||
connect( nex_out->pin( idx ), bsig->pin( idx ) );
|
||||
}
|
||||
|
||||
/* Figure out how many mux bits we are going to need. */
|
||||
for (unsigned idx = 0 ; idx < nex_out->pin_count(); idx += 1) {
|
||||
int flag = 0;
|
||||
if (asig->pin(idx).is_linked())
|
||||
flag |= 0100;
|
||||
if (bsig->pin(idx).is_linked())
|
||||
flag |= 0010;
|
||||
if (accum->pin(idx).is_linked())
|
||||
flag |= 0001;
|
||||
switch (flag) {
|
||||
case 0111:
|
||||
case 0110:
|
||||
case 0101:
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0100:
|
||||
if (sync_flag)
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0011:
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0010:
|
||||
if (sync_flag)
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0001:
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0000:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
} // end if latch_inferred
|
||||
else
|
||||
{
|
||||
unsigned mux_width = 0;
|
||||
|
||||
/* Create a mux and hook it up. */
|
||||
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
||||
mux_width, 2, 1);
|
||||
mux->set_line(*this);
|
||||
/* Figure out how many mux bits we are going to need. */
|
||||
for (unsigned idx = 0 ; idx < nex_out->pin_count(); idx += 1) {
|
||||
int flag = 0;
|
||||
if (asig->pin(idx).is_linked())
|
||||
flag |= 0100;
|
||||
if (bsig->pin(idx).is_linked())
|
||||
flag |= 0010;
|
||||
if (accum->pin(idx).is_linked())
|
||||
flag |= 0001;
|
||||
switch (flag) {
|
||||
case 0111:
|
||||
case 0110:
|
||||
case 0101:
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0100:
|
||||
if (sync_flag)
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0011:
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0010:
|
||||
if (sync_flag)
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0001:
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0000:
|
||||
break;
|
||||
}
|
||||
|
||||
NetNet*mux_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, mux_width);
|
||||
mux_sig->local_flag(true);
|
||||
mux_sig->set_line(*this);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < mux_width ; idx += 1)
|
||||
/* Create a mux and hook it up. */
|
||||
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
||||
mux_width, 2, 1);
|
||||
mux->set_line(*this);
|
||||
NetNet*mux_sig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, mux_width);
|
||||
mux_sig->local_flag(true);
|
||||
mux_sig->set_line(*this);
|
||||
|
||||
for (unsigned idx = 0 ; idx < mux_width ; idx += 1)
|
||||
connect(mux->pin_Result(idx), mux_sig->pin(idx));
|
||||
|
||||
if (debug_synth) {
|
||||
if (debug_synth) {
|
||||
cerr << get_line() << ": debug: Condit synth to MUX "
|
||||
<< " width=" << mux_width
|
||||
<< " sel_width=1" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
connect(mux->pin_Sel(0), ssig->pin(0));
|
||||
connect(mux->pin_Sel(0), ssig->pin(0));
|
||||
|
||||
/* Connected the clauses to the data inputs of the
|
||||
condition. If there are bits unassigned by the case, then
|
||||
bind them from the accum bits instead. If the bit is not
|
||||
represented in the accum list, but this is a synchronous
|
||||
output, then get the bit from the nex_map, which is the
|
||||
output held in the DFF. */
|
||||
mux_width = 0;
|
||||
for (unsigned idx = 0 ; idx < nex_out->pin_count() ; idx += 1) {
|
||||
/* Connected the clauses to the data inputs of the
|
||||
condition. If there are bits unassigned by the case, then
|
||||
bind them from the accum bits instead. If the bit is not
|
||||
represented in the accum list, but this is a synchronous
|
||||
output, then get the bit from the nex_map, which is the
|
||||
output held in the DFF. */
|
||||
mux_width = 0;
|
||||
for (unsigned idx = 0 ; idx < nex_out->pin_count() ; idx += 1) {
|
||||
int flag = 0;
|
||||
if (asig->pin(idx).is_linked())
|
||||
flag |= 0100;
|
||||
flag |= 0100;
|
||||
if (bsig->pin(idx).is_linked())
|
||||
flag |= 0010;
|
||||
flag |= 0010;
|
||||
if (accum->pin(idx).is_linked())
|
||||
flag |= 0001;
|
||||
flag |= 0001;
|
||||
|
||||
switch (flag) {
|
||||
case 0111:
|
||||
case 0110:
|
||||
connect(mux->pin_Data(mux_width, 1), asig->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), bsig->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0101:
|
||||
connect(mux->pin_Data(mux_width, 1), asig->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), accum->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0100:
|
||||
if (sync_flag) {
|
||||
connect(mux->pin_Data(mux_width, 1), asig->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0),nex_map->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
} else {
|
||||
case 0111:
|
||||
case 0110:
|
||||
connect(mux->pin_Data(mux_width, 1), asig->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), bsig->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0101:
|
||||
connect(mux->pin_Data(mux_width, 1), asig->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), accum->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0100:
|
||||
if (sync_flag) {
|
||||
connect(mux->pin_Data(mux_width, 1), asig->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0),nex_map->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
} else {
|
||||
#if 0
|
||||
cerr << get_line()
|
||||
<< ": error: Condition false clause "
|
||||
<< "does not assign expected outputs." << endl;
|
||||
des->errors += 1;
|
||||
return_flag = false;
|
||||
cerr << get_line()
|
||||
<< ": error: Condition false clause "
|
||||
<< "does not assign expected outputs." << endl;
|
||||
des->errors += 1;
|
||||
return_flag = false;
|
||||
#else
|
||||
/* This should check that bsig is latched by
|
||||
the condition select or is used
|
||||
internally by the false clause. but since
|
||||
there is no latch support, assume it is
|
||||
used internally. */
|
||||
connect(nex_out->pin(idx), asig->pin(idx));
|
||||
/* This should check that asig is latched by
|
||||
the condition select or is used
|
||||
internally by the false clause. but since
|
||||
there is no latch support, assume it is
|
||||
used internally. */
|
||||
// Now there is latch support, but if a latch is inferred this code will not be reached.
|
||||
// Note, however, the similarity to the latch inferred code.
|
||||
connect(nex_out->pin(idx), asig->pin(idx));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0011:
|
||||
connect(mux->pin_Data(mux_width, 1), accum->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), bsig->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0010:
|
||||
if (sync_flag) {
|
||||
connect(mux->pin_Data(mux_width, 1),nex_map->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), bsig->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
} else {
|
||||
}
|
||||
break;
|
||||
case 0011:
|
||||
connect(mux->pin_Data(mux_width, 1), accum->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), bsig->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0010:
|
||||
if (sync_flag) {
|
||||
connect(mux->pin_Data(mux_width, 1),nex_map->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), bsig->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
} else {
|
||||
#if 0
|
||||
cerr << get_line()
|
||||
<< ": error: Condition true clause "
|
||||
<< "does not assign expected outputs." << endl;
|
||||
des->errors += 1;
|
||||
return_flag = false;
|
||||
cerr << get_line()
|
||||
<< ": error: Condition true clause "
|
||||
<< "does not assign expected outputs." << endl;
|
||||
des->errors += 1;
|
||||
return_flag = false;
|
||||
#else
|
||||
/* This should check that bsig is latched by
|
||||
the condition select or is used
|
||||
internally by the false clause. but since
|
||||
there is no latch support, assume it is
|
||||
used internally. */
|
||||
connect(nex_out->pin(idx), bsig->pin(idx));
|
||||
/* This should check that bsig is latched by
|
||||
the condition select or is used
|
||||
internally by the false clause. but since
|
||||
there is no latch support, assume it is
|
||||
used internally. */
|
||||
// Now there is latch support, but if a latch is inferred this code will not be reached.
|
||||
// Note, however, the similarity to the latch inferred code.
|
||||
connect(nex_out->pin(idx), bsig->pin(idx));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0001:
|
||||
connect(mux->pin_Data(mux_width, 1), accum->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), accum->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0000:
|
||||
if (sync_flag) {
|
||||
connect(nex_out->pin(idx), nex_map->pin(idx));
|
||||
} else {
|
||||
cerr << get_line() << ": internal error: "
|
||||
<< "Unexplained mode?" << endl;
|
||||
cerr << get_line() << ": XXXX: "
|
||||
<< "nex_out->pin_count() = "
|
||||
<< nex_out->pin_count() << endl;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0001:
|
||||
connect(mux->pin_Data(mux_width, 1), accum->pin(idx));
|
||||
connect(mux->pin_Data(mux_width, 0), accum->pin(idx));
|
||||
connect(nex_out->pin(idx), mux->pin_Result(mux_width));
|
||||
mux_width += 1;
|
||||
break;
|
||||
case 0000:
|
||||
if (sync_flag) {
|
||||
connect(nex_out->pin(idx), nex_map->pin(idx));
|
||||
} else {
|
||||
cerr << get_line() << ": internal error: "
|
||||
<< "Unexplained mode?" << endl;
|
||||
cerr << get_line() << ": XXXX: "
|
||||
<< "nex_out->pin_count() = "
|
||||
<< nex_out->pin_count() << endl;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(mux_width == mux->width());
|
||||
assert(mux_width == mux->width());
|
||||
|
||||
|
||||
des->add_node(mux);
|
||||
des->add_node(mux);
|
||||
} // end if !latch_inferred
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEvWait::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in)
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
bool flag = statement_->synth_async(des, scope, sync_flag, nex_ff,
|
||||
nex_map, nex_out, accum_in);
|
||||
|
|
@ -2404,7 +2515,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|||
|
||||
bool NetWhile::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
||||
struct sync_accounting_cell*nex_ff,
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in)
|
||||
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in, bool latch_inferred, NetNet *gsig)
|
||||
{
|
||||
cerr << get_line()
|
||||
<< ": error: Cannot synthesize for or while loops."
|
||||
|
|
@ -2557,6 +2668,9 @@ void synth2(Design*des)
|
|||
|
||||
/*
|
||||
* $Log: synth2.cc,v $
|
||||
* Revision 1.39.2.48 2007/05/30 17:48:54 steve
|
||||
* Support Latch synthesis (Alan Feldstein)
|
||||
*
|
||||
* Revision 1.39.2.47 2006/11/11 23:10:20 steve
|
||||
* Fix async blocks to take accumulated input.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue