Handle asynchronous demux/bit replacements.

This commit is contained in:
steve 2006-03-26 23:09:21 +00:00
parent faf7f30283
commit 312d09dc1d
13 changed files with 484 additions and 86 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: design_dump.cc,v 1.149.2.3 2006/03/12 07:34:16 steve Exp $"
#ident "$Id: design_dump.cc,v 1.149.2.4 2006/03/26 23:09:21 steve Exp $"
#endif
# include "config.h"
@ -224,6 +224,14 @@ void NetDecode::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetDemux::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_DEMUX (NetDemux): " << name()
<< " word width=" << width() << ", address width=" << awidth() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetDivide::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NET_DIVIDE (NetDivide): " << name() << endl;
@ -1109,6 +1117,9 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.149.2.4 2006/03/26 23:09:21 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.149.2.3 2006/03/12 07:34:16 steve
* Fix the memsynth1 case.
*

10
emit.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: emit.cc,v 1.77.2.1 2006/02/19 00:11:31 steve Exp $"
#ident "$Id: emit.cc,v 1.77.2.2 2006/03/26 23:09:21 steve Exp $"
#endif
# include "config.h"
@ -91,6 +91,11 @@ bool NetDecode::emit_node(struct target_t*tgt) const
return tgt->lpm_decode(this);
}
bool NetDemux::emit_node(struct target_t*tgt) const
{
return tgt->lpm_demux(this);
}
bool NetDivide::emit_node(struct target_t*tgt) const
{
tgt->lpm_divide(this);
@ -516,6 +521,9 @@ bool emit(const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.77.2.2 2006/03/26 23:09:21 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.77.2.1 2006/02/19 00:11:31 steve
* Handle synthesis of FF vectors with l-value decoder.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: ivl_target.h,v 1.126.2.3 2006/03/12 07:34:16 steve Exp $"
#ident "$Id: ivl_target.h,v 1.126.2.4 2006/03/26 23:09:22 steve Exp $"
#endif
#ifdef __cplusplus
@ -227,6 +227,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_CMP_GT = 2,
IVL_LPM_CMP_NE = 11,
IVL_LPM_DECODE = 15,
IVL_LPM_DEMUX = 16,
IVL_LPM_DIVIDE = 12,
IVL_LPM_FF = 3,
IVL_LPM_MOD = 13,
@ -705,6 +706,17 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* "q" port has as many bits as the width. The ivl_lpm_data2 function
* gets the nexa of the input, with the sdx the word address and the
* idx the bit within the word.
*
* - IVL_LPM_DEMUX
* This device is a form of bit replacement. The device has a data
* width (ivl_lpm_width) and an address width. The Data outputs are
* ivl_lpm_q and have the data width. The ivl_lpm_data functions are
* inputs to the device. Normally, the device passes the data inputs
* through to the Q output.
*
* The ivl_lpm_select inputs address a bit of the device. The
* addressed bit is substituted by the replacement bit. This
* replacement bit comes from the ivl_lpm_datab(net,0) nexus.
*/
extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */
@ -732,20 +744,21 @@ extern ivl_lpm_t ivl_lpm_decode(ivl_lpm_t net);
extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
/* IVL_LPM_FF IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_RAM IVL_LPM_SUB */
/* IVL_LPM_ADD IVL_LPM_DEMUX IVL_LPM_FF IVL_LPM_MULT */
/* IVL_LPM_RAM IVL_LPM_SUB */
extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_SUB */
/* IVL_LPM_ADD IVL_LPM_DEMUX IVL_LPM_MULT IVL_LPM_SUB */
/* IVL_LPM_MUX IVL_LPM_UFUNC */
extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx);
extern ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx);
/* IVL_LPM_UFUNC */
extern unsigned ivl_lpm_data2_width(ivl_lpm_t net, unsigned sdx);
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_RAM IVL_LPM_SUB
/* IVL_LPM_ADD IVL_LPM_DEMUX IVL_LPM_FF IVL_LPM_MULT IVL_LPM_RAM IVL_LPM_SUB
IVL_LPM_UFUNC */
extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_RAM */
/* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_DEMUX IVL_LPM_RAM */
extern unsigned ivl_lpm_selects(ivl_lpm_t net);
/* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_RAM */
/* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_DEMUX IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_MUX, IVL_LPM_RAM */
extern unsigned ivl_lpm_size(ivl_lpm_t net);
@ -1288,6 +1301,9 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.126.2.4 2006/03/26 23:09:22 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.126.2.3 2006/03/12 07:34:16 steve
* Fix the memsynth1 case.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.cc,v 1.226.2.4 2006/03/16 05:40:18 steve Exp $"
#ident "$Id: netlist.cc,v 1.226.2.5 2006/03/26 23:09:22 steve Exp $"
#endif
# include "config.h"
@ -721,6 +721,89 @@ unsigned NetDecode::awidth() const
return pin_count();
}
NetDemux::NetDemux(NetScope*s, perm_string name,
unsigned word_width, unsigned address_width)
: NetNode(s, name, word_width*2+address_width+1)
{
width_ = word_width;
awidth_ = address_width;
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin_Q(idx).set_dir(Link::OUTPUT);
pin_Q(idx).set_name(perm_string::literal("Q"), idx);
}
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin_Data(idx).set_dir(Link::INPUT);
pin_Data(idx).set_name(perm_string::literal("Data"), idx);
}
for (unsigned idx = 0 ; idx < awidth_ ; idx += 1) {
pin_Address(idx).set_dir(Link::INPUT);
pin_Address(idx).set_name(perm_string::literal("Address"), idx);
}
pin_WriteData().set_dir(Link::INPUT);
pin_WriteData().set_name(perm_string::literal("Writedata"), 0);
}
NetDemux::~NetDemux()
{
}
unsigned NetDemux::width() const
{
return width_;
}
unsigned NetDemux::awidth() const
{
return awidth_;
}
Link& NetDemux::pin_Q(unsigned idx)
{
assert(idx < width_);
return pin(idx);
}
const Link& NetDemux::pin_Q(unsigned idx) const
{
assert(idx < width_);
return pin(idx);
}
Link& NetDemux::pin_Data(unsigned idx)
{
assert(idx < width_);
return pin(width_+idx);
}
const Link& NetDemux::pin_Data(unsigned idx) const
{
assert(idx < width_);
return pin(width_+idx);
}
Link& NetDemux::pin_Address(unsigned idx)
{
assert(idx < awidth_);
return pin(width_+width_+idx);
}
const Link& NetDemux::pin_Address(unsigned idx) const
{
assert(idx < awidth_);
return pin(width_+width_+idx);
}
Link& NetDemux::pin_WriteData()
{
return pin(width_+width_+awidth_);
}
const Link& NetDemux::pin_WriteData() const
{
return pin(width_+width_+awidth_);
}
NetDecode* NetFF::get_demux()
{
return demux_;
@ -2388,6 +2471,9 @@ const NetProc*NetTaskDef::proc() const
/*
* $Log: netlist.cc,v $
* Revision 1.226.2.5 2006/03/26 23:09:22 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.226.2.4 2006/03/16 05:40:18 steve
* Fix crash when memory exploding doesnot work
*

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.13 2006/03/18 18:43:21 steve Exp $"
#ident "$Id: netlist.h,v 1.321.2.14 2006/03/26 23:09:23 steve Exp $"
#endif
/*
@ -635,6 +635,46 @@ class NetDecode : public NetNode {
void make_pins_(unsigned awid);
};
/*
* The NetDemux is similar to the NetDecode, except that it is
* combinational. The inputs are an address, Data, and WriteData.
* The Q output is the same as the Data input, except for the bit that
* is addressed by the address input, which gets WriteData instead.
*/
class NetDemux : public NetNode {
public:
NetDemux(NetScope*s, perm_string name,
unsigned word_width, unsigned address_width);
~NetDemux();
// This is the width of the word. The width of the NetFF mem
// is an even multiple of this.
unsigned width() const;
// This is the width of the address. The address value for the
// base of a word is the address * width().
unsigned awidth() const;
Link& pin_Address(unsigned idx);
Link& pin_Data(unsigned idx);
Link& pin_Q(unsigned idx);
Link& pin_WriteData();
const Link& pin_Address(unsigned idx) const;
const Link& pin_Data(unsigned idx) const;
const Link& pin_Q(unsigned idx) const;
const Link& pin_WriteData() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
unsigned width_, awidth_;
private:
void make_pins_(unsigned wid, unsigned awid);
};
/*
* This class represents a theoretical (though not necessarily
* practical) integer divider gate. This is not to represent any real
@ -1425,9 +1465,13 @@ class NetProc : public virtual LineInfo {
// sync_flag is used to tell the async synthesizer that the
// output nex_map is ultimately connected to a DFF Q
// output. This can affect how cycles are handled.
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
bool synth_async_noaccum(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out);
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);
@ -1571,8 +1615,7 @@ class NetAssignBase : public NetProc {
unsigned lwidth() const;
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out);
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);
bool synth_sync(Design*des, NetScope*scope,
@ -1645,7 +1688,8 @@ class NetBlock : public NetProc {
// synthesize as asynchronous logic, and return true.
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out);
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
@ -1701,8 +1745,7 @@ class NetCase : public NetProc {
virtual void nex_output(NexusSet&out);
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out);
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);
virtual bool emit_proc(struct target_t*) const;
@ -1710,6 +1753,7 @@ class NetCase : public NetProc {
private:
bool synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in,
NetNet*esig, unsigned hot_items);
private:
@ -1789,8 +1833,7 @@ class NetCondit : public NetProc {
bool is_asynchronous();
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out);
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum);
bool synth_sync(Design*des, NetScope*scope,
@ -2017,7 +2060,9 @@ class NetEvWait : public NetProc {
virtual void nex_output(NexusSet&out);
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out);
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
NetNet*accum_in);
virtual bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
@ -2416,7 +2461,8 @@ class NetWhile : public NetProc {
virtual void dump(ostream&, unsigned ind) const;
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out);
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
private:
NetExpr* cond_;
@ -3466,6 +3512,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.321.2.14 2006/03/26 23:09:23 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.321.2.13 2006/03/18 18:43:21 steve
* Better error messages when synthesis fails.
*

146
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.25 2006/03/18 18:43:22 steve Exp $"
#ident "$Id: synth2.cc,v 1.39.2.26 2006/03/26 23:09:24 steve Exp $"
#endif
# include "config.h"
@ -41,17 +41,27 @@ static int debug_synth2=0;
#define DEBUG_SYNTH2_EXIT(class,val)
#endif
bool NetProc::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
bool NetProc::synth_async_noaccum(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out)
{
return false;
/* Make an unconnected stub for the accum_in net. */
const perm_string tmp = perm_string::literal("tmp");
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
bool flag = synth_async(des, scope, sync_flag, nex_ff,
nex_map, nex_out, stub);
delete stub;
return 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)
{
return synth_async(des, scope, sync_flag, nex_map, nex_out);
return false;
}
bool NetProc::synth_sync(Design*des, NetScope*scope,
@ -59,8 +69,7 @@ bool NetProc::synth_sync(Design*des, NetScope*scope,
NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events)
{
/* Synthesize the input to the DFF. */
return synth_async(des, scope, true, nex_map, nex_out);
return synth_async_noaccum(des, scope, true, nex_ff, nex_map, nex_out);
}
static unsigned find_nexus_in_set(const NetNet*nset, const Nexus*nex)
@ -85,16 +94,7 @@ static unsigned find_nexus_in_set(const NetNet*nset, const Nexus*nex)
*/
bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
{
const perm_string tmp = perm_string::literal("tmp");
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
bool flag = synth_async(des, scope, sync_flag, nex_map, nex_out, stub);
delete stub;
return flag;
}
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)
{
@ -160,6 +160,45 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
return false;
}
/* 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);
NetDemux*dq = new NetDemux(scope, scope->local_symbol(),
lsig->pin_count(),
adr->pin_count());
des->add_node(dq);
dq->set_line(*this);
for (unsigned idx = 0; idx < adr->pin_count() ; idx += 1)
connect(dq->pin_Address(idx), adr->pin(idx));
assert(cur->lwidth() == 1);
for (unsigned idx = 0; idx < lsig->pin_count(); idx += 1) {
unsigned off = cur->get_loff()+idx;
unsigned ptr = find_nexus_in_set(nex_map, lsig->pin(off).nexus());
assert(ptr <= nex_map->pin_count());
connect(nex_out->pin(ptr), dq->pin_Q(idx));
}
for (unsigned idx = 0 ; idx < lsig->pin_count(); idx += 1)
connect(dq->pin_Data(idx), nex_map->pin(roff+idx));
connect(dq->pin_WriteData(), 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());
/* Bind the outputs that we do make to the nex_out. Use the
@ -192,7 +231,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
* substatements.
*/
bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in)
{
DEBUG_SYNTH2_ENTRY("NetBlock")
if (last_ == 0) {
@ -241,7 +281,7 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
connect(new_accum->pin(idx), accum_out->pin(ptr));
}
bool ok_flag = cur->synth_async(des, scope, sync_flag,
bool ok_flag = cur->synth_async(des, scope, sync_flag, nex_ff,
tmp_map, tmp_out, new_accum);
flag = flag && ok_flag;
@ -307,16 +347,7 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
}
bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
{
const perm_string tmp = perm_string::literal("tmp");
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
bool flag = synth_async(des, scope, sync_flag, nex_map, nex_out, stub);
delete stub;
return 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)
{
unsigned cur;
@ -371,7 +402,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
/* Handle the special case that this can be done it a smaller
1-hot MUX. */
if (nondefault_items < sel_pins)
return synth_async_1hot_(des, scope, sync_flag,
return synth_async_1hot_(des, scope, sync_flag, nex_ff,
nex_map, nex_out, accum,
esig, nondefault_items);
@ -502,6 +533,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
connect all the output bits it knows how to the
sig net. */
statement_map[item]->synth_async(des, scope, sync_flag,
nex_ff,
nex_map, sig, accum);
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1) {
@ -529,6 +561,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
}
bool NetCase::synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum,
NetNet*esig, unsigned hot_items)
{
@ -583,7 +616,7 @@ bool NetCase::synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
NetNet*item_sig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, nex_map->pin_count());
assert(items_[item].statement);
items_[item].statement->synth_async(des, scope, sync_flag,
items_[item].statement->synth_async(des, scope, sync_flag, nex_ff,
nex_map, item_sig, accum);
for (unsigned idx = 0 ; idx < item_sig->pin_count() ; idx += 1)
connect(mux->pin_Data(idx, 1<<use_item), item_sig->pin(idx));
@ -600,7 +633,7 @@ bool NetCase::synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
if (default_statement) {
default_sig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, nex_map->pin_count());
default_statement->synth_async(des, scope, sync_flag,
default_statement->synth_async(des, scope, sync_flag, nex_ff,
nex_map, default_sig, accum);
}
@ -643,27 +676,13 @@ bool NetCase::synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
return true;
}
/*
* If the synth_async method is called without an accumulated input
* (in other words not from within a block) then stub the input signal
* with an unconnected net.
*/
bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
{
const perm_string tmp = perm_string::literal("tmp");
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
bool flag = synth_async(des, scope, sync_flag, nex_map, nex_out, stub);
delete stub;
return flag;
}
/*
* Handle synthesis for an asynchronous condition statement. If we get
* here, we know that the CE of a DFF has already been filled, so the
* condition expression goes to the select of an asynchronous mux.
*/
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)
{
@ -726,7 +745,7 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
}
} else {
bool flag = if_->synth_async(des, scope, sync_flag,
bool flag = if_->synth_async(des, scope, sync_flag, nex_ff,
nex_map, asig, accum);
if (!flag) {
delete asig;
@ -750,7 +769,7 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
connect(bsig->pin(idx), nex_map->pin(idx));
}
} else {
bool flag = else_->synth_async(des, scope, sync_flag,
bool flag = else_->synth_async(des, scope, sync_flag, nex_ff,
nex_map, bsig, accum);
if (!flag) {
delete asig;
@ -818,10 +837,11 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
}
bool NetEvWait::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in)
{
bool flag = statement_->synth_async(des, scope, sync_flag,
nex_map, nex_out);
bool flag = statement_->synth_async(des, scope, sync_flag, nex_ff,
nex_map, nex_out, accum_in);
return flag;
}
@ -836,8 +856,8 @@ bool NetProcTop::synth_async(Design*des)
for (unsigned idx = 0 ; idx < nex_out->pin_count() ; idx += 1)
connect(nex_set[idx], nex_out->pin(idx));
bool flag = statement_->synth_async(des, scope(), false,
nex_out, nex_out);
bool flag = statement_->synth_async_noaccum(des, scope(), false, 0,
nex_out, nex_out);
delete nex_out;
return flag;
@ -915,7 +935,8 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope,
assignments. */
if (demux == 0) {
/* Synthesize the input to the DFF. */
return synth_async(des, scope, true, nex_map, nex_out);
return synth_async_noaccum(des, scope, true, nex_ff,
nex_map, nex_out);
}
assert(demux->bmux() != 0);
@ -1256,7 +1277,8 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
asig->local_flag(true);
assert(if_ != 0);
bool flag = if_->synth_async(des, scope, true, nex_map, asig);
bool flag = if_->synth_async_noaccum(des, scope, true, nex_ff,
nex_map, asig);
assert(asig->pin_count() == ff->width());
@ -1347,7 +1369,8 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
NetNet*asig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, nex_map->pin_count());
asig->local_flag(true);
bool flag = if_->synth_async(des, scope, true, nex_map, asig);
bool flag = if_->synth_async_noaccum(des, scope, true, nex_ff,
nex_map, asig);
if (!flag) {
/* This path leads nowhere */
@ -1399,7 +1422,8 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
/* If this is an if/then/else, then it is likely a
combinational if, and I should synthesize it that way. */
if (if_ && else_) {
bool flag = synth_async(des, scope, true, nex_map, nex_out);
bool flag =synth_async_noaccum(des, scope, true, nex_ff,
nex_map, nex_out);
return flag;
}
@ -1531,7 +1555,8 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
}
bool NetWhile::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out)
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in)
{
cerr << get_line()
<< ": error: Cannot synthesize for or while loops."
@ -1671,6 +1696,9 @@ void synth2(Design*des)
/*
* $Log: synth2.cc,v $
* Revision 1.39.2.26 2006/03/26 23:09:24 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.39.2.25 2006/03/18 18:43:22 steve
* Better error messages when synthesis fails.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-api.cc,v 1.108.2.3 2006/03/12 07:34:19 steve Exp $"
#ident "$Id: t-dll-api.cc,v 1.108.2.4 2006/03/26 23:09:24 steve Exp $"
#endif
# include "config.h"
@ -765,6 +765,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
assert(idx < net->u_.arith.width);
return net->u_.arith.a[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.width);
return net->u_.demux.d[idx];
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
assert(idx < net->u_.shift.width);
@ -801,6 +805,10 @@ extern "C" ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx)
assert(idx < net->u_.arith.width);
return net->u_.arith.b[idx];
case IVL_LPM_DEMUX:
assert(idx < 1);
return net->u_.demux.bit_in;
default:
assert(0);
return 0;
@ -939,6 +947,10 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
else
return net->u_.mux.q.pins[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.width);
return net->u_.demux.q[idx];
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
assert(idx < net->u_.shift.width);
@ -978,6 +990,10 @@ extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx)
else
return net->u_.mux.s.pins[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.awid);
return net->u_.demux.a[idx];
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
assert(idx < net->u_.shift.select);
@ -997,6 +1013,8 @@ extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net)
case IVL_LPM_DECODE:
case IVL_LPM_MUX:
return net->u_.mux.swid;
case IVL_LPM_DEMUX:
return net->u_.demux.awid;
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.select;
@ -1013,6 +1031,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_FF:
case IVL_LPM_RAM:
case IVL_LPM_MUX:
case IVL_LPM_DEMUX:
return 0;
case IVL_LPM_ADD:
case IVL_LPM_CMP_EQ:
@ -1066,6 +1085,8 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
case IVL_LPM_DECODE:
case IVL_LPM_MUX:
return net->u_.mux.width;
case IVL_LPM_DEMUX:
return net->u_.demux.width;
case IVL_LPM_ADD:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
@ -1981,6 +2002,9 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net)
/*
* $Log: t-dll-api.cc,v $
* Revision 1.108.2.4 2006/03/26 23:09:24 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.108.2.3 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll.cc,v 1.131.2.5 2006/03/12 07:34:19 steve Exp $"
#ident "$Id: t-dll.cc,v 1.131.2.6 2006/03/26 23:09:24 steve Exp $"
#endif
# include "config.h"
@ -1547,6 +1547,66 @@ ivl_lpm_t dll_target::lpm_decode_ff_(const NetDecode*net)
return obj;
}
bool dll_target::lpm_demux(const NetDemux*net)
{
unsigned idx;
unsigned width = net->width();
unsigned awid = net->awidth();
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_DEMUX;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->u_.demux.width = width;
obj->u_.demux.awid = awid;
ivl_nexus_t*tmp = new ivl_nexus_t [2*net->width() + net->awidth()];
obj->u_.demux.q = tmp;
obj->u_.demux.d = tmp + width;
obj->u_.demux.a = tmp + 2*width;
for (idx = 0 ; idx < width ; idx += 1) {
const Nexus*nex = net->pin_Q(idx).nexus();
assert(nex->t_cookie());
obj->u_.demux.q[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.q[idx], obj, idx,
IVL_DR_STRONG, IVL_DR_STRONG);
}
for (idx = 0 ; idx < width ; idx += 1) {
const Nexus*nex = net->pin_Data(idx).nexus();
assert(nex->t_cookie());
obj->u_.demux.d[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.d[idx], obj, idx,
IVL_DR_HiZ, IVL_DR_HiZ);
}
for (idx = 0 ; idx < awid ; idx += 1) {
const Nexus*nex = net->pin_Address(idx).nexus();
assert(nex->t_cookie());
obj->u_.demux.a[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.a[idx], obj, idx,
IVL_DR_HiZ, IVL_DR_HiZ);
}
{
const Nexus*nex = net->pin_WriteData().nexus();
assert(nex->t_cookie());
obj->u_.demux.bit_in = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.bit_in, obj, 0,
IVL_DR_HiZ, IVL_DR_HiZ);
}
obj->nattr = net->attr_cnt();
obj->attr = fill_in_attributes(net);
scope_add_lpm(obj->scope, obj);
return true;
}
void dll_target::lpm_ff(const NetFF*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
@ -2271,6 +2331,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
/*
* $Log: t-dll.cc,v $
* Revision 1.131.2.6 2006/03/26 23:09:24 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.131.2.5 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*

13
t-dll.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll.h,v 1.115.2.3 2006/03/12 07:34:19 steve Exp $"
#ident "$Id: t-dll.h,v 1.115.2.4 2006/03/26 23:09:25 steve Exp $"
#endif
# include "target.h"
@ -77,6 +77,7 @@ struct dll_target : public target_t, public expr_scan_t {
void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*);
bool lpm_decode(const NetDecode*);
bool lpm_demux(const NetDemux*);
void lpm_divide(const NetDivide*);
void lpm_ff(const NetFF*);
void lpm_modulo(const NetModulo*);
@ -342,6 +343,13 @@ struct ivl_lpm_s {
} s;
} mux;
struct ivl_lpm_demux_s {
unsigned width;
unsigned awid;
ivl_nexus_t bit_in;
ivl_nexus_t *q,*d,*a;
} demux;
struct ivl_lpm_shift_s {
unsigned width;
unsigned select;
@ -694,6 +702,9 @@ struct ivl_variable_s {
/*
* $Log: t-dll.h,v $
* Revision 1.115.2.4 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.115.2.3 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.cc,v 1.69.2.1 2006/02/19 00:11:34 steve Exp $"
#ident "$Id: target.cc,v 1.69.2.2 2006/03/26 23:09:25 steve Exp $"
#endif
# include "config.h"
@ -108,6 +108,13 @@ bool target_t::lpm_decode(const NetDecode*)
return false;
}
bool target_t::lpm_demux(const NetDemux*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetDemux." << endl;
return false;
}
void target_t::lpm_divide(const NetDivide*)
{
cerr << "target (" << typeid(*this).name() << "): "
@ -427,6 +434,9 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.69.2.2 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.69.2.1 2006/02/19 00:11:34 steve
* Handle synthesis of FF vectors with l-value decoder.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.h,v 1.65.2.1 2006/02/19 00:11:34 steve Exp $"
#ident "$Id: target.h,v 1.65.2.2 2006/03/26 23:09:25 steve Exp $"
#endif
# include "netlist.h"
@ -80,6 +80,7 @@ struct target_t {
virtual void lpm_clshift(const NetCLShift*);
virtual void lpm_compare(const NetCompare*);
virtual bool lpm_decode(const NetDecode*);
virtual bool lpm_demux(const NetDemux*);
virtual void lpm_divide(const NetDivide*);
virtual void lpm_modulo(const NetModulo*);
virtual void lpm_ff(const NetFF*);
@ -171,6 +172,9 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.65.2.2 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.65.2.1 2006/02/19 00:11:34 steve
* Handle synthesis of FF vectors with l-value decoder.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: stub.c,v 1.90.2.7 2006/03/12 07:34:20 steve Exp $"
#ident "$Id: stub.c,v 1.90.2.8 2006/03/26 23:09:25 steve Exp $"
#endif
# include "config.h"
@ -233,6 +233,36 @@ static void show_lpm_ram(ivl_lpm_t net)
}
}
static void show_lpm_demux(ivl_lpm_t net)
{
unsigned idx;
unsigned width = ivl_lpm_width(net);
unsigned awid = ivl_lpm_selects(net);
fprintf(out, " LPM_DEMUX %s (word-width=%u, addr-width=%u)\n",
ivl_lpm_basename(net), width, awid);
for (idx = 0 ; idx < width ; idx += 1)
fprintf(out, " Q %u: %s\n", idx,
ivl_nexus_name(ivl_lpm_q(net, idx)));
for (idx = 0 ; idx < width ; idx += 1) {
ivl_nexus_t nex = ivl_lpm_data(net, idx);
fprintf(out, " Data %u: %s\n", idx,
nex? ivl_nexus_name(nex) : "");
}
for (idx = 0 ; idx < awid ; idx += 1) {
ivl_nexus_t nex = ivl_lpm_select(net, idx);
fprintf(out, " Address %u: %s\n", idx,
nex? ivl_nexus_name(nex) : "");
}
{
ivl_nexus_t nex = ivl_lpm_datab(net, 0);
fprintf(out, " WriteIn: %s\n",
nex? ivl_nexus_name(nex) : "");
}
}
static void show_lpm(ivl_lpm_t net)
{
unsigned idx;
@ -341,6 +371,10 @@ static void show_lpm(ivl_lpm_t net)
break;
}
case IVL_LPM_DEMUX:
show_lpm_demux(net);
break;
case IVL_LPM_RAM:
show_lpm_ram(net);
break;
@ -1073,6 +1107,9 @@ int target_design(ivl_design_t des)
/*
* $Log: stub.c,v $
* Revision 1.90.2.8 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.90.2.7 2006/03/12 07:34:20 steve
* Fix the memsynth1 case.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_scope.c,v 1.103.2.4 2006/03/12 07:34:20 steve Exp $"
#ident "$Id: vvp_scope.c,v 1.103.2.5 2006/03/26 23:09:26 steve Exp $"
#endif
# include "vvp_priv.h"
@ -402,6 +402,7 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_FF:
case IVL_LPM_MUX:
case IVL_LPM_DEMUX:
for (idx = 0 ; idx < ivl_lpm_width(lpm) ; idx += 1)
if (ivl_lpm_q(lpm, idx) == nex) {
sprintf(result, "L_%s.%s/%u",
@ -1296,6 +1297,49 @@ static void draw_lpm_decode(ivl_lpm_t net)
fprintf(vvp_out, ";\n");
}
/*
* Draw a demux as an address decoder and .decode bit slices.
*/
static void draw_lpm_demux(ivl_lpm_t net)
{
unsigned idx;
unsigned width = ivl_lpm_width(net);
/* Draw a .decode/adr node to do address decoding. */
draw_lpm_decode(net);
for (idx = 0 ; idx < width ; idx += 1) {
ivl_nexus_t nex;
/* This is a demux bit slice idx */
fprintf(vvp_out, "L_%s.%s/%u .demux ",
vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))),
vvp_mangle_id(ivl_lpm_basename(net)), idx);
/* Reference the address decoder... */
fprintf(vvp_out, "L_%s.%s, %u, ",
vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))),
vvp_mangle_id(ivl_lpm_basename(net)), idx);
/* not-selected bit value. */
nex = ivl_lpm_data(net, idx);
if (nex)
draw_input_from_net(nex);
else
fprintf(vvp_out, "C<z>");
/* selected bit value. */
fprintf(vvp_out, ", ");
nex = ivl_lpm_datab(net, 0);
if (nex)
draw_input_from_net(nex);
else
fprintf(vvp_out, "C<z>");
fprintf(vvp_out, ";\n");
}
}
/*
* Draw == and != gates. This is done as XNOR functors to compare each
* pair of bits. The result is combined with a wide and, or a NAND if
@ -1698,6 +1742,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_decode(net);
return;
case IVL_LPM_DEMUX:
draw_lpm_demux(net);
return;
default:
fprintf(stderr, "XXXX LPM not supported: %s.%s\n",
ivl_scope_name(ivl_lpm_scope(net)), ivl_lpm_basename(net));
@ -1821,6 +1869,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
/*
* $Log: vvp_scope.c,v $
* Revision 1.103.2.5 2006/03/26 23:09:26 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.103.2.4 2006/03/12 07:34:20 steve
* Fix the memsynth1 case.
*