diff --git a/design_dump.cc b/design_dump.cc index c616e01a6..a82582220 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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. * diff --git a/emit.cc b/emit.cc index 2df371447..841eda956 100644 --- a/emit.cc +++ b/emit.cc @@ -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. * diff --git a/ivl_target.h b/ivl_target.h index 975bf13ee..8c155b62f 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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. * diff --git a/netlist.cc b/netlist.cc index 65b1d212d..70fff8faf 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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 * diff --git a/netlist.h b/netlist.h index a37d6c207..c595bd8fe 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.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. * diff --git a/synth2.cc b/synth2.cc index ca581a02a..23082eee9 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.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&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<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. * diff --git a/t-dll-api.cc b/t-dll-api.cc index 9a8778388..b070e72ad 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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. * diff --git a/t-dll.cc b/t-dll.cc index 7b9ac023e..2b5b6d5d6 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -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. * diff --git a/t-dll.h b/t-dll.h index e70d0468b..e7277d7a9 100644 --- a/t-dll.h +++ b/t-dll.h @@ -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. * diff --git a/target.cc b/target.cc index 89dc6f2ef..0b3fecdb1 100644 --- a/target.cc +++ b/target.cc @@ -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. * diff --git a/target.h b/target.h index 2966f486c..3916566a3 100644 --- a/target.h +++ b/target.h @@ -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. * diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 71db83dc1..62bab132c 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -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. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 7c7484f7c..89d761210 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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"); + + /* selected bit value. */ + fprintf(vvp_out, ", "); + nex = ivl_lpm_datab(net, 0); + if (nex) + draw_input_from_net(nex); + else + fprintf(vvp_out, "C"); + + 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. *