diff --git a/PExpr.h b/PExpr.h index 68bf974a6..2ee7b0653 100644 --- a/PExpr.h +++ b/PExpr.h @@ -213,8 +213,15 @@ class PEAssignPattern : public PExpr { unsigned expr_wid, unsigned flags) const; private: - NetExpr* elaborate_expr_darray_(Design*des, NetScope*scope, - ivl_type_t type, unsigned flags) const; + NetExpr* elaborate_expr_packed_(Design *des, NetScope *scope, + ivl_variable_type_t base_type, + unsigned int width, + const std::vector &dims, + unsigned int cur_dim, + bool need_const) const; + NetExpr* elaborate_expr_darray_(Design *des, NetScope *scope, + const netdarray_t *array_type, + bool need_const) const; private: std::vectorparms_; diff --git a/elab_expr.cc b/elab_expr.cc index 0dc689e3e..5db504ae8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -118,7 +118,8 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, NetExpr *rval; int context_wid = -1; - bool fallback = true; + bool typed_elab = false; + switch (lv_type) { case IVL_VT_DARRAY: case IVL_VT_QUEUE: @@ -126,11 +127,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, // For these types, use a different elab_and_eval that // uses the lv_net_type. We should eventually transition // all the types to this new form. - if (lv_net_type) { - rval = elab_and_eval(des, scope, expr, lv_net_type, need_const); - fallback = false; - } - + typed_elab = true; break; case IVL_VT_REAL: case IVL_VT_STRING: @@ -145,7 +142,14 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, break; } - if (fallback) { + // Special case, PEAssignPattern is context dependend on the type and + // always uses the typed elaboration + if (dynamic_cast(expr)) + typed_elab = true; + + if (lv_net_type && typed_elab) { + rval = elab_and_eval(des, scope, expr, lv_net_type, need_const); + } else { rval = elab_and_eval(des, scope, expr, context_wid, need_const, false, lv_type, force_unsigned); } @@ -229,36 +233,45 @@ unsigned PEAssignPattern::test_width(Design*, NetScope*, width_mode_t&) NetExpr*PEAssignPattern::elaborate_expr(Design*des, NetScope*scope, ivl_type_t ntype, unsigned flags) const { - // Special case: If this is an empty pattern (i.e. '{}) and - // the expected type is a DARRAY or QUEUE, then convert this - // to a null handle. Internally, Icarus Verilog uses this to - // represent nil dynamic arrays. - if (parms_.size() == 0 && (ntype->base_type()==IVL_VT_DARRAY || - ntype->base_type()==IVL_VT_QUEUE)) { - NetENull*tmp = new NetENull; - tmp->set_line(*this); - return tmp; + bool need_const = NEED_CONST & flags; + + if (auto darray_type = dynamic_cast(ntype)) + return elaborate_expr_darray_(des, scope, darray_type, need_const); + + if (auto parray_type = dynamic_cast(ntype)) { + return elaborate_expr_packed_(des, scope, parray_type->base_type(), + parray_type->packed_width(), + parray_type->slice_dimensions(), 0, + need_const); } - if (ntype->base_type()==IVL_VT_DARRAY || - ntype->base_type()==IVL_VT_QUEUE) - return elaborate_expr_darray_(des, scope, ntype, flags); + if (auto vector_type = dynamic_cast(ntype)) { + return elaborate_expr_packed_(des, scope, vector_type->base_type(), + vector_type->packed_width(), + vector_type->slice_dimensions(), 0, + need_const); + } cerr << get_fileline() << ": sorry: I don't know how to elaborate " - << "assignment_pattern expressions yet." << endl; + << "assignment_pattern expressions for " << *ntype << " type yet." << endl; cerr << get_fileline() << ": : Expression is: " << *this << endl; des->errors += 1; return 0; } -NetExpr*PEAssignPattern::elaborate_expr_darray_(Design*des, NetScope*scope, - ivl_type_t ntype, unsigned flags) const +NetExpr* PEAssignPattern::elaborate_expr_darray_(Design *des, NetScope *scope, + const netdarray_t *array_type, + bool need_const) const { - const netdarray_t*array_type = dynamic_cast (ntype); - ivl_assert(*this, array_type); - - bool need_const = NEED_CONST & flags; + // Special case: If this is an empty pattern (i.e. '{}) then convert + // this to a null handle. Internally, Icarus Verilog uses this to + // represent nil dynamic arrays. + if (parms_.empty()) { + NetENull *tmp = new NetENull; + tmp->set_line(*this); + return tmp; + } // This is an array pattern, so run through the elements of // the expression and elaborate each as if they are @@ -276,6 +289,53 @@ NetExpr*PEAssignPattern::elaborate_expr_darray_(Design*des, NetScope*scope, return res; } +NetExpr* PEAssignPattern::elaborate_expr_packed_(Design *des, NetScope *scope, + ivl_variable_type_t base_type, + unsigned int width, + const std::vector &dims, + unsigned int cur_dim, + bool need_const) const +{ + if (dims.size() <= cur_dim) { + cerr << get_fileline() << ": error: scalar type is not a valid" + << " context for assignment pattern." << endl; + des->errors++; + return nullptr; + } + + if (dims[cur_dim].width() != parms_.size()) { + cerr << get_fileline() << ": error: Packed array assignment pattern expects " + << dims[cur_dim].width() << " element(s) in this context.\n" + << get_fileline() << ": : Found " + << parms_.size() << " element(s)." << endl; + des->errors++; + } + + width /= dims[cur_dim].width(); + cur_dim++; + + NetEConcat *concat = new NetEConcat(parms_.size(), 1, base_type); + for (size_t idx = 0; idx < parms_.size(); idx++) { + NetExpr *expr; + // Handle nested assignment patterns as a special case. We do not + // have a good way of passing the inner dimensions through the + // generic elaborate_expr() API and assigment patterns is the only + // place where we need it. + auto ap = dynamic_cast(parms_[idx]); + if (ap) + expr = ap->elaborate_expr_packed_(des, scope, base_type, + width, dims, cur_dim, need_const); + else + expr = elaborate_rval_expr(des, scope, nullptr, + base_type, width, + parms_[idx], need_const); + if (expr) + concat->set(idx, expr); + } + + return concat; +} + NetExpr* PEAssignPattern::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const { cerr << get_fileline() << ": sorry: I do not know how to" diff --git a/net_design.cc b/net_design.cc index a94582901..7a6b5585d 100644 --- a/net_design.cc +++ b/net_design.cc @@ -550,8 +550,16 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) << "use_type = " << use_type << endl; } - NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width, true, - cur->second.is_annotatable, use_type); + NetExpr *expr; + + // Handle assignment patterns as a special case as they need the type to + // be evaluated correctly. + if (param_type && dynamic_cast(val_expr)) { + expr = elab_and_eval(des, val_scope, val_expr, param_type, true); + } else { + expr = elab_and_eval(des, val_scope, val_expr, lv_width, true, + cur->second.is_annotatable, use_type); + } if (! expr) return; diff --git a/netmisc.cc b/netmisc.cc index b2548d377..13b79f14b 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1019,6 +1019,11 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, return 0; } + if (lv_net_type->packed()) + eval_expr(tmp, lv_net_type->packed_width()); + else + eval_expr(tmp, -1); + return tmp; }