From 18c338ad096468bfa89c5e12708f12e938c8499a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 29 Sep 2013 14:48:42 -0700 Subject: [PATCH] Handle array assignment patters through pform. This gets us to elaboration. In the process also fix up ivl_type_t type comparisons to do deep type comparison. --- PExpr.cc | 19 ++++++++++++ PExpr.h | 20 +++++++++++++ elab_expr.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++------- elaborate.cc | 30 ++++++++++++++----- netdarray.cc | 10 +++++++ netdarray.h | 1 + netmisc.cc | 20 +++++++++++++ netmisc.h | 15 ++++++++++ nettypes.cc | 13 +++++++++ nettypes.h | 22 ++++++++++++++ netvector.cc | 20 +++++++++++++ netvector.h | 3 ++ parse.y | 7 ++--- pform_dump.cc | 13 +++++++++ 14 files changed, 251 insertions(+), 22 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index 09e9e73e5..75792cded 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -94,6 +94,25 @@ const char* PExpr::width_mode_name(width_mode_t mode) } } +PEAssignPattern::PEAssignPattern() +{ +} + +PEAssignPattern::PEAssignPattern(const list&p) +: parms_(p.size()) +{ + size_t idx = 0; + for (list::const_iterator cur = p.begin() + ; cur != p.end() ; ++cur) { + parms_[idx] = *cur; + idx += 1; + } +} + +PEAssignPattern::~PEAssignPattern() +{ +} + PEBinary::PEBinary(char op, PExpr*l, PExpr*r) : op_(op), left_(l), right_(r) { diff --git a/PExpr.h b/PExpr.h index 40a75a9ed..fff5e4208 100644 --- a/PExpr.h +++ b/PExpr.h @@ -194,6 +194,26 @@ class PExpr : public LineInfo { ostream& operator << (ostream&, const PExpr&); +class PEAssignPattern : public PExpr { + public: + explicit PEAssignPattern(); + explicit PEAssignPattern(const std::list&p); + ~PEAssignPattern(); + + void dump(std::ostream&) const; + + virtual unsigned test_width(Design*des, NetScope*scope, width_mode_t&mode); + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + unsigned expr_wid, + unsigned flags) const; + + private: + std::vectorparms_; +}; + class PEConcat : public PExpr { public: diff --git a/elab_expr.cc b/elab_expr.cc index 915634179..1acb668dd 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -86,15 +86,34 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd) return 0; } -NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, +NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type, ivl_variable_type_t lv_type, unsigned lv_width, PExpr*expr, bool need_const) { + if (debug_elaborate) { + cerr << expr->get_fileline() << ": elaborate_rval_expr: " + << "expr=" << *expr; + if (lv_net_type) + cerr << ", lv_net_type=" << *lv_net_type; + else + cerr << ", lv_net_type="; + + cerr << ", lv_type=" << lv_type + << ", lv_width=" << lv_width + << endl; + } + int context_wid = -1; switch (lv_type) { + case IVL_VT_DARRAY: + // 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) + return elab_and_eval(des, scope, expr, lv_net_type, need_const); + break; case IVL_VT_REAL: case IVL_VT_STRING: - case IVL_VT_DARRAY: break; case IVL_VT_BOOL: case IVL_VT_LOGIC: @@ -163,6 +182,42 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const return 0; } +/* + * For now, assuse that assignment patterns are for dynamic + * objects. This is not really true as this expression type, fully + * supported, can assign to packed arrays and structs, unpacked arrays + * and dynamic arrays. + */ +unsigned PEAssignPattern::test_width(Design*des, NetScope*scope, width_mode_t&mode) +{ + expr_type_ = IVL_VT_DARRAY; + expr_width_ = 1; + min_width_ = 1; + signed_flag_= false; + return 1; +} + +NetExpr*PEAssignPattern::elaborate_expr(Design*des, NetScope*scope, + ivl_type_t ntype, unsigned flags) const +{ + cerr << get_fileline() << ": sorry: I don't know how to elaborate " + << "assignment_pattern expressions yet." << endl; + cerr << get_fileline() << ": : Expression is: " << *this + << endl; + des->errors += 1; + return 0; +} + +NetExpr* PEAssignPattern::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const +{ + cerr << get_fileline() << ": sorry: I do not know how to" + << " elaborate assignment patterns using old method." << endl; + cerr << get_fileline() << ": : Expression is: " << *this + << endl; + des->errors += 1; + ivl_assert(*this, 0); + return 0; +} unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode) { @@ -1524,7 +1579,8 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, // Process the method argument if it is available. NetExpr* count = 0; if (args != 0 && parg) { - count = elaborate_rval_expr(des, scope, IVL_VT_BOOL, 32, parg); + count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, + IVL_VT_BOOL, 32, parg); if (count == 0) { cerr << li->get_fileline() << ": error: unable to elaborate " "enumeration method argument " << use_path << "." @@ -1978,7 +2034,7 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::elaborate_base_: " << "Expecting " << parms_count - << " for function " << scope_path(dscope) << "." << endl; + << " argument for function " << scope_path(dscope) << "." << endl; } /* Elaborate the input expressions for the function. This is @@ -2061,6 +2117,7 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, PExpr*tmp = parms_[idx]; if (tmp) { parms[pidx] = elaborate_rval_expr(des, scope, + def->port(pidx)->net_type(), def->port(pidx)->data_type(), (unsigned)def->port(pidx)->vector_width(), tmp, need_const); @@ -2153,12 +2210,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, ivl_assert(*this, parms_.size() == 2); NetExpr*tmp; - tmp = elaborate_rval_expr(des, scope, IVL_VT_BOOL, - 32, parms_[0], false); + tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, + IVL_VT_BOOL, 32, parms_[0], false); sys_expr->parm(1, tmp); - tmp = elaborate_rval_expr(des, scope, IVL_VT_BOOL, - 32, parms_[1], false); + tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, + IVL_VT_BOOL, 32, parms_[1], false); sys_expr->parm(2, tmp); return sys_expr; @@ -2902,7 +2959,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return 0; } - if (net->net_type() != ntype) { + if (! ntype->type_compatible(net->net_type())) { cerr << get_fileline() << ": internal_error: " << "net type doesn't match context type." << endl; @@ -2920,7 +2977,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, ntype->debug_dump(cerr); cerr << endl; } - ivl_assert(*this, net->net_type() == ntype); + ivl_assert(*this, ntype->type_compatible(net->net_type())); NetESignal*tmp = new NetESignal(net); tmp->set_line(*this); @@ -4619,7 +4676,8 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, // While there are default arguments, check them. if (idx <= parms_.size() && parms_[idx-1]) { PExpr*tmp = parms_[idx-1]; - parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->data_type(), + parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->net_type(), + def->port(idx)->data_type(), def->port(idx)->vector_width(), tmp, false); if (parms[idx] == 0) diff --git a/elaborate.cc b/elaborate.cc index c90ca3421..4657d1e60 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -84,7 +84,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const << " width=" << lval->vector_width() << endl; } - NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->data_type(), + NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(), + lval->data_type(), lval->vector_width(), pin(1)); if (rval_expr == 0) { @@ -2249,7 +2250,11 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, { ivl_assert(*this, rval_); - NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval(), + // Don't have a good value for the lv_net_type argument to + // elaborate_rval_expr, so punt and pass nil. In the future we + // should look into fixing calls to this method to pass a + // net_type instead of the separate lv_width/lv_type values. + NetExpr*rv = elaborate_rval_expr(des, scope, 0, lv_type, lv_width, rval(), is_constant_); if (!is_constant_ || !rv) return rv; @@ -3463,7 +3468,8 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope, NetExpr*rv = 0; if (parms_idxnet_type(), + lv_type, wid, parms_ [parms_idx]); if (NetEEvent*evt = dynamic_cast (rv)) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -3617,7 +3623,11 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const unsigned lwid = count_lval_width(lval); ivl_variable_type_t ltype = lval->expr_type(); - NetExpr*rexp = elaborate_rval_expr(des, scope, ltype, lwid, expr_); + // Need to figure out a better thing to do about the + // lv_net_type argument to elaborate_rval_expr here. This + // would entail getting the NetAssign_ to give us an + // ivl_type_t as needed. + NetExpr*rexp = elaborate_rval_expr(des, scope, 0, ltype, lwid, expr_); if (rexp == 0) return 0; @@ -4295,7 +4305,11 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const unsigned lwid = count_lval_width(lval); ivl_variable_type_t ltype = lval->expr_type(); - NetExpr*rexp = elaborate_rval_expr(des, scope, ltype, lwid, expr_); + // Like a variety of other assigns, we need to figure out a + // better way to get a reasonable lv_net_type value, and that + // probably will involve NetAssign_ having a method for + // synthesizing one as needed. + NetExpr*rexp = elaborate_rval_expr(des, scope, 0, ltype, lwid, expr_); if (rexp == 0) return 0; @@ -4351,7 +4365,8 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const /* Make the r-value of the initial assignment, and size it properly. Then use it to build the assignment statement. */ - etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(), + etmp = elaborate_rval_expr(des, scope, sig->net_type(), + lv->expr_type(), lv->lwidth(), expr1_); if (debug_elaborate) { @@ -4566,7 +4581,8 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const unsigned long wid = res->vector_width(); NetAssign_*lv = new NetAssign_(res); - NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_); + NetExpr*val = elaborate_rval_expr(des, scope, res->net_type(), + lv_type, wid, expr_); NetBlock*proc = new NetBlock(NetBlock::SEQU, 0); proc->set_line( *this ); diff --git a/netdarray.cc b/netdarray.cc index b1845831a..f5cb1710b 100644 --- a/netdarray.cc +++ b/netdarray.cc @@ -18,6 +18,7 @@ */ # include "netdarray.h" +# include using namespace std; @@ -34,3 +35,12 @@ ivl_variable_type_t netdarray_t::base_type(void) const { return IVL_VT_DARRAY; } + +bool netdarray_t::test_compatibility(ivl_type_t that) const +{ + const netdarray_t*that_da = dynamic_cast(that); + if (that_da == 0) + return false; + + return element_type()->type_compatible(that_da->element_type()); +} diff --git a/netdarray.h b/netdarray.h index 8068896dd..509e32d73 100644 --- a/netdarray.h +++ b/netdarray.h @@ -45,6 +45,7 @@ class netdarray_t : public netarray_t { std::ostream& debug_dump(std::ostream&) const; private: + bool test_compatibility(ivl_type_t that) const; }; #endif diff --git a/netmisc.cc b/netmisc.cc index 6d4ccda27..61c7344da 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -809,6 +809,26 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, return tmp; } +NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, + ivl_type_t lv_net_type, bool need_const) +{ + if (debug_elaborate) { + cerr << pe->get_fileline() << ": elab_and_eval: " + << "pe=" << *pe + << ", lv_net_type=" << *lv_net_type << endl; + } + + // Elaborate the expression using the more general + // elaborate_expr method. + unsigned flags = PExpr::NO_FLAGS; + if (need_const) + flags |= PExpr::NEED_CONST; + + NetExpr*tmp = pe->elaborate_expr(des, scope, lv_net_type, flags); + + return tmp; +} + NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name, unsigned arg_idx, PExpr*pe, bool need_const) { diff --git a/netmisc.h b/netmisc.h index 2335952ae..90d73cb9c 100644 --- a/netmisc.h +++ b/netmisc.h @@ -244,6 +244,15 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope, bool annotatable =false, ivl_variable_type_t cast_type =IVL_VT_NO_TYPE); +/* + * This form of elab_and_eval uses the ivl_type_t to carry type + * information instead of the piecemeal form. We should transition to + * this form as we reasonably can. + */ +extern NetExpr* elab_and_eval(Design*des, NetScope*scope, + PExpr*expr, ivl_type_t lv_net_type, + bool need_const); + /* * This function is a variant of elab_and_eval that elaborates and * evaluates the arguments of a system task. @@ -256,8 +265,14 @@ extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, * of an assignment, The lv_type and lv_width are the type and width * of the l-value, and the expr is the expression to elaborate. The * result is the NetExpr elaborated and evaluated. (See elab_expr.cc) + * + * I would rather that all calls to elaborate_rval_expr use the + * lv_net_type argument to express the l-value type, but, for now, + * that it not possible. Those cases will be indicated by the + * lv_net_type being set to nil. */ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, + ivl_type_t lv_net_type, ivl_variable_type_t lv_type, unsigned lv_width, PExpr*expr, bool need_const =false); diff --git a/nettypes.cc b/nettypes.cc index 301f28603..c6e924f9b 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -46,6 +46,19 @@ bool ivl_type_s::get_signed() const return false; } +bool ivl_type_s::type_compatible(ivl_type_t that) const +{ + if (this == that) + return true; + + return test_compatibility(that); +} + +bool ivl_type_s::test_compatibility(const ivl_type_s*that) const +{ + return false; +} + netarray_t::~netarray_t() { } diff --git a/nettypes.h b/nettypes.h index 4f6db4199..2d122dcbb 100644 --- a/nettypes.h +++ b/nettypes.h @@ -44,7 +44,17 @@ class ivl_type_s { virtual ivl_variable_type_t base_type() const; virtual bool get_signed() const; + // Return true if "that" type is compatible with this + // type. Compatibile means the types are essentially the same. + bool type_compatible(ivl_type_t that) const; + virtual std::ostream& debug_dump(std::ostream&) const; + + private: + // The "type_compatibile" method uses this virtual method to + // invoke type-specific tests of compatibility. This should + // only be called by the type_compatible method above. + virtual bool test_compatibility(ivl_type_t that) const; }; /* @@ -100,6 +110,18 @@ class netrange_t { inline long get_msb() const { assert(defined()); return msb_; } inline long get_lsb() const { assert(defined()); return lsb_; } + inline bool operator == (const netrange_t&that) const + { if (msb_ != that.msb_) return false; + if (lsb_ != that.lsb_) return false; + return true; + } + + inline bool operator != (const netrange_t&that) const + { if (msb_ != that.msb_) return true; + if (lsb_ != that.lsb_) return true; + return false; + } + private: long msb_; long lsb_; diff --git a/netvector.cc b/netvector.cc index aa5f26231..bc829b729 100644 --- a/netvector.cc +++ b/netvector.cc @@ -18,6 +18,7 @@ */ # include "netvector.h" +# include using namespace std; @@ -62,3 +63,22 @@ vector netvector_t::slice_dimensions() const { return packed_dims_; } + +bool netvector_t::test_compatibility(ivl_type_t that) const +{ + const netvector_t*that_st = dynamic_cast(that); + if (that_st == 0) + return false; + + if (type_ != that_st->type_) + return false; + if (packed_dims_.size() != that_st->packed_dims_.size()) + return false; + + for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1) { + if (packed_dims_[idx] != that_st->packed_dims_[idx]) + return false; + } + + return true; +} diff --git a/netvector.h b/netvector.h index 0d5dd60f1..ead370cd6 100644 --- a/netvector.h +++ b/netvector.h @@ -78,6 +78,9 @@ class netvector_t : public ivl_type_s { static netvector_t scalar_bool; static netvector_t scalar_logic; + private: + bool test_compatibility(ivl_type_t that) const; + private: std::vector packed_dims_; ivl_variable_type_t type_; diff --git a/parse.y b/parse.y index 773752440..1e2313725 100644 --- a/parse.y +++ b/parse.y @@ -669,15 +669,14 @@ source_text : description_list | ; assignment_pattern /* IEEE1800-2005: A.6.7.1 */ : K_LP expression_list_proper '}' - { PEVoid*tmp = new PEVoid; + { PEAssignPattern*tmp = new PEAssignPattern(*$2); FILE_NAME(tmp, @1); - yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + delete $2; $$ = tmp; } | K_LP '}' - { PEVoid*tmp = new PEVoid; + { PEAssignPattern*tmp = new PEAssignPattern; FILE_NAME(tmp, @1); - yyerror(@1, "sorry: Assignment patterns (empty array literals) not supported."); $$ = tmp; } ; diff --git a/pform_dump.cc b/pform_dump.cc index d0426e136..55f5db8bd 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -230,6 +230,19 @@ void PExpr::dump(ostream&out) const out << typeid(*this).name(); } +void PEAssignPattern::dump(ostream&out) const +{ + out << "'{"; + if (parms_.size() > 0) { + parms_[0]->dump(out); + for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) { + out << ", "; + parms_[idx]->dump(out); + } + } + out << "}"; +} + void PEConcat::dump(ostream&out) const { if (repeat_)