From 3b0dfaadba004e15b0143d0ff7d9f1e5c7c5544c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 2 Sep 2014 09:23:54 -0700 Subject: [PATCH] Some support for unpacked arrays in class properties. --- elab_lval.cc | 52 +++++++++++++++++++++++++++++++++++- elab_sig.cc | 44 +----------------------------- elab_type.cc | 19 ++++++++++--- elaborate.cc | 35 ++++++++++++++++++++++++ net_proc.cc | 2 +- netmisc.cc | 75 +++++++++++++++++++++++++++++++++++++++++++++++----- netmisc.h | 8 ++++++ netparray.cc | 22 ++++++++++----- netparray.h | 57 ++++++++++++++++++++++++++++++++------- 9 files changed, 245 insertions(+), 69 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index f5ab1320e..84b283353 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -27,6 +27,7 @@ # include "netstruct.h" # include "netclass.h" # include "netdarray.h" +# include "netparray.h" # include "netvector.h" # include "compiler.h" # include @@ -259,6 +260,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } ivl_assert(*this, reg); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval: " + << "Lval reg = " << reg->name() << endl; + } + // We are processing the tail of a string of names. For // example, the verilog may be "a.b.c", so we are processing // "c" at this point. (Note that if method_name is not nil, @@ -389,7 +396,9 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, if (class_type == 0) return 0; - perm_string member_name = peek_tail_name(path_); + const name_component_t&name_comp = path_.back(); + + perm_string member_name = name_comp.name; int pidx = class_type->property_idx_from_name(member_name); if (pidx < 0) return 0; @@ -402,6 +411,46 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, return 0; } + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Ident " << member_name + << " is a property of class " << class_type->get_name() << endl; + } + + NetExpr*canon_index = 0; + if (name_comp.index.size() > 0) { + ivl_type_t property_type = class_type->get_prop_type(pidx); + + if (const netsarray_t* stype = dynamic_cast (property_type)) { + list indices_const; + list indices_expr; + indices_flags flags; + indices_to_expressions(des, scope, this, + name_comp.index, name_comp.index.size(), + false, flags, + indices_expr, indices_const); + + if (flags.undefined) { + cerr << get_fileline() << ": warning: " + << "ignoring undefined l-value array access " + << member_name + << " (" << path_ << ")" + << "." << endl; + } else if (flags.variable) { + canon_index = normalize_variable_unpacked(*this, stype, indices_expr); + + } else { + canon_index = normalize_variable_unpacked(stype, indices_const); + } + + + } else { + cerr << get_fileline() << ": error: " + << "Index expressions don't apply to this type of property." << endl; + des->errors += 1; + } + } + // Detect assignment to constant properties. Note that the // initializer constructor MAY assign to constant properties, // as this is how the property gets its value. @@ -438,6 +487,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, NetAssign_*this_lval = new NetAssign_(this_net); this_lval->set_property(member_name); + if (canon_index) this_lval->set_word(canon_index); return this_lval; } diff --git a/elab_sig.cc b/elab_sig.cc index 37c10f0b8..9d5df8245 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -836,48 +836,6 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } -static bool evaluate_ranges(Design*des, NetScope*scope, - vector&llist, - const list&rlist) -{ - bool bad_msb = false, bad_lsb = false; - - for (list::const_iterator cur = rlist.begin() - ; cur != rlist.end() ; ++cur) { - long use_msb, use_lsb; - - NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); - if (! eval_as_long(use_msb, texpr)) { - cerr << cur->first->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->first->get_fileline() << " : " - "This MSB expression violates the rule: " - << *cur->first << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, cur->second, -1, true); - if (! eval_as_long(use_lsb, texpr)) { - cerr << cur->second->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << cur->second->get_fileline() << " : " - "This LSB expression violates the rule: " - << *cur->second << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - - llist.push_back(netrange_t(use_msb, use_lsb)); - } - - return bad_msb | bad_lsb; -} - static netclass_t* locate_class_type(Design*, NetScope*scope, class_type_t*class_type) { @@ -1288,7 +1246,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype - << " parray=" << use_type->packed_dimensions() + << " parray=" << use_type->static_dimensions() << " " << name_ << unpacked_dimensions << " in scope " << scope_path(scope) << endl; } diff --git a/elab_type.cc b/elab_type.cc index 1167c1902..2f3dab573 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -22,6 +22,7 @@ # include "netclass.h" # include "netdarray.h" # include "netenum.h" +# include "netparray.h" # include "netscalar.h" # include "netstruct.h" # include "netvector.h" @@ -203,9 +204,21 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const ivl_type_t btype = base_type->elaborate_type(des, scope); - assert(dims->size() == 1); + assert(dims->size() >= 1); list::const_iterator cur = dims->begin(); - assert(cur->first == 0 && cur->second==0); - ivl_type_s*res = new netdarray_t(btype); + + // Special case: if the dimension is nil:nil, this is a + // dynamic array. Note that we only know how to handle dynamic + // arrays with 1 dimension at a time. + if (cur->first==0 && cur->second==0) { + assert(dims->size()==1); + ivl_type_s*res = new netdarray_t(btype); + return res; + } + + vector dimensions; + bool bad_range = evaluate_ranges(des, scope, dimensions, *dims); + + ivl_type_s*res = new netuarray_t(dimensions, btype); return res; } diff --git a/elaborate.cc b/elaborate.cc index c8e801a5f..9050f7065 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -40,6 +40,7 @@ # include "netlist.h" # include "netvector.h" # include "netdarray.h" +# include "netparray.h" # include "netclass.h" # include "netmisc.h" # include "util.h" @@ -2290,6 +2291,14 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const NetAssign_*lv = new NetAssign_(tmp); return lv; } + + if (debug_elaborate) { + cerr << get_fileline() << ": PAssign_::elaborate_lval: " + << "lval_ = " << *lval_ << endl; + cerr << get_fileline() << ": PAssign_::elaborate_lval: " + << "lval_ expr type = " << typeid(*lval_).name() << endl; + } + return lval_->elaborate_lval(des, scope, false, false); } @@ -2520,6 +2529,22 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const rv = elaborate_rval_(des, scope, use_lv_type); + } else if (const netuarray_t*utype = dynamic_cast(lv_net_type)) { + ivl_assert(*this, lv->more==0); + if (debug_elaborate) { + if (lv->word()) + cerr << get_fileline() << ": PAssign::elaborate: " + << "lv->word() = " << *lv->word() << endl; + else + cerr << get_fileline() << ": PAssign::elaborate: " + << "lv->word() = " << endl; + } + ivl_type_t use_lv_type = lv_net_type; + ivl_assert(*this, lv->word()); + use_lv_type = utype->element_type(); + + rv = elaborate_rval_(des, scope, use_lv_type); + } else { /* Elaborate the r-value expression, then try to evaluate it. */ rv = elaborate_rval_(des, scope, lv_net_type, lv->expr_type(), count_lval_width(lv)); @@ -4595,6 +4620,16 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const pform_name_t array_name; array_name.push_back(name_component_t(array_var_)); NetNet*array_sig = des->find_signal(scope, array_name); + + if (array_sig == 0) { + cerr << get_fileline() << ": error:" + << " Unable to find " << array_name + << " in scope " << scope_path(scope) + << "." << endl; + des->errors += 1; + return 0; + } + ivl_assert(*this, array_sig); if (debug_elaborate) { diff --git a/net_proc.cc b/net_proc.cc index c10bff7ab..93c746b6d 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -139,7 +139,7 @@ void NetForLoop::wrap_up() NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0); internal_block->set_line(*this); - internal_block->append(statement_); + if (statement_) internal_block->append(statement_); internal_block->append(step_statement_); NetWhile*wloop = new NetWhile(condition_, internal_block); diff --git a/netmisc.cc b/netmisc.cc index e4928ad76..6c5409db9 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -22,6 +22,7 @@ # include # include # include "netlist.h" +# include "netparray.h" # include "netvector.h" # include "netmisc.h" # include "PExpr.h" @@ -526,10 +527,8 @@ static void make_strides(const vector&dims, * word. If any of the indices are out of bounds, return nil instead * of an expression. */ -NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +static NetExpr* normalize_variable_unpacked(const vector&dims, list&indices) { - const vector&dims = net->unpacked_dims(); - // Make strides for each index. The stride is the distance (in // words) to the next element in the canonical array. vector stride (dims.size()); @@ -559,10 +558,20 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) return canonical_expr; } -NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) { const vector&dims = net->unpacked_dims(); + return normalize_variable_unpacked(dims, indices); +} +NetExpr* normalize_variable_unpacked(const netsarray_t*stype, list&indices) +{ + const vector&dims = stype->static_dimensions(); + return normalize_variable_unpacked(dims, indices); +} + +NetExpr* normalize_variable_unpacked(const LineInfo&loc, const vector&dims, list&indices) +{ // Make strides for each index. The stride is the distance (in // words) to the next element in the canonical array. vector stride (dims.size()); @@ -602,7 +611,7 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) if (use_stride != 1) min_wid += num_bits(use_stride); - tmp = pad_to_width(tmp, min_wid, *net); + tmp = pad_to_width(tmp, min_wid, loc); // Now generate the math to calculate the canonical address. NetExpr*tmp_scaled = 0; @@ -641,11 +650,23 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) // If we don't have an expression at this point, all the indices were // constant zero. But this variant of normalize_variable_unpacked() // is only used when at least one index is not a constant. - ivl_assert(*net, canonical_expr); + ivl_assert(loc, canonical_expr); return canonical_expr; } +NetExpr* normalize_variable_unpacked(const NetNet*net, list&indices) +{ + const vector&dims = net->unpacked_dims(); + return normalize_variable_unpacked(*net, dims, indices); +} + +NetExpr* normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*stype, list&indices) +{ + const vector&dims = stype->static_dimensions(); + return normalize_variable_unpacked(loc, dims, indices); +} + NetEConst* make_const_x(unsigned long wid) { verinum xxx (verinum::Vx, wid); @@ -885,6 +906,48 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, return tmp; } +bool evaluate_ranges(Design*des, NetScope*scope, + vector&llist, + const list&rlist) +{ + bool bad_msb = false, bad_lsb = false; + + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + long use_msb, use_lsb; + + NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); + if (! eval_as_long(use_msb, texpr)) { + cerr << cur->first->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->first->get_fileline() << " : " + "This MSB expression violates the rule: " + << *cur->first << endl; + des->errors += 1; + bad_msb = true; + } + + delete texpr; + + texpr = elab_and_eval(des, scope, cur->second, -1, true); + if (! eval_as_long(use_lsb, texpr)) { + cerr << cur->second->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->second->get_fileline() << " : " + "This LSB expression violates the rule: " + << *cur->second << endl; + des->errors += 1; + bad_lsb = true; + } + + delete texpr; + + llist.push_back(netrange_t(use_msb, use_lsb)); + } + + return bad_msb | bad_lsb; +} + void eval_expr(NetExpr*&expr, int context_width) { assert(expr); diff --git a/netmisc.h b/netmisc.h index 3e682fdd2..27583712b 100644 --- a/netmisc.h +++ b/netmisc.h @@ -21,6 +21,8 @@ # include "netlist.h" +class netsarray_t; + /* * Search for a symbol using the "start" scope as the starting * point. If the path includes a scope part, then locate the @@ -184,7 +186,10 @@ extern void indices_to_expressions(Design*des, NetScope*scope, list&indices,list&indices_const); extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const netsarray_t*net, list&indices); + extern NetExpr*normalize_variable_unpacked(const NetNet*net, list&indices); +extern NetExpr*normalize_variable_unpacked(const LineInfo&loc, const netsarray_t*net, list&indices); /* * This function takes as input a NetNet signal and adds a constant @@ -278,6 +283,9 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, unsigned lv_width, PExpr*expr, bool need_const =false); +extern bool evaluate_ranges(Design*des, NetScope*scope, + std::vector&llist, + const std::list&rlist); /* * This procedure evaluates an expression and if the evaluation is * successful the original expression is replaced with the new one. diff --git a/netparray.cc b/netparray.cc index 326b549fc..2adcac16e 100644 --- a/netparray.cc +++ b/netparray.cc @@ -22,6 +22,10 @@ using namespace std; +netsarray_t::~netsarray_t() +{ +} + netparray_t::~netparray_t() { } @@ -34,8 +38,8 @@ long netparray_t::packed_width(void) const { long cur_width = element_type()->packed_width(); - for (vector::const_iterator cur = packed_dims_.begin() - ; cur != packed_dims_.end() ; ++cur) { + for (vector::const_iterator cur = static_dimensions().begin() + ; cur != static_dimensions().end() ; ++cur) { cur_width *= cur->width(); } @@ -44,14 +48,20 @@ long netparray_t::packed_width(void) const vector netparray_t::slice_dimensions() const { + const vector&packed_dims = static_dimensions(); + vector elem_dims = element_type()->slice_dimensions(); - vector res (packed_dims_.size() + elem_dims.size()); + vector res (packed_dims.size() + elem_dims.size()); - for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1) - res[idx] = packed_dims_[idx]; + for (size_t idx = 0 ; idx < packed_dims.size() ; idx += 1) + res[idx] = packed_dims[idx]; for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1) - res[idx+packed_dims_.size()] = elem_dims[idx]; + res[idx+packed_dims.size()] = elem_dims[idx]; return res; } + +netuarray_t::~netuarray_t() +{ +} diff --git a/netparray.h b/netparray.h index 96e8735af..2e0142a65 100644 --- a/netparray.h +++ b/netparray.h @@ -23,10 +23,39 @@ # include "nettypes.h" # include +/* + * Arrays with static dimensions (packed and unpacked) share this + * common base type. + */ +class netsarray_t : public netarray_t { + + public: + explicit netsarray_t(const std::vector&packed, + ivl_type_t etype); + ~netsarray_t(); + + public: + // Virtual methods from the ivl_type_s type... + + public: + inline const std::vector& static_dimensions() const + { return dims_; } + + private: + std::vector dims_; + +}; + +inline netsarray_t::netsarray_t(const std::vector&pd, + ivl_type_t etype) +: netarray_t(etype), dims_(pd) +{ +} + /* * Packed arrays. */ -class netparray_t : public netarray_t { +class netparray_t : public netsarray_t { public: explicit netparray_t(const std::vector&packed, @@ -38,18 +67,28 @@ class netparray_t : public netarray_t { long packed_width(void) const; std::vector slice_dimensions() const; - public: - inline const std::vector& packed_dimensions() const - { return packed_dims_; } - - private: - std::vector packed_dims_; - }; inline netparray_t::netparray_t(const std::vector&pd, ivl_type_t etype) -: netarray_t(etype), packed_dims_(pd) +: netsarray_t(pd, etype) +{ +} + +/* + * Unpacked arrays are very similar, but lack packed slices. + */ +class netuarray_t : public netsarray_t { + + public: + explicit netuarray_t(const std::vector&packed, + ivl_type_t etype); + ~netuarray_t(); +}; + +inline netuarray_t::netuarray_t(const std::vector&pd, + ivl_type_t etype) +: netsarray_t(pd, etype) { }