From 91d84e7dc784c83503c246a106734c56048fa525 Mon Sep 17 00:00:00 2001 From: steve Date: Tue, 16 Jan 2007 05:44:14 +0000 Subject: [PATCH] Major rework of array handling. Memories are replaced with the more general concept of arrays. The NetMemory and NetEMemory classes are removed from the ivl core program, and the IVL_LPM_RAM lpm type is removed from the ivl_target API. --- PExpr.h | 51 ++++-- PWire.cc | 9 +- design_dump.cc | 74 +++----- elab_expr.cc | 279 +++++++++++----------------- elab_lval.cc | 222 +++++++++------------- elab_net.cc | 189 +++++++++++-------- elab_sig.cc | 132 +++++++------- elaborate.cc | 14 +- emit.cc | 31 ++-- eval.cc | 11 +- eval_tree.cc | 52 +----- expr_synth.cc | 12 +- ivl.def | 1 + ivl_target.h | 278 ++++++++-------------------- net_assign.cc | 44 ++--- net_nex_input.cc | 18 +- net_scope.cc | 53 +----- netlist.cc | 382 ++++++++++++-------------------------- netlist.h | 253 +++++++++---------------- netmisc.h | 12 +- parse.y | 42 ++++- pform.cc | 33 ++-- set_width.cc | 14 +- symbol_search.cc | 15 +- syn-rules.y | 48 +---- t-dll-api.cc | 86 +++++---- t-dll-expr.cc | 53 +++--- t-dll-proc.cc | 27 ++- t-dll.cc | 181 ++++++------------ t-dll.h | 40 ++-- target.cc | 36 ++-- target.h | 14 +- tgt-stub/Makefile.in | 4 +- tgt-stub/expression.c | 273 +++++++++++++++++++++++++++ tgt-stub/priv.h | 5 +- tgt-stub/statement.c | 20 +- tgt-stub/stub.c | 415 +++++++++++------------------------------- tgt-vvp/draw_mux.c | 14 +- tgt-vvp/draw_ufunc.c | 25 ++- tgt-vvp/draw_vpi.c | 27 ++- tgt-vvp/eval_expr.c | 64 +++++-- tgt-vvp/eval_real.c | 25 ++- tgt-vvp/vector.c | 20 +- tgt-vvp/vvp_priv.h | 10 +- tgt-vvp/vvp_process.c | 195 ++++++++++++++++---- tgt-vvp/vvp_scope.c | 229 +++++++++++++---------- vvp/Makefile.in | 5 +- vvp/README.txt | 12 +- vvp/codes.h | 16 +- vvp/compile.cc | 54 +++++- vvp/compile.h | 26 ++- vvp/lexor.lex | 10 +- vvp/opcodes.txt | 41 ++++- vvp/parse.y | 82 ++++++--- vvp/schedule.cc | 36 +++- vvp/schedule.h | 14 +- vvp/vpi_callback.cc | 20 +- vvp/vpi_priv.h | 16 +- vvp/vpi_signal.cc | 47 ++--- vvp/vthread.cc | 84 ++++++++- vvp/vvp_net.h | 16 +- vvp/words.cc | 81 ++++++++- 62 files changed, 2388 insertions(+), 2204 deletions(-) create mode 100644 tgt-stub/expression.c diff --git a/PExpr.h b/PExpr.h index 8b3fb080c..fc203d833 100644 --- a/PExpr.h +++ b/PExpr.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: PExpr.h,v 1.86 2006/11/10 04:54:26 steve Exp $" +#ident "$Id: PExpr.h,v 1.87 2007/01/16 05:44:14 steve Exp $" #endif # include @@ -294,9 +294,10 @@ class PEIdent : public PExpr { bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const; private: - NetAssign_*elaborate_lval_net_part_(Design*, NetScope*, NetNet*) const; - NetAssign_*elaborate_lval_net_idx_up_(Design*, NetScope*, NetNet*) const; - NetAssign_*elaborate_lval_net_idx_do_(Design*, NetScope*, NetNet*) const; + NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const; + bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const; + bool elaborate_lval_net_idx_up_(Design*, NetScope*, NetAssign_*) const; + bool elaborate_lval_net_idx_do_(Design*, NetScope*, NetAssign_*) const; private: NetExpr*elaborate_expr_param(Design*des, @@ -306,24 +307,30 @@ class PEIdent : public PExpr { const NetExpr*par_msb, const NetExpr*par_lsb) const; NetExpr*elaborate_expr_net(Design*des, - NetScope*scope, - NetNet*net, - NetScope*found) const; + NetScope*scope, + NetNet*net, + NetScope*found, + bool sys_task_arg) const; + NetExpr*elaborate_expr_net_word_(Design*des, + NetScope*scope, + NetNet*net, + NetScope*found, + bool sys_task_arg) const; NetExpr*elaborate_expr_net_part_(Design*des, NetScope*scope, - NetNet*net, + NetESignal*net, NetScope*found) const; NetExpr*elaborate_expr_net_idx_up_(Design*des, NetScope*scope, - NetNet*net, + NetESignal*net, NetScope*found) const; NetExpr*elaborate_expr_net_idx_do_(Design*des, NetScope*scope, - NetNet*net, + NetESignal*net, NetScope*found) const; NetExpr*elaborate_expr_net_bit_(Design*des, NetScope*scope, - NetNet*net, + NetESignal*net, NetScope*found) const; hname_t path_; @@ -338,12 +345,13 @@ class PEIdent : public PExpr { // expression. If this is a reference to a vector, this is a // bit select. std::vector idx_; - - NetNet* elaborate_net_ram_(Design*des, NetScope*scope, - NetMemory*mem, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; + NetNet* elaborate_net_array_(Design*des, NetScope*scope, + NetNet*sig, unsigned lwidth, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) const; NetNet* elaborate_net_bitmux_(Design*des, NetScope*scope, NetNet*sig, @@ -354,9 +362,6 @@ class PEIdent : public PExpr { Link::strength_t drive1) const; private: - NetAssign_* elaborate_mem_lval_(Design*des, NetScope*scope, - NetMemory*mem) const; - NetNet* elaborate_lnet_common_(Design*des, NetScope*scope, bool implicit_net_ok, bool bidirectional_flag) const; @@ -650,6 +655,12 @@ class PECallFunction : public PExpr { /* * $Log: PExpr.h,v $ + * Revision 1.87 2007/01/16 05:44:14 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.86 2006/11/10 04:54:26 steve * Add test_width methods for PETernary and PEString. * diff --git a/PWire.cc b/PWire.cc index e7e8e9fef..1b3d463bf 100644 --- a/PWire.cc +++ b/PWire.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: PWire.cc,v 1.11 2005/07/07 16:22:49 steve Exp $" +#ident "$Id: PWire.cc,v 1.12 2007/01/16 05:44:14 steve Exp $" #endif # include "config.h" @@ -154,13 +154,18 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) { assert(lidx_ == 0); assert(ridx_ == 0); - assert(type_ == NetNet::REG); lidx_ = ldx; ridx_ = rdx; } /* * $Log: PWire.cc,v $ + * Revision 1.12 2007/01/16 05:44:14 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.11 2005/07/07 16:22:49 steve * Generalize signals to carry types. * diff --git a/design_dump.cc b/design_dump.cc index a7e124fc8..1d6bb90e8 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.171 2006/10/30 05:44:49 steve Exp $" +#ident "$Id: design_dump.cc,v 1.172 2007/01/16 05:44:14 steve Exp $" #endif # include "config.h" @@ -112,8 +112,8 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const /* Dump a net. This can be a wire or register. */ void NetNet::dump_net(ostream&o, unsigned ind) const { - o << setw(ind) << "" << type() << ": " << name() << "[" << - pin_count() << "]"; + o << setw(ind) << "" << type() << ": " << name() + << "[" << s0_ << ":" << e0_ << " count=" << pin_count() << "]"; if (local_flag_) o << " (local)"; o << " " << data_type_; @@ -167,13 +167,6 @@ void NetNet::dump_net(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } -void NetMemory::dump(ostream&o, unsigned ind) const -{ - o << setw(ind) << "" << name_ << "[" << width_ << "] " << - "[" << idxh_ << ":" << idxl_ << "]" << endl; -} - - /* Dump a NetNode and its pins. Dump what I know about the netnode on the first line, then list all the pins, with the name of the connected signal. */ @@ -239,6 +232,15 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetArrayDq::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "NetArrayDq: " << name() + << " array=" << mem_->name() + << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetCLShift::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " << @@ -427,14 +429,6 @@ void NetPartSelect::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 NetReplicate::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "NetReplicate: " @@ -566,21 +560,9 @@ void NetAssign_::dump_lval(ostream&o) const { if (sig_) { o << sig_->name(); - if (bmux_) { - o << "[" << *bmux_ << "]"; - - } else if (base_) { - o << "[" << *base_ << " +: " << lwid_ << "]"; + if (word_) { + o << "[word=" << *word_ << "]"; } - } else if (mem_) { - // Is there an obvious way to flag memories in the dump - // as different from the _real_ bit mux case? - // o << "**memory**"; - o << mem_->name() << "["; - if (bmux_) o << *bmux_; - else o << "**oops**"; - o << "]"; - if (base_) { o << "[" << *base_ << " +: " << lwid_ << "]"; } @@ -906,15 +888,6 @@ void NetScope::dump(ostream&o) const } while (cur != signals_->sig_next_); } - // Dump the memories, - if (memories_) { - NetMemory*cur = memories_->snext_; - do { - cur->dump(o, 4); - cur = cur->snext_; - } while (cur != memories_->snext_); - } - // Dump specparams typedef map::const_iterator specparam_it_t; for (specparam_it_t cur = specparams.begin() @@ -1148,14 +1121,9 @@ void NetESignal::dump(ostream&o) const { if (has_sign()) o << "+"; - o << name() << "[" << msi()<<":"<name() << "["; - if (idx_) idx_->dump(o); - o << "]"; + o << name(); + if (word_) o << "[word=" << *word_ << "]"; + o << "[" << msi()<<":"<"; else - o << ""; + o << "<" "???" ">"; } void NetETernary::dump(ostream&o) const @@ -1231,6 +1199,12 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.172 2007/01/16 05:44:14 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.171 2006/10/30 05:44:49 steve * Expression widths with unsized literals are pseudo-infinite width. * diff --git a/elab_expr.cc b/elab_expr.cc index fa67d03b1..52a34c7fc 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_expr.cc,v 1.116 2006/11/10 04:54:26 steve Exp $" +#ident "$Id: elab_expr.cc,v 1.117 2007/01/16 05:44:14 steve Exp $" #endif # include "config.h" @@ -687,14 +687,13 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, bool&unsized_flag) const { NetNet* net = 0; - NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; const NetExpr*ex1, *ex2; NetScope*found_in = symbol_search(des, scope, path_, - net, mem, par, eve, + net, par, eve, ex1, ex2); if (net != 0) { @@ -741,14 +740,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, assert(scope); NetNet* net = 0; - NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; const NetExpr*ex1, *ex2; NetScope*found_in = symbol_search(des, scope, path_, - net, mem, par, eve, + net, par, eve, ex1, ex2); // If the identifier name is a parameter name, then return @@ -760,126 +758,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // If the identifier names a signal (a register or wire) // then create a NetESignal node to handle it. if (net != 0) - return elaborate_expr_net(des, scope, net, found_in); - - - // If the identifier names a memory, then this is a - // memory reference and I must generate a NetEMemory - // object to handle it. - if (mem != 0) { - - if (idx_.empty()) { - - if (msb_ || lsb_) { - cerr << get_line() << ": error: " - << "Part select of a memory: " - << mem->name() << endl; - des->errors += 1; - } - - // If this memory is an argument to a system task, - // then it is OK for it to not have an index. - if (sys_task_arg) { - NetEMemory*node = new NetEMemory(mem); - node->set_line(*this); - return node; - } - - // If it is not a simple system task argument, - // this a missing index is an error. - cerr << get_line() << ": error: memory " << mem->name() - << " needs an index in this context." << endl; - des->errors += 1; - return 0; - } - - if (idx_.size() != mem->dimensions()) { - cerr << get_line() << ": error: " << idx_.size() - << " indices do not properly address a " - << mem->dimensions() << "-dimension memory/array." - << endl; - des->errors += 1; - return 0; - } - - // XXXX For now, only support single word index. - assert(idx_.size() == 1); - PExpr*addr = idx_[0]; - assert(addr); - - NetExpr*i = addr->elaborate_expr(des, scope, -1, false); - if (i == 0) { - cerr << get_line() << ": error: Unable to elaborate " - "index expression `" << *addr << "'" << endl; - des->errors += 1; - return 0; - } - - NetEMemory*node = new NetEMemory(mem, i); - node->set_line(*this); - - if (msb_ == 0 && lsb_ == 0) - return node; - - assert(msb_ && lsb_); - - assert(sel_ != SEL_NONE); - - if (sel_ == SEL_PART) { - - NetExpr*le = elab_and_eval(des, scope, lsb_, -1); - NetExpr*me = elab_and_eval(des, scope, msb_, -1); - - NetEConst*lec = dynamic_cast(le); - NetEConst*mec = dynamic_cast(me); - - if (lec == 0 || mec == 0) { - cerr << get_line() << ": error: Part select " - << "expressions must be constant." << endl; - des->errors += 1; - delete le; - delete me; - return node; - } - - verinum wedv = mec->value() - lec->value(); - unsigned wid = wedv.as_long() + 1; - - NetESelect*se = new NetESelect(node, le, wid); - - delete me; - return se; - } - - assert(sel_ == SEL_IDX_UP || sel_ == SEL_IDX_DO); - - NetExpr*wid_ex = elab_and_eval(des, scope, lsb_, -1); - NetEConst*wid_ec = dynamic_cast (wid_ex); - if (wid_ec == 0) { - cerr << lsb_->get_line() << ": error: " - << "Second expression of indexed part select " - << "most be constant." << endl; - des->errors += 1; - return node; - } - - unsigned wid = wid_ec->value().as_ulong(); - - NetExpr*idx_ex = elab_and_eval(des, scope, msb_, -1); - if (idx_ex == 0) { - return 0; - } - - if (sel_ == SEL_IDX_DO && wid > 1) { - idx_ex = make_add_expr(idx_ex, 1-(long)wid); - } - - - /* Wrap the param expression with a part select. */ - NetESelect*se = new NetESelect(node, idx_ex, wid); - se->set_line(*this); - return se; - } + return elaborate_expr_net(des, scope, net, found_in, sys_task_arg); // If the identifier is a named event. // is a variable reference. @@ -1176,11 +1055,64 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des, return tmp; } +/* + * Handle word selects of vector arrays. + */ +NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, + NetNet*net, NetScope*found_in, + bool sys_task_arg) const +{ + assert(sys_task_arg || !idx_.empty()); + NetExpr*word_index = idx_.empty() + ? 0 + : elab_and_eval(des, scope, idx_[0], -1); + if (word_index == 0 && !sys_task_arg) + return 0; + + if (NetEConst*word_addr = dynamic_cast(word_index)) { + long addr = word_addr->value().as_long(); + + // Special case: The index is out of range, so the value + // of this expression is a 'bx vector the width of a word. + if (!net->array_index_is_valid(addr)) { + verinum xxx (verinum::Vx, net->vector_width()); + NetEConst*resx = new NetEConst(xxx); + resx->set_line(*this); + delete word_index; + return resx; + } + + // Recalculate the constant address with the adjusted base. + unsigned use_addr = net->array_index_to_address(addr); + if (use_addr != addr) { + verinum val (use_addr, 8*sizeof(use_addr)); + NetEConst*tmp = new NetEConst(val); + tmp->set_line(*this); + delete word_index; + word_index = tmp; + } + } + + NetESignal*res = new NetESignal(net, word_index); + res->set_line(*this); + + if (sel_ == SEL_PART) + return elaborate_expr_net_part_(des, scope, res, found_in); + + if (sel_ == SEL_IDX_UP) + return elaborate_expr_net_idx_up_(des, scope, res, found_in); + + if (sel_ == SEL_IDX_DO) + return elaborate_expr_net_idx_do_(des, scope, res, found_in); + + return res; +} + /* * Handle part selects of NetNet identifiers. */ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, - NetNet*net, NetScope*found_in)const + NetESignal*net, NetScope*found_in) const { long msv, lsv; assert(idx_.empty()); @@ -1199,40 +1131,37 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, des->errors += 1; //delete lsn; //delete msn; - return 0; + return net; } assert(wid <= net->vector_width()); - if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) { + if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) { cerr << get_line() << ": error: part select [" << msv << ":" << lsv << "] out of order." << endl; des->errors += 1; //delete lsn; //delete msn; - return 0; + return net; } - if (net->sb_to_idx(msv) >= net->vector_width()) { + if (net->sig()->sb_to_idx(msv) >= net->vector_width()) { cerr << get_line() << ": error: part select [" << msv << ":" << lsv << "] out of range." << endl; des->errors += 1; //delete lsn; //delete msn; - return 0; + return net; } - NetESignal*tmp = new NetESignal(net); - tmp->set_line(*this); - // If the part select convers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width()) - return tmp; + if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width()) + return net; - NetExpr*ex = new NetEConst(verinum(net->sb_to_idx(lsv))); - NetESelect*ss = new NetESelect(tmp, ex, wid); + NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv))); + NetESelect*ss = new NetESelect(net, ex, wid); ss->set_line(*this); return ss; @@ -1242,14 +1171,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, * Part select indexed up, i.e. net[ +: ] */ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, - NetNet*net, NetScope*found_in)const + NetESignal*net, NetScope*found_in) const { assert(lsb_ != 0); assert(msb_ != 0); - assert(idx_.empty()); - - NetESignal*sig = new NetESignal(net); - sig->set_line(*this); NetExpr*base = elab_and_eval(des, scope, msb_, -1); @@ -1266,11 +1191,11 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, // If the part select convers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width()) - return sig; + if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width()) + return net; } - NetESelect*ss = new NetESelect(sig, base, wid); + NetESelect*ss = new NetESelect(net, base, wid); ss->set_line(*this); if (debug_elaborate) { @@ -1285,14 +1210,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, * Part select up, i.e. net[ +: ] */ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, - NetNet*net, NetScope*found_in)const + NetESignal*net, NetScope*found_in)const { assert(lsb_ != 0); assert(msb_ != 0); - assert(idx_.empty()); - - NetESignal*sig = new NetESignal(net); - sig->set_line(*this); NetExpr*base = elab_and_eval(des, scope, msb_, -1); @@ -1308,12 +1229,13 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, // If the part select convers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sb_to_idx(lsv) == (wid-1) && wid == net->vector_width()) - return sig; + if (net->sig()->sb_to_idx(lsv) == (wid-1) + && wid == net->vector_width()) + return net; } NetExpr*base_adjusted = wid > 1? make_add_expr(base,1-wid) : base; - NetESelect*ss = new NetESelect(sig, base_adjusted, wid); + NetESelect*ss = new NetESelect(net, base_adjusted, wid); ss->set_line(*this); if (debug_elaborate) { @@ -1325,7 +1247,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, } NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, - NetNet*net, NetScope*found_in) const + NetESignal*net, NetScope*found_in) const { assert(msb_ == 0); assert(lsb_ == 0); @@ -1338,7 +1260,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, // making a mux part in the netlist. if (NetEConst*msc = dynamic_cast (ex)) { long msv = msc->value().as_long(); - unsigned idx = net->sb_to_idx(msv); + unsigned idx = net->sig()->sb_to_idx(msv); if (idx >= net->vector_width()) { /* The bit select is out of range of the @@ -1350,69 +1272,72 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, cerr << get_line() << ": warning: Bit select [" << msv << "] out of range of vector " - << net->name() << "[" << net->msb() - << ":" << net->lsb() << "]." << endl; + << net->name() << "[" << net->sig()->msb() + << ":" << net->sig()->lsb() << "]." << endl; cerr << get_line() << ": : Replacing " << "expression with a constant 1'bx." << endl; delete ex; return tmp; } - NetESignal*tmp = new NetESignal(net); - tmp->set_line(*this); // If the vector is only one bit, we are done. The // bit select will return the scaler itself. if (net->vector_width() == 1) - return tmp; + return net; // Make an expression out of the index NetEConst*idx_c = new NetEConst(verinum(idx)); idx_c->set_line(*net); // Make a bit select with the canonical index - NetESelect*res = new NetESelect(tmp, idx_c, 1); + NetESelect*res = new NetESelect(net, idx_c, 1); res->set_line(*net); return res; } - NetESignal*node = new NetESignal(net); - // Non-constant bit select? punt and make a subsignal // device to mux the bit in the net. This is a fairly // complicated task because we need to generate // expressions to convert calculated bit select // values to canonical values that are used internally. - if (net->msb() < net->lsb()) { - ex = make_sub_expr(net->lsb(), ex); + if (net->sig()->msb() < net->sig()->lsb()) { + ex = make_sub_expr(net->sig()->lsb(), ex); } else { - ex = make_add_expr(ex, - net->lsb()); + ex = make_add_expr(ex, - net->sig()->lsb()); } - NetESelect*ss = new NetESelect(node, ex, 1); + NetESelect*ss = new NetESelect(net, ex, 1); ss->set_line(*this); return ss; } NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, - NetNet*net, NetScope*found_in) const + NetNet*net, NetScope*found_in, + bool sys_task_arg) const { + if (net->array_dimensions() > 0) + return elaborate_expr_net_word_(des, scope, net, found_in, sys_task_arg); + + NetESignal*node = new NetESignal(net); + node->set_line(*this); + // If this is a part select of a signal, then make a new // temporary signal that is connected to just the // selected bits. The lsb_ and msb_ expressions are from // the foo[msb:lsb] expression in the original. if (sel_ == SEL_PART) - return elaborate_expr_net_part_(des, scope, net, found_in); + return elaborate_expr_net_part_(des, scope, node, found_in); if (sel_ == SEL_IDX_UP) - return elaborate_expr_net_idx_up_(des, scope, net, found_in); + return elaborate_expr_net_idx_up_(des, scope, node, found_in); if (sel_ == SEL_IDX_DO) - return elaborate_expr_net_idx_do_(des, scope, net, found_in); + return elaborate_expr_net_idx_do_(des, scope, node, found_in); if (!idx_.empty()) - return elaborate_expr_net_bit_(des, scope, net, found_in); + return elaborate_expr_net_bit_(des, scope, node, found_in); // It's not anything else, so this must be a simple identifier // expression with no part or bit select. Return the signal @@ -1422,8 +1347,6 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, assert(lsb_ == 0); assert(idx_.empty()); - NetESignal*node = new NetESignal(net); - node->set_line(*this); return node; } @@ -1675,6 +1598,12 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, /* * $Log: elab_expr.cc,v $ + * Revision 1.117 2007/01/16 05:44:14 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.116 2006/11/10 04:54:26 steve * Add test_width methods for PETernary and PEString. * diff --git a/elab_lval.cc b/elab_lval.cc index 936793354..f7ba2b4d4 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2006 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_lval.cc,v 1.37 2006/11/04 06:19:25 steve Exp $" +#ident "$Id: elab_lval.cc,v 1.38 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -25,7 +25,7 @@ # include "PExpr.h" # include "netlist.h" # include "netmisc.h" - +# include "compiler.h" # include /* @@ -149,25 +149,10 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, bool is_force) const { NetNet* reg = 0; - NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; - symbol_search(des, scope, path_, reg, mem, par, eve); - - if (mem) { - if (is_force) { - cerr << get_line() << ": error: Memories " - << "(" << path_ << " in this case)" - << " are not allowed" - << " as l-values to force statements." << endl; - des->errors += 1; - return 0; - } - - return elaborate_mem_lval_(des, scope, mem); - } - + symbol_search(des, scope, path_, reg, par, eve); if (reg == 0) { cerr << get_line() << ": error: Could not find variable ``" << path_ << "'' in ``" << scope->name() << @@ -179,14 +164,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, assert(reg); - if (sel_ == SEL_PART) - return elaborate_lval_net_part_(des, scope, reg); + if (reg->array_dimensions() > 0) + return elaborate_lval_net_word_(des, scope, reg); - if (sel_ == SEL_IDX_UP) - return elaborate_lval_net_idx_up_(des, scope, reg); + if (sel_ == SEL_PART) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_part_(des, scope, lv); + return lv; + } - if (sel_ == SEL_IDX_DO) - return elaborate_lval_net_idx_do_(des, scope, reg); + if (sel_ == SEL_IDX_UP) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_idx_up_(des, scope, lv); + return lv; + } + + if (sel_ == SEL_IDX_DO) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_idx_do_(des, scope, lv); + return lv; + } /* Get the signal referenced by the identifier, and make sure it is a register. Wires are not allows in this context, @@ -300,22 +297,60 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return lv; } -NetAssign_* PEIdent::elaborate_lval_net_part_(Design*des, +NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, NetScope*scope, NetNet*reg) const +{ + assert(idx_.size() == 1); + + NetExpr*word = elab_and_eval(des, scope, idx_[0], -1); + + // If there is a non-zero base to the memory, then build an + // expression to calculate the canonical address. + if (long base = reg->array_first()) { + + word = make_add_expr(word, 0-base); + if (NetExpr*tmp = word->eval_tree()) { + word = tmp; + } + } + + NetAssign_*lv = new NetAssign_(reg); + lv->set_word(word); + + if (debug_elaborate) + cerr << get_line() << ": debug: Set array word=" << *word << endl; + + /* An array word may also have part selects applied to them. */ + + if (sel_ == SEL_PART) + elaborate_lval_net_part_(des, scope, lv); + + if (sel_ == SEL_IDX_UP) + elaborate_lval_net_idx_up_(des, scope, lv); + + if (sel_ == SEL_IDX_DO) + elaborate_lval_net_idx_do_(des, scope, lv); + + return lv; +} + +bool PEIdent::elaborate_lval_net_part_(Design*des, + NetScope*scope, + NetAssign_*lv) const { long msb, lsb; bool flag = calculate_parts_(des, scope, msb, lsb); if (!flag) - return 0; + return false; - NetAssign_*lv = 0; + NetNet*reg = lv->sig(); + assert(reg); if (msb == reg->msb() && lsb == reg->lsb()) { /* No bit select, and part select covers the entire vector. Simplest case. */ - lv = new NetAssign_(reg); } else { @@ -331,7 +366,7 @@ NetAssign_* PEIdent::elaborate_lval_net_part_(Design*des, << reg->name() << "[" << msb<<":"<errors += 1; - return 0; + return false; } /* If the part select extends beyond the extreme of the @@ -344,23 +379,25 @@ NetAssign_* PEIdent::elaborate_lval_net_part_(Design*des, << reg->name() << "[" << msb<<":"<errors += 1; - return 0; + return false; } - lv = new NetAssign_(reg); lv->set_part(new NetEConst(verinum(loff)), wid); } - return lv; + return true; } -NetAssign_* PEIdent::elaborate_lval_net_idx_up_(Design*des, - NetScope*scope, - NetNet*reg) const +bool PEIdent::elaborate_lval_net_idx_up_(Design*des, + NetScope*scope, + NetAssign_*lv) const { assert(lsb_); assert(msb_); + NetNet*reg = lv->sig(); + assert(reg); + if (reg->type() != NetNet::REG) { cerr << get_line() << ": error: " << path_ << " is not a reg/integer/time in " << scope->name() << @@ -368,7 +405,7 @@ NetAssign_* PEIdent::elaborate_lval_net_idx_up_(Design*des, cerr << reg->get_line() << ": : " << path_ << " is declared here as " << reg->type() << "." << endl; des->errors += 1; - return 0; + return false; } unsigned long wid; @@ -382,112 +419,25 @@ NetAssign_* PEIdent::elaborate_lval_net_idx_up_(Design*des, else if (reg->lsb() != 0) base = make_add_expr(base, - reg->lsb()); - NetAssign_*lv = new NetAssign_(reg); + if (debug_elaborate) + cerr << get_line() << ": debug: Set part select width=" + << wid << ", base=" << *base << endl; + lv->set_part(base, wid); - return lv; + return true; } -NetAssign_* PEIdent::elaborate_lval_net_idx_do_(Design*des, - NetScope*scope, - NetNet*reg) const +bool PEIdent::elaborate_lval_net_idx_do_(Design*des, + NetScope*scope, + NetAssign_*lv) const { assert(lsb_); assert(msb_); cerr << get_line() << ": internal error: don't know how to " "deal with SEL_IDX_DO in lval?" << endl; des->errors += 1; - return 0; -} - -NetAssign_* PEIdent::elaborate_mem_lval_(Design*des, NetScope*scope, - NetMemory*mem) const -{ - if (idx_.empty()) { - cerr << get_line() << ": error: Assign to memory \"" - << mem->name() << "\" requires a word select index." - << endl; - des->errors += 1; - return 0; - } - - if (idx_.size() != mem->dimensions()) { - cerr << get_line() << ": error: " << idx_.size() - << " indices do not properly address a " - << mem->dimensions() << "-dimension memory/array." - << endl; - des->errors += 1; - return 0; - } - - // XXXX For now, require exactly 1 index. - assert(idx_.size() == 1); - - /* Elaborate the address expression. */ - NetExpr*ix = elab_and_eval(des, scope, idx_[0], -1); - if (ix == 0) - return 0; - - NetAssign_*lv = new NetAssign_(mem); - lv->set_bmux(ix); - - /* If there is no extra part select, then we are done. */ - if (msb_ == 0 && lsb_ == 0) { - lv->set_part(0, mem->width()); - return lv; - } - - assert(sel_ != SEL_NONE); - assert(msb_ && lsb_); - - if (sel_ == SEL_PART) { - NetExpr*le = elab_and_eval(des, scope, lsb_, -1); - NetExpr*me = elab_and_eval(des, scope, msb_, -1); - - NetEConst*lec = dynamic_cast(le); - NetEConst*mec = dynamic_cast(me); - - if (lec == 0 || mec == 0) { - cerr << get_line() << ": error: Part select " - << "expressions must be constant." << endl; - des->errors += 1; - delete le; - delete me; - return lv; - } - - verinum wedv = mec->value() - lec->value(); - unsigned wid = wedv.as_long() + 1; - - lv->set_part(lec, wid); - return lv; - } - - assert(sel_ == SEL_IDX_UP || sel_ == SEL_IDX_DO); - - NetExpr*wid_ex = elab_and_eval(des, scope, lsb_, -1); - NetEConst*wid_ec = dynamic_cast (wid_ex); - if (wid_ec == 0) { - cerr << lsb_->get_line() << ": error: " - << "Second expression of indexed part select " - << "most be constant." << endl; - des->errors += 1; - return lv; - } - - unsigned wid = wid_ec->value().as_ulong(); - - NetExpr*base_ex = elab_and_eval(des, scope, msb_, -1); - if (base_ex == 0) { - return 0; - } - - if (sel_ == SEL_IDX_DO && wid > 1) { - base_ex = make_add_expr(base_ex, 1-(long)wid); - } - - lv->set_part(base_ex, wid); - return lv; + return false; } NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const @@ -500,6 +450,12 @@ NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const /* * $Log: elab_lval.cc,v $ + * Revision 1.38 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.37 2006/11/04 06:19:25 steve * Remove last bits of relax_width methods, and use test_width * to calculate the width of an r-value expression that may diff --git a/elab_net.cc b/elab_net.cc index 15628fed8..122c0aaba 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_net.cc,v 1.191 2006/12/08 03:43:26 steve Exp $" +#ident "$Id: elab_net.cc,v 1.192 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -1594,18 +1594,10 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope, assert(scope); NetNet* sig = 0; - NetMemory* mem = 0; - const NetExpr*par = 0; + const NetExpr*par = 0; NetEvent* eve = 0; - symbol_search(des, scope, path_, sig, mem, par, eve); - - /* If the identifier is a memory instead of a signal, - then handle it elsewhere. Create a RAM. */ - if (mem != 0) { - return elaborate_net_ram_(des, scope, mem, lwidth, - rise, fall, decay); - } + symbol_search(des, scope, path_, sig, par, eve); /* If this is a parameter name, then create a constant node that connects to a signal with the correct name. */ @@ -1681,6 +1673,13 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope, assert(sig); + /* Handle the case that this is an array elsewhere. */ + if (sig->array_dimensions() > 0) { + return elaborate_net_array_(des, scope, sig, lwidth, + rise, fall, decay, + drive0, drive1); + } + /* Catch the case of a non-constant bit select. That should be handled elsewhere. */ if (! idx_.empty()) { @@ -1728,68 +1727,77 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope, return sig; } -/* - * When I run into an identifier in an expression that refers to a - * memory, create a RAM port object. - */ -NetNet* PEIdent::elaborate_net_ram_(Design*des, NetScope*scope, - NetMemory*mem, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const +NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope, + NetNet*sig, unsigned lwidth, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) const { - assert(scope); - - if (idx_.empty()) { - cerr << get_line() << ": error: memory reference without" - " the required index expression." << endl; - des->errors += 1; - return 0; - } - assert(msb_ == 0); assert(lsb_ == 0); assert(idx_.size() == 1); - /* Even if this expression must be fully self determined, the - index expression does not, so make sure this flag is off - while elaborating the address expression. */ - const bool must_be_self_determined_save = must_be_self_determined_flag; - must_be_self_determined_flag = false; - - NetExpr*adr_expr = elab_and_eval(des, scope, idx_[0], -1); - - /* If an offset is needed, subtract it from the address to get - an expression for the canonical address. */ - if (mem->index_to_address(0) != 0) { - adr_expr = make_add_expr(adr_expr, mem->index_to_address(0)); - if (NetExpr*tmp = adr_expr->eval_tree()) { - delete adr_expr; - adr_expr = tmp; - } - } - NetNet*adr = adr_expr->synthesize(des); - delete adr_expr; - - must_be_self_determined_flag = must_be_self_determined_save; - - if (adr == 0) + NetExpr*index_ex = elab_and_eval(des, scope, idx_[0], -1); + if (index_ex == 0) return 0; - NetRamDq*ram = new NetRamDq(scope, scope->local_symbol(), - mem, adr->vector_width()); - des->add_node(ram); + if (NetEConst*index_co = dynamic_cast (index_ex)) { + long index = index_co->value().as_long(); - connect(ram->pin_Address(), adr->pin(0)); + if (!sig->array_index_is_valid(index)) { + // Oops! The index is a constant known to be + // outside the array. Change the expression to a + // constant X vector. + verinum xxx (verinum::Vx, sig->vector_width()); + NetConst*con_n = new NetConst(scope, scope->local_symbol(), xxx); + des->add_node(con_n); + con_n->set_line(*index_co); - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, ram->width()); - osig->data_type(IVL_VT_LOGIC); - osig->local_flag(true); + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::IMPLICIT, sig->vector_width()); + tmp->set_line(*this); + tmp->local_flag(true); + tmp->data_type(sig->data_type()); + connect(tmp->pin(0), con_n->pin(0)); + return tmp; + } - connect(ram->pin_Q(), osig->pin(0)); + assert(sig->array_index_is_valid(index)); + index = sig->array_index_to_address(index); - return osig; + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::IMPLICIT, sig->vector_width()); + tmp->set_line(*this); + tmp->local_flag(true); + connect(tmp->pin(0), sig->pin(index)); + return tmp; + } + + unsigned selwid = index_ex->expr_width(); + + NetArrayDq*mux = new NetArrayDq(scope, scope->local_symbol(), + sig, selwid); + mux->set_line(*this); + des->add_node(mux); + + // Adjust the expression to calculate the canonical offset? + if (long array_base = sig->array_first()) { + index_ex = make_add_expr(index_ex, 0-array_base); + } + + NetNet*index_net = index_ex->synthesize(des); + connect(mux->pin_Address(), index_net->pin(0)); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::IMPLICIT, sig->vector_width()); + tmp->set_line(*this); + tmp->local_flag(true); + tmp->data_type(sig->data_type()); + connect(tmp->pin(0), mux->pin_Result()); + + return tmp; } /* @@ -2127,19 +2135,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, assert(scope); NetNet* sig = 0; - NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; - symbol_search(des, scope, path_, sig, mem, par, eve); - - if (mem != 0) { - cerr << get_line() << ": error: memories (" << path_ - << ") cannot be l-values in continuous " - << "assignments." << endl; - des->errors += 1; - return 0; - } + symbol_search(des, scope, path_, sig, par, eve); if (eve != 0) { cerr << get_line() << ": error: named events (" << path_ @@ -2184,12 +2183,44 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, sig->port_type(NetNet::PINOUT); } - unsigned midx, lidx; - if (! eval_part_select_(des, scope, sig, midx, lidx)) - return 0; + // Default part select is the entire word. + unsigned midx = sig->vector_width()-1, lidx = 0; + // The default word select is the first. + unsigned widx = 0; + + if (sig->array_dimensions() > 0) { + assert(!idx_.empty()); + + NetExpr*tmp_ex = elab_and_eval(des, scope, idx_[0], -1); + NetEConst*tmp = dynamic_cast(tmp_ex); + assert(tmp); + + long widx_val = tmp->value().as_long(); + widx = sig->array_index_to_address(widx_val); + delete tmp_ex; + + if (debug_elaborate) + cerr << get_line() << ": debug: Use [" << widx << "]" + << " to index l-value array." << endl; + + } else { + if (! eval_part_select_(des, scope, sig, midx, lidx)) + return 0; + } unsigned subnet_wid = midx-lidx+1; + if (sig->pin_count() > 1) { + assert(widx < sig->pin_count()); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + sig->type(), sig->vector_width()); + tmp->set_line(*this); + tmp->local_flag(true); + connect(sig->pin(widx), tmp->pin(0)); + sig = tmp; + } + /* If the desired l-value vector is narrower then the signal itself, then use a NetPartSelect node to arrange for connection to the desired bits. All this @@ -2850,6 +2881,12 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, /* * $Log: elab_net.cc,v $ + * Revision 1.192 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.191 2006/12/08 03:43:26 steve * Prevent name clash when processing parameter in net. * diff --git a/elab_sig.cc b/elab_sig.cc index 8d17fec29..4d1e71866 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_sig.cc,v 1.42 2006/06/02 04:48:50 steve Exp $" +#ident "$Id: elab_sig.cc,v 1.43 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -616,6 +616,9 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib, des, scope); + long array_s0 = 0; + long array_e0 = 0; + /* If the ident has idx expressions, then this is a memory. It can only have the idx registers after the msb and lsb expressions are filled. And, if it has one index, @@ -639,7 +642,7 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const if ((lcon == 0) || (rcon == 0)) { cerr << get_line() << ": internal error: The indices " - << "are not constant for memory ``" + << "are not constant for array ``" << hname_.peek_tail_name() << "''." << endl; des->errors += 1; return; @@ -653,73 +656,74 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const perm_string name = lex_strings.make(hname_.peek_tail_name()); - long lnum = lval.as_long(); - long rnum = rval.as_long(); - - new NetMemory(scope, name, wid, lnum, rnum); - // The constructor automatically adds the memory object - // to the scope. Do I need to set line number information? - - } else { - - /* If the net type is supply0 or supply1, replace it - with a simple wire with a pulldown/pullup with supply - strength. In other words, transform: - - supply0 foo; - - to: - - wire foo; - pulldown #(supply0) (foo); - - This reduces the backend burden, and behaves exactly - the same. */ - - NetLogic*pull = 0; - if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) { - NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1) - ? NetLogic::PULLUP - : NetLogic::PULLDOWN; - pull = new NetLogic(scope, scope->local_symbol(), - 1, pull_type, wid); - pull->set_line(*this); - pull->pin(0).drive0(Link::SUPPLY); - pull->pin(0).drive1(Link::SUPPLY); - des->add_node(pull); - wtype = NetNet::WIRE; - - if (debug_elaborate) { - cerr << get_line() << ": debug: " - << "Generate a SUPPLY pulldown for the " - << "supply0 net." << endl; - } - } - - perm_string name = lex_strings.make(hname_.peek_tail_name()); - if (debug_elaborate) { - cerr << get_line() << ": debug: Create signal " - << name << "["<name() << endl; - } - - NetNet*sig = new NetNet(scope, name, wtype, msb, lsb); - sig->data_type(data_type_); - sig->set_line(*this); - sig->port_type(port_type_); - sig->set_signed(get_signed()); - sig->set_isint(get_isint()); - - if (pull) - connect(sig->pin(0), pull->pin(0)); - - for (unsigned idx = 0 ; idx < nattrib ; idx += 1) - sig->attribute(attrib_list[idx].key, attrib_list[idx].val); + array_s0 = lval.as_long(); + array_e0 = rval.as_long(); } + + /* If the net type is supply0 or supply1, replace it + with a simple wire with a pulldown/pullup with supply + strength. In other words, transform: + + supply0 foo; + + to: + + wire foo; + pulldown #(supply0) (foo); + + This reduces the backend burden, and behaves exactly + the same. */ + + NetLogic*pull = 0; + if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) { + NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1) + ? NetLogic::PULLUP + : NetLogic::PULLDOWN; + pull = new NetLogic(scope, scope->local_symbol(), + 1, pull_type, wid); + pull->set_line(*this); + pull->pin(0).drive0(Link::SUPPLY); + pull->pin(0).drive1(Link::SUPPLY); + des->add_node(pull); + wtype = NetNet::WIRE; + + if (debug_elaborate) { + cerr << get_line() << ": debug: " + << "Generate a SUPPLY pulldown for the " + << "supply0 net." << endl; + } + } + + perm_string name = lex_strings.make(hname_.peek_tail_name()); + if (debug_elaborate) { + cerr << get_line() << ": debug: Create signal " + << name << "["<name() << endl; + } + + NetNet*sig = new NetNet(scope, name, wtype, msb, lsb, + array_s0, array_e0); + sig->data_type(data_type_); + sig->set_line(*this); + sig->port_type(port_type_); + sig->set_signed(get_signed()); + sig->set_isint(get_isint()); + + if (pull) + connect(sig->pin(0), pull->pin(0)); + + for (unsigned idx = 0 ; idx < nattrib ; idx += 1) + sig->attribute(attrib_list[idx].key, attrib_list[idx].val); } /* * $Log: elab_sig.cc,v $ + * Revision 1.43 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.42 2006/06/02 04:48:50 steve * Make elaborate_expr methods aware of the width that the context * requires of it. In the process, fix sizing of the width of unary diff --git a/elaborate.cc b/elaborate.cc index 1dbc70ad3..f2e352fe1 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elaborate.cc,v 1.354 2006/12/09 01:59:35 steve Exp $" +#ident "$Id: elaborate.cc,v 1.355 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -2295,12 +2295,11 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, if (PEIdent*id = dynamic_cast(expr_[idx]->expr())) { NetNet* sig = 0; - NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; NetScope*found_in = symbol_search(des, scope, id->path(), - sig, mem, par, eve); + sig, par, eve); if (found_in && eve) { wa->add_event(eve); @@ -2874,12 +2873,11 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const assert(scope); NetNet* sig = 0; - NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; NetScope*found_in = symbol_search(des, scope, event_, - sig, mem, par, eve); + sig, par, eve); if (found_in == 0) { cerr << get_line() << ": error: event <" << event_ << ">" @@ -3349,6 +3347,12 @@ Design* elaborate(listroots) /* * $Log: elaborate.cc,v $ + * Revision 1.355 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.354 2006/12/09 01:59:35 steve * Fix an uninitialized variable warning. * diff --git a/emit.cc b/emit.cc index 0ab23a61d..3d00ad606 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.88 2006/11/10 05:44:44 steve Exp $" +#ident "$Id: emit.cc,v 1.89 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -57,6 +57,11 @@ bool NetAddSub::emit_node(struct target_t*tgt) const return true; } +bool NetArrayDq::emit_node(struct target_t*tgt) const +{ + return tgt->lpm_array_dq(this); +} + bool NetCaseCmp::emit_node(struct target_t*tgt) const { tgt->net_case_cmp(this); @@ -125,12 +130,6 @@ bool NetPartSelect::emit_node(struct target_t*tgt) const return tgt->part_select(this); } -bool NetRamDq::emit_node(struct target_t*tgt) const -{ - tgt->lpm_ram_dq(this); - return true; -} - bool NetReplicate::emit_node(struct target_t*tgt) const { return tgt->replicate(this); @@ -357,13 +356,6 @@ void NetScope::emit_scope(struct target_t*tgt) const } while (cur != signals_->sig_next_); } - if (memories_) { - NetMemory*cur = memories_->snext_; - do { - tgt->memory(cur); - cur = cur->snext_; - } while (cur != memories_->snext_); - } } bool NetScope::emit_defs(struct target_t*tgt) const @@ -472,11 +464,6 @@ void NetECRealParam::expr_scan(struct expr_scan_t*tgt) const tgt->expr_rparam(this); } -void NetEMemory::expr_scan(struct expr_scan_t*tgt) const -{ - tgt->expr_memory(this); -} - void NetEParam::expr_scan(struct expr_scan_t*tgt) const { cerr << get_line() << ":internal error: unexpected NetEParam." @@ -540,6 +527,12 @@ int emit(const Design*des, const char*type) /* * $Log: emit.cc,v $ + * Revision 1.89 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.88 2006/11/10 05:44:44 steve * Process delay paths in second path over signals. * diff --git a/eval.cc b/eval.cc index 5c9feb553..3441410e1 100644 --- a/eval.cc +++ b/eval.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval.cc,v 1.43 2006/08/08 05:11:37 steve Exp $" +#ident "$Id: eval.cc,v 1.44 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -174,7 +174,6 @@ verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const { assert(scope); NetNet*net; - NetMemory*mem; NetEvent*eve; const NetExpr*expr; @@ -187,7 +186,7 @@ verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const } NetScope*found_in = symbol_search(des, scope, path_, - net, mem, expr, eve); + net, expr, eve); if (expr == 0) return 0; @@ -276,6 +275,12 @@ verinum* PEUnary::eval_const(const Design*des, NetScope*scope) const /* * $Log: eval.cc,v $ + * Revision 1.44 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.43 2006/08/08 05:11:37 steve * Handle 64bit delay constants. * diff --git a/eval_tree.cc b/eval_tree.cc index 4e3076bdb..d2f74fc16 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval_tree.cc,v 1.72 2006/11/04 06:16:27 steve Exp $" +#ident "$Id: eval_tree.cc,v 1.73 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -1190,50 +1190,6 @@ NetEConst* NetEConcat::eval_tree() return res; } -/* - * There are limits to our ability to evaluate a memory reference - * expression, because the content of a memory is never - * constant. However, the index expression may be precalculated, and - * there are certain index values that do give us constant results. - */ -NetExpr* NetEMemory::eval_tree() -{ - /* Attempt to evaluate the index expression to a constant, if - it is not already. */ - if (idx_ && !dynamic_cast(idx_)) { - NetExpr* tmp = idx_->eval_tree(); - if (tmp) { - delete idx_; - idx_ = tmp; - } - } - - NetEConst*itmp = dynamic_cast(idx_); - if (itmp == 0) - return 0; - - verinum ival = itmp->value(); - - /* If the index expression has any x or z bits, then we know - already that the expression result is a constant x. */ - if (! ival.is_defined()) { - verinum xres (verinum::Vx, mem_->width(), false); - NetEConst*res = new NetEConst(xres); - return res; - } - - /* If the index expression is outside the range of the memory, - then the result is a constant x. */ - unsigned norm_idx = mem_->index_to_address(ival.as_long()); - if (norm_idx >= mem_->count()) { - verinum xres (verinum::Vx, mem_->width(), false); - NetEConst*res = new NetEConst(xres); - return res; - } - - return 0; -} - NetExpr* NetEParam::eval_tree() { if (des_ == 0) { @@ -1696,6 +1652,12 @@ NetEConst* NetEUReduce::eval_tree() /* * $Log: eval_tree.cc,v $ + * Revision 1.73 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.72 2006/11/04 06:16:27 steve * Fix padding of constant eval of NetESelect. * diff --git a/expr_synth.cc b/expr_synth.cc index a19d3c66f..23926c426 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: expr_synth.cc,v 1.80 2006/08/08 05:11:37 steve Exp $" +#ident "$Id: expr_synth.cc,v 1.81 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -692,7 +692,7 @@ NetNet* NetEUReduce::synthesize(Design*des) return osig; } - +#if 0 NetNet* NetEMemory::synthesize(Design *des) { NetNet*adr = idx_->synthesize(des); @@ -719,7 +719,7 @@ NetNet* NetEMemory::synthesize(Design *des) return osig; } - +#endif NetNet* NetESelect::synthesize(Design *des) { @@ -890,6 +890,12 @@ NetNet* NetESignal::synthesize(Design*des) /* * $Log: expr_synth.cc,v $ + * Revision 1.81 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.80 2006/08/08 05:11:37 steve * Handle 64bit delay constants. * diff --git a/ivl.def b/ivl.def index b4df8863e..4d66cf449 100644 --- a/ivl.def +++ b/ivl.def @@ -62,6 +62,7 @@ ivl_logic_type ivl_logic_udp ivl_logic_width +ivl_lpm_array ivl_lpm_aset_value ivl_lpm_async_clr ivl_lpm_async_set diff --git a/ivl_target.h b/ivl_target.h index 55ba728c3..fa910ce61 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.171 2006/09/23 04:57:19 steve Exp $" +#ident "$Id: ivl_target.h,v 1.172 2007/01/16 05:44:15 steve Exp $" #endif # include @@ -59,6 +59,10 @@ _BEGIN_DECL * The following typedefs list the various cookies that may be passed * around. * + * ivl_array_t + * This object represent an array that can be a memory or a net + * array. (They are the same from the perspective of ivl_target.h.) + * * ivl_design_t * This object represents the entire elaborated design. Various * global properties and methods are available from this. @@ -137,6 +141,7 @@ _BEGIN_DECL * scope. These names are unique within a scope, but not necessarily * throughout the design. */ +typedef struct ivl_array_s *ivl_array_t; typedef struct ivl_delaypath_s*ivl_delaypath_t; typedef struct ivl_design_s *ivl_design_t; typedef struct ivl_event_s *ivl_event_t; @@ -153,7 +158,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t; typedef struct ivl_process_s *ivl_process_t; typedef struct ivl_scope_s *ivl_scope_t; typedef struct ivl_signal_s *ivl_signal_t; -typedef struct ivl_memory_s *ivl_memory_t; +typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */ typedef struct ivl_statement_s*ivl_statement_t; /* @@ -178,7 +183,7 @@ typedef enum ivl_drive_e { and incompatibilities to be introduced. */ typedef enum ivl_expr_type_e { IVL_EX_NONE = 0, - /* IVL_EX_BITSEL = 1, */ + IVL_EX_ARRAY = 18, IVL_EX_BINARY = 2, IVL_EX_CONCAT = 3, IVL_EX_EVENT = 17, @@ -225,6 +230,7 @@ typedef enum ivl_logic_e { /* This is the type of an LPM object. */ typedef enum ivl_lpm_type_e { IVL_LPM_ADD = 0, + IVL_LPM_ARRAY = 30, IVL_LPM_CONCAT = 16, IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */ IVL_LPM_CMP_EQ = 10, @@ -252,7 +258,7 @@ typedef enum ivl_lpm_type_e { IVL_LPM_SHIFTR = 7, IVL_LPM_SIGN_EXT=27, IVL_LPM_SUB = 8, - IVL_LPM_RAM = 9, + _IVL_LPM_RAM = 9, /* obsolete */ IVL_LPM_UFUNC = 14 } ivl_lpm_type_t; @@ -574,6 +580,14 @@ extern ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx); * * SEMANTIC NOTES * + * - IVL_EX_ARRAY + * This expression type is a special case of the IVL_EX_SIGNAL where + * the target is an array (ivl_signal_t with an array_count) but there + * is no index expression. This is used only in the special situation + * where the array is passed to a system task/function. The function + * ivl_expr_signal returns the ivl_signal_t of the array object, and + * from that all the properties of the array can be determined. + * * - IVL_EX_BINARY * * - IVL_EX_SELECT @@ -583,6 +597,21 @@ extern ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx); * is the base of a vector. The compiler has already figured out any * conversion from signal units to vector units, so the result of * ivl_expr_oper1 should range from 0 to ivl_expr_width(). + * + * - IVL_EX_SIGNAL + * This expression references a signal vector. The ivl_expr_signal + * function gets a handle for the signal that is referenced. The + * signal may be an array (see the ivl_signal_array_count function) + * that is addressed by the expression returned by the ivl_expr_oper1 + * function. This expression returns a *canonical* address. The core + * compiler already corrected the expression to account for index + * bases. + * + * The ivl_expr_width function returns the vector width of the signal + * word. The ivl_expr_value returns the data type of the word. + * + * Bit and part selects are not done here. The IVL_EX_SELECT + * expression does bit/part selects on the word read from the signal. */ extern ivl_expr_type_t ivl_expr_type(ivl_expr_t net); @@ -975,7 +1004,7 @@ extern const char* ivl_udp_name(ivl_udp_t net); * single ivl_lpm_data input are the same with, ivl_lpm_width. This * device carries a vector like other LPM devices. * - * - Memory port (IVL_LPM_RAM) + * - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY) * These are structural ports into a memory device. They represent * address/data ports of a memory device that the context can hook to * for read or write. Read devices have an ivl_lpm_q output port that @@ -1069,34 +1098,33 @@ extern ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_sync_clr(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net); + /* IVL_LPM_ARRAY */ +extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net); /* IVL_LPM_PART */ extern unsigned ivl_lpm_base(ivl_lpm_t net); - /* IVL_LPM_FF IVL_LPM_RAM */ + /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net); /* IVL_LPM_UFUNC */ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net); - /* IVL_LPM_FF IVL_LPM_RAM */ + /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); /* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT - IVL_LPM_MUX IVL_LPM_RAM IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB + IVL_LPM_MUX IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB IVL_LPM_UFUNC */ extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_SUB */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); - /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_RAM + /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_SUB IVL_LPM_UFUNC */ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx); - /* IVL_LPM_MUX IVL_LPM_RAM */ + /* IVL_LPM_MUX */ extern unsigned ivl_lpm_selects(ivl_lpm_t net); - /* IVL_LPM_MUX IVL_LPM_RAM */ + /* IVL_LPM_MUX */ extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net); /* IVL_LPM_CONCAT IVL_LPM_MUX IVL_LPM_REPEAT IVL_LPM_UFUNC */ extern unsigned ivl_lpm_size(ivl_lpm_t net); /* IVL_LPM_SFUNC */ extern const char*ivl_lpm_string(ivl_lpm_t net); - /* IVL_LPM_RAM */ -extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net); - /* LVAL * The l-values of assignments are concatenation of ivl_lval_t @@ -1149,12 +1177,21 @@ extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net); * The ivl_lval_part_off is the canonical base of a part or * bit select. * - * - Memory words + * - Memory words (Replace this with Array words below) * If the l-value is a memory word, the ivl_lval_mem function returns * a non-nil value. The ivl_lval_idx function will return an * expression that calculates an address for the memory. The compiler * will assure that the ivl_lval_width will exactly match the * ivl_memory_width of the memory word. + * + * - Array words + * If the l-value is an array, then ivl_lval_idx function will return + * an expression that calculates the address of the array word. If + * the referenced signal has more then one word, this expression must + * be present. If the signal has exactly one word (it is not an array) + * then the ivl_lval_idx exression must *not* be present. + * + * For array words, the ivl_lval_width is the width of the word. */ extern unsigned ivl_lval_width(ivl_lval_t net); @@ -1432,17 +1469,22 @@ extern int ivl_scope_time_units(ivl_scope_t net); * Signals have a name (obviously) and types. A signal may also be * signed or unsigned. * - * ivl_signal_pins (replace these with ivl_signal_nex) - * ivl_signal_pin - * The ivl_signal_pin function returns the nexus connected to the - * signal. If the signal is a vector, the idx can be a non-zero - * value, and the result is the nexus for the specified bit. - * * ivl_signal_nex * This is the nexus of the signal. This is used for managing * connections to the rest of the net. There is exactly one pin for - * a signal. If the signal represents a vector, then the entire - * vector is carried through the single output. + * each word of a signal. Each word may in turn be a vector. The + * word address is the zero-based index for the word. It is up to + * the context to translate different bases to the canonical address. + * + * ivl_signal_array_base + * ivl_signal_array_count + * The signal may be arrayed. If so, the array_count is >1. Each + * word of the array has its own nexus. The array_base is the + * address is the Verilg source for the canonical zero word. This + * may be negative, positive or zero. + * + * Note that arraying of the signal into words is distinct from the + * vectors. The width of a signal is the width of a WORD. * * ivl_signal_msb * ivl_signal_lsb @@ -1503,7 +1545,9 @@ extern int ivl_scope_time_units(ivl_scope_t net); * key does not exist, the function returns 0. */ -extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net); +extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word); +extern int ivl_signal_array_base(ivl_signal_t net); +extern unsigned ivl_signal_array_count(ivl_signal_t net); extern int ivl_signal_msb(ivl_signal_t net); extern int ivl_signal_lsb(ivl_signal_t net); extern unsigned ivl_signal_width(ivl_signal_t net); @@ -1706,10 +1750,6 @@ extern unsigned ivl_stmt_lvals(ivl_statement_t net); extern unsigned ivl_stmt_lwidth(ivl_statement_t net); /* IVL_ST_STASK */ extern const char* ivl_stmt_name(ivl_statement_t net); -#if 0 -extern ivl_nexus_t ivl_stmt_nexus(ivl_statement_t net, unsigned idx); -extern unsigned ivl_stmt_nexus_count(ivl_statement_t net); -#endif /* IVL_ST_STASK */ extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx); /* IVL_ST_STASK */ @@ -1752,6 +1792,12 @@ _END_DECL /* * $Log: ivl_target.h,v $ + * Revision 1.172 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.171 2006/09/23 04:57:19 steve * Basic support for specify timing. * @@ -1781,181 +1827,5 @@ _END_DECL * * Revision 1.162 2005/11/20 15:58:25 steve * Document the IVL_ST_DELAY statements. - * - * Revision 1.161 2005/09/19 21:45:35 steve - * Spelling patches from Larry. - * - * Revision 1.160 2005/09/01 04:11:37 steve - * Generate code to handle real valued muxes. - * - * Revision 1.159 2005/08/06 17:58:16 steve - * Implement bi-directional part selects. - * - * Revision 1.158 2005/07/11 16:56:50 steve - * Remove NetVariable and ivl_variable_t structures. - * - * Revision 1.157 2005/07/07 16:22:49 steve - * Generalize signals to carry types. - * - * Revision 1.156 2005/06/13 22:25:37 steve - * Document ivl_logic_delay function. - * - * Revision 1.155 2005/05/24 01:44:28 steve - * Do sign extension of structuran nets. - * - * Revision 1.154 2005/05/08 23:44:08 steve - * Add support for variable part select. - * - * Revision 1.153 2005/05/07 03:14:00 steve - * Clarify internal delays for assignments. - * - * Revision 1.152 2005/04/24 23:44:02 steve - * Update DFF support to new data flow. - * - * Revision 1.151 2005/04/13 06:35:11 steve - * Make logic aware of strength. - * - * Revision 1.150 2005/04/08 04:52:31 steve - * Make clear that memory addresses are cannonical. - * - * Revision 1.149 2005/04/06 05:29:08 steve - * Rework NetRamDq and IVL_LPM_RAM nodes. - * - * Revision 1.148 2005/04/01 06:04:30 steve - * Clean up handle of UDPs. - * - * Revision 1.147 2005/03/18 02:56:03 steve - * Add support for LPM_UFUNC user defined functions. - * - * Revision 1.146 2005/03/09 04:53:40 steve - * Generate code for new form of memory ports. - * - * Revision 1.145 2005/03/05 05:47:42 steve - * Handle memory words in l-value concatenations. - * - * Revision 1.144 2005/03/03 04:34:42 steve - * Rearrange how memories are supported as vvp_vector4 arrays. - * - * Revision 1.143 2005/02/19 02:43:38 steve - * Support shifts and divide. - * - * Revision 1.142 2005/02/14 01:51:39 steve - * Handle bit selects in l-values to assignments. - * - * Revision 1.141 2005/02/13 01:15:07 steve - * Replace supply nets with wires connected to pullup/down supply devices. - * - * Revision 1.140 2005/02/12 06:25:40 steve - * Restructure NetMux devices to pass vectors. - * Generate NetMux devices from ternary expressions, - * Reduce NetMux devices to bufif when appropriate. - * - * Revision 1.139 2005/02/08 00:12:36 steve - * Add the NetRepeat node, and code generator support. - * - * Revision 1.138 2005/02/03 04:56:20 steve - * laborate reduction gates into LPM_RED_ nodes. - * - * Revision 1.137 2005/01/29 18:46:18 steve - * Netlist boolean expressions generate gate vectors. - * - * Revision 1.136 2005/01/29 16:47:20 steve - * Clarify width of nexus. - * - * Revision 1.135 2005/01/28 05:39:33 steve - * Simplified NetMult and IVL_LPM_MULT. - * - * Revision 1.134 2005/01/24 05:28:30 steve - * Remove the NetEBitSel and combine all bit/part select - * behavior into the NetESelect node and IVL_EX_SELECT - * ivl_target expression type. - * - * Revision 1.133 2005/01/22 17:36:59 steve - * stub dump signed flags of magnitude compare. - * - * Revision 1.132 2005/01/22 01:06:55 steve - * Change case compare from logic to an LPM node. - * - * Revision 1.131 2005/01/09 20:16:01 steve - * Use PartSelect/PV and VP to handle part selects through ports. - * - * Revision 1.130 2004/12/29 23:55:43 steve - * Unify elaboration of l-values for all proceedural assignments, - * including assing, cassign and force. - * - * Generate NetConcat devices for gate outputs that feed into a - * vector results. Use this to hande gate arrays. Also let gate - * arrays handle vectors of gates when the outputs allow for it. - * - * Revision 1.129 2004/12/18 18:56:18 steve - * Add ivl_event_scope, and better document ivl_event_X methods. - * - * Revision 1.128 2004/12/15 17:10:40 steve - * Fixup force statement elaboration. - * - * Revision 1.127 2004/12/11 02:31:26 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - * Revision 1.126 2004/10/04 01:10:53 steve - * Clean up spurious trailing white space. - * - * Revision 1.125 2004/09/25 01:58:12 steve - * Some commentary on ivl_logic_pin. - * - * Revision 1.124 2003/12/03 02:46:24 steve - * Add support for wait on list of named events. - * - * Revision 1.123 2003/11/08 20:06:21 steve - * Spelling fixes in comments. - * - * Revision 1.122 2003/08/22 23:14:26 steve - * Preserve variable ranges all the way to the vpi. - * - * Revision 1.121 2003/08/15 02:23:52 steve - * Add synthesis support for synchronous reset. - * - * Revision 1.120 2003/07/30 01:13:28 steve - * Add support for triand and trior. - * - * Revision 1.119 2003/06/23 01:25:44 steve - * Module attributes make it al the way to ivl_target. - * - * Revision 1.118 2003/05/14 05:26:41 steve - * Support real expressions in case statements. - * - * Revision 1.117 2003/04/22 04:48:29 steve - * Support event names as expressions elements. - * - * Revision 1.116 2003/04/11 05:18:08 steve - * Handle signed magnitude compare all the - * way through to the vvp code generator. - * - * Revision 1.115 2003/03/10 23:40:53 steve - * Keep parameter constants for the ivl_target API. - * - * Revision 1.114 2003/03/06 01:24:37 steve - * Obsolete the ivl_event_name function. - * - * Revision 1.113 2003/03/06 00:28:41 steve - * All NetObj objects have lex_string base names. - * - * Revision 1.112 2003/02/26 01:29:24 steve - * LPM objects store only their base names. - * - * Revision 1.111 2003/01/30 16:23:07 steve - * Spelling fixes. - * - * Revision 1.110 2003/01/26 21:15:58 steve - * Rework expression parsing and elaboration to - * accommodate real/realtime values and expressions. - * - * Revision 1.109 2002/12/21 00:55:58 steve - * The $time system task returns the integer time - * scaled to the local units. Change the internal - * implementation of vpiSystemTime the $time functions - * to properly account for this. Also add $simtime - * to get the simulation time. */ #endif diff --git a/net_assign.cc b/net_assign.cc index 8926482ec..485b2cc45 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: net_assign.cc,v 1.21 2006/02/02 02:43:58 steve Exp $" +#ident "$Id: net_assign.cc,v 1.22 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -39,20 +39,13 @@ unsigned count_lval_width(const NetAssign_*idx) } NetAssign_::NetAssign_(NetNet*s) -: sig_(s), mem_(0), bmux_(0), base_(0) +: sig_(s), word_(0), base_(0) { lwid_ = sig_->vector_width(); sig_->incr_lref(); more = 0; } -NetAssign_::NetAssign_(NetMemory*s) -: sig_(0), mem_(s), bmux_(0), base_(0) -{ - lwid_ = mem_->width(); - more = 0; -} - NetAssign_::~NetAssign_() { if (sig_) { @@ -62,23 +55,23 @@ NetAssign_::~NetAssign_() } assert( more == 0 ); - if (bmux_) delete bmux_; + if (word_) delete word_; } -void NetAssign_::set_bmux(NetExpr*r) +void NetAssign_::set_word(NetExpr*r) { - assert(bmux_ == 0); - bmux_ = r; + assert(word_ == 0); + word_ = r; } -NetExpr* NetAssign_::bmux() +NetExpr* NetAssign_::word() { - return bmux_; + return word_; } -const NetExpr* NetAssign_::bmux() const +const NetExpr* NetAssign_::word() const { - return bmux_; + return word_; } const NetExpr* NetAssign_::get_base() const @@ -88,17 +81,13 @@ const NetExpr* NetAssign_::get_base() const unsigned NetAssign_::lwidth() const { - if (mem_) return lwid_; - else if (bmux_) return 1; - else return lwid_; + return lwid_; } perm_string NetAssign_::name() const { if (sig_) { return sig_->name(); - } else if (mem_) { - return mem_->name(); } else { return perm_string::literal(""); } @@ -109,11 +98,6 @@ NetNet* NetAssign_::sig() const return sig_; } -NetMemory* NetAssign_::mem() const -{ - return mem_; -} - void NetAssign_::set_part(NetExpr*base, unsigned wid) { base_ = base; @@ -275,6 +259,12 @@ NetRelease::~NetRelease() /* * $Log: net_assign.cc,v $ + * Revision 1.22 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.21 2006/02/02 02:43:58 steve * Allow part selects of memory words in l-values. * diff --git a/net_nex_input.cc b/net_nex_input.cc index e077d84a7..ea62af9ef 100644 --- a/net_nex_input.cc +++ b/net_nex_input.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_input.cc,v 1.15 2006/04/16 00:15:43 steve Exp $" +#ident "$Id: net_nex_input.cc,v 1.16 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -78,12 +78,6 @@ NexusSet* NetECReal::nex_input() return new NexusSet; } -NexusSet* NetEMemory::nex_input() -{ - NexusSet*result = idx_->nex_input(); - return result; -} - /* * A parameter by definition has no inputs. It represents a constant * value, even if that value is a constant expression. @@ -171,8 +165,8 @@ NexusSet* NetEUnary::nex_input() NexusSet* NetAssign_::nex_input() { NexusSet*result = new NexusSet; - if (bmux_) { - NexusSet*tmp = bmux_->nex_input(); + if (word_) { + NexusSet*tmp = word_->nex_input(); result->add(*tmp); delete tmp; } @@ -393,6 +387,12 @@ NexusSet* NetWhile::nex_input() /* * $Log: net_nex_input.cc,v $ + * Revision 1.16 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.15 2006/04/16 00:15:43 steve * Fix part selects in l-values. * diff --git a/net_scope.cc b/net_scope.cc index 6f7bd41ea..d0be84796 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: net_scope.cc,v 1.35 2005/11/27 05:56:20 steve Exp $" +#ident "$Id: net_scope.cc,v 1.36 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -38,7 +38,6 @@ NetScope::NetScope(NetScope*up, perm_string n, NetScope::TYPE t) : type_(t), up_(up), sib_(0), sub_(0) { - memories_ = 0; signals_ = 0; events_ = 0; lcounter_ = 0; @@ -358,50 +357,6 @@ NetNet* NetScope::find_signal_in_child(const hname_t&path) return cur->find_signal(path.peek_name(idx)); } -void NetScope::add_memory(NetMemory*mem) -{ - if (memories_ == 0) { - mem->snext_ = mem; - mem->sprev_ = mem; - } else { - mem->snext_ = memories_->snext_; - mem->sprev_ = memories_; - mem->snext_->sprev_ = mem; - mem->sprev_->snext_ = mem; - } - memories_ = mem; - mem->scope_ = this; -} - -void NetScope::rem_memory(NetMemory*mem) -{ - assert(mem->scope_ == this); - if (memories_ == mem) - memories_ = mem->sprev_; - - if (memories_ == mem) { - memories_ = 0; - } else { - mem->sprev_->snext_ = mem->snext_; - mem->snext_->sprev_ = mem->sprev_; - } - mem->scope_ = 0; -} - -NetMemory* NetScope::find_memory(const string&key) -{ - if (memories_ == 0) - return 0; - - NetMemory*cur = memories_; - do { - if (cur->name() == key.c_str()) - return cur; - cur = cur->sprev_; - } while (cur != memories_); - return 0; -} - /* * This method locates a child scope by name. The name is the simple * name of the child, no hierarchy is searched. @@ -457,6 +412,12 @@ string NetScope::local_hsymbol() /* * $Log: net_scope.cc,v $ + * Revision 1.36 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.35 2005/11/27 05:56:20 steve * Handle bit select of parameter with ranges. * diff --git a/netlist.cc b/netlist.cc index 5ada350b5..1eed66b15 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.250 2006/11/10 04:54:26 steve Exp $" +#ident "$Id: netlist.cc,v 1.251 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -333,7 +333,7 @@ uint64_t NetDelaySrc::get_delay(unsigned idx) const NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) : NetObj(s, n, 1), sig_next_(0), sig_prev_(0), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), - signed_(false), msb_(npins-1), lsb_(0), + signed_(false), msb_(npins-1), lsb_(0), s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0) { assert(s); @@ -367,11 +367,20 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) s->add_signal(this); } -NetNet::NetNet(NetScope*s, perm_string n, Type t, long ms, long ls) -: NetObj(s, n, 1), +static unsigned calculate_count(long s, long e) +{ + if (s >= e) + return s - e + 1; + else + return e - s + 1; +} + +NetNet::NetNet(NetScope*s, perm_string n, Type t, + long ms, long ls, long array_s, long array_e) +: NetObj(s, n, calculate_count(array_s, array_e)), sig_next_(0), sig_prev_(0), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), - msb_(ms), lsb_(ls), + msb_(ms), lsb_(ls), s0_(array_s), e0_(array_e), local_flag_(false), eref_count_(0), lref_count_(0) { assert(s); @@ -533,6 +542,43 @@ unsigned NetNet::sb_to_idx(long sb) const return lsb_ - sb; } +unsigned NetNet::array_dimensions() const +{ + if (s0_ == e0_) + return 0; + return 1; +} + +long NetNet::array_first() const +{ + if (s0_ < e0_) + return s0_; + else + return e0_; +} + +unsigned NetNet::array_count() const +{ + return calculate_count(s0_, e0_); +} + +bool NetNet::array_index_is_valid(long sb) const +{ + if (sb < s0_ && sb < e0_) + return false; + if (sb > e0_ && sb > s0_) + return false; + return true; +} + +unsigned NetNet::array_index_to_address(long sb) const +{ + if (s0_ <= e0_) + return sb - s0_; + else + return sb - e0_; +} + void NetNet::incr_eref() { eref_count_ += 1; @@ -973,6 +1019,55 @@ const Link& NetAddSub::pin_Result() const return pin(8); } +NetArrayDq::NetArrayDq(NetScope*s, perm_string n, NetNet*mem, unsigned awid) +: NetNode(s, n, 2), + mem_(mem), awidth_(awid) +{ + pin(0).set_dir(Link::OUTPUT); + pin(0).set_name(perm_string::literal("Result"), 0); + pin(1).set_dir(Link::INPUT); + pin(1).set_name(perm_string::literal("Address"), 0); +} + +NetArrayDq::~NetArrayDq() +{ +} + +unsigned NetArrayDq::width() const +{ + return mem_->vector_width(); +} + +unsigned NetArrayDq::awidth() const +{ + return awidth_; +} + +const NetNet* NetArrayDq::mem() const +{ + return mem_; +} + +Link& NetArrayDq::pin_Result() +{ + return pin(0); +} + +Link& NetArrayDq::pin_Address() +{ + return pin(1); +} + +const Link& NetArrayDq::pin_Result() const +{ + return pin(0); +} + +const Link& NetArrayDq::pin_Address() const +{ + return pin(1); +} + /* * The pinout for the NetCLShift is: * 0 -- Result @@ -1428,190 +1523,6 @@ const Link& NetMux::pin_Data(unsigned s) const return pin(2+s); } - -NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid) -: NetNode(s, n, 6), - mem_(mem), awidth_(awid) -{ - 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(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("WE"), 0); - pin(3).set_dir(Link::INPUT); - pin(3).set_name(perm_string::literal("Address"), 0); - pin(4).set_dir(Link::INPUT); - pin(4).set_name(perm_string::literal("Data"), 0); - pin(5).set_dir(Link::OUTPUT); - pin(5).set_name(perm_string::literal("Q"), 0); - - next_ = mem_->ram_list_; - mem_->ram_list_ = this; -} - -NetRamDq::~NetRamDq() -{ - 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_; - } - assert(cur->next_ == this); - cur->next_ = next_; - } -} - -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_; -} - -unsigned NetRamDq::count_partners() const -{ - unsigned count = 0; - for (NetRamDq*cur = mem_->ram_list_ ; cur ; cur = cur->next_) - count += 1; - - return count; -} - -void NetRamDq::absorb_partners() -{ - NetRamDq*cur, *tmp; - for (cur = mem_->ram_list_, tmp = 0 - ; cur||tmp ; cur = cur? cur->next_ : tmp) { - tmp = 0; - if (cur == this) continue; - - bool ok_flag = true; - ok_flag &= pin_Address().is_linked(cur->pin_Address()); - - if (!ok_flag) continue; - - if (pin_InClock().is_linked() - && cur->pin_InClock().is_linked() - && ! pin_InClock().is_linked(cur->pin_InClock())) - continue; - - if (pin_OutClock().is_linked() - && cur->pin_OutClock().is_linked() - && ! pin_OutClock().is_linked(cur->pin_OutClock())) - continue; - - if (pin_WE().is_linked() - && cur->pin_WE().is_linked() - && ! pin_WE().is_linked(cur->pin_WE())) - continue; - - if (pin_Data().is_linked() && cur->pin_Data().is_linked()) { - ok_flag &= pin_Data().is_linked(cur->pin_Data()); - } - - if (! ok_flag) continue; - - if (pin_Q().is_linked() && cur->pin_Q().is_linked()) { - - ok_flag &= pin_Q().is_linked(cur->pin_Q()); - } - - if (! ok_flag) continue; - - // I see no other reason to reject cur, so link up all - // my pins and delete it. - connect(pin_InClock(), cur->pin_InClock()); - connect(pin_OutClock(), cur->pin_OutClock()); - connect(pin_WE(), cur->pin_WE()); - - connect(pin_Address(), cur->pin_Address()); - connect(pin_Data(), cur->pin_Data()); - connect(pin_Q(), cur->pin_Q()); - - tmp = cur->next_; - delete cur; - cur = 0; - } -} - -Link& NetRamDq::pin_InClock() -{ - return pin(0); -} - -const Link& NetRamDq::pin_InClock() const -{ - return pin(0); -} - -Link& NetRamDq::pin_OutClock() -{ - return pin(1); -} - -const Link& NetRamDq::pin_OutClock() const -{ - return pin(1); -} - -Link& NetRamDq::pin_WE() -{ - return pin(2); -} - -const Link& NetRamDq::pin_WE() const -{ - return pin(2); -} - -Link& NetRamDq::pin_Address() -{ - return pin(3); -} - -const Link& NetRamDq::pin_Address() const -{ - return pin(3); -} - -Link& NetRamDq::pin_Data() -{ - return pin(4); -} - -const Link& NetRamDq::pin_Data() const -{ - return pin(4); -} - -Link& NetRamDq::pin_Q() -{ - return pin(5); -} - -const Link& NetRamDq::pin_Q() const -{ - return pin(5); -} - NetSignExtend::NetSignExtend(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 2), width_(w) { @@ -2027,68 +1938,6 @@ const NetScope* NetEConstParam::scope() const return scope_; } - -NetEMemory::NetEMemory(NetMemory*m, NetExpr*i) -: NetExpr(m->width()), mem_(m), idx_(i) -{ -} - -NetEMemory::~NetEMemory() -{ -} - -perm_string NetEMemory::name() const -{ - return mem_->name(); -} - -const NetExpr* NetEMemory::index() const -{ - return idx_; -} - -NetMemory::NetMemory(NetScope*sc, perm_string n, long w, long s, long e) -: width_(w), idxh_(s), idxl_(e), ram_list_(0), scope_(sc) -{ - name_ = n; - scope_->add_memory(this); -} - -NetMemory::~NetMemory() -{ - assert(scope_); - scope_->rem_memory(this); -} - -unsigned NetMemory::count() const -{ - if (idxh_ < idxl_) - return idxl_ - idxh_ + 1; - else - return idxh_ - idxl_ + 1; -} - -perm_string NetMemory::name() const -{ - return name_; -} - -long NetMemory::index_to_address(long idx) const -{ - if (idxh_ < idxl_) - return idx - idxh_; - else - return idx - idxl_; -} - - - -NetEMemory* NetEMemory::dup_expr() const -{ - assert(0); - return 0; -} - NetEEvent::NetEEvent(NetEvent*e) : event_(e) { @@ -2119,25 +1968,20 @@ const NetScope* NetEScope::scope() const } NetESignal::NetESignal(NetNet*n) -: NetExpr(n->vector_width()), net_(n) +: NetExpr(n->vector_width()), net_(n), word_(0) { net_->incr_eref(); set_line(*n); cast_signed(net_->get_signed()); } -#if 0 -NetESignal::NetESignal(NetNet*n, unsigned m, unsigned l) -: NetExpr(m - l + 1), net_(n) +NetESignal::NetESignal(NetNet*n, NetExpr*w) +: NetExpr(n->vector_width()), net_(n), word_(w) { - assert(m >= l); - msi_ = m; - lsi_ = l; net_->incr_eref(); set_line(*n); cast_signed(net_->get_signed()); } -#endif NetESignal::~NetESignal() { @@ -2149,18 +1993,22 @@ perm_string NetESignal::name() const return net_->name(); } -unsigned NetESignal::bit_count() const +const NetExpr* NetESignal::word_index() const +{ + return word_; +} + +unsigned NetESignal::vector_width() const { return net_->vector_width(); } -Link& NetESignal::bit(unsigned idx) +const NetNet* NetESignal::sig() const { - assert(idx <= 0); - return net_->pin(idx); + return net_; } -const NetNet* NetESignal::sig() const +NetNet* NetESignal::sig() { return net_; } @@ -2342,6 +2190,12 @@ const NetProc*NetTaskDef::proc() const /* * $Log: netlist.cc,v $ + * Revision 1.251 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.250 2006/11/10 04:54:26 steve * Add test_width methods for PETernary and PEString. * diff --git a/netlist.h b/netlist.h index 7a0b37e3e..c6f4a98d4 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.365 2006/11/04 06:19:25 steve Exp $" +#ident "$Id: netlist.h,v 1.366 2007/01/16 05:44:15 steve Exp $" #endif /* @@ -447,7 +447,12 @@ class NetNet : public NetObj { // that passed through. explicit NetNet(NetScope*s, perm_string n, Type t, unsigned width =1); - explicit NetNet(NetScope*s, perm_string n, Type t, long ms, long ls); + // This form supports an array of vectors. The [ms:ls] define + // the base vector, and the [s0:e0] define the array + // dimensions. If s0==e0, then this is not an array after + // all. + explicit NetNet(NetScope*s, perm_string n, Type t, + long ms, long ls, long s0 =0, long e0 =0); virtual ~NetNet(); @@ -488,6 +493,21 @@ class NetNet : public NetObj { the pin# from the index. */ bool sb_is_valid(long sb) const; + /* This method returns 0 for scalers and vectors, and greater + for arrays. The value is the number of array + indices. (Currently only one array index is supported.) */ + unsigned array_dimensions() const; + long array_first() const; + + // This is the number of array elements. + unsigned array_count() const; + + // This method returns a 0 based address of an array entry as + // indexed by idx. The Verilog source may give index ranges + // that are not zero based. + bool array_index_is_valid(long idx) const; + unsigned array_index_to_address(long idx) const; + bool local_flag() const { return local_flag_; } void local_flag(bool f) { local_flag_ = f; } @@ -524,6 +544,7 @@ class NetNet : public NetObj { bool isint_; // original type of integer long msb_, lsb_; + long s0_, e0_; bool local_flag_; unsigned eref_count_; @@ -571,6 +592,37 @@ class NetAddSub : public NetNode { unsigned width_; }; +/* + * The NetArrayDq node represents an array dereference. The NetNet + * that this object refers to is an array, and the Address pin selects + * which word of the array to place on the Result. +*/ +class NetArrayDq : public NetNode { + + public: + NetArrayDq(NetScope*s, perm_string name, NetNet*mem, unsigned awid); + ~NetArrayDq(); + + unsigned width() const; + unsigned awidth() const; + unsigned size() const; + const NetNet*mem() const; + + Link& pin_Address(); + Link& pin_Result(); + + const Link& pin_Address() const; + const Link& pin_Result() const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + + private: + NetNet*mem_; + unsigned awidth_; + +}; + /* * This type represents the LPM_CLSHIFT device. */ @@ -819,62 +871,6 @@ class NetFF : public NetNode { verinum sset_value_; }; - -/* - * This class represents the declared memory object. The parser - * creates one of these for each declared memory in the elaborated - * design. A reference to one of these is handled by the NetEMemory - * object, which is derived from NetExpr. This is not a node because - * memory objects can only be accessed by behavioral code. - */ -class NetMemory { - - public: - NetMemory(NetScope*sc, perm_string n, long w, long s, long e); - ~NetMemory(); - - // This is the BASE name of the memory object. It does not - // include scope name, get that from the scope itself. - perm_string name() const; - - // This is the width (in bits) of a single memory position. - unsigned width() const { return width_; } - - // This is the number of dimensions for the memory. A baseline - // verilog memory has always 1 dimension, but N-dimensional - // arrays have N. - unsigned dimensions() const { return 1; } - - const NetScope*scope() const { return scope_; }; - - // This is the number of memory positions. - unsigned count() const; - - // This method returns a 0 based address of a memory entry as - // indexed by idx. The Verilog source may give index ranges - // that are not zero based. - long index_to_address(long idx) const; - - void dump(ostream&o, unsigned lm) const; - - private: - perm_string name_; - unsigned width_; - long idxh_; - long idxl_; - - friend class NetRamDq; - NetRamDq* ram_list_; - - friend class NetScope; - NetMemory*snext_, *sprev_; - NetScope*scope_; - - private: // not implemented - NetMemory(const NetMemory&); - NetMemory& operator= (const NetMemory&); -}; - /* * This class implements a basic LPM_MULT combinational multiplier. It * is used as a structural representation of the * operator. The @@ -965,57 +961,6 @@ 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(NetScope*s, perm_string name, NetMemory*mem, unsigned awid); - ~NetRamDq(); - - unsigned width() const; - unsigned awidth() const; - unsigned size() const; - const NetMemory*mem() const; - - Link& pin_InClock(); - Link& pin_OutClock(); - Link& pin_WE(); - - Link& pin_Address(); - Link& pin_Data(); - Link& pin_Q(); - - const Link& pin_InClock() const; - const Link& pin_OutClock() const; - const Link& pin_WE() const; - - const Link& pin_Address() const; - const Link& pin_Data() const; - const Link& pin_Q() const; - - virtual void dump_node(ostream&, unsigned ind) const; - virtual bool emit_node(struct target_t*) const; - - // Use this method to absorb other NetRamDq objects that are - // connected to the same memory, and have compatible pin - // connections. - void absorb_partners(); - - // Use this method to count the partners (including myself) - // that are ports to the attached memory. - unsigned count_partners() const; - - private: - NetMemory*mem_; - NetRamDq*next_; - unsigned awidth_; - -}; /* * The NetReplicate node takes a vector input and makes it into a larger @@ -1710,20 +1655,18 @@ class NetAssign_ { public: NetAssign_(NetNet*sig); - NetAssign_(NetMemory*mem); ~NetAssign_(); - // If this expression exists, then only a single bit is to be - // set from the rval, and the value of this expression selects - // the pin that gets the value. - NetExpr*bmux(); - const NetExpr*bmux() const; + // If this expression exists, then it is used to select a word + // from an array/memory. + NetExpr*word(); + const NetExpr*word() const; // Get the base index of the part select, or 0 if there is no // part select. const NetExpr* get_base() const; - void set_bmux(NetExpr*); + void set_word(NetExpr*); void set_part(NetExpr* loff, unsigned wid); // Get the width of the r-value that this node expects. This @@ -1735,7 +1678,6 @@ class NetAssign_ { perm_string name() const; NetNet* sig() const; - NetMemory*mem() const; // Mark that the synthesizer has worked with this l-value, so // when it is released, the l-value signal should be turned @@ -1755,9 +1697,8 @@ class NetAssign_ { private: NetNet *sig_; - NetMemory*mem_; // Memory word index - NetExpr*bmux_; + NetExpr*word_; bool turn_sig_to_wire_on_release_; // indexed part select base @@ -3149,52 +3090,21 @@ class NetEUReduce : public NetEUnary { }; -/* - * A reference to a memory is represented by this expression. If the - * index is not supplied, then the node is only valid in certain - * specific contexts. - */ -class NetEMemory : public NetExpr { - - public: - NetEMemory(NetMemory*mem, NetExpr*idx =0); - virtual ~NetEMemory(); - - perm_string name () const; - const NetExpr* index() const; - - virtual bool set_width(unsigned, bool last_chance); - virtual NetNet* synthesize(Design*des); - - NetExpr* eval_tree(); - virtual NetEMemory*dup_expr() const; - - virtual NexusSet* nex_input(); - virtual void expr_scan(struct expr_scan_t*) const; - virtual void dump(ostream&) const; - - const NetMemory*memory() const { return mem_; }; - - private: - NetMemory*mem_; - NetExpr* idx_; -}; - /* * When a signal shows up in an expression, this type represents * it. From this the expression can get any kind of access to the - * structural signal. + * structural signal, including arrays. * - * A signal shows up as a node in the netlist so that structural - * activity can invoke the expression. This node also supports part - * select by indexing a range of the NetNet that is associated with - * it. The msi() is the more significant index, and lsi() the least - * significant index. + * The NetESignal may refer to an array, if the word_index is + * included. This expression calculates the index of the word in the + * array. It may only be nil if the expression refers to the whole + * array, and that is legal only in limited situation. */ class NetESignal : public NetExpr { public: NetESignal(NetNet*n); + NetESignal(NetNet*n, NetExpr*word_index); ~NetESignal(); perm_string name() const; @@ -3204,12 +3114,16 @@ class NetESignal : public NetExpr { NetNet* synthesize(Design*des); NexusSet* nex_input(); - // These methods actually reference the properties of the - // NetNet object that I point to. - unsigned bit_count() const; - Link& bit(unsigned idx); + // This is the expression for selecting an array word, if this + // signal refers to an array. + const NetExpr* word_index() const; + // This is the width of the vector that this signal refers to. + unsigned vector_width() const; + // Point back to the signal that this expression node references. const NetNet* sig() const; + NetNet* sig(); + // Declared vector dimensions for the signal. unsigned msi() const; unsigned lsi() const; @@ -3220,6 +3134,8 @@ class NetESignal : public NetExpr { private: NetNet*net_; + // Expression to select a word from the net. + NetExpr*word_; }; @@ -3278,15 +3194,6 @@ class NetScope : public Attrib { NetNet* find_signal_in_child(const hname_t&name); - /* ... and these methods manage memory the same way as signals - are managed above. */ - - void add_memory(NetMemory*); - void rem_memory(NetMemory*); - - NetMemory* find_memory(const string&name); - - /* The parent and child() methods allow users of NetScope objects to locate nearby scopes. */ NetScope* parent(); @@ -3399,8 +3306,6 @@ class NetScope : public Attrib { NetEvent *events_; NetNet *signals_; - NetMemory*memories_; - perm_string module_name_; union { NetTaskDef*task_; @@ -3567,6 +3472,12 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.366 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.365 2006/11/04 06:19:25 steve * Remove last bits of relax_width methods, and use test_width * to calculate the width of an r-value expression that may diff --git a/netmisc.h b/netmisc.h index 0f9372982..b9e51c6b3 100644 --- a/netmisc.h +++ b/netmisc.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: netmisc.h,v 1.26 2006/09/28 00:29:49 steve Exp $" +#ident "$Id: netmisc.h,v 1.27 2007/01/16 05:44:15 steve Exp $" #endif # include "netlist.h" @@ -42,7 +42,6 @@ extern NetScope* symbol_search(const Design*des, NetScope*start, hname_t path, NetNet*&net, /* net/reg */ - NetMemory*&mem, /* memory */ const NetExpr*&par,/* parameter */ NetEvent*&eve, /* named event */ const NetExpr*&ex1, const NetExpr*&ex2); @@ -50,12 +49,11 @@ extern NetScope* symbol_search(const Design*des, inline NetScope* symbol_search(const Design*des, NetScope*start, const hname_t&path, NetNet*&net, /* net/reg */ - NetMemory*&mem, /* memory */ const NetExpr*&par,/* parameter */ NetEvent*&eve /* named event */) { const NetExpr*ex1, *ex2; - return symbol_search(des, start, path, net, mem, par, eve, ex1, ex2); + return symbol_search(des, start, path, net, /*mem,*/ par, eve, ex1, ex2); } /* @@ -122,6 +120,12 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope, /* * $Log: netmisc.h,v $ + * Revision 1.27 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.26 2006/09/28 00:29:49 steve * Allow specparams as constants in expressions. * diff --git a/parse.y b/parse.y index 88185cff0..f961f3d98 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: parse.y,v 1.223 2006/12/06 05:32:36 steve Exp $" +#ident "$Id: parse.y,v 1.224 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -191,8 +191,8 @@ static list* list_from_identifier(list*tmp, char*id) %type udp_initial_expr_opt %type identifier -%type register_variable -%type register_variable_list list_of_identifiers +%type register_variable net_variable +%type register_variable_list net_variable_list list_of_identifiers %type net_decl_assign net_decl_assigns @@ -1629,7 +1629,7 @@ module_item : attribute_list_opt net_type primitive_type_opt signed_opt range_opt delay3_opt - list_of_identifiers ';' + net_variable_list ';' { ivl_variable_type_t dtype = $3; if (dtype == IVL_VT_NO_TYPE) @@ -2477,6 +2477,40 @@ register_variable_list } ; +net_variable + : IDENTIFIER + { pform_makewire(@1, $1, NetNet::IMPLICIT, + NetNet::NOT_A_PORT, + IVL_VT_NO_TYPE, 0); + $$ = $1; + } + | IDENTIFIER '[' expression ':' expression ']' + { pform_makewire(@1, $1, NetNet::IMPLICIT, + NetNet::NOT_A_PORT, + IVL_VT_NO_TYPE, 0); + if (! pform_expression_is_constant($3)) + yyerror(@3, "error: msb of net range must be constant."); + if (! pform_expression_is_constant($5)) + yyerror(@3, "error: lsb of net range must be constant."); + pform_set_reg_idx($1, $3, $5); + $$ = $1; + } + ; +net_variable_list + : net_variable + { list*tmp = new list; + tmp->push_back(lex_strings.make($1)); + $$ = tmp; + delete[]$1; + } + | net_variable_list ',' net_variable + { list*tmp = $1; + tmp->push_back(lex_strings.make($3)); + $$ = tmp; + delete[]$3; + } + ; + specify_item : K_specparam specparam_list ';' | specify_simple_path_decl ';' diff --git a/pform.cc b/pform.cc index b7b3d9434..c515c1893 100644 --- a/pform.cc +++ b/pform.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.cc,v 1.137 2006/09/23 04:57:19 steve Exp $" +#ident "$Id: pform.cc,v 1.138 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -1197,24 +1197,21 @@ void pform_makewire(const vlltype&li, const char*nm, PWire*cur = get_wire_in_module(name); - if (cur) { - if ((cur->get_wire_type() != NetNet::IMPLICIT) - && (cur->get_wire_type() != NetNet::IMPLICIT_REG)) { + // If this is not implicit ("implicit" meaning we don't know + // what the type is yet) then set thay type now. + if (cur && type != NetNet::IMPLICIT) { + bool rc = cur->set_wire_type(type); + if (rc == false) { ostringstream msg; - msg << name << " previously defined at " << - cur->get_line() << "."; + msg << name << " definition conflicts with " + << "definition at " << cur->get_line() + << "."; VLerror(msg.str().c_str()); - } else { - bool rc = cur->set_wire_type(type); - if (rc == false) { - ostringstream msg; - msg << name << " definition conflicts with " - << "definition at " << cur->get_line() - << "."; - VLerror(msg.str().c_str()); - } + cerr << "XXXX type=" << type <<", curtype=" << cur->get_wire_type() << endl; } + } + if (cur) { cur->set_file(li.text); cur->set_lineno(li.first_line); return; @@ -1747,6 +1744,12 @@ int pform_parse(const char*path, FILE*file) /* * $Log: pform.cc,v $ + * Revision 1.138 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.137 2006/09/23 04:57:19 steve * Basic support for specify timing. * diff --git a/set_width.cc b/set_width.cc index db36518c5..1c1bdae8b 100644 --- a/set_width.cc +++ b/set_width.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: set_width.cc,v 1.41 2006/11/04 06:19:25 steve Exp $" +#ident "$Id: set_width.cc,v 1.42 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -340,7 +340,7 @@ bool NetECReal::set_width(unsigned w, bool) expr_width(w); return true; } - +#if 0 bool NetEMemory::set_width(unsigned w, bool) { if (w != mem_->width()) @@ -349,7 +349,7 @@ bool NetEMemory::set_width(unsigned w, bool) expr_width(w); return true; } - +#endif bool NetEParam::set_width(unsigned, bool) { return false; @@ -374,7 +374,7 @@ bool NetESFunc::set_width(unsigned w, bool) */ bool NetESignal::set_width(unsigned w, bool) { - if (w != bit_count()) + if (w != vector_width()) return false; return true; @@ -441,6 +441,12 @@ bool NetEUReduce::set_width(unsigned w, bool) /* * $Log: set_width.cc,v $ + * Revision 1.42 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.41 2006/11/04 06:19:25 steve * Remove last bits of relax_width methods, and use test_width * to calculate the width of an r-value expression that may diff --git a/symbol_search.cc b/symbol_search.cc index e93c3b0f5..25f461711 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: symbol_search.cc,v 1.3 2005/11/27 05:56:20 steve Exp $" +#ident "$Id: symbol_search.cc,v 1.4 2007/01/16 05:44:15 steve Exp $" #endif # include "netlist.h" @@ -29,7 +29,6 @@ */ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path, NetNet*&net, - NetMemory*&mem, const NetExpr*&par, NetEvent*&eve, const NetExpr*&ex1, const NetExpr*&ex2) @@ -41,7 +40,6 @@ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path, /* Initialize output argument to cleared. */ net = 0; - mem = 0; par = 0; eve = 0; @@ -56,11 +54,6 @@ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path, return scope; } - if ( (mem = scope->find_memory(key)) ) { - delete key; - return scope; - } - if ( (eve = scope->find_event(key)) ) { delete key; return scope; @@ -83,6 +76,12 @@ NetScope*symbol_search(const Design*des, NetScope*scope, hname_t path, /* * $Log: symbol_search.cc,v $ + * Revision 1.4 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.3 2005/11/27 05:56:20 steve * Handle bit select of parameter with ranges. * diff --git a/syn-rules.y b/syn-rules.y index 2a36fff87..ca0937f31 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: syn-rules.y,v 1.33 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: syn-rules.y,v 1.34 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -118,7 +118,7 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk, // where lval is really a "reg [7:0]". In other words, part // selects in the l-value are handled by loff and the lwidth(). - connect(ff->pin_Data(), d->bit(0)); + connect(ff->pin_Data(), d->sig()->pin(0)); connect(ff->pin_Q(), a->sig()->pin(0)); connect(ff->pin_Clock(), pclk->pin(0)); @@ -137,41 +137,6 @@ static void hookup_DFF_CE(NetFF*ff, NetESignal*d, NetEvProbe*pclk, a->turn_sig_to_wire_on_release(); } -static void hookup_RAMDQ(NetRamDq*ram, NetESignal*d, NetNet*adr, - NetEvProbe*pclk, NetNet*ce, - NetAssign_*a, unsigned rval_pinoffset) -{ - assert(d); - assert(a); - - /* Connect the input Data bits of the RAM, from the r-value of - the assignment. */ - connect(ram->pin_Data(), d->bit(rval_pinoffset)); - - /* Connect the Address pins from the addr net discovered by the - caller. */ - connect(ram->pin_Address(), adr->pin(0)); - - /* Connect the input clock and the WE of the RAM. */ - assert(pclk); - connect(ram->pin_InClock(), pclk->pin(0)); - if (ce) { - connect(ram->pin_WE(), ce->pin(0)); - } /* XXX does ram CE default to true if not connected? */ - - /* This notices any other NetRamDq objects connected to the - same NetMemory, that have the same address pins and are - otherwise compatible. This absorbs them into this object. */ - ram->absorb_partners(); - - /* This lval_ represents a reg that is a WIRE in the - synthesized results. This function signals the destructor - to change the REG that this l-value refers to into a - WIRE. It is done then, at the last minute, so that pending - synthesis can continue to work with it as a WIRE. */ - a->turn_sig_to_wire_on_release(); -} - static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk, NetEvent*eclk, NetExpr*cexp, NetAssignBase*asn) { @@ -207,13 +172,6 @@ static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk, a->sig()->vector_width()); hookup_DFF_CE(ff, d, pclk, ce, a, rval_pinoffset); des->add_node(ff); - } else if (a->mem()) { - NetMemory *m=a->mem(); - NetNet *adr = a->bmux()->synthesize(des); - NetRamDq*ram = new NetRamDq(top->scope(), m->name(), - m, adr->pin_count()); - hookup_RAMDQ(ram, d, adr, pclk, ce, a, rval_pinoffset); - des->add_node(ram); } rval_pinoffset += a->lwidth(); } @@ -233,7 +191,7 @@ static void make_initializer(Design*des, NetProcTop*top, NetAssignBase*asn) for (unsigned idx = 0 ; idx < asn->l_val(0)->lwidth() ; idx += 1) { - verinum::V bit = rsig->bit(idx).nexus()->driven_value(); + verinum::V bit = rsig->sig()->pin(idx).nexus()->driven_value(); Nexus*nex = asn->l_val(0)->sig()->pin(idx).nexus(); for (Link*cur = nex->first_nlink() diff --git a/t-dll-api.cc b/t-dll-api.cc index 04d7bb21c..f895801f1 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.137 2006/09/23 04:57:19 steve Exp $" +#ident "$Id: t-dll-api.cc,v 1.138 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -317,6 +317,9 @@ extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net) case IVL_EX_MEMORY: return net->u_.memory_.idx_; + case IVL_EX_SIGNAL: + return net->u_.signal_.word; + case IVL_EX_TERNARY: return net->u_.ternary_.cond; @@ -443,6 +446,7 @@ extern "C" ivl_signal_t ivl_expr_signal(ivl_expr_t net) switch (net->type_) { case IVL_EX_SIGNAL: + case IVL_EX_ARRAY: return net->u_.signal_.sig; default: @@ -707,6 +711,18 @@ extern "C" ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net) } } +extern "C" ivl_signal_t ivl_lpm_array(ivl_lpm_t net) +{ + assert(net); + switch (net->type) { + case IVL_LPM_ARRAY: + return net->u_.array.sig; + default: + assert(0); + return 0; + } +} + extern "C" unsigned ivl_lpm_base(ivl_lpm_t net) { assert(net); @@ -726,7 +742,6 @@ extern "C" ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: - case IVL_LPM_RAM: return net->u_.ff.clk; default: assert(0); @@ -739,7 +754,6 @@ extern "C" ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: - case IVL_LPM_RAM: return net->u_.ff.aset_value; default: assert(0); @@ -751,7 +765,6 @@ extern "C" ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: - case IVL_LPM_RAM: return net->u_.ff.sset_value; default: assert(0); @@ -775,7 +788,6 @@ extern "C" ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net) { assert(net); switch (net->type) { - case IVL_LPM_RAM: case IVL_LPM_FF: return net->u_.ff.we; default: @@ -827,10 +839,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) else return net->u_.shift.s; - case IVL_LPM_RAM: - assert(idx == 0); - return net->u_.ff.d.pin; - case IVL_LPM_FF: assert(idx == 0); return net->u_.ff.d.pin; @@ -945,10 +953,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) assert(idx == 0); return net->u_.arith.q; - case IVL_LPM_RAM: - assert(idx == 0); - return net->u_.ff.q.pin; - case IVL_LPM_FF: assert(idx == 0); return net->u_.ff.q.pin; @@ -993,6 +997,10 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) assert(idx == 0); return net->u_.repeat.q; + case IVL_LPM_ARRAY: + assert(idx == 0); + return net->u_.array.q; + default: assert(0); return 0; @@ -1008,12 +1016,13 @@ extern "C" ivl_scope_t ivl_lpm_scope(ivl_lpm_t net) extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net) { switch (net->type) { - case IVL_LPM_RAM: - return net->u_.ff.s.pin; case IVL_LPM_MUX: return net->u_.mux.s; + case IVL_LPM_ARRAY: + return net->u_.array.a; + default: assert(0); return 0; @@ -1023,10 +1032,10 @@ extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net) extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net) { switch (net->type) { - case IVL_LPM_RAM: - return net->u_.ff.swid; case IVL_LPM_MUX: return net->u_.mux.swid; + case IVL_LPM_ARRAY: + return net->u_.array.swid; case IVL_LPM_CONCAT: return net->u_.concat.inputs; default: @@ -1040,7 +1049,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) assert(net); switch (net->type) { case IVL_LPM_FF: - case IVL_LPM_RAM: case IVL_LPM_MUX: return 0; case IVL_LPM_ADD: @@ -1079,6 +1087,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) return net->u_.part.signed_flag; case IVL_LPM_REPEAT: return 0; + case IVL_LPM_ARRAY: // Array ports take the signedness of the array. + return net->u_.array.sig->signed_; default: assert(0); return 0; @@ -1119,18 +1129,6 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net) return net->width; } -extern "C" ivl_memory_t ivl_lpm_memory(ivl_lpm_t net) -{ - assert(net); - switch (net->type) { - case IVL_LPM_RAM: - return net->u_.ff.mem; - default: - assert(0); - return 0; - } -} - extern "C" ivl_expr_t ivl_lval_mux(ivl_lval_t net) { assert(net); @@ -1144,6 +1142,8 @@ extern "C" ivl_expr_t ivl_lval_idx(ivl_lval_t net) assert(net); if (net->type_ == IVL_LVAL_MEM) return net->idx; + if (net->type_ == IVL_LVAL_ARR) + return net->idx; return 0x0; } @@ -1174,6 +1174,7 @@ extern "C" ivl_signal_t ivl_lval_sig(ivl_lval_t net) case IVL_LVAL_REG: case IVL_LVAL_NET: case IVL_LVAL_MUX: + case IVL_LVAL_ARR: return net->n.sig; default: return 0; @@ -1520,6 +1521,16 @@ extern "C" const char* ivl_scope_tname(ivl_scope_t net) return net->tname_; } +extern "C" int ivl_signal_array_base(ivl_signal_t net) +{ + return net->array_base; +} + +extern "C" unsigned ivl_signal_array_count(ivl_signal_t net) +{ + return net->array_words; +} + extern "C" const char* ivl_signal_attr(ivl_signal_t net, const char*key) { if (net->nattr == 0) @@ -1571,9 +1582,13 @@ extern "C" const char* ivl_signal_name(ivl_signal_t net) return name_buffer; } -extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net) +extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word) { - return net->pin_; + assert(word < net->array_words); + if (net->array_words > 1) + return net->pins[word]; + else + return net->pin; } extern "C" int ivl_signal_msb(ivl_signal_t net) @@ -1889,6 +1904,7 @@ extern "C" unsigned ivl_stmt_lwidth(ivl_statement_t net) sum += 1; break; case IVL_LVAL_REG: + case IVL_LVAL_ARR: sum += ivl_lval_width(cur); break; case IVL_LVAL_MEM: @@ -1976,6 +1992,12 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net) /* * $Log: t-dll-api.cc,v $ + * Revision 1.138 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.137 2006/09/23 04:57:19 steve * Basic support for specify timing. * diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 204a61664..74f1429a8 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.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-expr.cc,v 1.43 2005/09/14 02:53:15 steve Exp $" +#ident "$Id: t-dll-expr.cc,v 1.44 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -200,27 +200,6 @@ void dll_target::expr_concat(const NetEConcat*net) expr_ = cur; } -void dll_target::expr_memory(const NetEMemory*net) -{ - assert(expr_ == 0); - if (net->index()) { - net->index()->expr_scan(this); - assert(expr_); - } - - ivl_expr_t cur = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); - assert(cur); - - cur->type_ = IVL_EX_MEMORY; - cur->value_ = IVL_VT_VECTOR; - cur->width_= net->expr_width(); - cur->signed_ = net->has_sign()? 1 : 0; - cur->u_.memory_.mem_ = find_memory(des_, net->memory()); - cur->u_.memory_.idx_ = expr_; - - expr_ = cur; -} - void dll_target::expr_const(const NetEConst*net) { assert(expr_ == 0); @@ -410,8 +389,19 @@ void dll_target::expr_ternary(const NetETernary*net) void dll_target::expr_signal(const NetESignal*net) { + ivl_signal_t sig = find_signal(des_, net->sig()); + assert(expr_ == 0); + /* If there is a word expression, generate it. */ + ivl_expr_t word_expr = 0; + if (const NetExpr*word = net->word_index()) { + word->expr_scan(this); + assert(expr_); + word_expr = expr_; + expr_ = 0; + } + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); @@ -419,7 +409,18 @@ void dll_target::expr_signal(const NetESignal*net) expr_->value_= net->expr_type(); expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; - expr_->u_.signal_.sig = find_signal(des_, net->sig()); + expr_->u_.signal_.word = word_expr; + expr_->u_.signal_.sig = sig; + + /* Make account for the special case that this is a reference + to an array as a whole. We detect this case by noting that + this is an array (more then 1 word) and there is no word + select expression. In that case, this is an IVL_EX_ARRAY + expression instead of a SIGNAL expression. */ + if (sig->array_words > 1 && word_expr == 0) { + expr_->type_ = IVL_EX_ARRAY; + expr_->width_ = 0; // Doesn't make much sense for arrays. + } } @@ -473,6 +474,12 @@ void dll_target::expr_unary(const NetEUnary*net) /* * $Log: t-dll-expr.cc,v $ + * Revision 1.44 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.43 2005/09/14 02:53:15 steve * Support bool expressions and compares handle them optimally. * diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 82b1e63e8..8e126f86f 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: t-dll-proc.cc,v 1.68 2006/02/02 02:43:59 steve Exp $" +#ident "$Id: t-dll-proc.cc,v 1.69 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -171,30 +171,21 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net) cur->n.sig = find_signal(des_, asn->sig()); cur->idx = 0; - if (asn->bmux()) { + // If there is a word select expression, it is + // really an array index. + if (asn->word()) { assert(expr_ == 0); - asn->bmux()->expr_scan(this); + asn->word()->expr_scan(this); if (cur->n.sig->lsb_index != 0) sub_off_from_expr_(asn->sig()->lsb()); if (cur->n.sig->lsb_dist != 1) mul_expr_by_const_(cur->n.sig->lsb_dist); - cur->type_ = IVL_LVAL_MUX; + cur->type_ = IVL_LVAL_ARR; cur->idx = expr_; expr_ = 0; } - } else if (asn->mem()) { - assert(asn->mem()); - cur->type_ = IVL_LVAL_MEM; - cur->n.mem = find_memory(des_, asn->mem()); - assert(cur->n.mem); - cur->width_ = ivl_memory_width(cur->n.mem); - - assert(expr_ == 0); - asn->bmux()->expr_scan(this); - cur->idx = expr_; - expr_ = 0; } else { assert(0); } @@ -741,6 +732,12 @@ void dll_target::proc_while(const NetWhile*net) /* * $Log: t-dll-proc.cc,v $ + * Revision 1.69 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.68 2006/02/02 02:43:59 steve * Allow part selects of memory words in l-values. * diff --git a/t-dll.cc b/t-dll.cc index 4fcf2a30f..8587fc521 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.161 2006/11/10 05:44:45 steve Exp $" +#ident "$Id: t-dll.cc,v 1.162 2007/01/16 05:44:15 steve Exp $" #endif # include "config.h" @@ -242,27 +242,6 @@ ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net) return 0; } -/* - * This function locates an ivl_memory_t object that matches the - * NetMemory object. The search works by looking for the parent scope, - * then scanning the parent scope for the NetMemory object. - */ -ivl_memory_t dll_target::find_memory(ivl_design_s &des, const NetMemory*net) -{ - ivl_scope_t scope = find_scope(des, net->scope()); - assert(scope); - - const char*nname = net->name(); - - for (unsigned idx = 0 ; idx < scope->nmem_ ; idx += 1) { - if (strcmp(scope->mem_[idx]->basename_, nname) == 0) - return scope->mem_[idx]; - } - - assert(0); - return 0; -} - static ivl_nexus_t nexus_sig_make(ivl_signal_t net, unsigned pin) { ivl_nexus_t tmp = new struct ivl_nexus_s; @@ -417,14 +396,6 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net) } } -static void scope_add_mem(ivl_scope_t scope, ivl_memory_t net) -{ - scope->nmem_ += 1; - scope->mem_ = (ivl_memory_t*) - realloc(scope->mem_, scope->nmem_*sizeof(ivl_memory_t)); - scope->mem_[scope->nmem_-1] = net; -} - ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope, const char*name) { @@ -1186,20 +1157,6 @@ void dll_target::udp(const NetUDP*net) scope_add_logic(scope, obj); } -void dll_target::memory(const NetMemory*net) -{ - ivl_memory_t obj = new struct ivl_memory_s; - - obj->scope_ = find_scope(des_, net->scope()); - obj->basename_ = net->name(); - obj->width_ = net->width(); - obj->signed_ = 0; - obj->size_ = net->count(); - obj->root_ = -net->index_to_address(0); - - scope_add_mem(obj->scope_, obj); -} - void dll_target::lpm_add_sub(const NetAddSub*net) { ivl_lpm_t obj = new struct ivl_lpm_s; @@ -1252,6 +1209,35 @@ void dll_target::lpm_add_sub(const NetAddSub*net) scope_add_lpm(obj->scope, obj); } +bool dll_target::lpm_array_dq(const NetArrayDq*net) +{ + ivl_lpm_t obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_ARRAY; + obj->name = net->name(); + obj->u_.array.sig = find_signal(des_, net->mem()); + assert(obj->u_.array.sig); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + obj->width = net->width(); + obj->u_.array.swid = net->awidth(); + + scope_add_lpm(obj->scope, obj); + + const Nexus*nex; + + nex = net->pin_Address().nexus(); + assert(nex->t_cookie()); + obj->u_.array.a = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.array.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + nex = net->pin_Result().nexus(); + assert(nex->t_cookie()); + obj->u_.array.q = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.array.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); + + return true; +} + /* * The lpm_clshift device represents both left and right shifts, * depending on what is connected to the Direction pin. We convert @@ -1578,73 +1564,6 @@ void dll_target::lpm_ff(const NetFF*net) } -void dll_target::lpm_ram_dq(const NetRamDq*net) -{ - ivl_lpm_t obj = new struct ivl_lpm_s; - obj->type = IVL_LPM_RAM; - obj->name = net->name(); - obj->u_.ff.mem = find_memory(des_, net->mem()); - assert(obj->u_.ff.mem); - obj->scope = find_scope(des_, net->mem()->scope()); - assert(obj->scope); - - obj->width = net->width(); - obj->u_.ff.swid = net->awidth(); - - scope_add_lpm(obj->scope, obj); - - const Nexus*nex; - - // A write port is present only if something is connected to - // the clock input. - - bool has_write_port = net->pin_InClock().is_linked(); - - // Connect the write clock and write enable - - if (has_write_port) { - nex = net->pin_InClock().nexus(); - assert(nex->t_cookie()); - obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie(); - assert(obj->u_.ff.clk); - nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); - - nex = net->pin_WE().nexus(); - if (nex && nex->t_cookie()) { - obj->u_.ff.we = (ivl_nexus_t) nex->t_cookie(); - assert(obj->u_.ff.we); - nexus_lpm_add(obj->u_.ff.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); - } - else - obj->u_.ff.we = 0x0; - } - else { - obj->u_.ff.clk = 0x0; - obj->u_.ff.we = 0x0; - } - - // Connect the address bus - - nex = net->pin_Address().nexus(); - assert(nex->t_cookie()); - obj->u_.ff.s.pin = (ivl_nexus_t) nex->t_cookie(); - nexus_lpm_add(obj->u_.ff.s.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); - - // Connect the data busses - - nex = net->pin_Q().nexus(); - assert(nex->t_cookie()); - obj->u_.ff.q.pin = (ivl_nexus_t) nex->t_cookie(); - nexus_lpm_add(obj->u_.ff.q.pin, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); - - if (has_write_port) { - nex = net->pin_Data().nexus(); - assert(nex->t_cookie()); - obj->u_.ff.d.pin = (ivl_nexus_t) nex->t_cookie(); - nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); - } -} - /* * Make the NetMult object into an IVL_LPM_MULT node. */ @@ -2192,18 +2111,32 @@ void dll_target::signal(const NetNet*net) t_cookie of the Nexus object so that I find it again when I next encounter the nexus. */ - const Nexus*nex = net->pin(0).nexus(); - if (nex->t_cookie()) { - obj->pin_ = (ivl_nexus_t)nex->t_cookie(); - nexus_sig_add(obj->pin_, obj, 0); + obj->array_base = net->array_first(); + obj->array_words = net->array_count(); + if (obj->array_words > 1) + obj->pins = new ivl_nexus_t[obj->array_words]; - } else { - ivl_nexus_t tmp = nexus_sig_make(obj, 0); - tmp->name_ = strings_.add(nex->name()); - nex->t_cookie(tmp); - obj->pin_ = tmp; + for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) { + + const Nexus*nex = net->pin(idx).nexus(); + if (nex->t_cookie()) { + if (obj->array_words > 1) { + obj->pins[idx] = (ivl_nexus_t)nex->t_cookie(); + nexus_sig_add(obj->pins[idx], obj, idx); + } else { + obj->pin = (ivl_nexus_t)nex->t_cookie(); + nexus_sig_add(obj->pin, obj, idx); + } + } else { + ivl_nexus_t tmp = nexus_sig_make(obj, idx); + tmp->name_ = strings_.add(nex->name()); + nex->t_cookie(tmp); + if (obj->array_words > 1) + obj->pins[idx] = tmp; + else + obj->pin = tmp; + } } - } bool dll_target::signal_paths(const NetNet*net) @@ -2258,6 +2191,12 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj }; /* * $Log: t-dll.cc,v $ + * Revision 1.162 2007/01/16 05:44:15 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.161 2006/11/10 05:44:45 steve * Process delay paths in second path over signals. * diff --git a/t-dll.h b/t-dll.h index 2d53f6cb7..3a3e05f59 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.134 2006/11/10 05:44:45 steve Exp $" +#ident "$Id: t-dll.h,v 1.135 2007/01/16 05:44:16 steve Exp $" #endif # include "target.h" @@ -74,6 +74,7 @@ struct dll_target : public target_t, public expr_scan_t { void net_case_cmp(const NetCaseCmp*); void udp(const NetUDP*); void lpm_add_sub(const NetAddSub*); + bool lpm_array_dq(const NetArrayDq*); void lpm_clshift(const NetCLShift*); void lpm_compare(const NetCompare*); void lpm_divide(const NetDivide*); @@ -81,7 +82,6 @@ struct dll_target : public target_t, public expr_scan_t { void lpm_modulo(const NetModulo*); void lpm_mult(const NetMult*); void lpm_mux(const NetMux*); - void lpm_ram_dq(const NetRamDq*); bool concat(const NetConcat*); bool part_select(const NetPartSelect*); bool replicate(const NetReplicate*); @@ -97,8 +97,6 @@ struct dll_target : public target_t, public expr_scan_t { void scope(const NetScope*); void signal(const NetNet*); bool signal_paths(const NetNet*); - void memory(const NetMemory*); - ivl_dll_t dll_; ivl_design_s des_; @@ -134,7 +132,6 @@ struct dll_target : public target_t, public expr_scan_t { struct ivl_expr_s*expr_; void expr_binary(const NetEBinary*); void expr_concat(const NetEConcat*); - void expr_memory(const NetEMemory*); void expr_const(const NetEConst*); void expr_creal(const NetECReal*); void expr_param(const NetEConstParam*); @@ -157,8 +154,6 @@ struct dll_target : public target_t, public expr_scan_t { static ivl_scope_t find_scope(ivl_design_s &des, const NetScope*cur); static ivl_signal_t find_signal(ivl_design_s &des, const NetNet*net); - static ivl_memory_t find_memory(ivl_design_s &des, const NetMemory*net); - static ivl_parameter_t scope_find_param(ivl_scope_t scope, const char*name); @@ -231,6 +226,7 @@ struct ivl_expr_s { struct { ivl_signal_t sig; + ivl_expr_t word; } signal_; struct { @@ -294,7 +290,6 @@ struct ivl_lpm_s { union { struct ivl_lpm_ff_s { - unsigned swid; // ram only ivl_nexus_t clk; ivl_nexus_t we; ivl_nexus_t aclr; @@ -309,11 +304,6 @@ struct ivl_lpm_s { ivl_nexus_t*pins; ivl_nexus_t pin; } d; - union { // ram only - ivl_nexus_t*pins; - ivl_nexus_t pin; - } s; - ivl_memory_t mem; // ram only ivl_expr_t aset_value; ivl_expr_t sset_value; } ff; @@ -336,6 +326,12 @@ struct ivl_lpm_s { ivl_nexus_t q, a, b; } arith; + struct ivl_lpm_array_s { + ivl_signal_t sig; + unsigned swid; + ivl_nexus_t q, a; + } array; + struct ivl_concat_s { unsigned inputs; ivl_nexus_t*pins; @@ -380,8 +376,9 @@ struct ivl_lpm_s { enum ivl_lval_type_t { IVL_LVAL_REG = 0, IVL_LVAL_MUX = 1, - IVL_LVAL_MEM = 2, - IVL_LVAL_NET = 3 /* Only force can have NET l-values */ + IVL_LVAL_MEM = 2, /* Deprecated in favor of LVAL_ARR? */ + IVL_LVAL_NET = 3, /* Only force can have NET l-values */ + IVL_LVAL_ARR = 4 }; struct ivl_lval_s { @@ -589,7 +586,12 @@ struct ivl_signal_s { perm_string name_; ivl_scope_t scope_; - ivl_nexus_t pin_; + unsigned array_words; + int array_base; + union { + ivl_nexus_t pin; + ivl_nexus_t*pins; + }; ivl_delaypath_s*path; unsigned npath; @@ -680,6 +682,12 @@ struct ivl_statement_s { /* * $Log: t-dll.h,v $ + * Revision 1.135 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.134 2006/11/10 05:44:45 steve * Process delay paths in second path over signals. * diff --git a/target.cc b/target.cc index 1915fdcb8..9a6f6678f 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.79 2006/11/10 05:44:45 steve Exp $" +#ident "$Id: target.cc,v 1.80 2007/01/16 05:44:16 steve Exp $" #endif # include "config.h" @@ -45,13 +45,6 @@ bool target_t::signal_paths(const NetNet*) { return true; } - -void target_t::memory(const NetMemory*) -{ - cerr << "target (" << typeid(*this).name() << "): " - "Unhandled memory." << endl; -} - bool target_t::func_def(const NetScope*) { cerr << "target (" << typeid(*this).name() << "): " @@ -97,6 +90,13 @@ void target_t::lpm_add_sub(const NetAddSub*) "Unhandled NetAddSub." << endl; } +bool target_t::lpm_array_dq(const NetArrayDq*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetArrayDq." << endl; + return false; +} + void target_t::lpm_clshift(const NetCLShift*) { cerr << "target (" << typeid(*this).name() << "): " @@ -138,13 +138,6 @@ void target_t::lpm_mux(const NetMux*) cerr << "target (" << typeid(*this).name() << "): " "Unhandled NetMux." << endl; } - -void target_t::lpm_ram_dq(const NetRamDq*) -{ - cerr << "target (" << typeid(*this).name() << "): " - "Unhandled NetRamDq." << endl; -} - bool target_t::concat(const NetConcat*) { cerr << "target (" << typeid(*this).name() << "): " @@ -380,13 +373,6 @@ void expr_scan_t::expr_concat(const NetEConcat*that) cerr << that->get_line() << ": expr_scan_t (" << typeid(*this).name() << "): unhandled expr_concat." << endl; } - -void expr_scan_t::expr_memory(const NetEMemory*) -{ - cerr << "expr_scan_t (" << typeid(*this).name() << "): " - "unhandled expr_memory." << endl; -} - void expr_scan_t::expr_event(const NetEEvent*) { cerr << "expr_scan_t (" << typeid(*this).name() << "): " @@ -443,6 +429,12 @@ void expr_scan_t::expr_binary(const NetEBinary*ex) /* * $Log: target.cc,v $ + * Revision 1.80 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.79 2006/11/10 05:44:45 steve * Process delay paths in second path over signals. * diff --git a/target.h b/target.h index 08888a676..a227aa669 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.76 2006/11/10 05:44:45 steve Exp $" +#ident "$Id: target.h,v 1.77 2007/01/16 05:44:16 steve Exp $" #endif # include "netlist.h" @@ -66,15 +66,13 @@ struct target_t { virtual void signal(const NetNet*) =0; virtual bool signal_paths(const NetNet*); - /* Output a memory (called for each memory object) */ - virtual void memory(const NetMemory*); - /* Output a defined task. */ virtual void task_def(const NetScope*); virtual bool func_def(const NetScope*); /* LPM style components are handled here. */ virtual void lpm_add_sub(const NetAddSub*); + virtual bool lpm_array_dq(const NetArrayDq*); virtual void lpm_clshift(const NetCLShift*); virtual void lpm_compare(const NetCompare*); virtual void lpm_divide(const NetDivide*); @@ -82,7 +80,6 @@ struct target_t { virtual void lpm_ff(const NetFF*); virtual void lpm_mult(const NetMult*); virtual void lpm_mux(const NetMux*); - virtual void lpm_ram_dq(const NetRamDq*); virtual bool concat(const NetConcat*); virtual bool part_select(const NetPartSelect*); @@ -139,7 +136,6 @@ struct expr_scan_t { virtual void expr_rparam(const NetECRealParam*); virtual void expr_creal(const NetECReal*); virtual void expr_concat(const NetEConcat*); - virtual void expr_memory(const NetEMemory*); virtual void expr_event(const NetEEvent*); virtual void expr_scope(const NetEScope*); virtual void expr_select(const NetESelect*); @@ -172,6 +168,12 @@ extern const struct target *target_table[]; /* * $Log: target.h,v $ + * Revision 1.77 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.76 2006/11/10 05:44:45 steve * Process delay paths in second path over signals. * diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index f74a5314d..02f0a49c6 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.17 2006/10/30 22:45:37 steve Exp $" +#ident "$Id: Makefile.in,v 1.18 2007/01/16 05:44:16 steve Exp $" # # SHELL = /bin/sh @@ -52,7 +52,7 @@ dep: $(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = stub.o memory.o statement.o +O = stub.o expression.o memory.o statement.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c new file mode 100644 index 000000000..83abe219a --- /dev/null +++ b/tgt-stub/expression.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2007 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: expression.c,v 1.1 2007/01/16 05:44:16 steve Exp $" +#endif + +# include "config.h" +# include "priv.h" +# include +# include +# include + +static const char*vt_type_string(ivl_expr_t net) +{ + return data_type_string(ivl_expr_value(net)); +} + +static void show_array_expression(ivl_expr_t net, unsigned ind) +{ + ivl_signal_t sig = ivl_expr_signal(net); + const char*name = ivl_signal_basename(sig); + unsigned width = ivl_signal_width(sig); + const char*vt = vt_type_string(net); + + fprintf(out, "%*sArray: %s, word_count=%u, width=%u, type=%s\n", + ind, "", name, ivl_signal_array_count(sig), width, vt); +} + +static void show_binary_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + const char*vt = vt_type_string(net); + + fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "", + ivl_expr_opcode(net), width, sign, vt); + show_expression(ivl_expr_oper1(net), ind+3); + show_expression(ivl_expr_oper2(net), ind+3); + + switch (ivl_expr_opcode(net)) { + + case '*': + /* The width of multiply expressions is the sum of the + widths of the operands. This is slightly different + from the way the Verilog standard does it, but allows + us to keep operands smaller. */ + width = ivl_expr_width(ivl_expr_oper1(net)); + width += ivl_expr_width(ivl_expr_oper2(net)); + if (ivl_expr_width(net) != width) { + fprintf(out, "%*sERROR: Result width incorrect\n", + ind+3, ""); + stub_errors += 1; + } + break; + + default: + break; + } +} + +static void show_function_call(ivl_expr_t net, unsigned ind) +{ + ivl_scope_t def = ivl_expr_def(net); + const char*vt = vt_type_string(net); + + fprintf(out, "%*s<%s function %s>\n", ind, "", + vt, ivl_scope_name(def)); +} + +static void show_memory_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + + fprintf(out, "%*s\n", ind, "", + width); +} + +static void show_signal_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + const char*vt = vt_type_string(net); + ivl_expr_t word = ivl_expr_oper1(net); + + ivl_signal_t sig = ivl_expr_signal(net); + unsigned word_count = ivl_signal_array_count(sig); + + fprintf(out, "%*s\n", ind, "", + ivl_expr_name(net), word_count, width, sign, vt); + + /* If the expression refers to a signal array, then there must + also be a word select expression, and if the signal is not an + array, there must NOT be a word expression. */ + if (word_count == 1 && word != 0) { + fprintf(out, "%*sERROR: Unexpected word expression\n", ind+2, ""); + stub_errors += 1; + } + if (word_count > 1 && word == 0) { + fprintf(out, "%*sERROR: Missing word expression\n", ind+2, ""); + stub_errors += 1; + } + + if (word != 0) { + fprintf(out, "%*sAddress-0 word address:\n", ind+2, ""); + show_expression(word, ind+2); + } +} + +static void show_ternary_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + + fprintf(out, "%*s\n", ind, "", width, sign); + show_expression(ivl_expr_oper1(net), ind+4); + show_expression(ivl_expr_oper2(net), ind+4); + show_expression(ivl_expr_oper3(net), ind+4); + + if (ivl_expr_width(ivl_expr_oper2(net)) != width) { + fprintf(out, "ERROR: Width of TRUE expressions is %u, not %u\n", + ivl_expr_width(ivl_expr_oper2(net)), width); + stub_errors += 1; + } + + if (ivl_expr_width(ivl_expr_oper3(net)) != width) { + fprintf(out, "ERROR: Width of FALSE expressions is %u, not %u\n", + ivl_expr_width(ivl_expr_oper3(net)), width); + stub_errors += 1; + } +} + +void show_expression(ivl_expr_t net, unsigned ind) +{ + unsigned idx; + const ivl_expr_type_t code = ivl_expr_type(net); + ivl_parameter_t par = ivl_expr_parameter(net); + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + const char*vt = vt_type_string(net); + + switch (code) { + + case IVL_EX_ARRAY: + show_array_expression(net, ind); + break; + + case IVL_EX_BINARY: + show_binary_expression(net, ind); + break; + + case IVL_EX_CONCAT: + fprintf(out, "%*s\n", + ind, "", ivl_expr_repeat(net), width, sign, vt); + for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) + show_expression(ivl_expr_parm(net, idx), ind+3); + + break; + + case IVL_EX_MEMORY: + show_memory_expression(net, ind); + break; + + case IVL_EX_NUMBER: { + const char*bits = ivl_expr_bits(net); + + fprintf(out, "%*s 0 ; idx -= 1) + fprintf(out, "%c", bits[idx-1]); + + fprintf(out, ", %s %s", sign, vt); + if (par != 0) + fprintf(out, ", parameter=%s", + ivl_parameter_basename(par)); + + fprintf(out, ">\n"); + break; + } + + case IVL_EX_SELECT: + /* The SELECT expression can be used to express part + select, or if the base is null vector extension. */ + if (ivl_expr_oper2(net)) { + fprintf(out, "%*s\n", ind, "", + width, sign); + show_expression(ivl_expr_oper1(net), ind+3); + show_expression(ivl_expr_oper2(net), ind+3); + } else { + fprintf(out, "%*s\n", ind, "", + width, sign); + show_expression(ivl_expr_oper1(net), ind+3); + } + break; + + case IVL_EX_STRING: + fprintf(out, "%*s\n"); + break; + + case IVL_EX_SFUNC: + fprintf(out, "%*s\n", + ind, "", ivl_expr_name(net), width, sign, vt); + { unsigned cnt = ivl_expr_parms(net); + unsigned idx; + for (idx = 0 ; idx < cnt ; idx += 1) + show_expression(ivl_expr_parm(net, idx), ind+3); + } + break; + + case IVL_EX_SIGNAL: + show_signal_expression(net, ind); + break; + + case IVL_EX_TERNARY: + show_ternary_expression(net, ind); + break; + + case IVL_EX_UNARY: + fprintf(out, "%*s\n", ind, "", + ivl_expr_opcode(net), width, sign); + show_expression(ivl_expr_oper1(net), ind+4); + break; + + case IVL_EX_UFUNC: + show_function_call(net, ind); + break; + + case IVL_EX_REALNUM: + { + int idx; + union foo { + double rv; + unsigned char bv[sizeof(double)]; + } tmp; + tmp.rv = ivl_expr_dvalue(net); + fprintf(out, "%*s 0 ; idx -= 1) + fprintf(out, "%02x", tmp.bv[idx-1]); + fprintf(out, ")"); + if (par != 0) + fprintf(out, ", parameter=%s", + ivl_parameter_basename(par)); + + fprintf(out, ">\n"); + } + break; + + default: + fprintf(out, "%*s\n", ind, "", code); + break; + } +} + diff --git a/tgt-stub/priv.h b/tgt-stub/priv.h index 6e61dc1e2..4d4109a7c 100644 --- a/tgt-stub/priv.h +++ b/tgt-stub/priv.h @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: priv.h,v 1.3 2005/03/05 05:47:42 steve Exp $" +#ident "$Id: priv.h,v 1.4 2007/01/16 05:44:16 steve Exp $" #endif # include @@ -47,3 +47,6 @@ extern void show_memory(ivl_memory_t mem); */ extern void show_statement(ivl_statement_t net, unsigned ind); +/* +*/ +extern const char*data_type_string(ivl_variable_type_t vtype); diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 8fa88f002..e98916f36 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: statement.c,v 1.10 2006/08/08 05:11:37 steve Exp $" +#ident "$Id: statement.c,v 1.11 2007/01/16 05:44:16 steve Exp $" #endif # include "config.h" @@ -56,12 +56,30 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) } else { ivl_signal_t sig = ivl_lval_sig(lval); + assert(sig); fprintf(out, "%*s{name=%s width=%u lvwidth=%u}\n", ind, "", ivl_signal_name(sig), ivl_signal_width(sig), ivl_lval_width(lval)); + + if (ivl_lval_idx(lval)) { + fprintf(out, "%*sAddress-0 select expression:\n", ind+4, ""); + show_expression(ivl_lval_idx(lval), ind+6); + if (ivl_signal_array_count(sig) <= 1) { + fprintf(out, "%*sERROR: Address on signal with " + "word count=%u\n", ind+4, "", + ivl_signal_array_count(sig)); + stub_errors += 1; + } + } else if (ivl_signal_array_count(sig) > 1) { + fprintf(out, "%*sERROR: Address missing on signal with " + "word count=%u\n", ind+4, "", + ivl_signal_array_count(sig)); + stub_errors += 1; + } + if (ivl_lval_mux(lval)) { fprintf(out, "%*sBit select expression:\n", ind+4, ""); show_expression(ivl_lval_mux(lval), ind+8); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 0be9dbf9d..fb42b2ca2 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -17,9 +17,16 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: stub.c,v 1.142 2006/11/28 05:56:41 steve Exp $" +#ident "$Id: stub.c,v 1.143 2007/01/16 05:44:16 steve Exp $" #endif +/* + * This is a sample target module. All this does is write to the + * output file some information about each object handle when each of + * the various object functions is called. This can be used to + * understand the behavior of the core as it uses a target module. + */ + # include "config.h" # include "priv.h" # include @@ -127,213 +134,6 @@ const char*data_type_string(ivl_variable_type_t vtype) return vt; } -const char*vt_type_string(ivl_expr_t net) -{ - return data_type_string(ivl_expr_value(net)); -} - -void show_binary_expression(ivl_expr_t net, unsigned ind) -{ - unsigned width = ivl_expr_width(net); - const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; - const char*vt = vt_type_string(net); - - fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "", - ivl_expr_opcode(net), width, sign, vt); - show_expression(ivl_expr_oper1(net), ind+3); - show_expression(ivl_expr_oper2(net), ind+3); - - switch (ivl_expr_opcode(net)) { - - case '*': - /* The width of multiply expressions is the sum of the - widths of the operands. This is slightly different - from the way the Verilog standard does it, but allows - us to keep operands smaller. */ - width = ivl_expr_width(ivl_expr_oper1(net)); - width += ivl_expr_width(ivl_expr_oper2(net)); - if (ivl_expr_width(net) != width) { - fprintf(out, "%*sERROR: Result width incorrect\n", - ind+3, ""); - stub_errors += 1; - } - break; - - default: - break; - } -} - -void show_function_call(ivl_expr_t net, unsigned ind) -{ - ivl_scope_t def = ivl_expr_def(net); - const char*vt = vt_type_string(net); - - fprintf(out, "%*s<%s function %s>\n", ind, "", - vt, ivl_scope_name(def)); -} - -void show_memory_expression(ivl_expr_t net, unsigned ind) -{ - unsigned width = ivl_expr_width(net); - - fprintf(out, "%*s\n", ind, "", - width); -} - -/* - * This is a sample target module. All this does is write to the - * output file some information about each object handle when each of - * the various object functions is called. This can be used to - * understand the behavior of the core as it uses a target module. - */ - -void show_ternary_expression(ivl_expr_t net, unsigned ind) -{ - unsigned width = ivl_expr_width(net); - const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; - - fprintf(out, "%*s\n", ind, "", width, sign); - show_expression(ivl_expr_oper1(net), ind+4); - show_expression(ivl_expr_oper2(net), ind+4); - show_expression(ivl_expr_oper3(net), ind+4); - - if (ivl_expr_width(ivl_expr_oper2(net)) != width) { - fprintf(out, "ERROR: Width of TRUE expressions is %u, not %u\n", - ivl_expr_width(ivl_expr_oper2(net)), width); - stub_errors += 1; - } - - if (ivl_expr_width(ivl_expr_oper3(net)) != width) { - fprintf(out, "ERROR: Width of FALSE expressions is %u, not %u\n", - ivl_expr_width(ivl_expr_oper3(net)), width); - stub_errors += 1; - } -} - -void show_expression(ivl_expr_t net, unsigned ind) -{ - unsigned idx; - const ivl_expr_type_t code = ivl_expr_type(net); - ivl_parameter_t par = ivl_expr_parameter(net); - unsigned width = ivl_expr_width(net); - const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; - const char*vt = vt_type_string(net); - - switch (code) { - - case IVL_EX_BINARY: - show_binary_expression(net, ind); - break; - - case IVL_EX_CONCAT: - fprintf(out, "%*s\n", - ind, "", ivl_expr_repeat(net), width, sign, vt); - for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) - show_expression(ivl_expr_parm(net, idx), ind+3); - - break; - - case IVL_EX_MEMORY: - show_memory_expression(net, ind); - break; - - case IVL_EX_NUMBER: { - const char*bits = ivl_expr_bits(net); - - fprintf(out, "%*s 0 ; idx -= 1) - fprintf(out, "%c", bits[idx-1]); - - fprintf(out, ", %s %s", sign, vt); - if (par != 0) - fprintf(out, ", parameter=%s", - ivl_parameter_basename(par)); - - fprintf(out, ">\n"); - break; - } - - case IVL_EX_SELECT: - /* The SELECT expression can be used to express part - select, or if the base is null vector extension. */ - if (ivl_expr_oper2(net)) { - fprintf(out, "%*s\n", ind, "", - width, sign); - show_expression(ivl_expr_oper1(net), ind+3); - show_expression(ivl_expr_oper2(net), ind+3); - } else { - fprintf(out, "%*s\n", ind, "", - width, sign); - show_expression(ivl_expr_oper1(net), ind+3); - } - break; - - case IVL_EX_STRING: - fprintf(out, "%*s\n"); - break; - - case IVL_EX_SFUNC: - fprintf(out, "%*s\n", - ind, "", ivl_expr_name(net), width, sign, vt); - { unsigned cnt = ivl_expr_parms(net); - unsigned idx; - for (idx = 0 ; idx < cnt ; idx += 1) - show_expression(ivl_expr_parm(net, idx), ind+3); - } - break; - - case IVL_EX_SIGNAL: - fprintf(out, "%*s\n", ind, "", - ivl_expr_name(net), width, sign, vt); - break; - - case IVL_EX_TERNARY: - show_ternary_expression(net, ind); - break; - - case IVL_EX_UNARY: - fprintf(out, "%*s\n", ind, "", - ivl_expr_opcode(net), width, sign); - show_expression(ivl_expr_oper1(net), ind+4); - break; - - case IVL_EX_UFUNC: - show_function_call(net, ind); - break; - - case IVL_EX_REALNUM: - { - int idx; - union foo { - double rv; - unsigned char bv[sizeof(double)]; - } tmp; - tmp.rv = ivl_expr_dvalue(net); - fprintf(out, "%*s 0 ; idx -= 1) - fprintf(out, "%02x", tmp.bv[idx-1]); - fprintf(out, ")"); - if (par != 0) - fprintf(out, ", parameter=%s", - ivl_parameter_basename(par)); - - fprintf(out, ">\n"); - } - break; - - default: - fprintf(out, "%*s\n", ind, "", code); - break; - } -} - /* * The compare-like LPM nodes have input widths that match the * ivl_lpm_width() value, and an output width of 1. This function @@ -388,6 +188,35 @@ static void show_lpm_add(ivl_lpm_t net) show_lpm_arithmetic_pins(net); } +static void show_lpm_array(ivl_lpm_t net) +{ + ivl_nexus_t nex; + unsigned width = ivl_lpm_width(net); + ivl_signal_t array = ivl_lpm_array(net); + + fprintf(out, " LPM_ARRAY: \n", + width, ivl_signal_basename(array)); + nex = ivl_lpm_q(net, 0); + assert(nex); + fprintf(out, " Q: %s\n", ivl_nexus_name(nex)); + nex = ivl_lpm_select(net); + assert(nex); + fprintf(out, " Address: %s (address width=%u)\n", + ivl_nexus_name(nex), ivl_lpm_selects(net)); + + if (width_of_nexus(ivl_lpm_q(net,0)) != width) { + fprintf(out, " ERROR: Data Q width doesn't match " + "nexus width=%u\n", width_of_nexus(ivl_lpm_q(net,0))); + stub_errors += 1; + } + + if (ivl_signal_width(array) != width) { + fprintf(out, " ERROR: Data width doesn't match " + "word width=%u\n", ivl_signal_width(array)); + stub_errors += 1; + } +} + static void show_lpm_divide(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -735,42 +564,6 @@ static void show_lpm_part_bi(ivl_lpm_t net) } -static void show_lpm_ram(ivl_lpm_t net) -{ - ivl_nexus_t nex; - unsigned width = ivl_lpm_width(net); - ivl_memory_t mem = ivl_lpm_memory(net); - - fprintf(out, " LPM_RAM: \n", width); - nex = ivl_lpm_q(net, 0); - assert(nex); - fprintf(out, " Q: %s\n", ivl_nexus_name(nex)); - nex = ivl_lpm_select(net); - fprintf(out, " Address: %s (address width=%u)\n", - ivl_nexus_name(nex), ivl_lpm_selects(net)); - - - if (width_of_nexus(ivl_lpm_q(net,0)) != width) { - fprintf(out, " ERROR: Data width doesn't match " - "nexus width=%u\n", width_of_nexus(ivl_lpm_q(net,0))); - stub_errors += 1; - } - - if (width_of_nexus(ivl_lpm_select(net)) != ivl_lpm_selects(net)) { - fprintf(out, " ERROR: Width of address doesn't match " - "nexus width=%u\n", width_of_nexus(ivl_lpm_select(net))); - stub_errors += 1; - } - - /* The width of the port must match the width of the memory - word. the compile assures that for us. */ - if (width != ivl_memory_width(mem)) { - fprintf(out, " ERROR: Width doesn't match" - " memory word width=%u\n", ivl_memory_width(mem)); - stub_errors += 1; - } -} - /* * The reduction operators have similar characteristics and are * displayed here. @@ -983,6 +776,10 @@ static void show_lpm(ivl_lpm_t net) show_lpm_add(net); break; + case IVL_LPM_ARRAY: + show_lpm_array(net); + break; + case IVL_LPM_DIVIDE: show_lpm_divide(net); break; @@ -1012,10 +809,6 @@ static void show_lpm(ivl_lpm_t net) show_lpm_concat(net); break; - case IVL_LPM_RAM: - show_lpm_ram(net); - break; - case IVL_LPM_RE_AND: case IVL_LPM_RE_NAND: case IVL_LPM_RE_NOR: @@ -1203,6 +996,57 @@ static void signal_nexus_const(ivl_signal_t sig, } } +static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex) +{ + unsigned idx; + + for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { + ivl_net_const_t con; + ivl_net_logic_t log; + ivl_lpm_t lpm; + ivl_signal_t sig; + ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx); + + const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)]; + const char*dr1 = str_tab[ivl_nexus_ptr_drive1(ptr)]; + + if ((sig = ivl_nexus_ptr_sig(ptr))) { + fprintf(out, " SIG %s word=%u (%s0, %s1)", + ivl_signal_name(sig), ivl_nexus_ptr_pin(ptr), dr0, dr1); + + if (ivl_signal_width(sig) != ivl_signal_width(net)) { + fprintf(out, " (ERROR: Width=%u)", + ivl_signal_width(sig)); + stub_errors += 1; + } + + if (ivl_signal_data_type(sig) != ivl_signal_data_type(net)) { + fprintf(out, " (ERROR: data type mismatch)"); + stub_errors += 1; + } + + fprintf(out, "\n"); + + } else if ((log = ivl_nexus_ptr_log(ptr))) { + fprintf(out, " LOG %s.%s[%u] (%s0, %s1)\n", + ivl_scope_name(ivl_logic_scope(log)), + ivl_logic_basename(log), + ivl_nexus_ptr_pin(ptr), dr0, dr1); + + } else if ((lpm = ivl_nexus_ptr_lpm(ptr))) { + fprintf(out, " LPM %s.%s (%s0, %s1)\n", + ivl_scope_name(ivl_lpm_scope(lpm)), + ivl_lpm_basename(lpm), dr0, dr1); + + } else if ((con = ivl_nexus_ptr_con(ptr))) { + signal_nexus_const(net, ptr, con); + + } else { + fprintf(out, " ?[%u] (%s0, %s1)\n", + ivl_nexus_ptr_pin(ptr), dr0, dr1); + } + } +} static void show_signal(ivl_signal_t net) { @@ -1268,68 +1112,19 @@ static void show_signal(ivl_signal_t net) break; } - nex = ivl_signal_nex(net); + for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) { - fprintf(out, " %s %s %s%s[%d:%d] %s nexus=%s\n", - type, sign, port, data_type, - ivl_signal_msb(net), ivl_signal_lsb(net), - ivl_signal_basename(net), ivl_signal_width(net), - ivl_nexus_name(nex)); + nex = ivl_signal_nex(net, idx); + fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] nexus=%s\n", + type, sign, port, data_type, + ivl_signal_msb(net), ivl_signal_lsb(net), + ivl_signal_basename(net), + idx, ivl_signal_array_base(net)+idx, + ivl_signal_width(net), + ivl_nexus_name(nex)); - for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { - ivl_net_const_t con; - ivl_net_logic_t log; - ivl_lpm_t lpm; - ivl_signal_t sig; - ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx); - - const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)]; - const char*dr1 = str_tab[ivl_nexus_ptr_drive1(ptr)]; - - if ((sig = ivl_nexus_ptr_sig(ptr))) { - fprintf(out, " SIG %s (%s0, %s1)", - ivl_signal_name(sig), dr0, dr1); - - /* Only pin-0 of signals is used. If this is - something other then pin-0, report an error. */ - if (ivl_nexus_ptr_pin(ptr) != 0) { - fprintf(out, " (pin=%u, should be 0)", - ivl_nexus_ptr_pin(ptr)); - stub_errors += 1; - } - - if (ivl_signal_width(sig) != ivl_signal_width(net)) { - fprintf(out, " (ERROR: Width=%u)", - ivl_signal_width(sig)); - stub_errors += 1; - } - - if (ivl_signal_data_type(sig) != ivl_signal_data_type(net)) { - fprintf(out, " (ERROR: data type mismatch)"); - stub_errors += 1; - } - - fprintf(out, "\n"); - - } else if ((log = ivl_nexus_ptr_log(ptr))) { - fprintf(out, " LOG %s.%s[%u] (%s0, %s1)\n", - ivl_scope_name(ivl_logic_scope(log)), - ivl_logic_basename(log), - ivl_nexus_ptr_pin(ptr), dr0, dr1); - - } else if ((lpm = ivl_nexus_ptr_lpm(ptr))) { - fprintf(out, " LPM %s.%s (%s0, %s1)\n", - ivl_scope_name(ivl_lpm_scope(lpm)), - ivl_lpm_basename(lpm), dr0, dr1); - - } else if ((con = ivl_nexus_ptr_con(ptr))) { - signal_nexus_const(net, ptr, con); - - } else { - fprintf(out, " ?[%u] (%s0, %s1)\n", - ivl_nexus_ptr_pin(ptr), dr0, dr1); - } + show_nexus_details(net, nex); } for (idx = 0 ; idx < ivl_signal_npath(net) ; idx += 1) { @@ -1677,6 +1472,12 @@ int target_design(ivl_design_t des) /* * $Log: stub.c,v $ + * Revision 1.143 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.142 2006/11/28 05:56:41 steve * Dump nand logic. * diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index c25e9ee7e..ed53817f3 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: draw_mux.c,v 1.13 2005/10/12 17:26:17 steve Exp $" +#ident "$Id: draw_mux.c,v 1.14 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -76,9 +76,9 @@ static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz) for (idx = 0 ; idx < (ivl_lpm_size(net) >> level); idx += 2) { fprintf(vvp_out, "L_%p/%d/%d .functor %s %u", - net, width, level, muxz, idx); - fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx/2+0); - fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx/2+1); + net, level, idx/2, muxz, width); + fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx+0); + fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx+1); fprintf(vvp_out, ", L_%p/%ds", net, level); fprintf(vvp_out, ", C4<>;\n"); } @@ -127,6 +127,12 @@ void draw_lpm_mux(ivl_lpm_t net) /* * $Log: draw_mux.c,v $ + * Revision 1.14 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.13 2005/10/12 17:26:17 steve * MUX nodes get inputs from nets, not from net inputs, * Detect and draw alias nodes to reduce net size and diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 16f8ae0c0..02b73e55c 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: draw_ufunc.c,v 1.1 2005/07/13 04:52:31 steve Exp $" +#ident "$Id: draw_ufunc.c,v 1.2 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -32,10 +32,12 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t exp) { struct vector_info res; + /* ports cannot be arrays. */ + assert(ivl_signal_array_count(port) == 1); + res = draw_eval_expr_wid(exp, ivl_signal_width(port), 0); assert(res.wid <= ivl_signal_width(port)); - fprintf(vvp_out, " %%set/v V_%s, %u, %u;\n", - vvp_signal_label(port), res.base, res.wid); + fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, res.wid); clr_vector(res); } @@ -44,8 +46,10 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t exp) { int res = draw_eval_real(exp); - fprintf(vvp_out, " %%set/wr V_%s, %d;\n", - vvp_signal_label(port), res); + /* ports cannot be arrays. */ + assert(ivl_signal_array_count(port) == 1); + + fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res); } static void draw_function_argument(ivl_signal_t port, ivl_expr_t exp) @@ -113,8 +117,9 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) if (load_wid > ivl_signal_width(retval)) load_wid = ivl_signal_width(retval); - fprintf(vvp_out, " %%load/v %u, V_%s, %u;\n", - res.base, vvp_signal_label(retval), load_wid); + assert(ivl_signal_array_count(retval) == 1); + fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n", + res.base, retval, load_wid); if (load_wid < swid) fprintf(vvp_out, " %%mov %u, 0, %u;\n", @@ -148,10 +153,12 @@ int draw_ufunc_real(ivl_expr_t exp) fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); + /* Return value signal cannot be an array. */ + assert(ivl_signal_array_count(retval) == 1); + /* Load the result into a word. */ res = allocate_word(); - fprintf(vvp_out, " %%load/wr %d, V_%s;\n", - res, vvp_signal_label(retval)); + fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, retval); return res; } diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 47794f247..061b1fd71 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: draw_vpi.c,v 1.13 2005/10/11 18:30:50 steve Exp $" +#ident "$Id: draw_vpi.c,v 1.14 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -75,6 +75,7 @@ static void draw_vpi_taskfunc_args(const char*call_string, with VPI handles of their own. Therefore, skip them in the process of evaluating expressions. */ case IVL_EX_NONE: + case IVL_EX_ARRAY: case IVL_EX_NUMBER: case IVL_EX_STRING: case IVL_EX_EVENT: @@ -107,7 +108,8 @@ static void draw_vpi_taskfunc_args(const char*call_string, } else if (ivl_expr_signed(expr) != ivl_signal_signed(ivl_expr_signal(expr))) { break; - + } else if (ivl_signal_array_count(ivl_expr_signal(expr))>1){ + break; } else { continue; } @@ -153,6 +155,10 @@ static void draw_vpi_taskfunc_args(const char*call_string, fprintf(vvp_out, ", \" \""); continue; + case IVL_EX_ARRAY: + fprintf(vvp_out, ", v%p", ivl_expr_signal(expr)); + continue; + case IVL_EX_NUMBER: { unsigned bit, wid = ivl_expr_width(expr); const char*bits = ivl_expr_bits(expr); @@ -176,13 +182,16 @@ static void draw_vpi_taskfunc_args(const char*call_string, ivl_signal_signed(ivl_expr_signal(expr))) { break; + } else if (ivl_signal_array_count(ivl_expr_signal(expr))>1){ + break; + } else { - fprintf(vvp_out, ", V_%s", - vvp_signal_label(ivl_expr_signal(expr))); + ivl_signal_t sig = ivl_expr_signal(expr); + assert(ivl_signal_array_count(sig) == 1); + fprintf(vvp_out, ", v%p_0", sig); continue; } - fprintf(vvp_out, ", V_%s", - vvp_signal_label(ivl_expr_signal(expr))); + assert(0); continue; case IVL_EX_STRING: @@ -291,6 +300,12 @@ int draw_vpi_rfunc_call(ivl_expr_t fnet) /* * $Log: draw_vpi.c,v $ + * Revision 1.14 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.13 2005/10/11 18:30:50 steve * Remove obsolete vvp_memory_label function. * diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 5391b7615..0b8fdea18 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval_expr.c,v 1.130 2006/02/02 02:43:59 steve Exp $" +#ident "$Id: eval_expr.c,v 1.131 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -1531,21 +1531,39 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid) */ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res) { - unsigned idx; unsigned swid = ivl_expr_width(exp); ivl_signal_t sig = ivl_expr_signal(exp); + unsigned word = 0; + if (swid > res.wid) swid = res.wid; + /* If this is an access to an array, handle that by emiting a + load/av instruction. */ + if (ivl_signal_array_count(sig) > 1) { + ivl_expr_t ix = ivl_expr_oper1(exp); + if (!number_is_immediate(ix, 8*sizeof(unsigned long))) { + draw_eval_expr_into_integer(ix, 3); + fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", + res.base, sig, swid); + return; + } + + /* The index is constant, so we can return to direct + readout with the specific word selected. */ + word = get_number_immediate(ix); + } + /* If this is a REG (a variable) then I can do a vector read. */ - fprintf(vvp_out, " %%load/v %u, V_%s, %u;\n", - res.base, vvp_signal_label(sig), swid); + fprintf(vvp_out, " %%load/v %u, v%p_%u, %u;\n", + res.base, sig, word, swid); /* Pad the signal value with zeros. */ if (swid < res.wid) { if (ivl_expr_signed(exp)) { + unsigned idx; for (idx = swid ; idx < res.wid ; idx += 1) fprintf(vvp_out, " %%mov %u, %u, 1;\n", res.base+idx, res.base+swid-1); @@ -1671,6 +1689,24 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, struct vector_info res; unsigned idx; + /* Use this word of the signal. */ + unsigned use_word = 0; + /* If this is an access to an array, handle that by emiting a + load/av instruction. */ + if (ivl_signal_array_count(sig) > 1) { + ivl_expr_t ix = ivl_expr_oper1(sube); + if (!number_is_immediate(ix, 8*sizeof(unsigned long))) { + draw_eval_expr_into_integer(ix, 3); + assert(0); /* XXXX Don't know how to load part + select! */ + return res; + } + + /* The index is constant, so we can return to direct + readout with the specific word selected. */ + use_word = get_number_immediate(ix); + } + shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO); fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); @@ -1683,8 +1719,8 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, if (shiv.base == 0 && ivl_expr_width(sube) == wid) { res.base = allocate_vector(wid); res.wid = wid; - fprintf(vvp_out, " %%load/v %u, V_%p, %u;\n", - res.base, sig, ivl_expr_width(sube)); + fprintf(vvp_out, " %%load/v %u, v%p_%u, %u;\n", + res.base, sig, use_word, ivl_expr_width(sube)); return res; } @@ -1698,10 +1734,10 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, res.base = allocate_vector(ivl_expr_width(sube)); res.wid = ivl_expr_width(sube); - fprintf(vvp_out, " %%load/v %u, V_%p, %u; Only need %u bits\n", - res.base, sig, ivl_expr_width(sube), wid); + fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u bits\n", + res.base, sig, use_word, ivl_expr_width(sube), wid); - save_signal_lookaside(res.base, sig, res.wid); + save_signal_lookaside(res.base, sig, use_word, res.wid); { struct vector_info tmp; @@ -1724,8 +1760,8 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, ivl_expr_width(sube), wid); break; } - fprintf(vvp_out, " %%load/x.p %u, V_%p, 0;\n", - res.base+idx, sig); + fprintf(vvp_out, " %%load/x.p %u, v%p_%u, 0;\n", + res.base+idx, sig, use_word); } return res; @@ -2209,6 +2245,12 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag) /* * $Log: eval_expr.c,v $ + * Revision 1.131 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.130 2006/02/02 02:43:59 steve * Allow part selects of memory words in l-values. * diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index a9c82f721..4bb97b1c8 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval_real.c,v 1.16 2006/10/10 23:54:28 steve Exp $" +#ident "$Id: eval_real.c,v 1.17 2007/01/16 05:44:16 steve Exp $" #endif /* @@ -245,9 +245,22 @@ static int draw_signal_real_real(ivl_expr_t exp) { ivl_signal_t sig = ivl_expr_signal(exp); int res = allocate_word(); + unsigned long word = 0; - fprintf(vvp_out, " %%load/wr %d, V_%s;\n", - res, vvp_signal_label(sig)); + if (ivl_signal_array_count(sig) > 1) { + ivl_expr_t ix = ivl_expr_oper1(exp); + if (!number_is_immediate(ix, 8*sizeof(word))) { + /* XXXX Need to generate a %load/ar instruction. */ + assert(0); + return res; + } + + /* The index is constant, so we can return to direct + readout with the specific word selected. */ + word = get_number_immediate(ix); + } + + fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word); return res; } @@ -326,6 +339,12 @@ int draw_eval_real(ivl_expr_t exp) /* * $Log: eval_real.c,v $ + * Revision 1.17 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.16 2006/10/10 23:54:28 steve * Fix rendering of signed numbers in real expressions. * diff --git a/tgt-vvp/vector.c b/tgt-vvp/vector.c index 5387f9102..486f5fb34 100644 --- a/tgt-vvp/vector.c +++ b/tgt-vvp/vector.c @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vector.c,v 1.7 2005/09/17 01:01:00 steve Exp $" +#ident "$Id: vector.c,v 1.8 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -32,6 +32,7 @@ static struct allocation_score_s { ivl_expr_t exp; ivl_signal_t sig; + unsigned sig_word; unsigned exp_bit : 24; unsigned sig_bit : 24; unsigned alloc : 8; @@ -56,9 +57,10 @@ static inline void set_exp(unsigned addr, ivl_expr_t exp, unsigned ebit) allocation_map[addr].exp_bit = ebit; } -static inline void set_sig(unsigned addr, ivl_signal_t exp, unsigned ebit) +static inline void set_sig(unsigned addr, ivl_signal_t exp, unsigned sig_word, unsigned ebit) { allocation_map[addr].sig = exp; + allocation_map[addr].sig_word = sig_word; allocation_map[addr].sig_bit = ebit; } @@ -139,7 +141,7 @@ void clear_expression_lookaside(void) for (idx = 0 ; idx < lookaside_top ; idx += 1) { set_exp(idx, 0, 0); - set_sig(idx, 0, 0); + set_sig(idx, 0, 0, 0); } lookaside_top = 0; @@ -157,14 +159,14 @@ void save_expression_lookaside(unsigned addr, ivl_expr_t exp, unsigned wid) bits. */ for (idx = 0 ; idx < wid ; idx += 1) { set_exp(addr+idx, exp, idx); - set_sig(addr+idx, 0, 0); + set_sig(addr+idx, 0, 0, 0); } if ((addr+wid) > lookaside_top) lookaside_top = addr+wid; } -void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned wid) +void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned sig_word, unsigned wid) { unsigned idx; /* Don't bind any of hte low bits to a signal. */ @@ -174,7 +176,7 @@ void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned wid) assert((addr+wid) <= MAX_VEC); for (idx = 0 ; idx < wid ; idx += 1) - set_sig(addr+idx, sig, idx); + set_sig(addr+idx, sig, sig_word, idx); if ((addr+wid) > lookaside_top) lookaside_top = addr+wid; @@ -321,6 +323,12 @@ unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid, /* * $Log: vector.c,v $ + * Revision 1.8 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.7 2005/09/17 01:01:00 steve * More robust use of precalculated expressions, and * Separate lookaside for written variables that can diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 4eb016508..e5814bf76 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vvp_priv.h,v 1.40 2006/02/02 02:43:59 steve Exp $" +#ident "$Id: vvp_priv.h,v 1.41 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_config.h" @@ -212,7 +212,7 @@ extern void save_expression_lookaside(unsigned addr, ivl_expr_t exp, unsigned wid); extern void save_signal_lookaside(unsigned addr, - ivl_signal_t sig, + ivl_signal_t sig, unsigned use_word, unsigned wid); extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid, @@ -252,6 +252,12 @@ extern unsigned thread_count; /* * $Log: vvp_priv.h,v $ + * Revision 1.41 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.40 2006/02/02 02:43:59 steve * Allow part selects of memory words in l-values. * diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 8e0fa6201..62c71034c 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2005 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vvp_process.c,v 1.126 2006/10/05 01:37:34 steve Exp $" +#ident "$Id: vvp_process.c,v 1.127 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -78,6 +78,12 @@ static void set_to_lvariable(ivl_lval_t lval, ivl_expr_t part_off_ex = ivl_lval_part_off(lval); unsigned part_off = 0; + /* Although Verilog doesn't support it, we'll handle + here the case of an l-value part select of an array + word if the address is constant. */ + ivl_expr_t word_ix = ivl_lval_idx(lval); + unsigned long use_word = 0; + if (part_off_ex == 0) { part_off = 0; } else if (number_is_immediate(part_off_ex, 64)) { @@ -85,6 +91,14 @@ static void set_to_lvariable(ivl_lval_t lval, part_off_ex = 0; } + /* If the word index is a constand expression, then evaluate + it to select the word, and pay no further heed to the + expression itself. */ + if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word))) { + use_word = get_number_immediate(word_ix); + word_ix = 0; + } + if (ivl_lval_mux(lval)) part_off_ex = ivl_lval_mux(lval); @@ -95,12 +109,13 @@ static void set_to_lvariable(ivl_lval_t lval, a bit-select l-val. Presumably, the x0 index register has been loaded wit the result of the evaluated part select base expression. */ + assert(!word_ix); draw_eval_expr_into_integer(part_off_ex, 0); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); - fprintf(vvp_out, " %%set/x0 V_%s, %u, %u;\n", - vvp_signal_label(sig), bit, wid); + fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n", + sig, use_word, bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { @@ -108,15 +123,35 @@ static void set_to_lvariable(ivl_lval_t lval, offset. Load that into index x0 and generate a vector set instruction. */ assert(ivl_lval_width(lval) == wid); + assert(!word_ix); fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off); - fprintf(vvp_out, " %%set/x0 V_%s, %u, %u;\n", - vvp_signal_label(sig), bit, wid); + fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n", + sig, use_word, bit, wid); + + } else if (ivl_signal_array_count(sig) > 1) { + + /* If the word index is a constant, then we can write + directly to the word and save the index calculation. */ + if (word_ix == 0) { + fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n", + sig, use_word, bit, wid); + + } else { + unsigned skip_set = transient_id++; + unsigned index_reg = 3; + draw_eval_expr_into_integer(word_ix, index_reg); + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); + fprintf(vvp_out, " %%ix/load 1, 0;\n"); + fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", + sig, bit, wid); + fprintf(vvp_out, "t_%u ;\n", skip_set); + } } else { - save_signal_lookaside(bit, sig, wid); - fprintf(vvp_out, " %%set/v V_%s, %u, %u;\n", - vvp_signal_label(sig), bit, wid); + save_signal_lookaside(bit, sig, use_word, wid); + fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n", + sig, use_word, bit, wid); } } @@ -149,6 +184,26 @@ static void set_to_memory_word(ivl_lval_t lval, unsigned idx, fprintf(vvp_out, "t_%u ;\n", skip_set); } +static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, + unsigned bit, unsigned delay, unsigned width) +{ + unsigned skip_assign = transient_id++; + + /* Store expression width into index word 0 */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + /* Store constant (0) word part select into index 1 */ + fprintf(vvp_out, " %%ix/load 1, 0;\n"); + /* Calculate array word index into index register 3 */ + draw_eval_expr_into_integer(word_ix, 3); + /* Skip assignment if word expression is not defined. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + + fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, delay, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); + + clear_expression_lookaside(); +} + static void assign_to_lvector(ivl_lval_t lval, unsigned bit, unsigned delay, ivl_expr_t dexp, unsigned width) @@ -157,6 +212,20 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, ivl_expr_t part_off_ex = ivl_lval_part_off(lval); unsigned part_off = 0; + ivl_expr_t word_ix = ivl_lval_idx(lval); + unsigned long use_word = 0; + + if (ivl_signal_array_count(sig) > 1) { + assert(word_ix); + if (! number_is_immediate(word_ix, 8*sizeof(use_word))) { + assert(!dexp); + assign_to_array_word(sig, word_ix, bit, delay, width); + return; + } + + use_word = get_number_immediate(word_ix); + } + if (part_off_ex == 0) { part_off = 0; } else if (number_is_immediate(part_off_ex, 64)) { @@ -174,8 +243,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, /* If the index expression has XZ bits, skip the assign. */ fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%assign/v0/x1 V_%s, %u, %u;\n", - vvp_signal_label(sig), delay, bit); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); fprintf(vvp_out, "t_%u ;\n", skip_assign); } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { @@ -188,8 +257,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, /* Constant delay... */ fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); - fprintf(vvp_out, " %%assign/v0/x1 V_%s, %u, %u;\n", - vvp_signal_label(sig), delay, bit); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); } else { /* Calculated delay... */ @@ -197,20 +266,20 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, draw_eval_expr_into_integer(dexp, delay_index); fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); - fprintf(vvp_out, " %%assign/v0/x1/d V_%s, %u, %u;\n", - vvp_signal_label(sig), delay_index, bit); + fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %u, %u;\n", + sig, use_word, delay_index, bit); clr_word(delay_index); } } else if (dexp != 0) { draw_eval_expr_into_integer(dexp, 1); fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%assign/v0/d V_%s, 1, %u;\n", - vvp_signal_label(sig), bit); + fprintf(vvp_out, " %%assign/v0/d v%p_%lu, 1, %u;\n", + sig, use_word, bit); } else { fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%assign/v0 V_%s, %u, %u;\n", - vvp_signal_label(sig), delay, bit); + fprintf(vvp_out, " %%assign/v0 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); } } @@ -345,8 +414,9 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) var = ivl_lval_sig(lval); assert(var != 0); - fprintf(vvp_out, " %%set/wr V_%s, %d;\n", - vvp_signal_label(var), res); + assert(ivl_signal_array_count(var) == 1); + + fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); return 0; } @@ -390,13 +460,27 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) ivl_signal_t sig; ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t del = ivl_stmt_delay_expr(net); - + /* variables for the selection of word from an array. */ + ivl_expr_t word_ix; + unsigned long use_word = 0; + /* thread address for a word value. */ int word; unsigned long delay; /* Must be exactly 1 l-value. */ assert(ivl_stmt_lvals(net) == 1); + lval = ivl_stmt_lval(net, 0); + sig = ivl_lval_sig(lval); + assert(sig); + + if (ivl_signal_array_count(sig) > 1) { + word_ix = ivl_lval_idx(lval); + assert(word_ix); + assert(number_is_immediate(word_ix, 8*sizeof(use_word))); + use_word = get_number_immediate(word_ix); + } + delay = 0; if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { delay = ivl_expr_uvalue(del); @@ -409,11 +493,8 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* Evaluate the r-value */ word = draw_eval_real(rval); - lval = ivl_stmt_lval(net, 0); - sig = ivl_lval_sig(lval); - assert(sig); - fprintf(vvp_out, " %%assign/wr V_%s, %lu, %u;\n", - vvp_signal_label(sig), delay, word); + fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", + sig, use_word, delay, word); clr_word(word); @@ -750,6 +831,8 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec) unsigned use_wid = ivl_lval_width(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); unsigned part_off; + ivl_expr_t word_idx = ivl_lval_idx(lval); + unsigned long use_word = 0; if (part_off_ex == 0) { part_off = 0; @@ -758,6 +841,11 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec) part_off = get_number_immediate(part_off_ex); } + if (word_idx != 0) { + assert(number_is_immediate(word_idx, 8*sizeof(unsigned long))); + use_word = get_number_immediate(word_idx); + } + /* L-Value must be a signal: reg or wire */ assert(lsig != 0); @@ -775,8 +863,8 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec) assert((roff + use_wid) <= rvec.wid); } - fprintf(vvp_out, " %s V_%s, %u, %u;\n", command_name, - vvp_signal_label(lsig), rvec.base+roff, use_wid); + fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name, + lsig, use_word, rvec.base+roff, use_wid); if (rvec.base >= 4) roff += use_wid; @@ -790,6 +878,9 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) ivl_signal_t lsig; const char*command_name; + ivl_expr_t lword_idx, rword_idx; + unsigned long use_lword = 0, use_rword = 0; + if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return; @@ -811,9 +902,23 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) lval = ivl_stmt_lval(net, 0); lsig = ivl_lval_sig(lval); + /* At least for now, only handle force to fixed words of an array. */ + if ((lword_idx = ivl_lval_idx(lval)) != 0) { + assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long))); + use_lword = get_number_immediate(lword_idx); + } + + if ((rword_idx = ivl_expr_oper1(rval)) != 0) { + assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long))); + use_rword = get_number_immediate(rword_idx); + } + + assert(ivl_signal_array_count(rsig) == 1); + use_rword = 0; + fprintf(vvp_out, " %s/link", command_name); - fprintf(vvp_out, " V_%s", vvp_signal_label(lsig)); - fprintf(vvp_out, ", V_%s;\n", vvp_signal_label(rsig)); + fprintf(vvp_out, " v%p_%lu", lsig, use_lword); + fprintf(vvp_out, ", v%p_%lu;\n", rsig, use_rword); } static int show_stmt_cassign(ivl_statement_t net) @@ -848,11 +953,20 @@ static int show_stmt_deassign(ivl_statement_t net) ivl_lval_t lval = ivl_stmt_lval(net, lidx); ivl_signal_t lsig = ivl_lval_sig(lval); + ivl_expr_t word_idx = ivl_lval_idx(lval); + unsigned long use_word = 0; + assert(lsig != 0); assert(ivl_lval_mux(lval) == 0); assert(ivl_lval_part_off(lval) == 0); - fprintf(vvp_out, " %%deassign V_%s;\n", vvp_signal_label(lsig)); + if (word_idx != 0) { + assert(number_is_immediate(word_idx, 8*sizeof(use_word))); + use_word = get_number_immediate(word_idx); + } + + + fprintf(vvp_out, " %%deassign v%p_%lu;\n", lsig, use_word); } return 0; @@ -1086,6 +1200,8 @@ static int show_stmt_release(ivl_statement_t net) ivl_signal_t lsig = ivl_lval_sig(lval); const char*opcode = 0; + ivl_expr_t word_idx = ivl_lval_idx(lval); + unsigned long use_word = 0; assert(lsig != 0); assert(ivl_lval_mux(lval) == 0); assert(ivl_lval_part_off(lval) == 0); @@ -1099,10 +1215,15 @@ static int show_stmt_release(ivl_statement_t net) break; } + if (word_idx != 0) { + assert(number_is_immediate(word_idx, 8*sizeof(use_word))); + use_word = get_number_immediate(word_idx); + } + /* Generate the appropriate release statement for this l-value. */ - fprintf(vvp_out, " %%release/%s V_%s;\n", - opcode, vvp_signal_label(lsig)); + fprintf(vvp_out, " %%release/%s v%p_%lu;\n", + opcode, lsig, use_word); } return 0; @@ -1491,6 +1612,12 @@ int draw_func_definition(ivl_scope_t scope) /* * $Log: vvp_process.c,v $ + * Revision 1.127 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.126 2006/10/05 01:37:34 steve * Remove dead code. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index d4e125ba2..f3776b318 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.150 2006/11/23 22:42:48 steve Exp $" +#ident "$Id: vvp_scope.c,v 1.151 2007/01/16 05:44:16 steve Exp $" #endif # include "vvp_priv.h" @@ -178,7 +178,7 @@ const char* vvp_signal_label(ivl_signal_t sig) return buf; } -ivl_signal_t signal_of_nexus(ivl_nexus_t nex) +ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word) { unsigned idx; for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { @@ -188,9 +188,8 @@ ivl_signal_t signal_of_nexus(ivl_nexus_t nex) continue; if (ivl_signal_local(sig)) continue; - + *word = ivl_nexus_ptr_pin(ptr); return sig; - } return 0; @@ -575,11 +574,9 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) sptr = ivl_nexus_ptr_sig(nptr); if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) { - /* Input is a .var. Note that these devices have only - exactly one pin (that carries a vector) so nptr_pin - must be 0. */ - assert(nptr_pin == 0); - sprintf(result, "V_%s", vvp_signal_label(sptr)); + /* Input is a .var. This device may be a non-zero pin + because it may be an array of reg vectors. */ + snprintf(result, sizeof result, "v%p_%u", sptr, nptr_pin); return result; } @@ -620,8 +617,8 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) if (lpm) switch (ivl_lpm_type(lpm)) { case IVL_LPM_FF: - case IVL_LPM_RAM: case IVL_LPM_ADD: + case IVL_LPM_ARRAY: case IVL_LPM_CONCAT: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: @@ -936,12 +933,13 @@ const char*draw_net_input(ivl_nexus_t nex) const char*draw_input_from_net(ivl_nexus_t nex) { static char result[32]; + unsigned word; - ivl_signal_t sig = signal_of_nexus(nex); + ivl_signal_t sig = signal_of_nexus(nex, &word); if (sig == 0) return draw_net_input(nex); - snprintf(result, sizeof result, "V_%p", sig); + snprintf(result, sizeof result, "v%p_%u", sig, word); return result; } @@ -949,7 +947,8 @@ const char*draw_input_from_net(ivl_nexus_t nex) /* * This function draws a reg/int/variable in the scope. This is a very * simple device to draw as there are no inputs to connect so no need - * to scan the nexus. + * to scan the nexus. We do have to account for the possibility that + * the device is arrayed, though, by making a node for each array element. */ static void draw_reg_in_scope(ivl_signal_t sig) { @@ -967,9 +966,29 @@ static void draw_reg_in_scope(ivl_signal_t sig) break; } - fprintf(vvp_out, "V_%s .var%s \"%s\", %d, %d;\n", - vvp_signal_label(sig), datatype_flag, - vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb); + /* If the reg objects are collected into an array, then first + write out the .array record to declare the array indices. */ + if (ivl_signal_array_count(sig) > 1) { + unsigned word_count = ivl_signal_array_count(sig); + unsigned iword; + int last = ivl_signal_array_base(sig)+ivl_signal_array_count(sig)-1; + int first = ivl_signal_array_base(sig); + fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n", + sig, vvp_mangle_name(ivl_signal_basename(sig)), + last, first); + + /* Scan the words of the array... */ + for (iword = 0 ; iword < word_count ; iword += 1) { + fprintf(vvp_out, "v%p_%u .var%s v%p, %d %d;\n", + sig, iword, datatype_flag, sig, msb, lsb); + } + + } else { + + fprintf(vvp_out, "v%p_0 .var%s \"%s\", %d %d;\n", + sig, datatype_flag, + vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb); + } } @@ -981,28 +1000,14 @@ static void draw_net_in_scope(ivl_signal_t sig) { int msb = ivl_signal_msb(sig); int lsb = ivl_signal_lsb(sig); - typedef const char*const_charp; - const char* arg; - const char* driver; const char*datatype_flag = ivl_signal_signed(sig)? "/s" : ""; - - struct vvp_nexus_data*nex_data; + unsigned iword; /* Skip the local signal. */ if (ivl_signal_local(sig)) return; - /* Connect the pin of the signal to something. */ - { - ivl_nexus_t nex = ivl_signal_nex(sig); - driver = draw_net_input(nex); - arg = driver; - - nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex); - assert(nex_data); - } - switch (ivl_signal_data_type(sig)) { case IVL_VT_REAL: datatype_flag = "/real"; @@ -1011,30 +1016,70 @@ static void draw_net_in_scope(ivl_signal_t sig) break; } - if (nex_data->net == 0) { - const char*vec8 = ""; - if (nex_data->drivers_count > 1) - vec8 = "8"; - if (nex_data->flags & VVP_NEXUS_DATA_STR) - vec8 = "8"; + for (iword = 0 ; iword < ivl_signal_array_count(sig); iword += 1) { - fprintf(vvp_out, "V_%p .net%s%s \"%s\", %d, %d, %s;" - " %u drivers%s\n", - sig, vec8, datatype_flag, - vvp_mangle_name(ivl_signal_basename(sig)), - msb, lsb, arg, - nex_data->drivers_count, - nex_data->flags&VVP_NEXUS_DATA_STR?", strength-aware":""); - nex_data->net = sig; + unsigned word_count = ivl_signal_array_count(sig); + struct vvp_nexus_data*nex_data; - } else { - /* Detect that this is an alias of nex_data->net. Create - a different kind of node that refers to the alias - source data instead of holding our own data. */ - fprintf(vvp_out, "V_%p .alias%s \"%s\", %d, %d, V_%p;\n", - sig, datatype_flag, - vvp_mangle_name(ivl_signal_basename(sig)), - msb, lsb, nex_data->net); + /* Connect the pin of the signal to something. */ + ivl_nexus_t nex = ivl_signal_nex(sig, iword); + const char*driver = draw_net_input(nex); + + nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex); + assert(nex_data); + + if (nex_data->net == 0) { + int strength_aware_flag = 0; + const char*vec8 = ""; + if (nex_data->flags&VVP_NEXUS_DATA_STR) + strength_aware_flag = 1; + if (nex_data->drivers_count > 1) + vec8 = "8"; + if (strength_aware_flag) + vec8 = "8"; + + if (iword == 0 && word_count > 1) { + int last = ivl_signal_array_base(sig) + word_count-1; + int first = ivl_signal_array_base(sig); + fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n", + sig, vvp_mangle_name(ivl_signal_basename(sig)), + last, first); + } + if (word_count > 1) { + /* If this is a word of an array, then use an + array reference in place of the net name. */ + fprintf(vvp_out, "v%p_%u .net%s%s v%p, %d %d, %s;" + " %u drivers%s\n", + sig, iword, vec8, datatype_flag, sig, + msb, lsb, driver, + nex_data->drivers_count, + strength_aware_flag?", strength-aware":""); + } else { + /* If this is an isolated word, it uses its + own name. */ + fprintf(vvp_out, "v%p_%u .net%s%s \"%s\", %d %d, %s;" + " %u drivers%s\n", + sig, iword, vec8, datatype_flag, + vvp_mangle_name(ivl_signal_basename(sig)), + msb, lsb, driver, + nex_data->drivers_count, + strength_aware_flag?", strength-aware":""); + } + nex_data->net = sig; + + } else { + + assert(word_count == 1); + assert(ivl_signal_array_count(nex_data->net) == 1); + + /* Detect that this is an alias of nex_data->net. Create + a different kind of node that refers to the alias + source data instead of holding our own data. */ + fprintf(vvp_out, "v%p_0 .alias%s \"%s\", %d %d, v%p_0;\n", + sig, datatype_flag, + vvp_mangle_name(ivl_signal_basename(sig)), + msb, lsb, nex_data->net); + } } } @@ -1373,13 +1418,16 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr); sig = ivl_expr_signal(rise_exp); - fprintf(vvp_out, ", V_%p", sig); + assert(ivl_signal_array_count(sig) == 1); + fprintf(vvp_out, ", v%p_0", sig); sig = ivl_expr_signal(fall_exp); - fprintf(vvp_out, ", V_%p", sig); + assert(ivl_signal_array_count(sig) == 1); + fprintf(vvp_out, ", v%p_0", sig); sig = ivl_expr_signal(decay_exp); - fprintf(vvp_out, ", V_%p;\n", sig); + assert(ivl_signal_array_count(sig) == 1); + fprintf(vvp_out, ", v%p_0;\n", sig); } } } @@ -1515,38 +1563,6 @@ static void draw_event_in_scope(ivl_event_t obj) } } -static void draw_lpm_ram(ivl_lpm_t net) -{ - ivl_memory_t mem = ivl_lpm_memory(net); - ivl_nexus_t clk = ivl_lpm_clk(net); - ivl_nexus_t pin; - - if (clk) { - fprintf(vvp_out, "CLK_%p .event posedge, %s;\n", - net, draw_net_input(clk)); - } - - fprintf(vvp_out, "L_%p .mem/port M_%p, ", net, mem); - - pin = ivl_lpm_select(net); - fprintf(vvp_out, "%s", draw_net_input(pin)); - - if (clk) { - fprintf(vvp_out, ", CLK_%p, ", net); - pin = ivl_lpm_enable(net); - if (pin) - fprintf(vvp_out, "%s", draw_net_input(pin)); - else - fprintf(vvp_out, "C4<1>"); - - pin = ivl_lpm_data(net, 0); - fprintf(vvp_out, ", %s", draw_net_input(pin)); - } - - fprintf(vvp_out, ";\n"); -} - - /* * This function draws any functors needed to calculate the input to * this nexus, and leaves in the data array strings that can be used @@ -1611,6 +1627,23 @@ static void draw_lpm_add(ivl_lpm_t net) net, type, width, src_table[0], src_table[1]); } +/* +* The read port to an array is generated as a single record that takes +* the address as an input. +*/ +static void draw_lpm_array(ivl_lpm_t net) +{ + ivl_nexus_t nex; + ivl_signal_t mem = ivl_lpm_array(net); + + fprintf(vvp_out, "L_%p .array/port v%p, ", net, mem); + + nex = ivl_lpm_select(net); + fprintf(vvp_out, "%s", draw_net_input(nex)); + + fprintf(vvp_out, ";\n"); +} + static void draw_lpm_cmp(ivl_lpm_t net) { const char*src_table[2]; @@ -1951,7 +1984,8 @@ static void draw_lpm_ufunc(ivl_lpm_t net) else fprintf(vvp_out, ", "); - fprintf(vvp_out, "V_%s", vvp_signal_label(psig)); + assert(ivl_signal_array_count(psig) == 1); + fprintf(vvp_out, "v%p_0", psig); } fprintf(vvp_out, ")"); @@ -1960,8 +1994,9 @@ static void draw_lpm_ufunc(ivl_lpm_t net) result is collected. */ { ivl_signal_t psig = ivl_scope_port(def, 0); assert(ivl_lpm_width(net) == ivl_signal_width(psig)); + assert(ivl_signal_array_count(psig) == 1); - fprintf(vvp_out, " V_%s", vvp_signal_label(psig)); + fprintf(vvp_out, " v%p_0", psig); } fprintf(vvp_out, ";\n"); @@ -2123,10 +2158,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net) { switch (ivl_lpm_type(net)) { - case IVL_LPM_RAM: - draw_lpm_ram(net); - return; - case IVL_LPM_ADD: case IVL_LPM_SUB: case IVL_LPM_MULT: @@ -2135,6 +2166,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_add(net); return; + case IVL_LPM_ARRAY: + draw_lpm_array(net); + return; + case IVL_LPM_PART_BI: draw_lpm_part_bi(net); return; @@ -2335,6 +2370,12 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) /* * $Log: vvp_scope.c,v $ + * Revision 1.151 2007/01/16 05:44:16 steve + * Major rework of array handling. Memories are replaced with the + * more general concept of arrays. The NetMemory and NetEMemory + * classes are removed from the ivl core program, and the IVL_LPM_RAM + * lpm type is removed from the ivl_target API. + * * Revision 1.150 2006/11/23 22:42:48 steve * Do not intertangle modpaths due to references to input nets. * diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 91a6ac0d4..c298574b0 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.71 2006/10/30 22:45:38 steve Exp $" +#ident "$Id: Makefile.in,v 1.72 2007/01/16 05:44:16 steve Exp $" # # SHELL = /bin/sh @@ -81,7 +81,8 @@ vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \ vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o -O = main.o parse.o parse_misc.o lexor.o arith.o bufif.o compile.o concat.o \ +O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \ +concat.o \ dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \ ufunc.o codes.o \ vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \ diff --git a/vvp/README.txt b/vvp/README.txt index 72182c20b..d872ad80d 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -1,7 +1,7 @@ /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) * - * $Id: README.txt,v 1.79 2006/11/23 23:02:36 steve Exp $ + * $Id: README.txt,v 1.80 2007/01/16 05:44:16 steve Exp $ */ VVP SIMULATION ENGINE @@ -370,6 +370,16 @@ activates the delay. .modpath , [ () ] ; +ARRAY INDEX STATEMENTS: + +Variables can be collected into arrays. The words of the array are +declared seperately, this statement collects them together: + +