Rework l-value handling to allow for more l-value type flexibility.

This commit is contained in:
steve 2006-01-18 01:23:23 +00:00
parent fc227aa3e1
commit 52b8ed9077
5 changed files with 279 additions and 132 deletions

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #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 #endif
# include "config.h" # 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 void NetRamDq::dump_node(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): " o << setw(ind) << "" << "LPM_RAM_DQ (";
<< name() << endl;
if (mem_) o << "mem=" << mem_->name();
if (sig_) o << "sig=" << sig_->name();
o << "): " << name() << endl;
dump_node_pins(o, ind+4); dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4); dump_obj_attr(o, ind+4);
} }
@ -1089,6 +1094,9 @@ void Design::dump(ostream&o) const
/* /*
* $Log: design_dump.cc,v $ * $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 * Revision 1.149 2004/10/04 01:10:52 steve
* Clean up spurious trailing white space. * Clean up spurious trailing white space.
* *

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #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 #endif
# include "config.h" # include "config.h"
@ -47,6 +47,14 @@ void NetAssignBase::nex_output(NexusSet&out)
{ {
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) {
if (NetNet*lsig = cur->sig()) { 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) { for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
unsigned off = cur->get_loff() + idx; unsigned off = cur->get_loff() + idx;
out.add(lsig->pin(off).nexus()); out.add(lsig->pin(off).nexus());
@ -122,6 +130,9 @@ void NetWhile::nex_output(NexusSet&out)
/* /*
* $Log: net_nex_output.cc,v $ * $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 * Revision 1.11 2004/09/16 03:17:33 steve
* net_output handles l-value concatenations. * net_output handles l-value concatenations.
* *

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #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 #endif
# include "config.h" # include "config.h"
@ -234,6 +234,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
assert(s); assert(s);
release_list_ = 0; release_list_ = 0;
ram_ = 0;
verinum::V init_value = verinum::Vz; verinum::V init_value = verinum::Vz;
Link::DIR dir = Link::PASSIVE; Link::DIR dir = Link::PASSIVE;
@ -275,6 +276,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, long ms, long ls)
assert(s); assert(s);
release_list_ = 0; release_list_ = 0;
ram_ = 0;
verinum::V init_value = verinum::Vz; verinum::V init_value = verinum::Vz;
Link::DIR dir = Link::PASSIVE; 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); return pin(2+width_+swidth_+s*width_+w);
} }
void NetRamDq::make_pins_(unsigned wid)
NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid)
: NetNode(s, n, 3+2*mem->width()+awid),
mem_(mem), awidth_(awid)
{ {
pin(0).set_dir(Link::INPUT); pin(0).set_name(perm_string::literal("InClock"), 0); 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); pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("OutClock"), 0);
@ -1399,22 +1398,40 @@ NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid)
pin(3+idx).set_name(perm_string::literal("Address"), idx); 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_dir(Link::INPUT);
pin(3+awidth_+idx).set_name(perm_string::literal("Data"), idx); pin(3+awidth_+idx).set_name(perm_string::literal("Data"), idx);
} }
for (unsigned idx = 0 ; idx < width() ; idx += 1) { for (unsigned idx = 0 ; idx < wid ; idx += 1) {
pin(3+awidth_+width()+idx).set_dir(Link::OUTPUT); pin(3+awidth_+wid+idx).set_dir(Link::OUTPUT);
pin(3+awidth_+width()+idx).set_name(perm_string::literal("Q"), idx); 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_; next_ = mem_->ram_list_;
mem_->ram_list_ = this; 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() NetRamDq::~NetRamDq()
{ {
if (mem_) {
if (mem_->ram_list_ == this) { if (mem_->ram_list_ == this) {
mem_->ram_list_ = next_; mem_->ram_list_ = next_;
@ -1427,11 +1444,19 @@ NetRamDq::~NetRamDq()
assert(cur->next_ == this); assert(cur->next_ == this);
cur->next_ = next_; cur->next_ = next_;
} }
}
if (sig_) {
assert(sig_->ram_ == this);
sig_->ram_ = 0;
}
} }
unsigned NetRamDq::width() const unsigned NetRamDq::width() const
{ {
return mem_->width(); if (mem_) return mem_->width();
if (sig_) return 1;
return 0;
} }
unsigned NetRamDq::awidth() const unsigned NetRamDq::awidth() const
@ -1441,7 +1466,9 @@ unsigned NetRamDq::awidth() const
unsigned NetRamDq::size() 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 const NetMemory* NetRamDq::mem() const
@ -1449,6 +1476,11 @@ const NetMemory* NetRamDq::mem() const
return mem_; return mem_;
} }
const NetNet* NetRamDq::sig() const
{
return sig_;
}
unsigned NetRamDq::count_partners() const unsigned NetRamDq::count_partners() const
{ {
unsigned count = 0; unsigned count = 0;
@ -2281,6 +2313,9 @@ const NetProc*NetTaskDef::proc() const
/* /*
* $Log: netlist.cc,v $ * $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 * Revision 1.226 2004/10/04 01:10:54 steve
* Clean up spurious trailing white space. * Clean up spurious trailing white space.
* *

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #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 #endif
/* /*
@ -58,6 +58,7 @@ class NetEvProbe;
class NetExpr; class NetExpr;
class NetESignal; class NetESignal;
class NetEVariable; class NetEVariable;
class NetFF;
class NetFuncDef; class NetFuncDef;
class NetRamDq; class NetRamDq;
@ -67,6 +68,12 @@ class NetEvWait;
struct target; struct target;
struct functor_t; 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 * A NetObj is anything that has any kind of behavior in the
* netlist. Nodes can be gates, registers, etc. and are linked * netlist. Nodes can be gates, registers, etc. and are linked
@ -440,6 +447,9 @@ class NetNet : public NetObj {
friend class NetRelease; friend class NetRelease;
NetRelease*release_list_; NetRelease*release_list_;
friend class NetRamDq;
class NetRamDq*ram_;
private: private:
Type type_; Type type_;
PortType port_type_; PortType port_type_;
@ -876,12 +886,14 @@ class NetRamDq : public NetNode {
public: public:
NetRamDq(NetScope*s, perm_string name, NetMemory*mem, unsigned awid); NetRamDq(NetScope*s, perm_string name, NetMemory*mem, unsigned awid);
NetRamDq(NetScope*s, perm_string name, NetNet*mem, unsigned awid);
~NetRamDq(); ~NetRamDq();
unsigned width() const; unsigned width() const;
unsigned awidth() const; unsigned awidth() const;
unsigned size() const; unsigned size() const;
const NetMemory*mem() const; const NetMemory*mem() const;
const NetNet*sig() const;
Link& pin_InClock(); Link& pin_InClock();
Link& pin_OutClock(); Link& pin_OutClock();
@ -913,9 +925,12 @@ class NetRamDq : public NetNode {
private: private:
NetMemory*mem_; NetMemory*mem_;
NetNet* sig_;
NetRamDq*next_; NetRamDq*next_;
unsigned awidth_; 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* // was created to receive the Data inputs. The method *may*
// delete that DFF in favor of multiple smaller devices, but // delete that DFF in favor of multiple smaller devices, but
// in that case it will set the ff argument to nil. // 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events); const svector<NetEvProbe*>&events);
@ -1570,7 +1586,8 @@ class NetBlock : public NetProc {
bool synth_async(Design*des, NetScope*scope, bool sync_flag, bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out); 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events); const svector<NetEvProbe*>&events);
@ -1711,7 +1728,8 @@ class NetCondit : public NetProc {
bool synth_async(Design*des, NetScope*scope, bool sync_flag, bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out, NetNet*accum); 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events); const svector<NetEvProbe*>&events);
@ -1936,7 +1954,8 @@ class NetEvWait : public NetProc {
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag, virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
NetNet*nex_map, NetNet*nex_out); 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events); const svector<NetEvProbe*>&events);
@ -3379,6 +3398,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/* /*
* $Log: netlist.h,v $ * $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 * Revision 1.321.2.7 2005/12/31 04:28:14 steve
* Fix crashes caused bu synthesis of sqrt32.v. * Fix crashes caused bu synthesis of sqrt32.v.
* *

275
synth2.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #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 #endif
# include "config.h" # 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); 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events) const svector<NetEvProbe*>&events)
{ {
@ -120,6 +121,39 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
return false; 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 /* 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 nex_map to map the l-value bit position to the nex_out bit
position. */ 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 /* Build a map of guard values to mux select values. This
helps account for constant select bits that are being helps account for constant select bits that are being
elided. */ elided. The guard2sel mapping will only be valid for
reachable guards. */
map<unsigned long,unsigned long>guard2sel; map<unsigned long,unsigned long>guard2sel;
cur = 0; cur = 0;
for (unsigned idx = 0 ; idx < (1U<<esig->pin_count()) ; idx += 1) { for (unsigned idx = 0 ; idx < (1U<<esig->pin_count()) ; idx += 1) {
@ -355,6 +396,12 @@ bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard); NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
assert(ge); assert(ge);
verinum gval = ge->value(); 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()]; unsigned sel_idx = guard2sel[gval.as_ulong()];
assert(items_[item].statement); assert(items_[item].statement);
@ -649,15 +696,6 @@ bool NetProcTop::synth_async(Design*des)
static bool merge_ff_slices(NetFF*ff1, unsigned idx1, static bool merge_ff_slices(NetFF*ff1, unsigned idx1,
NetFF*ff2, unsigned idx2) 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 /* If the Aset inputs are connected, and not to each other
(possible since pre-existing Asets are carried forwards) (possible since pre-existing Asets are carried forwards)
@ -680,12 +718,22 @@ static bool merge_ff_slices(NetFF*ff1, unsigned idx1,
return false; return false;
} }
#if XXXX
if (ff2->pin_Data(idx2).is_linked()) if (ff2->pin_Data(idx2).is_linked())
connect(ff1->pin_Data(idx1), ff2->pin_Data(idx2)); connect(ff1->pin_Data(idx1), ff2->pin_Data(idx2));
if (ff2->pin_Aset().is_linked()) if (ff2->pin_Aset().is_linked())
connect(ff1->pin_Aset(), ff2->pin_Aset()); connect(ff1->pin_Aset(), ff2->pin_Aset());
if (ff2->pin_Aclr().is_linked()) if (ff2->pin_Aclr().is_linked())
connect(ff1->pin_Aclr(), ff2->pin_Aclr()); 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; 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 * This needs to be split into a DFF bank for each statement, because
* the statements may each infer different reset and enable signals. * 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events_in) const svector<NetEvProbe*>&events_in)
{ {
@ -712,25 +761,21 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff,
if (last_ == 0) if (last_ == 0)
return true; 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; bool flag = true;
const perm_string tmp1 = perm_string::literal("tmp1"); const perm_string tmp1 = perm_string::literal("tmp1");
const perm_string tmp2 = perm_string::literal("tmp2"); 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_; NetProc*cur = last_;
do { do {
cur = cur->next_; cur = cur->next_;
@ -767,6 +812,9 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff,
ff2->set_line(*cur); ff2->set_line(*cur);
des->add_node(ff2); 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 aset_value2 (verinum::V1, ff2->width());
verinum sset_value2 (verinum::V1, ff2->width()); verinum sset_value2 (verinum::V1, ff2->width());
for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) { 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()) if (ptr < tmp_sset.len())
sset_value2.set(idx, tmp_sset[ptr]); sset_value2.set(idx, tmp_sset[ptr]);
if (pin_accounting[ptr].proc != 0) { // Connect the tmp_out vector, what the
// sub-synthesis is linking, to the inputs of this
} else { // new FF.
pin_accounting[ptr].proc = cur; connect(tmp_out->pin(idx), ff2->pin_Data(idx));
pin_accounting[ptr].ff = ff2; tmp_ff[idx].ff = ff2;
pin_accounting[ptr].pin = idx; tmp_ff[idx].pin = idx;
tmp_ff[idx].proc = cur;
/* 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));
}
} }
/* PUll the non-sliced inputs (clock, set, reset, etc) /* 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_Aset().is_linked()
&& !ff2->pin_Aclr().is_linked()) { && !ff2->pin_Aclr().is_linked()) {
connect(ff2->pin_Aclr(), ff2->pin_Aset());
ff2->pin_Aset().unlink(); ff2->pin_Aset().unlink();
connect(ff2->pin_Aclr(), ff->pin_Aset());
} else { } else {
ff2->aset_value(aset_value2); 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 statement of the block. The tmp_map is the output
nexa that we expect, and the tmp_out is where we want nexa that we expect, and the tmp_out is where we want
those outputs connected. */ those outputs connected. */
NetFF*ff2_tmp = ff2; bool ok_flag = cur->synth_sync(des, scope,
bool ok_flag = cur->synth_sync(des, scope, ff2_tmp, tmp_map, tmp_ff, tmp_map, tmp_out,
tmp_out, events_in); events_in);
ff2 = 0; // NOTE: The synth_sync may delete ff2.
flag = flag && ok_flag; flag = flag && ok_flag;
if (ok_flag == false) if (ok_flag == false)
continue; 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 /* Use the nex_map to link up the output from the
substatement to the output of the block as a substatement to the output of the block as a
whole. It is occasionally possible to have outputs whole. It is occasionally possible to have outputs
beyond the input set, for example when the l-value of beyond the input set, for example when the l-value of
an assignment is smaller then the r-value. */ an assignment is smaller then the r-value. */
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) { 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, unsigned ptr = find_nexus_in_set(nex_map,
tmp_map->pin(idx).nexus()); tmp_map->pin(idx).nexus());
if (ptr < nex_out->pin_count()) if (ptr >= nex_out->pin_count())
connect(nex_out->pin(ptr), tmp_out->pin(idx)); 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_map;
delete tmp_out; delete tmp_out;
delete tmp_ff;
} while (cur != last_); } 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 /* Run through the pin accounting one more time to make sure
the data inputs are all connected. */ the data inputs are all connected. */
for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) { for (unsigned idx = 0 ; idx < block_width ; idx += 1) {
NetFF*ff2 = pin_accounting[idx].ff; if (nex_ff[idx].proc == 0)
unsigned pin = pin_accounting[idx].pin; continue;
NetFF*ff2 = nex_ff[idx].ff;
unsigned pin = nex_ff[idx].pin;
/* Skip this output if it is not handled in this block. */ /* Skip this output if it is not handled in this block. */
if (ff2 == 0) if (ff2 == 0)
continue; continue;
@ -911,19 +965,12 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*&ff,
been set here. */ been set here. */
} else if (!ff2->pin_Data(pin).is_linked()) { } else if (!ff2->pin_Data(pin).is_linked()) {
cerr << ff2->get_line() << ": error: " cerr << ff2->get_line() << ": error: "
<< "DFF introduced here is missing Data inputs." << "DFF introduced here is missing Data "
<< endl; << pin << " input." << endl;
flag = false; 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; 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 * asynchronous set/reset, depending on whether the pin of the
* expression is connected to an event, or not. * 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events_in) const svector<NetEvProbe*>&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 /* First try to turn the condition expression into an
asynchronous set/reset. If the condition expression has asynchronous set/reset. If the condition expression has
inputs that are included in the sensitivity list, then it 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]; 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); nex_out, events_tmp);
return flag; return flag;
@ -1108,8 +1163,9 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*&ff,
delete a_set; delete a_set;
assert(else_ != 0); assert(else_ != 0);
flag = else_->synth_sync(des, scope, ff, nex_map, flag = else_->synth_sync(des, scope,
nex_out, svector<NetEvProbe*>(0)) nex_ff, nex_map, nex_out,
svector<NetEvProbe*>(0))
&& flag; && flag;
return flag; return flag;
} }
@ -1173,12 +1229,15 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*&ff,
connect(ff->pin_Enable(), ce->pin(0)); 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; 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, NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events_in) const svector<NetEvProbe*>&events_in)
{ {
@ -1238,12 +1297,13 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*&ff,
return false; return false;
} }
NetFF*ff = nex_ff[0].ff;
connect(ff->pin_Clock(), pclk->pin(0)); connect(ff->pin_Clock(), pclk->pin(0));
if (pclk->edge() == NetEvProbe::NEGEDGE) if (pclk->edge() == NetEvProbe::NEGEDGE)
ff->attribute(perm_string::literal("Clock:LPM_Polarity"), verinum("INVERT")); ff->attribute(perm_string::literal("Clock:LPM_Polarity"), verinum("INVERT"));
/* Synthesize the input to the DFF. */ /* 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); nex_map, nex_out, events);
DEBUG_SYNTH2_EXIT("NetEvWait",flag) 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) bool NetProcTop::synth_sync(Design*des)
{ {
DEBUG_SYNTH2_ENTRY("NetProcTop")
NexusSet nex_set; NexusSet nex_set;
statement_->nex_output(nex_set); statement_->nex_output(nex_set);
@ -1261,6 +1320,14 @@ bool NetProcTop::synth_sync(Design*des)
des->add_node(ff); des->add_node(ff);
ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF")); 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 D inputs to the DFF device will receive the output from
the statements of the process. */ the statements of the process. */
NetNet*nex_d = new NetNet(scope(), scope()->local_symbol(), 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. */ /* 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, nex_q, nex_d,
svector<NetEvProbe*>()); svector<NetEvProbe*>());
delete nex_q; delete nex_q;
delete[]nex_ff;
DEBUG_SYNTH2_EXIT("NetProcTop",flag)
return flag; return flag;
} }
@ -1371,6 +1439,9 @@ void synth2(Design*des)
/* /*
* $Log: synth2.cc,v $ * $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 * Revision 1.39.2.15 2006/01/01 02:25:07 steve
* Case statement handles partial outputs. * Case statement handles partial outputs.
* *