From 16646c547cbf94ecb9835080b6ad5fa6d9ceca50 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 24 Dec 2020 18:12:06 -0800 Subject: [PATCH] Rework parsing of parameter types Use the common data_type_or_implicit rules to support type definitions for parameters. This eliminates a bunch of special rules in parse.y, and opens the door for parameters having more complex types. --- PExpr.cc | 5 +- PExpr.h | 19 ++---- PScope.h | 9 +-- design_dump.cc | 10 +-- elab_expr.cc | 115 ++++++++++---------------------- elab_scope.cc | 115 ++++++++++++++++++++++---------- elaborate.cc | 5 +- net_design.cc | 169 +++++++++++++++++++++++++++++++---------------- net_scope.cc | 62 +++++++++-------- netlist.h | 52 +++++++-------- netmisc.cc | 49 ++++++++++++++ netmisc.h | 6 +- nettypes.cc | 1 + nettypes.h | 10 +++ netvector.cc | 12 ++++ netvector.h | 1 + parse.y | 73 ++++---------------- pform.cc | 51 ++------------ pform.h | 8 +-- pform_dump.cc | 54 +++++++++++---- pform_types.h | 15 ++++- symbol_search.cc | 13 ++-- t-dll.cc | 31 ++++----- 23 files changed, 468 insertions(+), 417 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index bbc7b1ff6..004f4c6c0 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -434,11 +434,10 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const { NetNet* net = 0; const NetExpr*par = 0; + ivl_type_t par_type; NetEvent* eve = 0; - const NetExpr*ex1, *ex2; - - scope = symbol_search(this, des, scope, path_, net, par, eve, ex1, ex2); + scope = symbol_search(this, des, scope, path_, net, par, eve, par_type); if (scope) return scope->is_auto(); diff --git a/PExpr.h b/PExpr.h index 344f95fb5..97aa1ef97 100644 --- a/PExpr.h +++ b/PExpr.h @@ -407,10 +407,6 @@ class PEIdent : public PExpr { // flag is set to *false*. bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb, bool&defined) const; NetExpr* calculate_up_do_base_(Design*, NetScope*, bool need_const) const; - bool calculate_param_range_(Design*, NetScope*, - const NetExpr*msb_ex, long&msb, - const NetExpr*lsb_ex, long&lsb, - long length) const; bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const; @@ -450,37 +446,32 @@ class PEIdent : public PExpr { NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, unsigned expr_wid, unsigned flags) const; NetExpr*elaborate_expr_param_bit_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, bool need_const) const; NetExpr*elaborate_expr_param_part_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, unsigned expr_wid) const; NetExpr*elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, bool need_const) const; NetExpr*elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, bool need_const) const; NetExpr*elaborate_expr_net(Design*des, NetScope*scope, diff --git a/PScope.h b/PScope.h index 21f751601..416f195c5 100644 --- a/PScope.h +++ b/PScope.h @@ -98,12 +98,9 @@ class LexicalScope { is elaborated. During parsing, I put the parameters into this map. */ struct param_expr_t : public PNamedItem { - param_expr_t() : type(IVL_VT_NO_TYPE), msb(0), lsb(0), signed_flag(false), expr(0), range(0) { } - // Type information - ivl_variable_type_t type; - PExpr*msb; - PExpr*lsb; - bool signed_flag; + inline param_expr_t() : data_type(0), expr(0), range(0) { } + // Type information. + data_type_t*data_type; // Value expression PExpr*expr; // If there are range constraints, list them here diff --git a/design_dump.cc b/design_dump.cc index c1335fd85..6e6c098d0 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1465,14 +1465,8 @@ void NetScope::dump(ostream&o) const else o << " parameter "; - o << pp->second.type << " "; - - if ((*pp).second.signed_flag) - o << "signed "; - - if ((*pp).second.msb) - o << "[" << *(*pp).second.msb - << ":" << *(*pp).second.lsb << "] "; + if (pp->second.ivl_type) + pp->second.ivl_type->debug_dump(o); o << (*pp).first << " = "; if (pp->second.val) diff --git a/elab_expr.cc b/elab_expr.cc index 9466910a1..b38dcfcb3 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1333,11 +1333,10 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, NetNet *net = 0; const NetExpr *par; + ivl_type_t par_type = 0; NetEvent *eve; - const NetExpr *ex1, *ex2; - symbol_search(this, des, scope, use_path, - net, par, eve, ex1, ex2); + symbol_search(this, des, scope, use_path, net, par, eve, par_type); const netdarray_t*use_darray = 0; @@ -1354,7 +1353,7 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, net = 0; symbol_search(this, des, scope, tmp_path, - net, par, eve, ex1, ex2); + net, par, eve, par_type); if (net && net->class_type()) { if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::test_width_method_: " @@ -2647,11 +2646,10 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, NetNet *net = 0; const NetExpr *par; + ivl_type_t par_type; NetEvent *eve; - const NetExpr *ex1, *ex2; - symbol_search(this, des, scope, use_path, - net, par, eve, ex1, ex2); + symbol_search(this, des, scope, use_path, net, par, eve, par_type); if (net == 0) return 0; @@ -3429,33 +3427,6 @@ NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope, return tmp; } -bool PEIdent::calculate_param_range_(Design*, NetScope*, - const NetExpr*par_msb, long&par_msv, - const NetExpr*par_lsb, long&par_lsv, - long length) const -{ - if (par_msb == 0) { - // If the parameter doesn't have an explicit range, then - // just return range values of [length-1:0]. - ivl_assert(*this, par_lsb == 0); - par_msv = length-1; - par_lsv = 0; - return true; - } - - const NetEConst*tmp = dynamic_cast (par_msb); - ivl_assert(*this, tmp); - - par_msv = tmp->value().as_long(); - - tmp = dynamic_cast (par_lsb); - ivl_assert(*this, tmp); - - par_lsv = tmp->value().as_long(); - - return true; -} - unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&) { if (!gn_system_verilog()) @@ -3475,9 +3446,9 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&) NetNet*net = 0; const NetExpr*par = 0; + ivl_type_t par_type = 0; NetEvent*eve = 0; - const NetExpr*ex1 = 0, *ex2 = 0; - symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2); + symbol_search(this, des, scope, use_path, net, par, eve, par_type); if (net == 0) { if (debug_elaborate) cerr << get_fileline() << ": PEIdent::test_width_method_: " @@ -3521,10 +3492,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) { NetNet* net = 0; const NetExpr*par = 0; + ivl_type_t par_type = 0; NetEvent* eve = 0; - const NetExpr*ex1, *ex2; - NetScope*use_scope = scope; if (package_) { use_scope = des->find_package(package_->pscope_name()); @@ -3536,8 +3506,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) } NetScope*found_in = symbol_search(this, des, use_scope, path_, - net, par, eve, - ex1, ex2); + net, par, eve, par_type); // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the @@ -3713,7 +3682,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) use_path.pop_back(); ivl_assert(*this, net == 0); - symbol_search(this, des, scope, use_path, net, par, eve, ex1, ex2); + symbol_search(this, des, scope, use_path, net, par, eve, par_type); // Check to see if we have a net and if so is it a structure? if (net != 0) { @@ -3775,8 +3744,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, NetNet* net = 0; const NetExpr*par = 0; + ivl_type_t par_type = 0; NetEvent* eve = 0; - const NetExpr*ex1, *ex2; NetScope*use_scope = scope; if (package_) { @@ -3788,9 +3757,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return tmp; } - /* NetScope*found_in = */ symbol_search(this, des, use_scope, path_, - net, par, eve, - ex1, ex2); + symbol_search(this, des, use_scope, path_, net, par, eve, par_type); if (net == 0 && gn_system_verilog() && path_.size() >= 2) { // NOTE: this is assuming the member_path is only one @@ -3802,7 +3769,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, use_path.pop_back(); ivl_assert(*this, net == 0); - symbol_search(this, des, use_scope, use_path, net, par, eve, ex1, ex2); + symbol_search(this, des, use_scope, use_path, net, par, eve, par_type); if (net == 0) { // Nope, no struct/class with member. @@ -4051,10 +4018,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, NetNet* net = 0; const NetExpr*par = 0; + ivl_type_t par_type = 0; NetEvent* eve = 0; - const NetExpr*ex1, *ex2; - if (debug_elaborate) { cerr << get_fileline() << ": PEIdent::elaborate_expr: " << "path_=" << path_ @@ -4112,7 +4078,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, NetScope*found_in = 0; while (net==0 && par==0 && eve==0 && base_path.size()>0) { found_in = symbol_search(this, des, use_scope, base_path, - net, par, eve, ex1, ex2); + net, par, eve, par_type); if (net) break; if (par) break; if (eve) break; @@ -4144,7 +4110,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, } NetExpr*tmp = elaborate_expr_param_(des, scope, par, found_in, - ex1, ex2, expr_wid, flags); + par_type, expr_wid, flags); if (!tmp) return 0; @@ -4463,17 +4429,15 @@ static verinum param_part_select_bits(const verinum&par_val, long wid, NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, bool need_const) const { const NetEConst*par_ex = dynamic_cast (par); ivl_assert(*this, par_ex); long par_msv, par_lsv; - if(! calculate_param_range_(des, scope, par_msb, par_msv, - par_lsb, par_lsv, - par_ex->value().len())) return 0; + if(! calculate_param_range(*this, par_type, par_msv, par_lsv, + par_ex->value().len())) return 0; const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -4559,8 +4523,7 @@ NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope, const NetExpr*par, NetScope*, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, unsigned expr_wid) const { long msv, lsv; @@ -4574,9 +4537,8 @@ NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope, long par_msv, par_lsv; - if (! calculate_param_range_(des, scope, par_msb, par_msv, - par_lsb, par_lsv, - par_ex->value().len())) return 0; + if (! calculate_param_range(*this, par_type, par_msv, par_lsv, + par_ex->value().len())) return 0; if (! parts_defined_flag) { if (warn_ob_select) { @@ -4685,17 +4647,15 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined, NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, bool need_const) const { const NetEConst*par_ex = dynamic_cast (par); ivl_assert(*this, par_ex); long par_msv, par_lsv; - if(! calculate_param_range_(des, scope, par_msb, par_msv, - par_lsb, par_lsv, - par_ex->value().len())) return 0; + if(! calculate_param_range(*this, par_type, par_msv, par_lsv, + par_ex->value().len())) return 0; NetExpr*base = calculate_up_do_base_(des, scope, need_const); if (base == 0) return 0; @@ -4737,8 +4697,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, if (warn_ob_select) { bool defined = true; // Check to see if the parameter has a defined range. - if (par_msb == 0) { - assert(par_lsb == 0); + if (par_type == 0) { defined = false; } // Get the parameter values width. @@ -4769,17 +4728,15 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, bool need_const) const { const NetEConst*par_ex = dynamic_cast (par); ivl_assert(*this, par_ex); long par_msv, par_lsv; - if(! calculate_param_range_(des, scope, par_msb, par_msv, - par_lsb, par_lsv, - par_ex->value().len())) return 0; + if(! calculate_param_range(*this, par_type, par_msv, par_lsv, + par_ex->value().len())) return 0; NetExpr*base = calculate_up_do_base_(des, scope, need_const); if (base == 0) return 0; @@ -4821,8 +4778,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, if (warn_ob_select) { bool defined = true; // Check to see if the parameter has a defined range. - if (par_msb == 0) { - assert(par_lsb == 0); + if (par_type == 0) { defined = false; } // Get the parameter values width. @@ -4860,8 +4816,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, NetScope*scope, const NetExpr*par, NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb, + ivl_type_t par_type, unsigned expr_wid, unsigned flags) const { bool need_const = NEED_CONST & flags; @@ -4894,19 +4849,19 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, if (use_sel == index_component_t::SEL_BIT) return elaborate_expr_param_bit_(des, scope, par, found_in, - par_msb, par_lsb, need_const); + par_type, need_const); if (use_sel == index_component_t::SEL_PART) return elaborate_expr_param_part_(des, scope, par, found_in, - par_msb, par_lsb, expr_wid); + par_type, expr_wid); if (use_sel == index_component_t::SEL_IDX_UP) return elaborate_expr_param_idx_up_(des, scope, par, found_in, - par_msb, par_lsb, need_const); + par_type, need_const); if (use_sel == index_component_t::SEL_IDX_DO) return elaborate_expr_param_idx_do_(des, scope, par, found_in, - par_msb, par_lsb, need_const); + par_type, need_const); NetExpr*tmp = 0; diff --git a/elab_scope.cc b/elab_scope.cc index 9c7613d88..d33f3fedf 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -65,11 +65,26 @@ void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope) typedef map::const_iterator mparm_it_t; -static void collect_parm_item_(Design*des, NetScope*scope, perm_string name, - const LexicalScope::param_expr_t&cur, - bool is_annotatable, - bool local_flag) +static void collect_parm_item(Design*des, NetScope*scope, perm_string name, + const LexicalScope::param_expr_t&cur, + bool is_annotatable, bool local_flag) { + if (debug_scopes) { + cerr << cur.get_fileline() << ": " << __func__ << ": " + << "parameter " << name << " "; + if (cur.data_type) + cerr << *cur.data_type; + else + cerr << "(nil type)"; + ivl_assert(cur, cur.expr); + cerr << " = " << *cur.expr << "; "; + if (cur.range) + cerr << "with ranges "; + else + cerr << "without ranges "; + cerr << "; in scope " << scope_path(scope) << endl; + } + NetScope::range_t*range_list = 0; for (LexicalScope::range_t*range = cur.range ; range ; range = range->next) { NetScope::range_t*tmp = new NetScope::range_t; @@ -104,38 +119,57 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name, range_list = tmp; } + // The type of the parameter, if unspecified in the source, will come + // from the type of the value assigned to it. Therefore, if the type is + // not yet known, don't try to guess here, put the type guess off. Also + // don't try to elaborate it here, because there may be references to + // other parameters still being located during scope elaboration. + scope->set_parameter(name, is_annotatable, cur.expr, cur.data_type, local_flag, range_list, cur); - scope->set_parameter(name, is_annotatable, cur.expr, cur.type, cur.msb, - cur.lsb, cur.signed_flag, local_flag, range_list, cur); } -static void collect_scope_parameters_(Design*des, NetScope*scope, +static void collect_scope_parameters(Design*des, NetScope*scope, const map¶meters) { + if (debug_scopes) { + cerr << scope->get_fileline() << ": " << __func__ << ": " + << "collect parameters for " << scope_path(scope) << "." << endl; + } + for (mparm_it_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur ) { - collect_parm_item_(des, scope, cur->first, *(cur->second), false, false); + collect_parm_item(des, scope, cur->first, *(cur->second), false, false); } } -static void collect_scope_localparams_(Design*des, NetScope*scope, +static void collect_scope_localparams(Design*des, NetScope*scope, const map&localparams) { + if (debug_scopes) { + cerr << scope->get_fileline() << ": " << __func__ << ": " + << "collect localparams for " << scope_path(scope) << "." << endl; + } + for (mparm_it_t cur = localparams.begin() ; cur != localparams.end() ; ++ cur ) { - collect_parm_item_(des, scope, cur->first, *(cur->second), false, true); + collect_parm_item(des, scope, cur->first, *(cur->second), false, true); } } -static void collect_scope_specparams_(Design*des, NetScope*scope, +static void collect_scope_specparams(Design*des, NetScope*scope, const map&specparams) { + if (debug_scopes) { + cerr << scope->get_fileline() << ": " << __func__ << ": " + << "collect specparams for " << scope_path(scope) << "." << endl; + } + for (mparm_it_t cur = specparams.begin() ; cur != specparams.end() ; ++ cur ) { - collect_parm_item_(des, scope, cur->first, *(cur->second), true, false); + collect_parm_item(des, scope, cur->first, *(cur->second), true, false); } } @@ -356,6 +390,13 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, static void elaborate_scope_enumerations(Design*des, NetScope*scope, const set&enum_types) { + if (debug_scopes) { + cerr << scope->get_fileline() << ": " << __func__ << ": " + << "Elaborate " << enum_types.size() << " enumerations" + << " in scope " << scope_path(scope) << "." + << endl; + } + for (set::const_iterator cur = enum_types.begin() ; cur != enum_types.end() ; ++ cur) { enum_type_t*curp = *cur; @@ -564,15 +605,27 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) static void elaborate_scope_classes(Design*des, NetScope*scope, const vector&classes) { + if (debug_scopes) { + cerr << scope->get_fileline() << ": " << __func__ << ": " + << "Elaborate " << classes.size() << " classes" + << " in scope " << scope_path(scope) << "." + << endl; + } + for (size_t idx = 0 ; idx < classes.size() ; idx += 1) { blend_class_constructors(classes[idx]); elaborate_scope_class(des, scope, classes[idx]); } } -static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, - const Module::replace_t&replacements) +static void replace_scope_parameters(NetScope*scope, const LineInfo&loc, + const Module::replace_t&replacements) { + if (debug_scopes) { + cerr << scope->get_fileline() << ": " << __func__ << ": " + << "Replace scope parameters for " << scope_path(scope) << "." << endl; + } + for (Module::replace_t::const_iterator cur = replacements.begin() ; cur != replacements.end() ; ++ cur ) { @@ -712,8 +765,8 @@ bool PPackage::elaborate_scope(Design*des, NetScope*scope) scope->add_typedefs(&typedefs); - collect_scope_parameters_(des, scope, parameters); - collect_scope_localparams_(des, scope, localparams); + collect_scope_parameters(des, scope, parameters); + collect_scope_localparams(des, scope, localparams); if (debug_scopes) { cerr << get_fileline() << ": PPackage::elaborate_scope: " @@ -751,23 +804,17 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // will be evaluated later, once all parameter overrides for this // module have been done. - collect_scope_parameters_(des, scope, parameters); + collect_scope_parameters(des, scope, parameters); - collect_scope_localparams_(des, scope, localparams); + collect_scope_localparams(des, scope, localparams); - collect_scope_specparams_(des, scope, specparams); + collect_scope_specparams(des, scope, specparams); // Run parameter replacements that were collected from the // containing scope and meant for me. - replace_scope_parameters_(scope, *this, replacements); + replace_scope_parameters(scope, *this, replacements); - if (debug_scopes) { - cerr << get_fileline() << ": Module::elaborate_scope: " - << "Elaborate " << enum_sets.size() << " enumerations" - << " in scope " << scope_path(scope) << "." - << endl; - } elaborate_scope_enumerations(des, scope, enum_sets); assert(classes.size() == classes_lexical.size()); @@ -796,7 +843,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // we can not do that until defparams are run, so push it off // into an elaborate work item. if (debug_scopes) - cerr << get_fileline() << ": debug: " + cerr << get_fileline() << ": " << __func__ << ": " << "Schedule generates within " << scope_path(scope) << " for elaboration after defparams." << endl; @@ -1216,7 +1263,7 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) // needed to evaluate the parameter expressions. The expressions // will be evaluated later, once all parameter overrides for this // module have been done. - collect_scope_localparams_(des, scope, localparams); + collect_scope_localparams(des, scope, localparams); // Run through the defparams for this scope and save the result // in a table for later final override. @@ -1564,9 +1611,9 @@ void PFunction::elaborate_scope(Design*des, NetScope*scope) const // Scan the parameters in the function, and store the information // needed to evaluate the parameter expressions. - collect_scope_parameters_(des, scope, parameters); + collect_scope_parameters(des, scope, parameters); - collect_scope_localparams_(des, scope, localparams); + collect_scope_localparams(des, scope, localparams); // Scan through all the named events in this scope. elaborate_scope_events_(des, scope, events); @@ -1584,9 +1631,9 @@ void PTask::elaborate_scope(Design*des, NetScope*scope) const // Scan the parameters in the task, and store the information // needed to evaluate the parameter expressions. - collect_scope_parameters_(des, scope, parameters); + collect_scope_parameters(des, scope, parameters); - collect_scope_localparams_(des, scope, localparams); + collect_scope_localparams(des, scope, localparams); // Scan through all the named events in this scope. elaborate_scope_events_(des, scope, events); @@ -1634,9 +1681,9 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const // Scan the parameters in the scope, and store the information // needed to evaluate the parameter expressions. - collect_scope_parameters_(des, my_scope, parameters); + collect_scope_parameters(des, my_scope, parameters); - collect_scope_localparams_(des, my_scope, localparams); + collect_scope_localparams(des, my_scope, localparams); // Scan through all the named events in this scope. elaborate_scope_events_(des, my_scope, events); diff --git a/elaborate.cc b/elaborate.cc index 4fad62ab3..9cb0b1fcf 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3780,8 +3780,8 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, NetNet *net; const NetExpr *par; + ivl_type_t par_type = 0; NetEvent *eve; - const NetExpr *ex1, *ex2; /* Add the implicit this reference when requested. */ if (add_this_flag) { @@ -3796,8 +3796,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, // resolve to a class object. Note that the "this" symbol // (internally represented as "@") is handled by there being a // "this" object in the instance scope. - symbol_search(this, des, scope, use_path, - net, par, eve, ex1, ex2); + symbol_search(this, des, scope, use_path, net, par, eve, par_type); if (net == 0) return 0; diff --git a/net_design.cc b/net_design.cc index 6dc0bced0..cbfc55507 100644 --- a/net_design.cc +++ b/net_design.cc @@ -29,6 +29,8 @@ */ # include "netlist.h" +# include "netscalar.h" +# include "netvector.h" # include "util.h" # include "compiler.h" # include "netmisc.h" @@ -508,56 +510,71 @@ void Design::evaluate_parameters() void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) { - long msb = 0; - long lsb = 0; - bool range_flag = false; - - /* Evaluate the msb expression, if it is present. */ - PExpr*msb_expr = (*cur).second.msb_expr; - if (msb_expr) { - (*cur).second.msb = elab_and_eval(des, this, msb_expr, -1, true); - if (! eval_as_long(msb, (*cur).second.msb)) { - cerr << (*cur).second.val->get_fileline() - << ": error: Unable to evaluate msb expression " - << "for parameter " << (*cur).first << ": " - << *(*cur).second.msb << endl; - des->errors += 1; - return; - } - - range_flag = true; - } - - /* Evaluate the lsb expression, if it is present. */ - PExpr*lsb_expr = (*cur).second.lsb_expr; - if (lsb_expr) { - (*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -1, true); - if (! eval_as_long(lsb, (*cur).second.lsb)) { - cerr << (*cur).second.val->get_fileline() - << ": error: Unable to evaluate lsb expression " - << "for parameter " << (*cur).first << ": " - << *(*cur).second.lsb << endl; - des->errors += 1; - return; - } - - range_flag = true; - } - /* Evaluate the parameter expression. */ PExpr*val_expr = (*cur).second.val_expr; NetScope*val_scope = (*cur).second.val_scope; + // The param_type may be nil if the parameter has no declared type. In + // this case, we'll try to take our type from the r-value. + ivl_type_t param_type = cur->second.ivl_type; + + // Most parameter declarations are packed vectors, of the form: + // parameter [H:L] foo == bar; + // so get the netvector_t. Note that this may also be the special + // case of a netvector_t with no dimensions, that exists only to carry + // signed-ness, e.g.: + // parameter signed foo = bar; + // (Scalars are handled differently, not by a netvector_t with no + // dimensions.) + const netvector_t* param_vect = dynamic_cast (param_type); + + if (debug_elaborate) { + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "parameter=" << cur->first << endl; + if (param_type) + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "param_type=" << *param_type << endl; + else + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "param_type=(nil)" << endl; + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "val_expr=" << *val_expr << endl; + } + + ivl_variable_type_t use_type; int lv_width = -2; - if (range_flag) - lv_width = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb; + if (param_type) { + use_type = param_type->base_type(); + // Is this a netvector_t with no dimenions? + if (param_vect && param_vect->packed_dims().size()==0) + lv_width = -2; + else if (param_type->packed()) + lv_width = param_type->packed_width(); + } else { + use_type = val_expr->expr_type(); + } + + if (debug_elaborate) { + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "use_type = " << use_type << endl; + } NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width, true, - (*cur).second.is_annotatable, - (*cur).second.type); + cur->second.is_annotatable, use_type); if (! expr) return; + // Make sure to carry the signed-ness from a vector type. + if (param_vect) + expr->cast_signed(param_vect->get_signed()); + + if (debug_elaborate) { + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "expr = " << *expr << endl; + cerr << val_expr->get_fileline() << ": " << __func__ << ": " + << "expr type = " << expr->expr_type() << endl; + } + switch (expr->expr_type()) { case IVL_VT_REAL: if (! dynamic_cast(expr)) { @@ -567,6 +584,13 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) des->errors += 1; return; } + + // If the parameter has no type, then infer its type from the + // r-value expression. + if (param_type==0) { + param_type = &netreal_t::type_real; + cur->second.ivl_type = param_type; + } break; case IVL_VT_LOGIC: @@ -579,17 +603,20 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) return; } - // If the parameter has type or range information, then - // make sure the type is set right. Note that if the - // parameter doesn't have an explicit type or range, - // then it will get the signedness from the expression itself. - if (cur->second.type != IVL_VT_NO_TYPE) { - expr->cast_signed(cur->second.signed_flag); - } else if (cur->second.signed_flag) { - expr->cast_signed(true); + // If the parameter has no type, then infer its type from the + // r-value expression. + if (param_type==0) { + param_type = new netvector_t(expr->expr_type(), expr->expr_width()-1, + 0, expr->has_sign()); + cur->second.ivl_type = param_type; } - if (!range_flag && !expr->has_width()) { + if (param_type->base_type() != IVL_VT_NO_TYPE) + expr->cast_signed(param_type->get_signed()); + + if (!expr->has_width()) { + expr = pad_to_width(expr, integer_width, *expr); + } else if (param_type->slice_dimensions().size()==0 && !expr->has_width()) { expr = pad_to_width(expr, integer_width, *expr); } break; @@ -597,18 +624,25 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) default: cerr << expr->get_fileline() << ": internal error: " - << "Unhandled expression type?" << endl; + << "Unhandled expression type " + << expr->expr_type() << "?" << endl; + cerr << expr->get_fileline() + << ": : " + << "param_type: " << *param_type << endl; des->errors += 1; return; } + // By the time we're done with the above, we should certainly know the + // type of the parameter. + ivl_assert(*expr, cur->second.ivl_type); + cur->second.val = expr; // If there are no value ranges to test the value against, // then we are done. - if ((*cur).second.range == 0) { + if ((*cur).second.range == 0) return; - } NetEConst*val = dynamic_cast((*cur).second.val); ivl_assert(*(*cur).second.val, (*cur).second.val); @@ -671,10 +705,12 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) { PExpr*val_expr = (*cur).second.val_expr; NetScope*val_scope = (*cur).second.val_scope; + ivl_type_t param_type = cur->second.ivl_type; + ivl_assert(*val_expr, param_type); NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1, true, - (*cur).second.is_annotatable, - (*cur).second.type); + cur->second.is_annotatable, + param_type->base_type()); if (! expr) return; @@ -755,18 +791,37 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) void NetScope::evaluate_parameter_(Design*des, param_ref_t cur) { - // If the parameter has already been evaluated, quietly return. + ivl_type_t param_type = cur->second.ivl_type; + + // If the parameter type is present, then elaborate it now. + if (cur->second.val_type) { + param_type = cur->second.val_type->elaborate_type(des, cur->second.val_scope); + cur->second.ivl_type = param_type; + cur->second.val_type = 0; + } + + // If the parameter has already been evaluated, quietly return. if (cur->second.val_expr == 0) return; + // Guess the varaiable type of the parameter. If the parameter has no + // given type, then guess the type from the expression and use that to + // evaluate. + ivl_variable_type_t use_type; + if (param_type) + use_type = param_type->base_type(); + else + use_type = cur->second.val_expr->expr_type(); + if (cur->second.solving) { cerr << cur->second.get_fileline() << ": error: " << "Recursive parameter reference found involving " << cur->first << "." << endl; des->errors += 1; + } else { cur->second.solving = true; - switch (cur->second.type) { + switch (use_type) { case IVL_VT_NO_TYPE: case IVL_VT_BOOL: case IVL_VT_LOGIC: @@ -779,7 +834,7 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur) default: cerr << cur->second.get_fileline() << ": internal error: " - << "Unexpected expression type " << cur->second.type + << "Unexpected expression type " << use_type << "." << endl; cerr << cur->second.get_fileline() << ": : " << "Parameter name: " << cur->first << endl; diff --git a/net_scope.cc b/net_scope.cc index 48c3d7642..a25b16a81 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -198,6 +198,22 @@ void NetScope::set_line(perm_string file, unsigned lineno) def_lineno_ = lineno; } +string NetScope::get_fileline() const +{ + ostringstream buf; + buf << (file_? file_ : "") << ":" << lineno_; + string res = buf.str(); + return res; +} + +string NetScope::get_def_fileline() const +{ + ostringstream buf; + buf << (def_file_? def_file_ : "") << ":" << def_lineno_; + string res = buf.str(); + return res; +} + void NetScope::set_line(perm_string file, perm_string def_file, unsigned lineno, unsigned def_lineno) { @@ -279,27 +295,28 @@ const netenum_t*NetScope::find_enumeration_for_name(const Design*des, perm_strin return cur_scope->enum_names_[name]->enumeration(); } +/* + * Attach to the a parameter name in the scope a value and a type. The value + * (val_expr) is the PExpr form that is not yet elaborated. Later, when + * elaboration happens, the val_expr is elaborated and written to the val + * member. + */ void NetScope::set_parameter(perm_string key, bool is_annotatable, - PExpr*val, ivl_variable_type_t type__, - PExpr*msb, PExpr*lsb, bool signed_flag, + PExpr*val, data_type_t*val_type, bool local_flag, NetScope::range_t*range_list, const LineInfo&file_line) { param_expr_t&ref = parameters[key]; ref.is_annotatable = is_annotatable; - ref.msb_expr = msb; - ref.lsb_expr = lsb; ref.val_expr = val; + ref.val_type = val_type; ref.val_scope = this; - ref.type = type__; - ref.msb = 0; - ref.lsb = 0; - ref.signed_flag = signed_flag; ref.local_flag = local_flag; ivl_assert(file_line, ref.range == 0); ref.range = range_list; ref.val = 0; + ref.ivl_type = 0; ref.set_line(file_line); } @@ -313,14 +330,11 @@ void NetScope::set_parameter(perm_string key, NetExpr*val, { param_expr_t&ref = parameters[key]; ref.is_annotatable = false; - ref.msb_expr = 0; - ref.lsb_expr = 0; ref.val_expr = 0; + ref.val_type = 0; ref.val_scope = this; - ref.type = IVL_VT_BOOL; - ref.msb = 0; - ref.lsb = 0; - ref.signed_flag = false; + ref.ivl_type = netvector_t::integer_type(); + ivl_assert(file_line, ref.ivl_type); ref.val = val; ref.set_line(file_line); } @@ -399,18 +413,14 @@ bool NetScope::make_parameter_unannotatable(perm_string key) * perm_string::literal method to fake the compiler into doing the * compare without actually creating a perm_string. */ -const NetExpr* NetScope::get_parameter(Design*des, - const char* key, - const NetExpr*&msb, - const NetExpr*&lsb) +const NetExpr* NetScope::get_parameter(Design*des, const char* key, + ivl_type_t&ivl_type) { - return get_parameter(des, perm_string::literal(key), msb, lsb); + return get_parameter(des, perm_string::literal(key), ivl_type); } -const NetExpr* NetScope::get_parameter(Design*des, - perm_string key, - const NetExpr*&msb, - const NetExpr*&lsb) +const NetExpr* NetScope::get_parameter(Design*des, perm_string key, + ivl_type_t&ivl_type) { map::iterator idx; @@ -419,13 +429,11 @@ const NetExpr* NetScope::get_parameter(Design*des, if (idx->second.val_expr) evaluate_parameter_(des, idx); - msb = idx->second.msb; - lsb = idx->second.lsb; + ivl_type = idx->second.ivl_type; return idx->second.val; } - msb = 0; - lsb = 0; + ivl_type = 0; const NetExpr*tmp = enumeration_expr(key); return tmp; } diff --git a/netlist.h b/netlist.h index 3c43517e2..88fdb7a53 100644 --- a/netlist.h +++ b/netlist.h @@ -79,6 +79,7 @@ class PExpr; class PFunction; class PPackage; class PTaskFunc; +class data_type_t; struct enum_type_t; class netclass_t; class netdarray_t; @@ -965,22 +966,17 @@ class NetScope : public Definitions, public Attrib { struct range_t; void set_parameter(perm_string name, bool is_annotatable, - PExpr*val, ivl_variable_type_t type, - PExpr*msb, PExpr*lsb, bool signed_flag, + PExpr*val, data_type_t*data_type, bool local_flag, NetScope::range_t*range_list, const LineInfo&file_line); void set_parameter(perm_string name, NetExpr*val, const LineInfo&file_line); - const NetExpr*get_parameter(Design*des, - const char* name, - const NetExpr*&msb, - const NetExpr*&lsb); - const NetExpr*get_parameter(Design*des, - perm_string name, - const NetExpr*&msb, - const NetExpr*&lsb); + const NetExpr*get_parameter(Design*des, const char* name, + ivl_type_t&ivl_type); + const NetExpr*get_parameter(Design*des, perm_string name, + ivl_type_t&ivl_type); /* These are used by defparam elaboration to replace the expression with a new expression, without affecting the @@ -1073,6 +1069,9 @@ class NetScope : public Definitions, public Attrib { unsigned get_lineno() const { return lineno_; }; unsigned get_def_lineno() const { return def_lineno_; }; + std::string get_fileline() const; + std::string get_def_fileline() const; + bool in_func() const; /* Provide a link back to the pform to allow early elaboration of @@ -1210,31 +1209,26 @@ class NetScope : public Definitions, public Attrib { /* After everything is all set up, the code generators like access to these things to make up the parameter lists. */ struct param_expr_t : public LineInfo { - param_expr_t() : msb_expr(0), lsb_expr(0), val_expr(0), val_scope(0), - solving(false), is_annotatable(false), - type(IVL_VT_NO_TYPE), signed_flag(false), - local_flag(false), - msb(0), lsb(0), range(0), val(0) { } - // Source expressions - PExpr*msb_expr; - PExpr*lsb_expr; + param_expr_t() : val_expr(0), val_type(0), val_scope(0), + solving(false), is_annotatable(false), + local_flag(false), + range(0), val(0), ivl_type(0) { } + // Source expression and data type (before elaboration) PExpr*val_expr; - // Scope information + data_type_t*val_type; + // Scope information NetScope*val_scope; - // Evaluation status + // Evaluation status bool solving; - // specparam status + // specparam status bool is_annotatable; - // Type information - ivl_variable_type_t type; - bool signed_flag; - bool local_flag; - NetExpr*msb; - NetExpr*lsb; - // range constraints + // Is this a localparam? + bool local_flag; + // range constraints struct range_t*range; - // Expression value + // Expression value and type (elaborated versoins of val_expr/val_type) NetExpr*val; + ivl_type_t ivl_type; }; mapparameters; diff --git a/netmisc.cc b/netmisc.cc index 78e35a78e..4f6ab426d 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1809,3 +1809,52 @@ void check_for_inconsistent_delays(NetScope*scope) display_ts_dly_warning = false; } } + + +/* + * Calculate the bit vector range for a parameter, from the type of the + * parameter. This is expecting that the type is a vector type. The parameter + * is presumably declared something like this: + * + * parameter [4:1] foo = ; + * + * In this case, the par_type is a netvector with a single dimension. The + * par_msv gets 4, and par_lsv get 1. The caller uses these values to + * interpret things like bit selects. + */ +bool calculate_param_range(const LineInfo&line, ivl_type_t par_type, + long&par_msv, long&par_lsv, long length) +{ + const netvector_t*vector_type = dynamic_cast (par_type); + if (vector_type == 0) { + // If the parameter doesn't have an explicit range, then + // just return range values of [length-1:0]. + par_msv = length-1; + par_lsv = 0; + return true; + } + + ivl_assert(line, vector_type->packed()); + const std::vector& packed_dims = vector_type->packed_dims(); + + // This is a netvector_t with 0 dimensions, then the parameter was + // declared with a statement like this: + // + // parameter signed foo = ; + // + // The netvector_t is just here to carry the signed-ness, which we don't + // even need here. So act like the type is defined by the r-value + // length. + if (packed_dims.size() == 0) { + par_msv = length-1; + par_lsv = 0; + return true; + } + ivl_assert(line, packed_dims.size() == 1); + + netrange_t use_range = packed_dims[0]; + par_msv = use_range.get_msb(); + par_lsv = use_range.get_lsb(); + + return true; +} diff --git a/netmisc.h b/netmisc.h index ec99c0b16..b5f514ed0 100644 --- a/netmisc.h +++ b/netmisc.h @@ -45,7 +45,7 @@ extern NetScope* symbol_search(const LineInfo*li, NetNet*&net, /* net/reg */ const NetExpr*&par,/* parameter/expr */ NetEvent*&eve, /* named event */ - const NetExpr*&ex1, const NetExpr*&ex2); + ivl_type_t&par_type); inline NetScope* symbol_search(const LineInfo*li, Design*des, @@ -55,8 +55,8 @@ inline NetScope* symbol_search(const LineInfo*li, const NetExpr*&par,/* parameter/expr */ NetEvent*&eve /* named event */) { - const NetExpr*ex1, *ex2; - return symbol_search(li, des, start, path, net, par, eve, ex1, ex2); + ivl_type_t par_type; + return symbol_search(li, des, start, path, net, par, eve, par_type); } /* diff --git a/nettypes.cc b/nettypes.cc index 807956b4b..23360fcee 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -160,3 +160,4 @@ bool prefix_to_slice(const std::vector&dims, return true; } + diff --git a/nettypes.h b/nettypes.h index 0741216d1..b2254026a 100644 --- a/nettypes.h +++ b/nettypes.h @@ -27,6 +27,7 @@ # include class netrange_t; +class LineInfo; /* * This is a fully abstract type that is a type that can be attached @@ -135,6 +136,15 @@ extern std::ostream&operator << (std::ostream&out, const std::vector extern unsigned long netrange_width(const std::vector&dims); +/* + * There are a few cases where we need to know about the single-level + * dimensions of a parameter declaration, for example: + * + * parameter [msv:lsv] foo ...; + */ +extern bool calculate_param_range(const LineInfo&line, ivl_type_t par_type, + long&par_msv, long&par_lsv, long length); + /* * Take as input a list of packed dimensions and a list of prefix * indices, and calculate the offset/width of the resulting slice into diff --git a/netvector.cc b/netvector.cc index 8bf39d902..f874635e6 100644 --- a/netvector.cc +++ b/netvector.cc @@ -18,6 +18,7 @@ */ # include "netvector.h" +# include "compiler.h" # include using namespace std; @@ -31,6 +32,17 @@ netvector_t netvector_t::atom2u16 (IVL_VT_BOOL, 15, 0, false); netvector_t netvector_t::atom2s8 (IVL_VT_BOOL, 7, 0, true); netvector_t netvector_t::atom2u8 (IVL_VT_BOOL, 7, 0, false); +static netvector_t* save_integer_type = 0; +const netvector_t* netvector_t::integer_type() +{ + if (save_integer_type) + return save_integer_type; + + save_integer_type = new netvector_t(IVL_VT_LOGIC, integer_width-1, 0, true); + save_integer_type->set_isint(true); + return save_integer_type; +} + //netvector_t netvector_t::scalar_bool (IVL_VT_BOOL); netvector_t netvector_t::scalar_logic (IVL_VT_LOGIC); diff --git a/netvector.h b/netvector.h index 12acfae1f..59b7905c2 100644 --- a/netvector.h +++ b/netvector.h @@ -78,6 +78,7 @@ class netvector_t : public ivl_type_s { static netvector_t atom2u8; static netvector_t scalar_bool; static netvector_t scalar_logic; + static const netvector_t*integer_type(); private: bool test_compatibility(ivl_type_t that) const; diff --git a/parse.y b/parse.y index bf0b93f90..1a21c7878 100644 --- a/parse.y +++ b/parse.y @@ -35,9 +35,8 @@ class PSpecPath; extern void lex_end_table(); -static list* param_active_range = 0; -static bool param_active_signed = false; -static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; +static data_type_t* param_data_type = 0; +static list* specparam_active_range = 0; /* Port declaration lists use this structure for context. */ static struct { @@ -649,7 +648,6 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type net_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt -%type bit_logic bit_logic_opt %type integer_vector_type %type parameter_value_opt @@ -5484,17 +5482,6 @@ net_decl_assigns } ; -bit_logic - : K_logic { $$ = IVL_VT_LOGIC; } - | K_bool { $$ = IVL_VT_BOOL; /* Icarus misc */} - | K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */} - ; - -bit_logic_opt - : bit_logic - | { $$ = IVL_VT_NO_TYPE; } - ; - net_type : K_wire { $$ = NetNet::WIRE; } | K_tri { $$ = NetNet::TRI; } @@ -5514,42 +5501,12 @@ net_type | K_uwire { $$ = NetNet::UNRESOLVED_WIRE; } ; -param_type - : bit_logic_opt unsigned_signed_opt dimensions_opt - { param_active_range = $3; - param_active_signed = $2; - if (($1 == IVL_VT_NO_TYPE) && ($3 != 0)) - param_active_type = IVL_VT_LOGIC; - else - param_active_type = $1; - } - | K_integer signed_unsigned_opt - { param_active_range = make_range_from_width(integer_width); - param_active_signed = $2; - param_active_type = IVL_VT_LOGIC; - } - | K_time unsigned_signed_opt - { param_active_range = make_range_from_width(64); - param_active_signed = $2; - param_active_type = IVL_VT_LOGIC; - } - | real_or_realtime - { param_active_range = 0; - param_active_signed = true; - param_active_type = IVL_VT_REAL; - } - | atom2_type signed_unsigned_opt - { param_active_range = make_range_from_width($1); - param_active_signed = $2; - param_active_type = IVL_VT_BOOL; - } - | TYPE_IDENTIFIER - { pform_set_type_referenced(@1, $1.text); - pform_set_param_from_type(@1, $1.type, $1.text, param_active_range, - param_active_signed, param_active_type); - delete[]$1.text; - } - ; + /* The param_type rule is just the data_type_or_implicit rule wrapped + with an assignment to para_data_type with the figured data type. + This is used by parameter_assign, which is found to the right of + the param_type in various rules. */ + +param_type : data_type_or_implicit { param_data_type = $1; } /* parameter and localparam assignment lists are broken into separate BNF so that I can call slightly different parameter @@ -5569,8 +5526,7 @@ localparam_assign_list parameter_assign : IDENTIFIER '=' expression parameter_value_ranges_opt { PExpr*tmp = $3; - pform_set_parameter(@1, lex_strings.make($1), param_active_type, - param_active_signed, param_active_range, tmp, $4); + pform_set_parameter(@1, lex_strings.make($1), param_data_type, tmp, $4); delete[]$1; } ; @@ -5578,8 +5534,7 @@ parameter_assign localparam_assign : IDENTIFIER '=' expression { PExpr*tmp = $3; - pform_set_localparam(@1, lex_strings.make($1), param_active_type, - param_active_signed, param_active_range, tmp); + pform_set_localparam(@1, lex_strings.make($1), param_data_type, tmp); delete[]$1; } ; @@ -6305,7 +6260,7 @@ specparam : IDENTIFIER '=' expression { PExpr*tmp = $3; pform_set_specparam(@1, lex_strings.make($1), - param_active_range, tmp); + specparam_active_range, tmp); delete[]$1; } | IDENTIFIER '=' expression ':' expression ':' expression @@ -6344,7 +6299,7 @@ specparam min_typ_max_warn -= 1; } pform_set_specparam(@1, lex_strings.make($1), - param_active_range, tmp); + specparam_active_range, tmp); delete[]$1; } | PATHPULSE_IDENTIFIER '=' expression @@ -6366,9 +6321,9 @@ specparam_list specparam_decl : specparam_list | dimensions - { param_active_range = $1; } + { specparam_active_range = $1; } specparam_list - { param_active_range = 0; } + { specparam_active_range = 0; } ; spec_polarity diff --git a/pform.cc b/pform.cc index e6b836280..7de5bd628 100644 --- a/pform.cc +++ b/pform.cc @@ -3168,8 +3168,7 @@ LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, } void pform_set_parameter(const struct vlltype&loc, - perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr, + perm_string name, data_type_t*data_type, PExpr*expr, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; @@ -3190,20 +3189,7 @@ void pform_set_parameter(const struct vlltype&loc, scope->parameters[name] = parm; parm->expr = expr; - - parm->type = type; - if (range) { - assert(range->size() == 1); - pform_range_t&rng = range->front(); - assert(rng.first); - assert(rng.second); - parm->msb = rng.first; - parm->lsb = rng.second; - } else { - parm->msb = 0; - parm->lsb = 0; - } - parm->signed_flag = signed_flag; + parm->data_type = data_type; parm->range = value_range; // Only a Module keeps the position of the parameter. @@ -3212,8 +3198,7 @@ void pform_set_parameter(const struct vlltype&loc, } void pform_set_localparam(const struct vlltype&loc, - perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr) + perm_string name, data_type_t*data_type, PExpr*expr) { LexicalScope*scope = lexical_scope; if (is_compilation_unit(scope) && !gn_system_verilog()) { @@ -3229,20 +3214,7 @@ void pform_set_localparam(const struct vlltype&loc, scope->localparams[name] = parm; parm->expr = expr; - - parm->type = type; - if (range) { - assert(range->size() == 1); - pform_range_t&rng = range->front(); - assert(rng.first); - assert(rng.second); - parm->msb = rng.first; - parm->lsb = rng.second; - } else { - parm->msb = 0; - parm->lsb = 0; - } - parm->signed_flag = signed_flag; + parm->data_type = data_type; parm->range = 0; } @@ -3261,22 +3233,13 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name, pform_cur_module.front()->specparams[name] = parm; parm->expr = expr; + parm->range = 0; if (range) { assert(range->size() == 1); - pform_range_t&rng = range->front(); - assert(rng.first); - assert(rng.second); - parm->type = IVL_VT_LOGIC; - parm->msb = rng.first; - parm->lsb = rng.second; - } else { - parm->type = IVL_VT_NO_TYPE; - parm->msb = 0; - parm->lsb = 0; + parm->data_type = new vector_type_t(IVL_VT_LOGIC, false, range); + parm->range = 0; } - parm->signed_flag = false; - parm->range = 0; } void pform_set_defparam(const pform_name_t&name, PExpr*expr) diff --git a/pform.h b/pform.h index b58b3b148..070f23829 100644 --- a/pform.h +++ b/pform.h @@ -418,15 +418,11 @@ extern LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, extern void pform_set_parameter(const struct vlltype&loc, perm_string name, - ivl_variable_type_t type, - bool signed_flag, - list*range, + data_type_t*data_type, PExpr*expr, LexicalScope::range_t*value_range); extern void pform_set_localparam(const struct vlltype&loc, perm_string name, - ivl_variable_type_t type, - bool signed_flag, - list*range, + data_type_t*data_type, PExpr*expr); extern void pform_set_specparam(const struct vlltype&loc, perm_string name, diff --git a/pform_dump.cc b/pform_dump.cc index 5b70b99d0..dec209fd7 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -165,6 +165,12 @@ void data_type_t::pform_dump(ostream&out, unsigned indent) const out << setw(indent) << "" << typeid(*this).name() << endl; } +ostream& data_type_t::debug_dump(ostream&out) const +{ + out << typeid(*this).name(); + return out; +} + void void_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "void" << endl; @@ -213,6 +219,25 @@ void vector_type_t::pform_dump(ostream&fd, unsigned indent) const fd << endl; } +ostream& vector_type_t::debug_dump(ostream&fd) const +{ + if (signed_flag) + fd << "signed "; + if (pdims==nullptr) { + fd << "/* vector_type_t nil */"; + return fd; + } + + for (list::iterator cur = pdims->begin() + ; cur != pdims->end() ; ++cur) { + fd << "["; + if (cur->first) fd << *(cur->first); + if (cur->second) fd << ":" << *(cur->second); + fd << "]"; + } + return fd; +} + void class_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << name; @@ -1389,14 +1414,12 @@ void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const typedef map::const_iterator parm_iter_t; for (parm_iter_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur ) { - out << setw(indent) << "" << "parameter " - << (*cur).second->type << " "; - if ((*cur).second->signed_flag) - out << "signed "; - if ((*cur).second->msb) - out << "[" << *(*cur).second->msb << ":" - << *(*cur).second->lsb << "] "; - out << (*cur).first << " = "; + out << setw(indent) << "" << "parameter "; + if (cur->second->data_type) + cur->second->data_type->debug_dump(out); + else + out << "(nil type)"; + out << " " << (*cur).first << " = "; if ((*cur).second->expr) out << *(*cur).second->expr; else @@ -1439,9 +1462,10 @@ void LexicalScope::dump_localparams_(ostream&out, unsigned indent) const for (parm_iter_t cur = localparams.begin() ; cur != localparams.end() ; ++ cur ) { out << setw(indent) << "" << "localparam "; - if ((*cur).second->msb) - out << "[" << *(*cur).second->msb << ":" - << *(*cur).second->lsb << "] "; + if (cur->second->data_type) { + cur->second->data_type->debug_dump(out); + out << " "; + } out << (*cur).first << " = "; if ((*cur).second->expr) out << *(*cur).second->expr << ";" << endl; @@ -1544,9 +1568,11 @@ void Module::dump_specparams_(ostream&out, unsigned indent) const for (parm_iter_t cur = specparams.begin() ; cur != specparams.end() ; ++ cur ) { out << setw(indent) << "" << "specparam "; - if ((*cur).second->msb) - out << "[" << *(*cur).second->msb << ":" - << *(*cur).second->lsb << "] "; + if (cur->second->data_type) + cur->second->data_type->debug_dump(out); + else + out << "(nil type)"; + out << (*cur).first << " = "; if ((*cur).second->expr) out << *(*cur).second->expr << ";" << endl; diff --git a/pform_types.h b/pform_types.h index d78847d55..d2f807ec2 100644 --- a/pform_types.h +++ b/pform_types.h @@ -141,11 +141,14 @@ class data_type_t : public PNamedItem { public: inline explicit data_type_t() { } virtual ~data_type_t() = 0; - // This method is used to figure out the base type of a packed - // compound object. Return IVL_VT_NO_TYPE if the type is not packed. + // This method is used to figure out the base type of a packed + // compound object. Return IVL_VT_NO_TYPE if the type is not packed. virtual ivl_variable_type_t figure_packed_base_type(void)const; - // This method is used by the pform dumper to diagnostic dump. + // This method is used by the pform dumper to diagnostic dump. The + // pform_dump dumps type type in pform format, and the debug_dump + // prints the output in a linear form. virtual void pform_dump(std::ostream&out, unsigned indent) const; + virtual std::ostream& debug_dump(std::ostream&out) const; ivl_type_s* elaborate_type(Design*des, NetScope*scope); @@ -237,6 +240,7 @@ struct vector_type_t : public data_type_t { : base_type(bt), signed_flag(sf), reg_flag(false), integer_flag(false), implicit_flag(false), pdims(pd) { } virtual ivl_variable_type_t figure_packed_base_type(void)const; virtual void pform_dump(std::ostream&out, unsigned indent) const; + virtual std::ostream& debug_dump(std::ostream&out) const; ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; ivl_variable_type_t base_type; @@ -389,6 +393,11 @@ inline perm_string peek_tail_name(const pform_name_t&that) # define SUPER_TOKEN "#" # define THIS_TOKEN "@" +static inline std::ostream& operator<< (std::ostream&out, const data_type_t&that) +{ + return that.debug_dump(out); +} + extern std::ostream& operator<< (std::ostream&out, const pform_name_t&); extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); diff --git a/symbol_search.cc b/symbol_search.cc index 013a0064c..fce0bf666 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -31,8 +31,7 @@ struct symbol_search_results { scope = 0; net = 0; par_val = 0; - par_msb = 0; - par_lsb = 0; + par_type = 0; eve = 0; } @@ -52,8 +51,7 @@ struct symbol_search_results { // If this was a parameter, the value expression and the // optional value dimensions. const NetExpr*par_val; - const NetExpr*par_msb; - const NetExpr*par_lsb; + ivl_type_t par_type; // If this is a named event, ... NetEvent*eve; }; @@ -129,7 +127,7 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, return true; } - if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_msb, res->par_lsb)) { + if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_type)) { res->scope = scope; res->par_val = par; return true; @@ -191,14 +189,13 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, NetNet*&net, const NetExpr*&par, NetEvent*&eve, - const NetExpr*&ex1, const NetExpr*&ex2) + ivl_type_t&par_type) { symbol_search_results recurse; bool flag = symbol_search(li, des, scope, path, &recurse); net = recurse.net; par = recurse.par_val; - ex1 = recurse.par_msb; - ex2 = recurse.par_lsb; + par_type = recurse.par_type; eve = recurse.eve; if (! flag) { return 0; diff --git a/t-dll.cc b/t-dll.cc index 779fcb9a5..c28d07509 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -506,26 +506,19 @@ void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net) ivl_parameter_t cur_par = &scop->param[idx]; cur_par->basename = cur_pit->first; cur_par->local = cur_pit->second.local_flag; - /* Either both the MSB and LSB expressions are provided or - * neither are provided. */ - if (cur_pit->second.msb) { - assert(cur_pit->second.lsb); - /* The MSB and LSB expressions must be integral constants. */ - const NetEConst *msbc = - dynamic_cast(cur_pit->second.msb); - const NetEConst *lsbc = - dynamic_cast(cur_pit->second.lsb); - assert(msbc); - assert(lsbc); - cur_par->msb = msbc->value().as_long(); - cur_par->lsb = lsbc->value().as_long(); - } else { - assert(! cur_pit->second.lsb); - cur_par->msb = cur_pit->second.val->expr_width() - 1; - assert(cur_par->msb >= 0); - cur_par->lsb = 0; + calculate_param_range(cur_pit->second, + cur_pit->second.ivl_type, + cur_par->msb, cur_par->lsb, + cur_pit->second.val->expr_width()); + + if (cur_pit->second.ivl_type == 0) { + cerr << "?:?: internal error: " + << "No type for parameter " << cur_pit->first + << " in scope " << net->fullname() << "?" << endl; } - cur_par->signed_flag = cur_pit->second.signed_flag; + assert(cur_pit->second.ivl_type); + + cur_par->signed_flag = cur_pit->second.ivl_type->get_signed(); cur_par->scope = scop; FILE_NAME(cur_par, &(cur_pit->second));