From 16646c547cbf94ecb9835080b6ad5fa6d9ceca50 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 24 Dec 2020 18:12:06 -0800 Subject: [PATCH 1/2] 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)); From a286764c1d5947ada8fa38c5f0a3da324f749c95 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 27 Dec 2020 18:53:34 -0800 Subject: [PATCH 2/2] Add support for string parameters Parameters can have string type and do the usual string stuff, and also implement some of the string methods on string parameters so that they evaluate down to constants. --- PExpr.h | 11 +++-- design_dump.cc | 12 +++++ elab_expr.cc | 123 +++++++++++++++++++++++++++++++++++++++++++++++-- net_design.cc | 44 +++++++++++++++++- net_expr.cc | 13 ++++++ netlist.h | 10 ++++ netmisc.cc | 2 +- netscalar.h | 4 ++ 8 files changed, 207 insertions(+), 12 deletions(-) diff --git a/PExpr.h b/PExpr.h index 97aa1ef97..304975050 100644 --- a/PExpr.h +++ b/PExpr.h @@ -935,11 +935,12 @@ class PECallFunction : public PExpr { NetExpr*elaborate_expr_method_(Design*des, NetScope*scope, unsigned expr_wid, bool add_this_flag = false) const; -#if 0 - NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const; - NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope, - unsigned expr_wid) const; -#endif + NetExpr*elaborate_expr_method_net_(Design*des, NetScope*scope, + NetNet*net, unsigned expr_wid) const; + NetExpr*elaborate_expr_method_par_(Design*des, NetScope*scope, + const NetExpr *par, ivl_type_t par_type, + unsigned expr_wid) const; + NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, unsigned expr_wid, diff --git a/design_dump.cc b/design_dump.cc index 6e6c098d0..fbdbda160 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -31,6 +31,7 @@ # include "netclass.h" # include "netdarray.h" # include "netqueue.h" +# include "netscalar.h" # include "netvector.h" # include "ivl_assert.h" # include "PExpr.h" @@ -238,6 +239,17 @@ ostream& netqueue_t::debug_dump(ostream&fd) const return fd; } +ostream& netreal_t::debug_dump(ostream&fd) const +{ + fd << "real"; + return fd; +} +ostream& netstring_t::debug_dump(ostream&fd) const +{ + fd << "string"; + return fd; +} + ostream& netvector_t::debug_dump(ostream&o) const { o << "netvector_t:" << type_ << (signed_? " signed" : " unsigned") << packed_dims_; diff --git a/elab_expr.cc b/elab_expr.cc index b38dcfcb3..8ddd26cb1 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2640,6 +2640,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, use_path.push_front(name_component_t(perm_string::literal(THIS_TOKEN))); } + if (debug_elaborate) { + cerr << get_fileline() << ": " << __func__ << ": " + << "use_path: " << use_path << endl; + cerr << get_fileline() << ": " << __func__ << ": " + << "method_name: " << method_name << endl; + cerr << get_fileline() << ": " << __func__ << ": " + << "expr_wid: " << expr_wid << endl; + } + // If there is no object to the left of the method name, then // give up on the idea of looking for an object method. if (use_path.empty()) return 0; @@ -2651,8 +2660,38 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, symbol_search(this, des, scope, use_path, net, par, eve, par_type); - if (net == 0) - return 0; + if (debug_elaborate) { + if (net) { + cerr << get_fileline() << ": " << __func__ << ": " + << "net: " << net->name() << endl; + } + if (par) { + cerr << get_fileline() << ": " << __func__ << ": " + << "par: " << *par << endl; + } + if (par_type) { + cerr << get_fileline() << ": " << __func__ << ": " + << "par_type: " << *par_type << endl; + } + } + + // If we found a net with a method... + if (net) + return elaborate_expr_method_net_(des, scope, net, expr_wid); + + // If we found a parameter with a method... + if (par) + return elaborate_expr_method_par_(des, scope, par, par_type, expr_wid); + + return 0; +} + +NetExpr* PECallFunction::elaborate_expr_method_net_(Design*des, NetScope*scope, + NetNet*net, unsigned expr_wid) const +{ + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); if (net->data_type() == IVL_VT_STRING) { @@ -2812,6 +2851,70 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, return 0; } +NetExpr* PECallFunction::elaborate_expr_method_par_(Design*, NetScope*scope, + const NetExpr*par, + ivl_type_t par_type, + unsigned expr_wid) const +{ + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + // If the parameter is of type string, then look for the standard string + // method. Return an error if not found. Since we are assured that the + // expression is a constant string, it should be able to calculate the + // result at compile time. + if (dynamic_cast(par_type)) { + + const NetECString*par_string = dynamic_cast(par); + ivl_assert(*par, par_string); + string par_value = par_string->value().as_string(); + + if (method_name == "len") { + NetEConst*use_val = make_const_val(par_value.size()); + use_val->set_line(*this); + return pad_to_width(use_val, expr_wid, *this); + } + + if (method_name == "atoi") { + NetEConst*use_val = make_const_val(atoi(par_value.c_str())); + use_val->set_line(*this); + return pad_to_width(use_val, expr_wid, true, *this); + } + + if (method_name == "atoreal") { + NetECReal*use_val = new NetECReal(verireal(par_value.c_str())); + use_val->set_line(*this); + return use_val; + } + + if (method_name == "atohex") { + NetEConst*use_val = make_const_val(strtoul(par_value.c_str(),0,16)); + use_val->set_line(*this); + return pad_to_width(use_val, expr_wid, true, *this); + } + + // Returning 0 here will cause the caller to print an error + // message and increment the error count, so there is no need to + // increment des->error_count here. + cerr << get_fileline() << ": error: " + << "Unknown or unsupport string method: " << method_name + << endl; + return 0; + } + + // If we haven't figured out what to do with this method by now, + // something went wrong. + cerr << get_fileline() << ": sorry: Don't know how to handle methods of parameters of type:" << endl; + cerr << get_fileline() << ": : " << *par_type << endl; + cerr << get_fileline() << ": : in scope " << scope_path(scope) << endl; + + // Returning 0 here will cause the caller to print an error message and + // increment the error count, so there is no need to increment + // des->error_count here. + return 0; +} + unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&) { ivl_assert(*this, size_); @@ -4821,6 +4924,13 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, { bool need_const = NEED_CONST & flags; + if (debug_elaborate) { + cerr << get_fileline() << ": " << __func__ << ": " + << "Parameter: " << path_ << endl; + cerr << get_fileline() << ": " << __func__ << ": " + << "par_type: " << *par_type << endl; + } + if (need_const && !(ANNOTATABLE & flags)) { perm_string name = peek_tail_name(path_); if (found_in->make_parameter_unannotatable(name)) { @@ -6034,16 +6144,19 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&) return expr_width_; } -NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned)const +NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned) const { - verinum val(value()); - NetEConst*tmp = new NetEConst(val); + NetECString*tmp = new NetECString(value()); tmp->cast_signed(signed_flag_); tmp->set_line(*this); return tmp; } +/* + * When the expression is being elaborated with a width, then we are trying to + * make a vector, so create a NetEConst with the basic types. + */ NetEConst* PEString::elaborate_expr(Design*, NetScope*, unsigned expr_wid, unsigned) const { diff --git a/net_design.cc b/net_design.cc index cbfc55507..cd0efabdb 100644 --- a/net_design.cc +++ b/net_design.cc @@ -789,6 +789,41 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur) } } +/* + * Evaluate a parameter that is forced to type string. This comes to pass when + * the input is something like this: + * + * parameter string foo = ; + * + * The param_type should be netstring_t, the val_expr is the pform of the + * input , and we try to elaborate/evaluate down to a IVL_VT_STRING + * expression. + */ +void NetScope::evaluate_parameter_string_(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(cur->second, val_expr); + ivl_assert(cur->second, param_type); + + NetExpr*expr = elab_and_eval(des, val_scope, val_expr, param_type, true); + if (! expr) + return; + + cur->second.val = expr; + + if (debug_elaborate) { + cerr << cur->second.get_fileline() << ": " << __func__ << ": " + << "Parameter type: " << *param_type << endl; + cerr << cur->second.get_fileline() << ": " << __func__ << ": " + << "Parameter value: " << *val_expr << endl; + cerr << cur->second.get_fileline() << ": " << __func__ << ": " + << "Elaborated value: " << *expr << endl; + } +} + void NetScope::evaluate_parameter_(Design*des, param_ref_t cur) { ivl_type_t param_type = cur->second.ivl_type; @@ -832,12 +867,19 @@ void NetScope::evaluate_parameter_(Design*des, param_ref_t cur) evaluate_parameter_real_(des, cur); break; + case IVL_VT_STRING: + evaluate_parameter_string_(des, cur); + break; + default: cerr << cur->second.get_fileline() << ": internal error: " - << "Unexpected expression type " << use_type + << "Unexpected parameter type " << use_type << "." << endl; cerr << cur->second.get_fileline() << ": : " << "Parameter name: " << cur->first << endl; + if (param_type) + cerr << cur->second.get_fileline() << ": : " + << "Parameter ivl_type: " << *param_type << endl; cerr << cur->second.get_fileline() << ": : " << "Expression is: " << *cur->second.val_expr << endl; ivl_assert(cur->second, 0); diff --git a/net_expr.cc b/net_expr.cc index 804fae96d..2a6a1faee 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -320,6 +320,19 @@ const NetScope* NetECRealParam::scope() const return scope_; } +NetECString::NetECString(const std::string& val) +: NetEConst(verinum(val)) +{ +} + +NetECString::~NetECString() +{ +} + +ivl_variable_type_t NetECString::expr_type() const +{ + return IVL_VT_STRING; +} NetELast::NetELast(NetNet*s) : sig_(s) diff --git a/netlist.h b/netlist.h index 88fdb7a53..ccc33312a 100644 --- a/netlist.h +++ b/netlist.h @@ -1252,6 +1252,7 @@ class NetScope : public Definitions, public Attrib { private: void evaluate_parameter_logic_(Design*des, param_ref_t cur); void evaluate_parameter_real_(Design*des, param_ref_t cur); + void evaluate_parameter_string_(Design*des, param_ref_t cur); void evaluate_parameter_(Design*des, param_ref_t cur); private: @@ -2219,6 +2220,15 @@ class NetECReal : public NetExpr { verireal value_; }; +class NetECString : public NetEConst { + public: + explicit NetECString(const std::string& val); + ~NetECString(); + + // The type of a string is IVL_VT_STRING + ivl_variable_type_t expr_type() const; +}; + class NetECRealParam : public NetECReal { public: diff --git a/netmisc.cc b/netmisc.cc index 4f6ab426d..e4e96119f 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1004,7 +1004,7 @@ 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: " + cerr << pe->get_fileline() << ": " << __func__ << ": " << "pe=" << *pe << ", lv_net_type=" << *lv_net_type << endl; } diff --git a/netscalar.h b/netscalar.h index ad63d404d..ba1ba7975 100644 --- a/netscalar.h +++ b/netscalar.h @@ -29,6 +29,8 @@ class netreal_t : public ivl_type_s { ivl_variable_type_t base_type() const; + std::ostream& debug_dump(std::ostream&) const; + public: static netreal_t type_real; static netreal_t type_shortreal; @@ -42,6 +44,8 @@ class netstring_t : public ivl_type_s { ivl_variable_type_t base_type() const; + std::ostream& debug_dump(std::ostream&) const; + public: static netstring_t type_string; };