diff --git a/PExpr.h b/PExpr.h index 5fce3032d..8f6e3778c 100644 --- a/PExpr.h +++ b/PExpr.h @@ -367,6 +367,8 @@ class PEIdent : public PExpr { bool elaborate_lval_net_packed_member_(Design*, NetScope*, NetAssign_*, const perm_string&) const; + bool elaborate_lval_darray_bit_(Design*, NetScope*, + NetAssign_*) const; private: NetExpr*elaborate_expr_param_(Design*des, diff --git a/elab_expr.cc b/elab_expr.cc index 6b07e7691..91085f3da 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -29,6 +29,7 @@ # include "netenum.h" # include "discipline.h" # include "netmisc.h" +# include "netdarray.h" # include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -2308,6 +2309,21 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) ivl_assert(*this, 0); } + if (netdarray_t*darray = net? net->darray_type() : 0) { + if (use_sel == index_component_t::SEL_BIT) { + expr_type_ = darray->data_type(); + expr_width_ = darray->vector_width(); + min_width_ = expr_width_; + signed_flag_ = net->get_signed(); + } else { + expr_type_ = net->data_type(); + expr_width_ = net->vector_width(); + min_width_ = expr_width_; + signed_flag_ = net->get_signed(); + } + return expr_width_; + } + if (use_width != UINT_MAX) { expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic expr_width_ = use_width; @@ -2322,8 +2338,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) expr_type_ = net->data_type(); expr_width_ = net->vector_width(); min_width_ = expr_width_; - signed_flag_ = net->get_signed(); - + signed_flag_ = net->get_signed(); return expr_width_; } @@ -3739,6 +3754,20 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } + if (netdarray_t*darray = net->sig()->darray_type()) { + // Special case: This is a select of a dynamic + // array. Generate a NetESelect ant attach it to + // the NetESignal. This should be interpreted as + // an array word select downstream. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of a dynamic array becomes NetESelect." << endl; + } + NetESelect*res = new NetESelect(net, mux, darray->vector_width()); + res->set_line(*net); + return res; + } + long idx = net->sig()->sb_to_idx(prefix_indices,msv); if (idx >= (long)net->vector_width() || idx < 0) { diff --git a/elab_lval.cc b/elab_lval.cc index c1e853417..71421e742 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -257,9 +257,15 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, if (use_sel == index_component_t::SEL_BIT) { - NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_bit_(des, scope, lv); - return lv; + if (reg->darray_type()) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_darray_bit_(des, scope, lv); + return lv; + } else { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_bit_(des, scope, lv); + return lv; + } } ivl_assert(*this, use_sel == index_component_t::SEL_NONE); @@ -458,6 +464,26 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, return true; } +bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*lv)const +{ + const name_component_t&name_tail = path_.back(); + ivl_assert(*this, !name_tail.index.empty()); + + // For now, only support single-dimension dynamic arrays. + ivl_assert(*this, name_tail.index.size() == 1); + + const index_component_t&index_tail = name_tail.index.back(); + ivl_assert(*this, index_tail.msb != 0); + ivl_assert(*this, index_tail.lsb == 0); + + // Evaluate the select expression... + NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1); + + lv->set_word(mux); + + return true; +} + bool PEIdent::elaborate_lval_net_part_(Design*des, NetScope*scope, NetAssign_*lv) const diff --git a/elab_sig.cc b/elab_sig.cc index d421462b2..232fc0b0d 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1063,7 +1063,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const // put all the packed dimensions there. if (use_lidx==0 && use_ridx==0) { ivl_assert(*this, netarray==0); - netarray = new netdarray_t(packed_dimensions, data_type_); + netarray = new netdarray_t(packed_dimensions, data_type_, wid); packed_dimensions.clear(); continue; } diff --git a/net_assign.cc b/net_assign.cc index d8df40286..b132fbcdc 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -20,6 +20,7 @@ # include "config.h" # include "netlist.h" +# include "netdarray.h" /* * NetAssign @@ -84,13 +85,25 @@ ivl_select_type_t NetAssign_::select_type() const unsigned NetAssign_::lwidth() const { + if (netdarray_t*darray = sig_->darray_type()) { + if (word_ == 0) + return 1; + else + return darray->vector_width(); + } + return lwid_; } ivl_variable_type_t NetAssign_::expr_type() const { - if (sig_->darray_type()) - return IVL_VT_DARRAY; + if (netdarray_t*darray = sig_->darray_type()) { + if (word_ == 0) + return IVL_VT_DARRAY; + else + return darray->data_type(); + } + return sig_->data_type(); } diff --git a/netdarray.cc b/netdarray.cc index 997da92c0..e622beea9 100644 --- a/netdarray.cc +++ b/netdarray.cc @@ -22,8 +22,8 @@ using namespace std; netdarray_t::netdarray_t(const std::list&packed, - ivl_variable_type_t type) -: packed_dims_(packed), type_(type) + ivl_variable_type_t type, unsigned long wid) +: packed_dims_(packed), type_(type), width_(wid) { } diff --git a/netdarray.h b/netdarray.h index b9a968910..2fb1a6f8c 100644 --- a/netdarray.h +++ b/netdarray.h @@ -27,14 +27,17 @@ class netdarray_t : public nettype_base_t { public: explicit netdarray_t(const std::list&packed, - ivl_variable_type_t type); + ivl_variable_type_t type, + unsigned long wid); ~netdarray_t(); - ivl_variable_type_t data_type() const { return type_; } + inline ivl_variable_type_t data_type() const { return type_; } + inline unsigned long vector_width(void) const { return width_; } private: std::list packed_dims_; ivl_variable_type_t type_; + unsigned long width_; }; #endif diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 1b89e43ec..1bfa6318a 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -21,10 +21,36 @@ # include "priv.h" # include +/* + * If the l-value signal is a darray object, then the ivl_lval_mux() + * gets you the array index expression. + */ +static unsigned show_assign_lval_darray(ivl_lval_t lval, unsigned ind) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + assert(sig); + + if (ivl_lval_idx(lval)) { + fprintf(out, "%*sAddress-0 select of dynamic array:\n", ind+4, ""); + show_expression(ivl_lval_idx(lval), ind+6); + } + + if (ivl_lval_mux(lval)) { + fprintf(out, "%*sERROR: unexpected ivl_lval_mux() expression:\n", ind+4, ""); + stub_errors += 1; + show_expression(ivl_lval_mux(lval), ind+6); + } + if (ivl_lval_part_off(lval)) { + fprintf(out, "%*sERROR: unexpected Part select expression:\n", ind+4, ""); + stub_errors += 1; + show_expression(ivl_lval_part_off(lval), ind+8); + } + + return ivl_lval_width(lval); +} + static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) { - unsigned wid = 0; - ivl_signal_t sig = ivl_lval_sig(lval); assert(sig); @@ -34,6 +60,10 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) ivl_signal_width(sig), ivl_lval_width(lval)); + /* Special case: target signal is a darray. */ + if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) + return show_assign_lval_darray(lval, ind); + if (ivl_lval_idx(lval)) { fprintf(out, "%*sAddress-0 select expression:\n", ind+4, ""); show_expression(ivl_lval_idx(lval), ind+6); @@ -59,9 +89,7 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) show_expression(ivl_lval_part_off(lval), ind+8); } - wid = ivl_lval_width(lval); - - return wid; + return ivl_lval_width(lval); } static void show_stmt_cassign(ivl_statement_t net, unsigned ind)