diff --git a/PExpr.h b/PExpr.h index 18e0080a9..b6daca87f 100644 --- a/PExpr.h +++ b/PExpr.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: PExpr.h,v 1.24 1999/11/14 20:24:28 steve Exp $" +#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $" #endif # include @@ -159,6 +159,12 @@ class PEIdent : public PExpr { // If this is a reference to a memory, this is the index // expression. PExpr*idx_; + + NetNet* elaborate_net_ram_(Design*des, const string&path, + NetMemory*mem, unsigned lwidth, + unsigned long rise, + unsigned long fall, + unsigned long decay) const; }; class PENumber : public PExpr { @@ -307,6 +313,9 @@ class PECallFunction : public PExpr { /* * $Log: PExpr.h,v $ + * Revision 1.25 1999/11/21 00:13:08 steve + * Support memories in continuous assignments. + * * Revision 1.24 1999/11/14 20:24:28 steve * Add support for the LPM_CLSHIFT device. * diff --git a/design_dump.cc b/design_dump.cc index 3f128a8fa..aa03fca18 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 */ #if !defined(WINNT) -#ident "$Id: design_dump.cc,v 1.57 1999/11/14 23:43:45 steve Exp $" +#ident "$Id: design_dump.cc,v 1.58 1999/11/21 00:13:08 steve Exp $" #endif /* @@ -241,6 +241,14 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetRamDq::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): " + << name() << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetTaskDef::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "task " << name_ << ";" << endl; @@ -834,6 +842,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.58 1999/11/21 00:13:08 steve + * Support memories in continuous assignments. + * * Revision 1.57 1999/11/14 23:43:45 steve * Support combinatorial comparators. * diff --git a/elab_net.cc b/elab_net.cc index 09e34c115..c02f941b2 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elab_net.cc,v 1.6 1999/11/14 23:43:45 steve Exp $" +#ident "$Id: elab_net.cc,v 1.7 1999/11/21 00:13:08 steve Exp $" #endif # include "PExpr.h" @@ -493,6 +493,258 @@ NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path, return osig; } +NetNet* PEIdent::elaborate_net(Design*des, const string&path, + unsigned lwidth, + unsigned long rise, + unsigned long fall, + unsigned long decay) const +{ + NetNet*sig = des->find_signal(path, text_); + + if (sig == 0) { + /* If the identifier is a memory instead of a signal, + then handle it elsewhere. Create a RAM. */ + if (NetMemory*mem = des->find_memory(path+"."+text_)) + return elaborate_net_ram_(des, path, mem, lwidth, + rise, fall, decay); + + + if (const NetExpr*pe = des->find_parameter(path, text_)) { + + const NetEConst*pc = dynamic_cast(pe); + assert(pc); + verinum pvalue = pc->value(); + sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, + pc->expr_width()); + for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) { + NetConst*cp = new NetConst(des->local_symbol(path), + pvalue[idx]); + connect(sig->pin(idx), cp->pin(0)); + des->add_node(cp); + } + + } else { + + sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1); + des->add_signal(sig); + cerr << get_line() << ": warning: Implicitly defining " + "wire " << path << "." << text_ << "." << endl; + } + } + + assert(sig); + + if (msb_ && lsb_) { + verinum*mval = msb_->eval_const(des, path); + if (mval == 0) { + cerr << msb_->get_line() << ": error: unable to " + "evaluate constant expression: " << *msb_ << + endl; + des->errors += 1; + return 0; + } + + verinum*lval = lsb_->eval_const(des, path); + if (lval == 0) { + cerr << lsb_->get_line() << ": error: unable to " + "evaluate constant expression: " << *lsb_ << + endl; + delete mval; + des->errors += 1; + return 0; + } + + assert(mval); + assert(lval); + unsigned midx = sig->sb_to_idx(mval->as_long()); + unsigned lidx = sig->sb_to_idx(lval->as_long()); + + if (midx >= lidx) { + NetTmp*tmp = new NetTmp(des->local_symbol(path), + midx-lidx+1); + des->add_signal(tmp); + if (tmp->pin_count() > sig->pin_count()) { + cerr << get_line() << ": bit select out of " + << "range for " << sig->name() << endl; + return sig; + } + + for (unsigned idx = lidx ; idx <= midx ; idx += 1) + connect(tmp->pin(idx-lidx), sig->pin(idx)); + + sig = tmp; + + } else { + NetTmp*tmp = new NetTmp(des->local_symbol(path), + lidx-midx+1); + des->add_signal(tmp); + assert(tmp->pin_count() <= sig->pin_count()); + for (unsigned idx = lidx ; idx >= midx ; idx -= 1) + connect(tmp->pin(idx-midx), sig->pin(idx)); + + sig = tmp; + } + + } else if (msb_) { + verinum*mval = msb_->eval_const(des, path); + if (mval == 0) { + cerr << get_line() << ": index of " << text_ << + " needs to be constant in this context." << + endl; + des->errors += 1; + return 0; + } + assert(mval); + unsigned idx = sig->sb_to_idx(mval->as_long()); + if (idx >= sig->pin_count()) { + cerr << get_line() << "; index " << sig->name() << + "[" << mval->as_long() << "] out of range." << endl; + des->errors += 1; + idx = 0; + } + NetTmp*tmp = new NetTmp(des->local_symbol(path), 1); + des->add_signal(tmp); + connect(tmp->pin(0), sig->pin(idx)); + sig = tmp; + } + + return sig; +} + +/* + * When I run into an identifier in an expression that referrs to a + * memory, create a RAM port object. + */ +NetNet* PEIdent::elaborate_net_ram_(Design*des, const string&path, + NetMemory*mem, unsigned lwidth, + unsigned long rise, + unsigned long fall, + unsigned long decay) const +{ + if (msb_ == 0) { + cerr << get_line() << ": error: memory reference without" + " the required index expression." << endl; + des->errors += 1; + return 0; + } + + NetNet*adr = msb_->elaborate_net(des, path, 0, 0, 0, 0); + if (adr == 0) + return 0; + + + NetRamDq*ram = new NetRamDq(des->local_symbol(mem->name()), + mem, adr->pin_count()); + des->add_node(ram); + + for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1) + connect(ram->pin_Address(idx), adr->pin(idx)); + + NetNet*osig = new NetTmp(des->local_symbol(mem->name()), ram->width()); + des->add_signal(osig); + + for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) + connect(ram->pin_Q(idx), osig->pin(idx)); + + return osig; +} + +/* + * Identifiers in continuous assignment l-values are limited to wires + * and that ilk. Detect registers and memories here and report errors. + */ +NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const +{ + NetNet*sig = des->find_signal(path, text_); + if (sig == 0) { + /* Don't allow memories here. Is it a memory? */ + if (des->find_memory(path+"."+text_)) { + cerr << get_line() << ": error: memories (" << text_ + << ") cannot be l-values in continuous " + << "assignments." << endl; + return 0; + } + + /* Fine, create an implicit wire as an l-value. */ + sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1); + des->add_signal(sig); + cerr << get_line() << ": warning: Implicitly defining " + "wire " << path << "." << text_ << "." << endl; + } + + assert(sig); + + /* Don't allow registers as assign l-values. */ + if (sig->type() == NetNet::REG) { + cerr << get_line() << ": error: registers (" << sig->name() + << ") cannot be l-values in continuous" + << " assignments." << endl; + return 0; + } + + if (msb_ && lsb_) { + /* Detect a part select. Evaluate the bits and elaborate + the l-value by creating a sub-net that links to just + the right pins. */ + verinum*mval = msb_->eval_const(des, path); + assert(mval); + verinum*lval = lsb_->eval_const(des, path); + assert(lval); + unsigned midx = sig->sb_to_idx(mval->as_long()); + unsigned lidx = sig->sb_to_idx(lval->as_long()); + + if (midx >= lidx) { + NetTmp*tmp = new NetTmp(des->local_symbol(path), + midx-lidx+1); + des->add_signal(tmp); + if (tmp->pin_count() > sig->pin_count()) { + cerr << get_line() << ": bit select out of " + << "range for " << sig->name() << endl; + return sig; + } + + for (unsigned idx = lidx ; idx <= midx ; idx += 1) + connect(tmp->pin(idx-lidx), sig->pin(idx)); + + sig = tmp; + + } else { + NetTmp*tmp = new NetTmp(des->local_symbol(path), + lidx-midx+1); + des->add_signal(tmp); + assert(tmp->pin_count() <= sig->pin_count()); + for (unsigned idx = lidx ; idx >= midx ; idx -= 1) + connect(tmp->pin(idx-midx), sig->pin(idx)); + + sig = tmp; + } + + } else if (msb_) { + verinum*mval = msb_->eval_const(des, path); + if (mval == 0) { + cerr << get_line() << ": index of " << text_ << + " needs to be constant in this context." << + endl; + des->errors += 1; + return 0; + } + assert(mval); + unsigned idx = sig->sb_to_idx(mval->as_long()); + if (idx >= sig->pin_count()) { + cerr << get_line() << "; index " << sig->name() << + "[" << mval->as_long() << "] out of range." << endl; + des->errors += 1; + idx = 0; + } + NetTmp*tmp = new NetTmp(des->local_symbol(path), 1); + des->add_signal(tmp); + connect(tmp->pin(0), sig->pin(idx)); + sig = tmp; + } + + return sig; +} + /* * Elaborate a number as a NetConst object. */ @@ -564,6 +816,9 @@ NetNet* PETernary::elaborate_net(Design*des, const string&path, /* * $Log: elab_net.cc,v $ + * Revision 1.7 1999/11/21 00:13:08 steve + * Support memories in continuous assignments. + * * Revision 1.6 1999/11/14 23:43:45 steve * Support combinatorial comparators. * diff --git a/elaborate.cc b/elaborate.cc index 09deabd36..b3b9af23b 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elaborate.cc,v 1.124 1999/11/18 03:52:19 steve Exp $" +#ident "$Id: elaborate.cc,v 1.125 1999/11/21 00:13:08 steve Exp $" #endif /* @@ -706,218 +706,6 @@ NetNet* PEConcat::elaborate_lnet(Design*des, const string&path) const return osig; } -NetNet* PEIdent::elaborate_net(Design*des, const string&path, - unsigned lwidth, - unsigned long rise, - unsigned long fall, - unsigned long decay) const -{ - NetNet*sig = des->find_signal(path, text_); - if (sig == 0) { - if (des->find_memory(path+"."+text_)) { - cerr << get_line() << ": sorry: memories not supported" - " in this context." << endl; - return 0; - } - - if (const NetExpr*pe = des->find_parameter(path, text_)) { - - const NetEConst*pc = dynamic_cast(pe); - assert(pc); - verinum pvalue = pc->value(); - sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, - pc->expr_width()); - for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) { - NetConst*cp = new NetConst(des->local_symbol(path), - pvalue[idx]); - connect(sig->pin(idx), cp->pin(0)); - des->add_node(cp); - } - - } else { - - sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1); - des->add_signal(sig); - cerr << get_line() << ": warning: Implicitly defining " - "wire " << path << "." << text_ << "." << endl; - } - } - - assert(sig); - - if (msb_ && lsb_) { - verinum*mval = msb_->eval_const(des, path); - if (mval == 0) { - cerr << msb_->get_line() << ": error: unable to " - "evaluate constant expression: " << *msb_ << - endl; - des->errors += 1; - return 0; - } - - verinum*lval = lsb_->eval_const(des, path); - if (lval == 0) { - cerr << lsb_->get_line() << ": error: unable to " - "evaluate constant expression: " << *lsb_ << - endl; - delete mval; - des->errors += 1; - return 0; - } - - assert(mval); - assert(lval); - unsigned midx = sig->sb_to_idx(mval->as_long()); - unsigned lidx = sig->sb_to_idx(lval->as_long()); - - if (midx >= lidx) { - NetTmp*tmp = new NetTmp(des->local_symbol(path), - midx-lidx+1); - des->add_signal(tmp); - if (tmp->pin_count() > sig->pin_count()) { - cerr << get_line() << ": bit select out of " - << "range for " << sig->name() << endl; - return sig; - } - - for (unsigned idx = lidx ; idx <= midx ; idx += 1) - connect(tmp->pin(idx-lidx), sig->pin(idx)); - - sig = tmp; - - } else { - NetTmp*tmp = new NetTmp(des->local_symbol(path), - lidx-midx+1); - des->add_signal(tmp); - assert(tmp->pin_count() <= sig->pin_count()); - for (unsigned idx = lidx ; idx >= midx ; idx -= 1) - connect(tmp->pin(idx-midx), sig->pin(idx)); - - sig = tmp; - } - - } else if (msb_) { - verinum*mval = msb_->eval_const(des, path); - if (mval == 0) { - cerr << get_line() << ": index of " << text_ << - " needs to be constant in this context." << - endl; - des->errors += 1; - return 0; - } - assert(mval); - unsigned idx = sig->sb_to_idx(mval->as_long()); - if (idx >= sig->pin_count()) { - cerr << get_line() << "; index " << sig->name() << - "[" << mval->as_long() << "] out of range." << endl; - des->errors += 1; - idx = 0; - } - NetTmp*tmp = new NetTmp(des->local_symbol(path), 1); - des->add_signal(tmp); - connect(tmp->pin(0), sig->pin(idx)); - sig = tmp; - } - - return sig; -} - -/* - * Identifiers in continuous assignment l-values are limited to wires - * and that ilk. Detect registers and memories here and report errors. - */ -NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const -{ - NetNet*sig = des->find_signal(path, text_); - if (sig == 0) { - /* Don't allow memories here. Is it a memory? */ - if (des->find_memory(path+"."+text_)) { - cerr << get_line() << ": error: memories (" << text_ - << ") cannot be l-values in continuous " - << "assignments." << endl; - return 0; - } - - /* Fine, create an implicit wire as an l-value. */ - sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1); - des->add_signal(sig); - cerr << get_line() << ": warning: Implicitly defining " - "wire " << path << "." << text_ << "." << endl; - } - - assert(sig); - - /* Don't allow registers as assign l-values. */ - if (sig->type() == NetNet::REG) { - cerr << get_line() << ": error: registers (" << sig->name() - << ") cannot be l-values in continuous" - << " assignments." << endl; - return 0; - } - - if (msb_ && lsb_) { - /* Detect a part select. Evaluate the bits and elaborate - the l-value by creating a sub-net that links to just - the right pins. */ - verinum*mval = msb_->eval_const(des, path); - assert(mval); - verinum*lval = lsb_->eval_const(des, path); - assert(lval); - unsigned midx = sig->sb_to_idx(mval->as_long()); - unsigned lidx = sig->sb_to_idx(lval->as_long()); - - if (midx >= lidx) { - NetTmp*tmp = new NetTmp(des->local_symbol(path), - midx-lidx+1); - des->add_signal(tmp); - if (tmp->pin_count() > sig->pin_count()) { - cerr << get_line() << ": bit select out of " - << "range for " << sig->name() << endl; - return sig; - } - - for (unsigned idx = lidx ; idx <= midx ; idx += 1) - connect(tmp->pin(idx-lidx), sig->pin(idx)); - - sig = tmp; - - } else { - NetTmp*tmp = new NetTmp(des->local_symbol(path), - lidx-midx+1); - des->add_signal(tmp); - assert(tmp->pin_count() <= sig->pin_count()); - for (unsigned idx = lidx ; idx >= midx ; idx -= 1) - connect(tmp->pin(idx-midx), sig->pin(idx)); - - sig = tmp; - } - - } else if (msb_) { - verinum*mval = msb_->eval_const(des, path); - if (mval == 0) { - cerr << get_line() << ": index of " << text_ << - " needs to be constant in this context." << - endl; - des->errors += 1; - return 0; - } - assert(mval); - unsigned idx = sig->sb_to_idx(mval->as_long()); - if (idx >= sig->pin_count()) { - cerr << get_line() << "; index " << sig->name() << - "[" << mval->as_long() << "] out of range." << endl; - des->errors += 1; - idx = 0; - } - NetTmp*tmp = new NetTmp(des->local_symbol(path), 1); - des->add_signal(tmp); - connect(tmp->pin(0), sig->pin(idx)); - sig = tmp; - } - - return sig; -} - NetNet* PEUnary::elaborate_net(Design*des, const string&path, unsigned width, unsigned long rise, @@ -2345,6 +2133,9 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.125 1999/11/21 00:13:08 steve + * Support memories in continuous assignments. + * * Revision 1.124 1999/11/18 03:52:19 steve * Turn NetTmp objects into normal local NetNet objects, * and add the nodangle functor to clean up the local diff --git a/emit.cc b/emit.cc index fc2f7cc07..704eb365d 100644 --- a/emit.cc +++ b/emit.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: emit.cc,v 1.28 1999/11/14 23:43:45 steve Exp $" +#ident "$Id: emit.cc,v 1.29 1999/11/21 00:13:08 steve Exp $" #endif /* @@ -90,6 +90,11 @@ void NetMux::emit_node(ostream&o, struct target_t*tgt) const tgt->lpm_mux(o, this); } +void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const +{ + tgt->lpm_ram_dq(o, this); +} + void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const { tgt->net_event(o, this); @@ -377,6 +382,9 @@ bool emit(ostream&o, const Design*des, const char*type) /* * $Log: emit.cc,v $ + * Revision 1.29 1999/11/21 00:13:08 steve + * Support memories in continuous assignments. + * * Revision 1.28 1999/11/14 23:43:45 steve * Support combinatorial comparators. * diff --git a/netlist.cc b/netlist.cc index 2663290e9..64d6421ca 100644 --- a/netlist.cc +++ b/netlist.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.cc,v 1.89 1999/11/19 05:02:37 steve Exp $" +#ident "$Id: netlist.cc,v 1.90 1999/11/21 00:13:08 steve Exp $" #endif # include @@ -998,6 +998,120 @@ const NetObj::Link& NetMux::pin_Data(unsigned w, unsigned s) const return pin(2+width_+swidth_+s*width_+w); } + +NetRamDq::NetRamDq(const string&n, NetMemory*mem, unsigned awid) +: NetNode(n, 3+2*mem->width()+awid), mem_(mem), awidth_(awid) +{ + pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("InClock", 0); + pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("OutClock", 0); + pin(2).set_dir(NetObj::Link::INPUT); pin(2).set_name("WE", 0); + + for (unsigned idx = 0 ; idx < awidth_ ; idx += 1) { + pin(3+idx).set_dir(NetObj::Link::INPUT); + pin(3+idx).set_name("Address", idx); + } + + for (unsigned idx = 0 ; idx < width() ; idx += 1) { + pin(3+awidth_+idx).set_dir(NetObj::Link::INPUT); + pin(3+awidth_+idx).set_name("Data", idx); + } + + for (unsigned idx = 0 ; idx < width() ; idx += 1) { + pin(3+awidth_+width()+idx).set_dir(NetObj::Link::OUTPUT); + pin(3+awidth_+width()+idx).set_name("Q", idx); + } +} + +NetRamDq::~NetRamDq() +{ +} + +unsigned NetRamDq::width() const +{ + return mem_->width(); +} + +unsigned NetRamDq::awidth() const +{ + return awidth_; +} + +unsigned NetRamDq::size() const +{ + return mem_->count(); +} + +const NetMemory* NetRamDq::mem() const +{ + return mem_; +} + +NetObj::Link& NetRamDq::pin_InClock() +{ + return pin(0); +} + +const NetObj::Link& NetRamDq::pin_InClock() const +{ + return pin(0); +} + +NetObj::Link& NetRamDq::pin_OutClock() +{ + return pin(1); +} + +const NetObj::Link& NetRamDq::pin_OutClock() const +{ + return pin(1); +} + +NetObj::Link& NetRamDq::pin_WE() +{ + return pin(2); +} + +const NetObj::Link& NetRamDq::pin_WE() const +{ + return pin(2); +} + +NetObj::Link& NetRamDq::pin_Address(unsigned idx) +{ + assert(idx < awidth_); + return pin(3+idx); +} + +const NetObj::Link& NetRamDq::pin_Address(unsigned idx) const +{ + assert(idx < awidth_); + return pin(3+idx); +} + +NetObj::Link& NetRamDq::pin_Data(unsigned idx) +{ + assert(idx < width()); + return pin(3+awidth_+idx); +} + +const NetObj::Link& NetRamDq::pin_Data(unsigned idx) const +{ + assert(idx < width()); + return pin(3+awidth_+idx); +} + +NetObj::Link& NetRamDq::pin_Q(unsigned idx) +{ + assert(idx < width()); + return pin(3+awidth_+width()+idx); +} + +const NetObj::Link& NetRamDq::pin_Q(unsigned idx) const +{ + assert(idx < width()); + return pin(3+awidth_+width()+idx); +} + /* * NetAssign */ @@ -2404,6 +2518,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.90 1999/11/21 00:13:08 steve + * Support memories in continuous assignments. + * * Revision 1.89 1999/11/19 05:02:37 steve * handle duplicate connect to a nexus. * diff --git a/netlist.h b/netlist.h index 0e65acbac..d67930817 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.h,v 1.91 1999/11/19 05:02:37 steve Exp $" +#ident "$Id: netlist.h,v 1.92 1999/11/21 00:13:09 steve Exp $" #endif /* @@ -514,6 +514,50 @@ class NetMux : public NetNode { unsigned swidth_; }; +/* + * This device represents an LPM_RAM_DQ device. The actual content is + * represented by a NetMemory object allocated elsewhere, but that + * object fixes the width and size of the device. The pin count of the + * address input is given in the constructor. + */ +class NetRamDq : public NetNode { + + public: + NetRamDq(const string&name, NetMemory*mem, unsigned awid); + ~NetRamDq(); + + unsigned width() const; + unsigned awidth() const; + unsigned size() const; + const NetMemory*mem() const; + + NetObj::Link& pin_InClock(); + NetObj::Link& pin_OutClock(); + NetObj::Link& pin_WE(); + + NetObj::Link& pin_Address(unsigned idx); + NetObj::Link& pin_Data(unsigned idx); + NetObj::Link& pin_Q(unsigned idx); + + const NetObj::Link& pin_InClock() const; + const NetObj::Link& pin_OutClock() const; + const NetObj::Link& pin_WE() const; + + const NetObj::Link& pin_Address(unsigned idx) const; + const NetObj::Link& pin_Data(unsigned idx) const; + const NetObj::Link& pin_Q(unsigned idx) const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual void emit_node(ostream&, struct target_t*) const; + + private: + friend class NetMemory; + NetMemory*mem_; + NetRamDq*next_; + unsigned awidth_; + +}; + /* ========= * There are cases where expressions need to be represented. The * NetExpr class is the root of a heirarchy that serves that purpose. @@ -1933,6 +1977,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.92 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.91 1999/11/19 05:02:37 steve * handle duplicate connect to a nexus. * diff --git a/netlist.txt b/netlist.txt index 10bdc8c4a..7f52dbfc4 100644 --- a/netlist.txt +++ b/netlist.txt @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ident "$Id: netlist.txt,v 1.5 1999/11/02 04:55:34 steve Exp $" +#ident "$Id: netlist.txt,v 1.6 1999/11/21 00:13:09 steve Exp $" Note that the netlist.h header contains detailed descriptions of how @@ -114,6 +114,35 @@ and a NetProc. The NetAssign_ node has pins that represent the l-value of the statement, and carries behavioral expressions that represent the r-value of the assignment. +MEMORIES + +The netlist form includes the NetMemory type to hold the content of a +memory. Instances of this type represent the declaration of a memory, +and occur once for each memory. References to the memory are managed +by the NetEMemory and NetAssignMem_ classes. + +An instance of the NetEMemory class is created whenever a procedural +expression references a memory element. The operand is the index to +use to address (and read) the memory. + +An instance of the NetAssignMem_ class is created when there is a +procedural assignment to the memory. The NetAssignMem_ object +represents the l-value reference (a write) to the memory. As with the +NetEMemory class, this is a procedural reference only. + +When a memory reference appears in structural context (i.e. continuous +assignments) elaboration creates a NetRamDq. This is a LPM_RAM_DQ +device. Elaboration leaves the write control and data input pins +unconnected for now, because memories cannot appear is l-values of +continuous assignments. However, the synthesis functor may connect +signals to the write control lines to get a fully operational RAM. + +By the time elaboration completes, there may be many NetAssignMem_, +NetEMemory and NetRamDq objects referencing the same NetMemory +object. Each represents a port into the memory. It is up to the +synthesis steps (and the target code) to figure out what to do with +these ports. + EXPRESSIONS Expressions are represented as a tree of NetExpr nodes. The NetExpr @@ -214,6 +243,9 @@ some task calls. C++ programmers recognize this as inlining a task.) $Log: netlist.txt,v $ + Revision 1.6 1999/11/21 00:13:09 steve + Support memories in continuous assignments. + Revision 1.5 1999/11/02 04:55:34 steve Add the synthesize method to NetExpr to handle synthesis of expressions, and use that method diff --git a/t-vvm.cc b/t-vvm.cc index 0a6a1dcb0..a325ca3e8 100644 --- a/t-vvm.cc +++ b/t-vvm.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-vvm.cc,v 1.76 1999/11/14 23:43:45 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.77 1999/11/21 00:13:09 steve Exp $" #endif # include @@ -64,6 +64,7 @@ class target_vvm : public target_t { virtual void lpm_compare(ostream&os, const NetCompare*); virtual void lpm_ff(ostream&os, const NetFF*); virtual void lpm_mux(ostream&os, const NetMux*); + virtual void lpm_ram_dq(ostream&os, const NetRamDq*); virtual void logic(ostream&os, const NetLogic*); virtual void bufz(ostream&os, const NetBUFZ*); @@ -937,6 +938,22 @@ void target_vvm::lpm_mux(ostream&os, const NetMux*mux) } } +void target_vvm::lpm_ram_dq(ostream&os, const NetRamDq*ram) +{ + string mname = mangle(ram->name()); + os << "static vvm_ram_dq<" << ram->width() << "," << + ram->awidth() << "," << ram->size() << "> " << mname << + "(&" << mangle(ram->mem()->name()) << ");" << endl; + + for (unsigned idx = 0 ; idx < ram->width() ; idx += 1) { + unsigned pin = ram->pin_Q(idx).get_pin(); + string outfun = defn_gate_outputfun_(os, ram, pin); + init_code << " " << mangle(ram->name()) << + ".config_rout(" << idx << ", &" << outfun << ");" << endl; + emit_gate_outputfun_(ram, pin); + } +} + void target_vvm::logic(ostream&os, const NetLogic*gate) { string outfun = defn_gate_outputfun_(os, gate, 0); @@ -1417,8 +1434,9 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem) defn << " /* " << amem->get_line() << " */" << endl; if (mem->width() == amem->rval()->expr_width()) { - defn << " " << mangle(mem->name()) << ".set_word(" << - index << ".as_unsigned(), " << rval << ");" << endl; + defn << " " << mangle(mem->name()) << + ".set_word(sim_, " << index << ".as_unsigned(), " << + rval << ");" << endl; } else { assert(mem->width() <= amem->rval()->expr_width()); @@ -1429,8 +1447,8 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem) defn << " " << tmp << "[" << idx << "] = " << rval << "[" << idx << "];" << endl; - defn << " " << mangle(mem->name()) << ".set_word(" << - index << ".as_unsigned(), " << tmp << ");" << endl; + defn << " " << mangle(mem->name()) << ".set_word(sim_, " + << index << ".as_unsigned(), " << tmp << ");" << endl; } } @@ -1902,6 +1920,9 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.77 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.76 1999/11/14 23:43:45 steve * Support combinatorial comparators. * diff --git a/target.cc b/target.cc index b4f18b17b..9d271a9cb 100644 --- a/target.cc +++ b/target.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: target.cc,v 1.25 1999/11/14 23:43:45 steve Exp $" +#ident "$Id: target.cc,v 1.26 1999/11/21 00:13:09 steve Exp $" #endif # include "target.h" @@ -99,6 +99,12 @@ void target_t::lpm_mux(ostream&, const NetMux*) "Unhandled NetMux." << endl; } +void target_t::lpm_ram_dq(ostream&, const NetRamDq*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetRamDq." << endl; +} + void target_t::net_assign(ostream&os, const NetAssign*) { } @@ -299,6 +305,9 @@ void expr_scan_t::expr_binary(const NetEBinary*ex) /* * $Log: target.cc,v $ + * Revision 1.26 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.25 1999/11/14 23:43:45 steve * Support combinatorial comparators. * diff --git a/target.h b/target.h index e88ab06e7..284cda051 100644 --- a/target.h +++ b/target.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: target.h,v 1.24 1999/11/14 23:43:46 steve Exp $" +#ident "$Id: target.h,v 1.25 1999/11/21 00:13:09 steve Exp $" #endif # include "netlist.h" @@ -71,6 +71,7 @@ struct target_t { virtual void lpm_compare(ostream&os, const NetCompare*); virtual void lpm_ff(ostream&os, const NetFF*); virtual void lpm_mux(ostream&os, const NetMux*); + virtual void lpm_ram_dq(ostream&os, const NetRamDq*); /* Output a gate (called for each gate) */ virtual void logic(ostream&os, const NetLogic*); @@ -141,6 +142,9 @@ extern const struct target *target_table[]; /* * $Log: target.h,v $ + * Revision 1.25 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.24 1999/11/14 23:43:46 steve * Support combinatorial comparators. * diff --git a/vvm/vvm.h b/vvm/vvm.h index 321f1c49f..6679f9104 100644 --- a/vvm/vvm.h +++ b/vvm/vvm.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm.h,v 1.21 1999/11/10 02:52:24 steve Exp $" +#ident "$Id: vvm.h,v 1.22 1999/11/21 00:13:09 steve Exp $" #endif # include @@ -254,14 +254,27 @@ template class vvm_signal_t : public __vpiSignal { } }; +struct vvm_ram_callback { + vvm_ram_callback(); + virtual ~vvm_ram_callback(); + virtual void handle_write(vvm_simulation*sim, unsigned idx) =0; + vvm_ram_callback*next_; +}; + template class vvm_memory_t : public __vpiMemory { public: - void set_word(unsigned addr, const vvm_bitset_t&val) + vvm_memory_t() + { cb_list_ = 0; + } + + void set_word(vvm_simulation*sim, unsigned addr, + const vvm_bitset_t&val) { unsigned base = WIDTH * addr; for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) bits[base+idx] = val[idx]; + call_list_(sim, addr); } vvm_bitset_t get_word(unsigned addr) const @@ -271,10 +284,25 @@ class vvm_memory_t : public __vpiMemory { val[idx] = bits[base+idx]; return val; } + + void set_callback(vvm_ram_callback*ram) + { ram->next_ = cb_list_; + cb_list_ = ram; + } + + private: + vvm_ram_callback*cb_list_; + void call_list_(vvm_simulation*sim, unsigned idx) + { for (vvm_ram_callback*cur = cb_list_; cur; cur = cur->next_) + cur->handle_write(sim, idx); + } }; /* * $Log: vvm.h,v $ + * Revision 1.22 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.21 1999/11/10 02:52:24 steve * Create the vpiMemory handle type. * diff --git a/vvm/vvm_bit.cc b/vvm/vvm_bit.cc index cace5c1f0..5c7c1a0ab 100644 --- a/vvm/vvm_bit.cc +++ b/vvm/vvm_bit.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_bit.cc,v 1.4 1999/11/01 02:07:41 steve Exp $" +#ident "$Id: vvm_bit.cc,v 1.5 1999/11/21 00:13:09 steve Exp $" #endif # include "vvm.h" @@ -68,6 +68,14 @@ vvm_bits_t::~vvm_bits_t() { } +vvm_ram_callback::vvm_ram_callback() +{ +} + +vvm_ram_callback::~vvm_ram_callback() +{ +} + vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry) { unsigned li, ri, ci; @@ -114,6 +122,9 @@ vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry) /* * $Log: vvm_bit.cc,v $ + * Revision 1.5 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.4 1999/11/01 02:07:41 steve * Add the synth functor to do generic synthesis * and add the LPM_FF device to handle rows of diff --git a/vvm/vvm_gates.h b/vvm/vvm_gates.h index 1f12f775d..e9341d00a 100644 --- a/vvm/vvm_gates.h +++ b/vvm/vvm_gates.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_gates.h,v 1.23 1999/11/15 00:42:31 steve Exp $" +#ident "$Id: vvm_gates.h,v 1.24 1999/11/21 00:13:09 steve Exp $" #endif # include "vvm.h" @@ -553,6 +553,62 @@ template class vvm_nor { vvm_out_event::action_t output_; }; +template +class vvm_ram_dq : protected vvm_ram_callback { + + public: + vvm_ram_dq(vvm_memory_t*mem) + : mem_(mem) + { mem->set_callback(this); + for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) + out_[idx] = 0; + for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1) + addr_[idx] = Vx; + } + + void init_Address(unsigned idx, vpip_bit_t val) + { addr_[idx] = val; } + + void set_Address(vvm_simulation*sim, unsigned idx, vpip_bit_t val) + { if (addr_[idx] == val) return; + addr_[idx] = val; + compute_(); + send_out_(sim); + } + + void handle_write(vvm_simulation*sim, unsigned idx) + { if (idx == addr_val_) send_out_(sim); } + + void config_rout(unsigned idx, vvm_out_event::action_t o) + { out_[idx] = o; } + + private: + vvm_memory_t*mem_; + vpip_bit_t addr_[AWIDTH]; + vvm_out_event::action_t out_[WIDTH]; + + unsigned long addr_val_; + + void compute_() + { unsigned bit; + unsigned mask; + addr_val_ = 0; + for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1) + if (addr_[bit] == V1) addr_val_ |= mask; + } + + void send_out_(vvm_simulation*sim) + { vvm_bitset_tov = mem_->get_word(addr_val_); + for (unsigned bit = 0 ; bit < WIDTH ; bit += 1) + if (out_[bit]) { + vvm_event*ev = new vvm_out_event(sim, + ov[bit], + out_[bit]); + sim->active_event(ev); + } + } +}; + template class vvm_bufif1 { public: @@ -931,6 +987,9 @@ template class vvm_pevent { /* * $Log: vvm_gates.h,v $ + * Revision 1.24 1999/11/21 00:13:09 steve + * Support memories in continuous assignments. + * * Revision 1.23 1999/11/15 00:42:31 steve * Fixup to include right shift support. *