From 52b8ed9077f7e11112501c2423dc6bb48ca7435d Mon Sep 17 00:00:00 2001 From: steve Date: Wed, 18 Jan 2006 01:23:23 +0000 Subject: [PATCH] Rework l-value handling to allow for more l-value type flexibility. --- design_dump.cc | 14 ++- net_nex_output.cc | 13 ++- netlist.cc | 75 +++++++++---- netlist.h | 32 +++++- synth2.cc | 277 +++++++++++++++++++++++++++++----------------- 5 files changed, 279 insertions(+), 132 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index e9c960b07..d82bb4098 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 2004/10/04 01:10:52 steve Exp $" +#ident "$Id: design_dump.cc,v 1.149.2.1 2006/01/18 01:23:23 steve Exp $" #endif # include "config.h" @@ -355,8 +355,13 @@ void NetModulo::dump_node(ostream&o, unsigned ind) const void NetRamDq::dump_node(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): " - << name() << endl; + o << setw(ind) << "" << "LPM_RAM_DQ ("; + + if (mem_) o << "mem=" << mem_->name(); + if (sig_) o << "sig=" << sig_->name(); + + o << "): " << name() << endl; + dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } @@ -1089,6 +1094,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.149.2.1 2006/01/18 01:23:23 steve + * Rework l-value handling to allow for more l-value type flexibility. + * * Revision 1.149 2004/10/04 01:10:52 steve * Clean up spurious trailing white space. * diff --git a/net_nex_output.cc b/net_nex_output.cc index 5ecb435ca..63c5ba2fe 100644 --- a/net_nex_output.cc +++ b/net_nex_output.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: net_nex_output.cc,v 1.11 2004/09/16 03:17:33 steve Exp $" +#ident "$Id: net_nex_output.cc,v 1.11.2.1 2006/01/18 01:23:23 steve Exp $" #endif # include "config.h" @@ -47,6 +47,14 @@ void NetAssignBase::nex_output(NexusSet&out) { for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { if (NetNet*lsig = cur->sig()) { +#if 0 + if (cur->bmux()) { + cerr << get_line() << ": internal error: " + << "L-Value mux not supported by nex_output: "; + cur->dump_lval(cerr); + cerr << endl; + } +#endif for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) { unsigned off = cur->get_loff() + idx; out.add(lsig->pin(off).nexus()); @@ -122,6 +130,9 @@ void NetWhile::nex_output(NexusSet&out) /* * $Log: net_nex_output.cc,v $ + * Revision 1.11.2.1 2006/01/18 01:23:23 steve + * Rework l-value handling to allow for more l-value type flexibility. + * * Revision 1.11 2004/09/16 03:17:33 steve * net_output handles l-value concatenations. * diff --git a/netlist.cc b/netlist.cc index 151af46c1..9ab5e976f 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 2004/10/04 01:10:54 steve Exp $" +#ident "$Id: netlist.cc,v 1.226.2.1 2006/01/18 01:23:23 steve Exp $" #endif # include "config.h" @@ -234,6 +234,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) assert(s); release_list_ = 0; + ram_ = 0; verinum::V init_value = verinum::Vz; Link::DIR dir = Link::PASSIVE; @@ -275,6 +276,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, long ms, long ls) assert(s); release_list_ = 0; + ram_ = 0; verinum::V init_value = verinum::Vz; Link::DIR dir = Link::PASSIVE; @@ -1385,10 +1387,7 @@ const Link& NetMux::pin_Data(unsigned w, unsigned s) const return pin(2+width_+swidth_+s*width_+w); } - -NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid) -: NetNode(s, n, 3+2*mem->width()+awid), - mem_(mem), awidth_(awid) +void NetRamDq::make_pins_(unsigned wid) { pin(0).set_dir(Link::INPUT); pin(0).set_name(perm_string::literal("InClock"), 0); pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("OutClock"), 0); @@ -1399,39 +1398,65 @@ NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid) pin(3+idx).set_name(perm_string::literal("Address"), idx); } - for (unsigned idx = 0 ; idx < width() ; idx += 1) { + for (unsigned idx = 0 ; idx < wid ; idx += 1) { pin(3+awidth_+idx).set_dir(Link::INPUT); pin(3+awidth_+idx).set_name(perm_string::literal("Data"), idx); } - for (unsigned idx = 0 ; idx < width() ; idx += 1) { - pin(3+awidth_+width()+idx).set_dir(Link::OUTPUT); - pin(3+awidth_+width()+idx).set_name(perm_string::literal("Q"), idx); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + pin(3+awidth_+wid+idx).set_dir(Link::OUTPUT); + pin(3+awidth_+wid+idx).set_name(perm_string::literal("Q"), idx); } +} + +NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid) +: NetNode(s, n, 3+2*mem->width()+awid), + mem_(mem), sig_(0), awidth_(awid) +{ + make_pins_(mem->width()); next_ = mem_->ram_list_; mem_->ram_list_ = this; } +NetRamDq::NetRamDq(NetScope*s, perm_string n, NetNet*sig, unsigned awid) +: NetNode(s, n, 3+2*1+awid), + mem_(0), sig_(sig), awidth_(awid) +{ + make_pins_(1); + + assert(sig->ram_ == 0); + sig->ram_ = this; +} + NetRamDq::~NetRamDq() { - if (mem_->ram_list_ == this) { - mem_->ram_list_ = next_; + if (mem_) { + if (mem_->ram_list_ == this) { + mem_->ram_list_ = next_; - } else { - NetRamDq*cur = mem_->ram_list_; - while (cur->next_ != this) { - assert(cur->next_); - cur = cur->next_; + } else { + NetRamDq*cur = mem_->ram_list_; + while (cur->next_ != this) { + assert(cur->next_); + cur = cur->next_; + } + assert(cur->next_ == this); + cur->next_ = next_; } - assert(cur->next_ == this); - cur->next_ = next_; + } + + if (sig_) { + assert(sig_->ram_ == this); + sig_->ram_ = 0; } } unsigned NetRamDq::width() const { - return mem_->width(); + if (mem_) return mem_->width(); + if (sig_) return 1; + return 0; } unsigned NetRamDq::awidth() const @@ -1441,7 +1466,9 @@ unsigned NetRamDq::awidth() const unsigned NetRamDq::size() const { - return mem_->count(); + if (mem_) return mem_->count(); + if (sig_) return sig_->pin_count(); + return 0; } const NetMemory* NetRamDq::mem() const @@ -1449,6 +1476,11 @@ const NetMemory* NetRamDq::mem() const return mem_; } +const NetNet* NetRamDq::sig() const +{ + return sig_; +} + unsigned NetRamDq::count_partners() const { unsigned count = 0; @@ -2281,6 +2313,9 @@ const NetProc*NetTaskDef::proc() const /* * $Log: netlist.cc,v $ + * Revision 1.226.2.1 2006/01/18 01:23:23 steve + * Rework l-value handling to allow for more l-value type flexibility. + * * Revision 1.226 2004/10/04 01:10:54 steve * Clean up spurious trailing white space. * diff --git a/netlist.h b/netlist.h index fcf9bf863..b63d8c0e9 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.7 2005/12/31 04:28:14 steve Exp $" +#ident "$Id: netlist.h,v 1.321.2.8 2006/01/18 01:23:24 steve Exp $" #endif /* @@ -58,6 +58,7 @@ class NetEvProbe; class NetExpr; class NetESignal; class NetEVariable; +class NetFF; class NetFuncDef; class NetRamDq; @@ -67,6 +68,12 @@ class NetEvWait; struct target; struct functor_t; +struct sync_accounting_cell { + NetProc*proc; + NetFF*ff; + unsigned pin; +}; + /* ========= * A NetObj is anything that has any kind of behavior in the * netlist. Nodes can be gates, registers, etc. and are linked @@ -440,6 +447,9 @@ class NetNet : public NetObj { friend class NetRelease; NetRelease*release_list_; + friend class NetRamDq; + class NetRamDq*ram_; + private: Type type_; PortType port_type_; @@ -876,12 +886,14 @@ class NetRamDq : public NetNode { public: NetRamDq(NetScope*s, perm_string name, NetMemory*mem, unsigned awid); + NetRamDq(NetScope*s, perm_string name, NetNet*mem, unsigned awid); ~NetRamDq(); unsigned width() const; unsigned awidth() const; unsigned size() const; const NetMemory*mem() const; + const NetNet*sig() const; Link& pin_InClock(); Link& pin_OutClock(); @@ -913,9 +925,12 @@ class NetRamDq : public NetNode { private: NetMemory*mem_; + NetNet* sig_; NetRamDq*next_; unsigned awidth_; + private: + void make_pins_(unsigned wid); }; /* @@ -1365,7 +1380,8 @@ class NetProc : public virtual LineInfo { // was created to receive the Data inputs. The method *may* // delete that DFF in favor of multiple smaller devices, but // in that case it will set the ff argument to nil. - virtual bool synth_sync(Design*des, NetScope*scope, NetFF*&ff, + virtual bool synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events); @@ -1570,7 +1586,8 @@ class NetBlock : public NetProc { bool synth_async(Design*des, NetScope*scope, bool sync_flag, NetNet*nex_map, NetNet*nex_out); - bool synth_sync(Design*des, NetScope*scope, NetFF*&ff, + bool synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events); @@ -1711,7 +1728,8 @@ class NetCondit : public NetProc { bool synth_async(Design*des, NetScope*scope, bool sync_flag, NetNet*nex_map, NetNet*nex_out, NetNet*accum); - bool synth_sync(Design*des, NetScope*scope, NetFF*&ff, + bool synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events); @@ -1936,7 +1954,8 @@ class NetEvWait : public NetProc { virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag, NetNet*nex_map, NetNet*nex_out); - virtual bool synth_sync(Design*des, NetScope*scope, NetFF*&ff, + virtual bool synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events); @@ -3379,6 +3398,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.321.2.8 2006/01/18 01:23:24 steve + * Rework l-value handling to allow for more l-value type flexibility. + * * Revision 1.321.2.7 2005/12/31 04:28:14 steve * Fix crashes caused bu synthesis of sqrt32.v. * diff --git a/synth2.cc b/synth2.cc index fedb5b779..b75395153 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.15 2006/01/01 02:25:07 steve Exp $" +#ident "$Id: synth2.cc,v 1.39.2.16 2006/01/18 01:23:25 steve Exp $" #endif # include "config.h" @@ -54,7 +54,8 @@ bool NetProc::synth_async(Design*des, NetScope*scope, bool sync_flag, return synth_async(des, scope, sync_flag, nex_map, nex_out); } -bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF*&ff, +bool NetProc::synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events) { @@ -120,6 +121,39 @@ 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; + } + + /* Detect and handle the special case that this is a + memory-like access to a vector. */ + if (cur->bmux()) { + NetNet*adr = cur->bmux()->synthesize(des); + NetRamDq*dq = new NetRamDq(scope, scope->local_symbol(), + lsig, 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)); +#if 0 + /* Connect the Q bit to all the bits of the + output. This is a signal to a later stage that + the DFF should be replaced with a RAM to + support this port. */ + for (unsigned idx = 0; idx < lsig->pin_count(); idx += 1){ + unsigned ptr = find_nexus_in_set(nex_map, lsig->pin(idx).nexus()); + connect(dq->pin_Q(0), nex_out->pin(ptr)); + } +#endif + connect(dq->pin_Data(0), rsig->pin(roff)); + roff += cur->lwidth(); + continue; + } + /* 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. */ @@ -300,9 +334,16 @@ bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag, } } + /* At this point, sel_ref represents the constant part of the + select input. That is, (select&sel_mask) == sel_ref for all + guard values that are reachable. We can use this to skip + unreachable guards. */ + + /* Build a map of guard values to mux select values. This helps account for constant select bits that are being - elided. */ + elided. The guard2sel mapping will only be valid for + reachable guards. */ mapguard2sel; cur = 0; for (unsigned idx = 0 ; idx < (1U<pin_count()) ; idx += 1) { @@ -355,6 +396,12 @@ bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag, NetEConst*ge = dynamic_cast(items_[item].guard); assert(ge); verinum gval = ge->value(); + + /* Skip guards that are unreachable. */ + if ((sel_ref&~sel_mask) != (gval.as_ulong()&~sel_mask)) { + continue; + } + unsigned sel_idx = guard2sel[gval.as_ulong()]; assert(items_[item].statement); @@ -649,15 +696,6 @@ bool NetProcTop::synth_async(Design*des) static bool merge_ff_slices(NetFF*ff1, unsigned idx1, NetFF*ff2, unsigned idx2) { - /* If the Data inputs to both FFs are connected, then there - are multiple descriptions of the inputs to this DFF - device. That is an error. */ - if (ff1->pin_Data(idx1).is_linked() && ff2->pin_Data(idx2).is_linked()) { - cerr << ff2->get_line() << ": error: " - << "Synchronous output conflicts with " - << ff1->get_line() << "." << endl; - return false; - } /* If the Aset inputs are connected, and not to each other (possible since pre-existing Asets are carried forwards) @@ -680,12 +718,22 @@ static bool merge_ff_slices(NetFF*ff1, unsigned idx1, return false; } +#if XXXX if (ff2->pin_Data(idx2).is_linked()) connect(ff1->pin_Data(idx1), ff2->pin_Data(idx2)); if (ff2->pin_Aset().is_linked()) connect(ff1->pin_Aset(), ff2->pin_Aset()); if (ff2->pin_Aclr().is_linked()) connect(ff1->pin_Aclr(), ff2->pin_Aclr()); + if (ff2->pin_Sclr().is_linked()) + connect(ff1->pin_Sclr(), ff2->pin_Sclr()); + if (ff2->pin_Sset().is_linked()) + connect(ff1->pin_Sset(), ff2->pin_Sset()); + if (ff2->pin_Clock().is_linked()) + connect(ff1->pin_Clock(), ff2->pin_Clock()); +#endif + if (ff2->pin_Enable().is_linked()) + connect(ff1->pin_Enable(),ff2->pin_Enable()); return true; } @@ -704,7 +752,8 @@ static bool merge_ff_slices(NetFF*ff1, unsigned idx1, * This needs to be split into a DFF bank for each statement, because * the statements may each infer different reset and enable signals. */ -bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, +bool NetBlock::synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events_in) { @@ -712,25 +761,21 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, if (last_ == 0) return true; + /* Assert that this region still represents a single DFF. */ + for (unsigned idx = 1 ; idx < nex_out->pin_count() ; idx += 1) { + assert(nex_ff[0].ff == nex_ff[idx].ff); + } + + NetFF*ff = nex_ff[0].ff; + + assert(ff->width() == nex_out->pin_count()); + unsigned block_width = nex_out->pin_count(); + bool flag = true; const perm_string tmp1 = perm_string::literal("tmp1"); const perm_string tmp2 = perm_string::literal("tmp2"); - /* Keep an accounting of which statement accounts for which - bit slice of the FF bank. This is used for error - checking. */ - struct accounting_struct { - NetProc*proc; - NetFF*ff; - unsigned pin; - }; - struct accounting_struct*pin_accounting - = new accounting_struct [ff->pin_count()]; - for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) { - pin_accounting[idx].proc = 0; - pin_accounting[idx].ff = 0; - } NetProc*cur = last_; do { cur = cur->next_; @@ -767,6 +812,9 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, ff2->set_line(*cur); des->add_node(ff2); + struct sync_accounting_cell*tmp_ff + = new struct sync_accounting_cell[ff2->width()]; + verinum aset_value2 (verinum::V1, ff2->width()); verinum sset_value2 (verinum::V1, ff2->width()); for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) { @@ -781,17 +829,13 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, if (ptr < tmp_sset.len()) sset_value2.set(idx, tmp_sset[ptr]); - if (pin_accounting[ptr].proc != 0) { - - } else { - pin_accounting[ptr].proc = cur; - pin_accounting[ptr].ff = ff2; - pin_accounting[ptr].pin = idx; - - /* Connect Data and Q bits to the new FF. */ - connect(ff->pin_Data(ptr), ff2->pin_Data(idx)); - connect(ff->pin_Q(ptr), ff2->pin_Q(idx)); - } + // Connect the tmp_out vector, what the + // sub-synthesis is linking, to the inputs of this + // new FF. + connect(tmp_out->pin(idx), ff2->pin_Data(idx)); + tmp_ff[idx].ff = ff2; + tmp_ff[idx].pin = idx; + tmp_ff[idx].proc = cur; } /* PUll the non-sliced inputs (clock, set, reset, etc) @@ -818,8 +862,8 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, && ff2->pin_Aset().is_linked() && !ff2->pin_Aclr().is_linked()) { - connect(ff2->pin_Aclr(), ff2->pin_Aset()); ff2->pin_Aset().unlink(); + connect(ff2->pin_Aclr(), ff->pin_Aset()); } else { ff2->aset_value(aset_value2); @@ -830,73 +874,83 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, statement of the block. The tmp_map is the output nexa that we expect, and the tmp_out is where we want those outputs connected. */ - NetFF*ff2_tmp = ff2; - bool ok_flag = cur->synth_sync(des, scope, ff2_tmp, tmp_map, - tmp_out, events_in); + bool ok_flag = cur->synth_sync(des, scope, + tmp_ff, tmp_map, tmp_out, + events_in); + ff2 = 0; // NOTE: The synth_sync may delete ff2. flag = flag && ok_flag; if (ok_flag == false) continue; - if (ff2_tmp != 0) { - unsigned ff2_pins_used = ff2->width(); - for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) { - unsigned ptr = find_nexus_in_set(nex_map, - tmp_map->pin(idx).nexus()); - if (pin_accounting[ptr].ff == ff2) - continue; - - assert(ff2_pins_used > 0); - ff2_pins_used -= 1; - bool tflag = merge_ff_slices(pin_accounting[ptr].ff, - pin_accounting[ptr].pin, - ff2, idx); - if (! tflag) { - flag = false; - } - } - - if (ff2_pins_used == 0) - delete ff2; - - } else { - /* Oh, the cur->synth_sync deleted my ff2 DFF, so - erase any mention of it from the pin - accounting. */ - for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) { - if (pin_accounting[idx].ff != ff2) - continue; - - pin_accounting[idx].ff = 0; - pin_accounting[idx].pin = 0; - } - - ff2 = 0; - } - /* Use the nex_map to link up the output from the substatement to the output of the block as a whole. It is occasionally possible to have outputs beyond the input set, for example when the l-value of an assignment is smaller then the r-value. */ for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) { + ff2 = tmp_ff[idx].ff; + unsigned ff2_pin = tmp_ff[idx].pin; unsigned ptr = find_nexus_in_set(nex_map, - tmp_map->pin(idx).nexus()); + tmp_map->pin(idx).nexus()); - if (ptr < nex_out->pin_count()) - connect(nex_out->pin(ptr), tmp_out->pin(idx)); + if (ptr >= nex_out->pin_count()) + continue; + + // This is the current DFF for this bit slice... + NetFF*ff1 = nex_ff[ptr].ff; + unsigned ff1_pin = nex_ff[ptr].pin; + + // Connect the new NetFF to the baseline + // NetFF Q and D pins. + connect(ff1->pin_Data(ff1_pin), ff2->pin_Data(ff2_pin)); + connect(ff1->pin_Q(ff1_pin), ff2->pin_Q(ff2_pin)); + // Merge the new ff2 with the current ff1. This + // brings all the non-sliced bits forward from + // ff1, as well as any other merging needed. + merge_ff_slices(ff2, ff2_pin, ff1, ff1_pin); + + // Save the bit slice map as the new referece. + nex_ff[ptr] = tmp_ff[idx]; + + // If the (old) current DFF is not the same as the + // baseline DFF, then it is possible that the + // slice update rendered ff1 obsolete. If so, it + // will no longer appear in the nex_ff map, so + // remove it. + if (ff1 != ff) { + bool found_flag = false; + for (unsigned scan=0 + ; scan < ff->width() && !found_flag + ; scan += 1) { + if (nex_ff[scan].ff == ff1) + found_flag = true; + } + if (! found_flag) { + delete ff1; + } + } } delete tmp_map; delete tmp_out; + delete tmp_ff; } while (cur != last_); + /* Done. The large NetFF is no longer needed, as it has been + taken up by the smaller NetFF devices. */ + delete ff; + ff = 0; + /* Run through the pin accounting one more time to make sure the data inputs are all connected. */ - for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) { - NetFF*ff2 = pin_accounting[idx].ff; - unsigned pin = pin_accounting[idx].pin; + for (unsigned idx = 0 ; idx < block_width ; idx += 1) { + if (nex_ff[idx].proc == 0) + continue; + + NetFF*ff2 = nex_ff[idx].ff; + unsigned pin = nex_ff[idx].pin; /* Skip this output if it is not handled in this block. */ if (ff2 == 0) continue; @@ -911,19 +965,12 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, been set here. */ } else if (!ff2->pin_Data(pin).is_linked()) { cerr << ff2->get_line() << ": error: " - << "DFF introduced here is missing Data inputs." - << endl; + << "DFF introduced here is missing Data " + << pin << " input." << endl; flag = false; } } - delete[]pin_accounting; - - /* Done. The large NetFF is no longer needed, as it has been - taken up by the smaller NetFF devices. */ - delete ff; - ff = 0; - return flag; } @@ -933,10 +980,17 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff, * asynchronous set/reset, depending on whether the pin of the * expression is connected to an event, or not. */ -bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*&ff, +bool NetCondit::synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events_in) { + for (unsigned idx = 1 ; idx < nex_out->pin_count() ; idx += 1) { + assert(nex_ff[0].ff == nex_ff[idx].ff); + } + + NetFF*ff = nex_ff[0].ff; + /* First try to turn the condition expression into an asynchronous set/reset. If the condition expression has inputs that are included in the sensitivity list, then it @@ -1043,7 +1097,8 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*&ff, events_tmp[count_events++] = events_in[tmp]; } - flag = flag && else_->synth_sync(des, scope, ff, nex_map, + flag = flag && else_->synth_sync(des, scope, + nex_ff, nex_map, nex_out, events_tmp); return flag; @@ -1108,8 +1163,9 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*&ff, delete a_set; assert(else_ != 0); - flag = else_->synth_sync(des, scope, ff, nex_map, - nex_out, svector(0)) + flag = else_->synth_sync(des, scope, + nex_ff, nex_map, nex_out, + svector(0)) && flag; return flag; } @@ -1173,12 +1229,15 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*&ff, connect(ff->pin_Enable(), ce->pin(0)); } - bool flag = if_->synth_sync(des, scope, ff, nex_map, nex_out, events_in); + bool flag = if_->synth_sync(des, scope, + nex_ff, nex_map, nex_out, + events_in); return flag; } -bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*&ff, +bool NetEvWait::synth_sync(Design*des, NetScope*scope, + struct sync_accounting_cell*nex_ff, NetNet*nex_map, NetNet*nex_out, const svector&events_in) { @@ -1238,12 +1297,13 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*&ff, return false; } + NetFF*ff = nex_ff[0].ff; connect(ff->pin_Clock(), pclk->pin(0)); if (pclk->edge() == NetEvProbe::NEGEDGE) ff->attribute(perm_string::literal("Clock:LPM_Polarity"), verinum("INVERT")); /* Synthesize the input to the DFF. */ - bool flag = statement_->synth_sync(des, scope, ff, + bool flag = statement_->synth_sync(des, scope, nex_ff, nex_map, nex_out, events); DEBUG_SYNTH2_EXIT("NetEvWait",flag) @@ -1252,7 +1312,6 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*&ff, bool NetProcTop::synth_sync(Design*des) { - DEBUG_SYNTH2_ENTRY("NetProcTop") NexusSet nex_set; statement_->nex_output(nex_set); @@ -1261,6 +1320,14 @@ bool NetProcTop::synth_sync(Design*des) des->add_node(ff); ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF")); + struct sync_accounting_cell*nex_ff + = new struct sync_accounting_cell[ff->pin_count()]; + for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) { + nex_ff[idx].ff = ff; + nex_ff[idx].pin = idx; + nex_ff[idx].proc = statement_; + } + /* The D inputs to the DFF device will receive the output from the statements of the process. */ NetNet*nex_d = new NetNet(scope(), scope()->local_symbol(), @@ -1282,13 +1349,14 @@ bool NetProcTop::synth_sync(Design*des) } /* Synthesize the input to the DFF. */ - bool flag = statement_->synth_sync(des, scope(), ff, + bool flag = statement_->synth_sync(des, scope(), + nex_ff, nex_q, nex_d, svector()); delete nex_q; + delete[]nex_ff; - DEBUG_SYNTH2_EXIT("NetProcTop",flag) return flag; } @@ -1371,6 +1439,9 @@ void synth2(Design*des) /* * $Log: synth2.cc,v $ + * Revision 1.39.2.16 2006/01/18 01:23:25 steve + * Rework l-value handling to allow for more l-value type flexibility. + * * Revision 1.39.2.15 2006/01/01 02:25:07 steve * Case statement handles partial outputs. *