From 8b3f0d63b40c5affdec404db7f025416f669a4b1 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 18 Feb 2024 15:46:56 +0000 Subject: [PATCH 01/12] Record the lexical order of identifiers whilst scanning the source files. This is needed for detecting use before declaration. The lexical scanner is the only place where we process the source text in strict lexical order, so do it there. As Verilog allows modules to span multiple source files, don't reset the counter when we reset the lexor. --- lexor.lex | 7 ++++++- parse.y | 2 ++ parse_misc.h | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lexor.lex b/lexor.lex index f94c68f5f..4e93cb87b 100644 --- a/lexor.lex +++ b/lexor.lex @@ -26,6 +26,7 @@ //# define YYSTYPE lexval +# include # include # include # include "compiler.h" @@ -40,7 +41,7 @@ using namespace std; -# define YY_USER_INIT reset_lexor(); +# define YY_USER_INIT do { reset_lexor(); yylloc.lexical_pos = 0; } while (0); # define yylval VLlval # define YY_NO_INPUT @@ -338,6 +339,8 @@ TU [munpf] int rc = lexor_keyword_code(yytext, yyleng); switch (rc) { case IDENTIFIER: + assert(yylloc.lexical_pos != UINT_MAX); + yylloc.lexical_pos += 1; yylval.text = strdupnew(yytext); if (strncmp(yylval.text,"PATHPULSE$", 10) == 0) rc = PATHPULSE_IDENTIFIER; @@ -429,6 +432,8 @@ TU [munpf] \\[^ \t\b\f\r\n]+ { + assert(yylloc.lexical_pos != UINT_MAX); + yylloc.lexical_pos += 1; yylval.text = strdupnew(yytext+1); if (gn_system_verilog()) { if (PPackage*pkg = pform_test_package_identifier(yylval.text)) { diff --git a/parse.y b/parse.y index 61ea8aa81..9d06fa16e 100644 --- a/parse.y +++ b/parse.y @@ -115,12 +115,14 @@ static std::list*attributes_in_context = 0; (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + (Current).lexical_pos = YYRHSLOC (Rhs, 1).lexical_pos; \ (Current).text = YYRHSLOC (Rhs, 1).text; \ } else { \ (Current).first_line = YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = YYRHSLOC (Rhs, 0).last_column; \ (Current).last_line = YYRHSLOC (Rhs, 0).last_line; \ (Current).last_column = YYRHSLOC (Rhs, 0).last_column; \ + (Current).lexical_pos = YYRHSLOC (Rhs, 0).lexical_pos; \ (Current).text = YYRHSLOC (Rhs, 0).text; \ } \ } while (0) diff --git a/parse_misc.h b/parse_misc.h index 86e86314b..23547e85c 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -1,7 +1,7 @@ #ifndef IVL_parse_misc_H #define IVL_parse_misc_H /* - * Copyright (c) 1998-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -34,6 +34,7 @@ struct vlltype { int first_column; int last_line; int last_column; + unsigned lexical_pos; const char*text; std::string get_fileline() const; }; From 079108f32b1d257a02120a9d0bc0426cdbf5884e Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 18 Feb 2024 16:08:24 +0000 Subject: [PATCH 02/12] Add lexical position information to PEIdent objects. --- PExpr.cc | 14 +++++++------- PExpr.h | 9 ++++++--- elaborate.cc | 3 ++- parse.y | 21 +++++++++++---------- pform.cc | 12 ++++++------ pform_analog.cc | 8 ++++---- pform_package.cc | 4 ++-- pform_pclass.cc | 4 ++-- 8 files changed, 40 insertions(+), 35 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index 73679a4b1..ac1eb66d1 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2021 Stephen Williams + * Copyright (c) 1998-2024 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -360,19 +360,19 @@ const verireal& PEFNumber::value() const return *value_; } -PEIdent::PEIdent(const pform_name_t&that) -: path_(that), no_implicit_sig_(false) +PEIdent::PEIdent(const pform_name_t&that, unsigned lexical_pos) +: path_(that), lexical_pos_(lexical_pos), no_implicit_sig_(false) { } -PEIdent::PEIdent(perm_string s, bool no_implicit_sig) -: no_implicit_sig_(no_implicit_sig) +PEIdent::PEIdent(perm_string s, unsigned lexical_pos, bool no_implicit_sig) +: lexical_pos_(lexical_pos), no_implicit_sig_(no_implicit_sig) { path_.name.push_back(name_component_t(s)); } -PEIdent::PEIdent(PPackage*pkg, const pform_name_t&that) -: path_(pkg, that), no_implicit_sig_(true) +PEIdent::PEIdent(PPackage*pkg, const pform_name_t&that, unsigned lexical_pos) +: path_(pkg, that), lexical_pos_(lexical_pos), no_implicit_sig_(true) { } diff --git a/PExpr.h b/PExpr.h index 991ad395a..ba494ada3 100644 --- a/PExpr.h +++ b/PExpr.h @@ -336,9 +336,9 @@ class PEFNumber : public PExpr { class PEIdent : public PExpr { public: - explicit PEIdent(perm_string, bool no_implicit_sig=false); - explicit PEIdent(PPackage*pkg, const pform_name_t&name); - explicit PEIdent(const pform_name_t&); + explicit PEIdent(perm_string, unsigned lexical_pos, bool no_implicit_sig=false); + explicit PEIdent(PPackage*pkg, const pform_name_t&name, unsigned lexical_pos); + explicit PEIdent(const pform_name_t&, unsigned lexical_pos); ~PEIdent(); // Add another name to the string of hierarchy that is the @@ -386,8 +386,11 @@ class PEIdent : public PExpr { const pform_scoped_name_t& path() const { return path_; } + unsigned lexical_pos() const { return lexical_pos_; } + private: pform_scoped_name_t path_; + unsigned lexical_pos_; bool no_implicit_sig_; private: diff --git a/elaborate.cc b/elaborate.cc index 6e4cc99a0..928032db6 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -29,6 +29,7 @@ # include # include +# include # include # include # include @@ -1272,7 +1273,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const symbol_search_results sr; symbol_search(this, des, scope, path_, &sr); if (sr.net != 0) { - pins[j] = new PEIdent(rmod->ports[j]->name, true); + pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); pins[j]->set_lineno(get_lineno()); pins[j]->set_file(get_file()); } diff --git a/parse.y b/parse.y index 9d06fa16e..791797fb1 100644 --- a/parse.y +++ b/parse.y @@ -22,6 +22,7 @@ # include "config.h" +# include # include # include "parse_misc.h" # include "compiler.h" @@ -1084,7 +1085,7 @@ class_new /* IEEE1800-2005 A.2.4 */ $$ = new_expr; } | K_new hierarchy_identifier - { PEIdent*tmpi = new PEIdent(*$2); + { PEIdent*tmpi = new PEIdent(*$2, @2.lexical_pos); FILE_NAME(tmpi, @2); PENewCopy*tmp = new PENewCopy(tmpi); FILE_NAME(tmp, @1); @@ -3167,7 +3168,7 @@ delay_value_simple } } | IDENTIFIER - { PEIdent*tmp = new PEIdent(lex_strings.make($1)); + { PEIdent*tmp = new PEIdent(lex_strings.make($1), @1.lexical_pos); FILE_NAME(tmp, @1); $$ = tmp; delete[]$1; @@ -3963,13 +3964,13 @@ expr_primary $$ = tmp; } | K_this - { PEIdent*tmp = new PEIdent(perm_string::literal(THIS_TOKEN)); + { PEIdent*tmp = new PEIdent(perm_string::literal(THIS_TOKEN), UINT_MAX); FILE_NAME(tmp,@1); $$ = tmp; } | class_hierarchy_identifier - { PEIdent*tmp = new PEIdent(*$1); + { PEIdent*tmp = new PEIdent(*$1, @1.lexical_pos); FILE_NAME(tmp, @1); delete $1; $$ = tmp; @@ -4633,7 +4634,7 @@ lpvalue } | class_hierarchy_identifier - { PEIdent*tmp = new PEIdent(*$1); + { PEIdent*tmp = new PEIdent(*$1, @1.lexical_pos); FILE_NAME(tmp, @1); $$ = tmp; delete $1; @@ -5729,7 +5730,7 @@ port_name named_pexpr_t*tmp = new named_pexpr_t; FILE_NAME(tmp, @$); tmp->name = lex_strings.make($3); - tmp->parm = new PEIdent(lex_strings.make($3), true); + tmp->parm = new PEIdent(lex_strings.make($3), @3.lexical_pos, true); FILE_NAME(tmp->parm, @3); delete[]$3; delete $1; @@ -5814,7 +5815,7 @@ port_reference pform_name_t pname; pname.push_back(ntmp); - PEIdent*wtmp = new PEIdent(pname); + PEIdent*wtmp = new PEIdent(pname, @1.lexical_pos); FILE_NAME(wtmp, @1); Module::port_t*ptmp = new Module::port_t; @@ -5837,7 +5838,7 @@ port_reference pform_name_t pname; pname.push_back(ntmp); - PEIdent*tmp = new PEIdent(pname); + PEIdent*tmp = new PEIdent(pname, @1.lexical_pos); FILE_NAME(tmp, @1); Module::port_t*ptmp = new Module::port_t; @@ -5850,7 +5851,7 @@ port_reference | IDENTIFIER '[' error ']' { yyerror(@1, "error: Invalid port bit select"); Module::port_t*ptmp = new Module::port_t; - PEIdent*wtmp = new PEIdent(lex_strings.make($1)); + PEIdent*wtmp = new PEIdent(lex_strings.make($1), @1.lexical_pos); FILE_NAME(wtmp, @1); ptmp->name = lex_strings.make($1); ptmp->expr.push_back(wtmp); @@ -7168,7 +7169,7 @@ udp_sequ_entry udp_initial : K_initial IDENTIFIER '=' number ';' { PExpr*etmp = new PENumber($4); - PEIdent*itmp = new PEIdent(lex_strings.make($2)); + PEIdent*itmp = new PEIdent(lex_strings.make($2), @2.lexical_pos); PAssign*atmp = new PAssign(itmp, etmp); FILE_NAME(atmp, @2); delete[]$2; diff --git a/pform.cc b/pform.cc index fb8b73534..f19bbceb0 100644 --- a/pform.cc +++ b/pform.cc @@ -708,7 +708,7 @@ PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) if (gn_system_verilog()) check_potential_imports(loc, name.front().name, false); - return new PEIdent(name); + return new PEIdent(name, loc.lexical_pos); } PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, @@ -1376,7 +1376,7 @@ Module::port_t* pform_module_port_reference(const struct vlltype&loc, perm_string name) { Module::port_t*ptmp = new Module::port_t; - PEIdent*tmp = new PEIdent(name); + PEIdent*tmp = new PEIdent(name, loc.lexical_pos); FILE_NAME(tmp, loc); ptmp->name = name; ptmp->expr.push_back(tmp); @@ -2486,7 +2486,7 @@ void pform_make_var_init(const struct vlltype&li, return; } - PEIdent*lval = new PEIdent(name); + PEIdent*lval = new PEIdent(name, li.lexical_pos); FILE_NAME(lval, li); PAssign*ass = new PAssign(lval, expr, !gn_system_verilog(), true); FILE_NAME(ass, li); @@ -2666,7 +2666,7 @@ void pform_makewire(const struct vlltype&li, if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { pform_make_var_init(li, first->name, expr); } else { - PEIdent*lval = new PEIdent(first->name); + PEIdent*lval = new PEIdent(first->name, li.lexical_pos); FILE_NAME(lval, li); PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); FILE_NAME(ass, li); @@ -2797,7 +2797,7 @@ PExpr* pform_genvar_inc_dec(const struct vlltype&loc, const char*name, bool inc_ { pform_requires_sv(loc, "Increment/decrement operator"); - PExpr*lval = new PEIdent(lex_strings.make(name)); + PExpr*lval = new PEIdent(lex_strings.make(name), loc.lexical_pos); PExpr*rval = new PENumber(new verinum(1)); FILE_NAME(lval, loc); FILE_NAME(rval, loc); @@ -2813,7 +2813,7 @@ PExpr* pform_genvar_compressed(const struct vlltype &loc, const char *name, { pform_requires_sv(loc, "Compressed assignment operator"); - PExpr *lval = new PEIdent(lex_strings.make(name)); + PExpr *lval = new PEIdent(lex_strings.make(name), loc.lexical_pos); FILE_NAME(lval, loc); PExpr *expr; diff --git a/pform_analog.cc b/pform_analog.cc index eb96cce61..b5058d655 100644 --- a/pform_analog.cc +++ b/pform_analog.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -47,10 +47,10 @@ PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*n1, char*n2) { vector parms (2); - parms[0].parm = new PEIdent(lex_strings.make(n1)); + parms[0].parm = new PEIdent(lex_strings.make(n1), loc.lexical_pos); FILE_NAME(parms[0].parm, loc); - parms[1].parm = new PEIdent(lex_strings.make(n2)); + parms[1].parm = new PEIdent(lex_strings.make(n2), loc.lexical_pos); FILE_NAME(parms[1].parm, loc); PECallFunction*res = new PECallFunction(lex_strings.make(name), parms); @@ -62,7 +62,7 @@ PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*branch_name) { vector parms (1); - parms[0].parm = new PEIdent(lex_strings.make(branch_name)); + parms[0].parm = new PEIdent(lex_strings.make(branch_name), loc.lexical_pos); FILE_NAME(parms[0].parm, loc); PECallFunction*res = new PECallFunction(lex_strings.make(name), parms); diff --git a/pform_package.cc b/pform_package.cc index 002bb359f..ea602c5cc 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2024 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -232,7 +232,7 @@ PExpr* pform_package_ident(const struct vlltype&loc, PPackage*pkg, pform_name_t*ident_name) { ivl_assert(loc, ident_name); - PEIdent*tmp = new PEIdent(pkg, *ident_name); + PEIdent*tmp = new PEIdent(pkg, *ident_name, loc.lexical_pos); FILE_NAME(tmp, loc); return tmp; } diff --git a/pform_pclass.cc b/pform_pclass.cc index b438f4cde..fc3c19709 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -91,7 +91,7 @@ void pform_class_property(const struct vlltype&loc, FILE_NAME(&pform_cur_class->type->properties[curp->name], loc); if (PExpr*rval = curp->expr.release()) { - PExpr*lval = new PEIdent(curp->name); + PExpr*lval = new PEIdent(curp->name, loc.lexical_pos); FILE_NAME(lval, loc); PAssign*tmp = new PAssign(lval, rval); FILE_NAME(tmp, loc); From bb80ee6905bc982093b19440afd948d941bc4684 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 18 Feb 2024 16:22:50 +0000 Subject: [PATCH 03/12] Add lexical position information to PWire and PEvent objects. --- PEvent.cc | 6 +++--- PEvent.h | 7 +++++-- PExpr.cc | 2 +- PWire.cc | 5 +++-- PWire.h | 6 +++++- parse.y | 6 +++--- pform.cc | 10 +++++----- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/PEvent.cc b/PEvent.cc index 9bf56ea5b..ed6fce388 100644 --- a/PEvent.cc +++ b/PEvent.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -21,8 +21,8 @@ # include "PEvent.h" -PEvent::PEvent(perm_string n) -: name_(n) +PEvent::PEvent(perm_string n, unsigned lexical_pos) +: name_(n), lexical_pos_(lexical_pos) { } diff --git a/PEvent.h b/PEvent.h index ba5bb668b..3b648f757 100644 --- a/PEvent.h +++ b/PEvent.h @@ -1,7 +1,7 @@ #ifndef IVL_PEvent_H #define IVL_PEvent_H /* - * Copyright (c) 2000-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -36,17 +36,20 @@ class PEvent : public PNamedItem { public: // The name is a perm-allocated string. It is the simple name // of the event, without any scope. - explicit PEvent(perm_string name); + explicit PEvent(perm_string name, unsigned lexical_pos); ~PEvent(); perm_string name() const; + unsigned lexical_pos() const { return lexical_pos_; } + void elaborate_scope(Design*des, NetScope*scope) const; SymbolType symbol_type() const; private: perm_string name_; + unsigned lexical_pos_; private: // not implemented PEvent(const PEvent&); diff --git a/PExpr.cc b/PExpr.cc index ac1eb66d1..db9667877 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -426,7 +426,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) ss = ss->parent_scope(); } - PWire*net = new PWire(name, type, NetNet::NOT_A_PORT); + PWire*net = new PWire(name, lexical_pos_, type, NetNet::NOT_A_PORT); net->set_file(get_file()); net->set_lineno(get_lineno()); scope->wires[name] = net; diff --git a/PWire.cc b/PWire.cc index c4bc817f2..817c1d1b5 100644 --- a/PWire.cc +++ b/PWire.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,10 +25,11 @@ using namespace std; PWire::PWire(perm_string n, + unsigned lp, NetNet::Type t, NetNet::PortType pt, PWSRType rt) -: name_(n), type_(t), port_type_(pt), signed_(false), +: name_(n), lexical_pos_(lp), type_(t), port_type_(pt), signed_(false), port_set_(false), net_set_(false), is_scalar_(false), error_cnt_(0), discipline_(0) { diff --git a/PWire.h b/PWire.h index f9178d11c..4ab66d430 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ #ifndef IVL_PWire_H #define IVL_PWire_H /* - * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -55,6 +55,7 @@ class PWire : public PNamedItem { public: PWire(perm_string name, + unsigned lexical_pos, NetNet::Type t, NetNet::PortType pt, PWSRType rt = SR_NET); @@ -62,6 +63,8 @@ class PWire : public PNamedItem { // Return a hierarchical name. perm_string basename() const; + unsigned lexical_pos() const { return lexical_pos_; } + NetNet::Type get_wire_type() const; bool set_wire_type(NetNet::Type); @@ -99,6 +102,7 @@ class PWire : public PNamedItem { private: perm_string name_; + unsigned lexical_pos_; NetNet::Type type_; NetNet::PortType port_type_; bool signed_; diff --git a/parse.y b/parse.y index 791797fb1..47a356098 100644 --- a/parse.y +++ b/parse.y @@ -7249,7 +7249,7 @@ udp_port_decl { $$ = pform_make_udp_input_ports($2); } | K_output IDENTIFIER ';' { perm_string pname = lex_strings.make($2); - PWire*pp = new PWire(pname, NetNet::IMPLICIT, NetNet::POUTPUT); + PWire*pp = new PWire(pname, @2.lexical_pos, NetNet::IMPLICIT, NetNet::POUTPUT); vector*tmp = new std::vector(1); (*tmp)[0] = pp; $$ = tmp; @@ -7257,7 +7257,7 @@ udp_port_decl } | K_reg IDENTIFIER ';' { perm_string pname = lex_strings.make($2); - PWire*pp = new PWire(pname, NetNet::REG, NetNet::PIMPLICIT); + PWire*pp = new PWire(pname, @2.lexical_pos, NetNet::REG, NetNet::PIMPLICIT); vector*tmp = new std::vector(1); (*tmp)[0] = pp; $$ = tmp; @@ -7265,7 +7265,7 @@ udp_port_decl } | K_output K_reg IDENTIFIER ';' { perm_string pname = lex_strings.make($3); - PWire*pp = new PWire(pname, NetNet::REG, NetNet::POUTPUT); + PWire*pp = new PWire(pname, @3.lexical_pos, NetNet::REG, NetNet::POUTPUT); vector*tmp = new std::vector(1); (*tmp)[0] = pp; $$ = tmp; diff --git a/pform.cc b/pform.cc index f19bbceb0..0311ad731 100644 --- a/pform.cc +++ b/pform.cc @@ -2056,7 +2056,7 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, std::vector pins(parms->size() + 1); /* Make the PWire for the output port. */ - pins[0] = new PWire(out_name, + pins[0] = new PWire(out_name, loc.lexical_pos, synchronous_flag? NetNet::REG : NetNet::WIRE, NetNet::POUTPUT); FILE_NAME(pins[0], loc); @@ -2068,7 +2068,7 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, ; cur != parms->end() ; idx += 1, ++ cur) { ivl_assert(loc, idx < pins.size()); - pins[idx] = new PWire(*cur, NetNet::WIRE, + pins[idx] = new PWire(*cur, loc.lexical_pos, NetNet::WIRE, NetNet::PINPUT); FILE_NAME(pins[idx], loc); } @@ -2153,7 +2153,7 @@ static void pform_set_net_range(PWire *wire, */ static void pform_make_event(const struct vlltype&loc, perm_string name) { - PEvent*event = new PEvent(name); + PEvent*event = new PEvent(name, loc.lexical_pos); FILE_NAME(event, loc); add_local_symbol(lexical_scope, name, event); @@ -2547,7 +2547,7 @@ static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name, // to the scope. Do not delete the old wire - it will // remain in the local symbol map. - cur = new PWire(name, type, ptype, rt); + cur = new PWire(name, li.lexical_pos, type, ptype, rt); FILE_NAME(cur, li); pform_put_wire_in_scope(name, cur); @@ -3243,7 +3243,7 @@ vector* pform_make_udp_input_ports(list*names) for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - PWire*pp = new PWire(txt, + PWire*pp = new PWire(txt, /* FIXME */ 0, NetNet::IMPLICIT, NetNet::PINPUT); (*out)[idx] = pp; From 4159a6a6b165357a5d0213c09740f51c63fc6424 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 18 Feb 2024 16:47:10 +0000 Subject: [PATCH 04/12] Pass on lexical position information to NetNet and NetEvent objects. --- elab_scope.cc | 3 ++- elab_sig.cc | 1 + netlist.cc | 4 ++-- netlist.h | 8 ++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index c5e26c596..aa97a9027 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2024 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -1553,6 +1553,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s void PEvent::elaborate_scope(Design*, NetScope*scope) const { NetEvent*ev = new NetEvent(name_); + ev->lexical_pos(lexical_pos_); ev->set_line(*this); scope->add_event(ev); } diff --git a/elab_sig.cc b/elab_sig.cc index 34692f1c1..65c2899f7 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1209,6 +1209,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (wtype == NetNet::WIRE) sig->devirtualize_pins(); sig->set_line(*this); sig->port_type(port_type_); + sig->lexical_pos(lexical_pos_); if (ivl_discipline_t dis = get_discipline()) { sig->set_discipline(dis); diff --git a/netlist.cc b/netlist.cc index 0ad54660f..80a2fd096 100644 --- a/netlist.cc +++ b/netlist.cc @@ -557,7 +557,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, const netranges_t&unpacked, ivl_type_t use_net_type) : NetObj(s, n, calculate_count(unpacked)), type_(t), port_type_(NOT_A_PORT), coerced_to_uwire_(false), - local_flag_(false), net_type_(use_net_type), + local_flag_(false), lexical_pos_(0), net_type_(use_net_type), discipline_(0), unpacked_dims_(unpacked), eref_count_(0), lref_count_(0) { @@ -580,7 +580,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, NetNet::NetNet(NetScope*s, perm_string n, Type t, ivl_type_t type) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), coerced_to_uwire_(false), - local_flag_(false), net_type_(type), + local_flag_(false), lexical_pos_(0), net_type_(type), discipline_(0), eref_count_(0), lref_count_(0) { diff --git a/netlist.h b/netlist.h index 68a408899..79e158baa 100644 --- a/netlist.h +++ b/netlist.h @@ -695,6 +695,9 @@ class NetNet : public NetObj, public PortType { PortType port_type() const; void port_type(PortType t); + unsigned lexical_pos() const { return lexical_pos_; } + void lexical_pos(unsigned lp) { lexical_pos_ = lp; } + // If this net net is a port (i.e. a *sub*port net of a module port) // its port index is number of the module it connects through int get_module_port_index() const; // -1 Not connected to port... @@ -819,6 +822,7 @@ class NetNet : public NetObj, public PortType { PortType port_type_ : 3; bool coerced_to_uwire_: 1; bool local_flag_: 1; + unsigned lexical_pos_; ivl_type_t net_type_; netuarray_t *array_type_ = nullptr; ivl_discipline_t discipline_; @@ -3421,6 +3425,9 @@ class NetEvent : public LineInfo { perm_string name() const; + unsigned lexical_pos() const { return lexical_pos_; } + void lexical_pos(unsigned lp) { lexical_pos_ = lp; } + bool local_flag() const { return local_flag_; } void local_flag(bool f) { local_flag_ = f; } @@ -3455,6 +3462,7 @@ class NetEvent : public LineInfo { private: perm_string name_; + unsigned lexical_pos_; bool local_flag_; // The NetScope class uses these to list the events. From e22831553da7b7eca60ccc642007ebbfec1c7376 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 18 Feb 2024 22:34:48 +0000 Subject: [PATCH 05/12] Improve identifier lexical position accuracy in declarations. Enhance the lists of identifiers and declaration assignments generated by the parser to associate each identifier with its lexical_pos. Also do this for single items in complex parser rules where the location passed to the pform is not the location of the identifier. --- elab_type.cc | 4 +- parse.y | 92 ++++++++++++++++++++----------------------- pform.cc | 94 +++++++++++++++++++++----------------------- pform.h | 22 ++++++----- pform_disciplines.cc | 8 ++-- pform_dump.cc | 4 +- pform_pclass.cc | 8 ++-- pform_types.h | 12 ++++-- 8 files changed, 121 insertions(+), 123 deletions(-) diff --git a/elab_type.cc b/elab_type.cc index 7ae224836..9048e3afc 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -250,7 +250,7 @@ ivl_type_t struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const } netstruct_t::member_t memb; - memb.name = namep->name; + memb.name = namep->name.first; memb.net_type = elaborate_array_type(des, scope, *this, mem_vec, namep->index); res->append_member(des, memb); diff --git a/parse.y b/parse.y index 47a356098..9128f29e5 100644 --- a/parse.y +++ b/parse.y @@ -135,32 +135,39 @@ static std::list*attributes_in_context = 0; static const struct str_pair_t pull_strength = { IVL_DR_PULL, IVL_DR_PULL }; static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG }; -static std::list* make_port_list(char*id, std::list*udims, PExpr*expr) +static std::list* make_port_list(char*id, unsigned idn, + std::list*udims, + PExpr*expr) { std::list*tmp = new std::list; - tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr)); + pform_ident_t tmp_name = { lex_strings.make(id), idn }; + tmp->push_back(pform_port_t(tmp_name, udims, expr)); delete[]id; return tmp; } static std::list* make_port_list(list*tmp, - char*id, std::list*udims, PExpr*expr) + char*id, unsigned idn, + std::list*udims, + PExpr*expr) { - tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr)); + pform_ident_t tmp_name = { lex_strings.make(id), idn }; + tmp->push_back(pform_port_t(tmp_name, udims, expr)); delete[]id; return tmp; } -static std::list* list_from_identifier(char*id) +static std::list* list_from_identifier(char*id, unsigned idn) { - std::list*tmp = new std::list; - tmp->push_back(lex_strings.make(id)); + std::list*tmp = new std::list; + tmp->push_back({ lex_strings.make(id), idn }); delete[]id; return tmp; } -static std::list* list_from_identifier(list*tmp, char*id) +static std::list* list_from_identifier(list*tmp, + char*id, unsigned idn) { - tmp->push_back(lex_strings.make(id)); + tmp->push_back({ lex_strings.make(id), idn }); delete[]id; return tmp; } @@ -376,10 +383,10 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, PExpr *default_value, std::list *attributes) { - perm_string name = lex_strings.make(id); + pform_ident_t name = { lex_strings.make(id), loc.lexical_pos }; delete[] id; - Module::port_t *port = pform_module_port_reference(loc, name); + Module::port_t *port = pform_module_port_reference(loc, name.first); switch (port_type) { case NetNet::PINOUT: @@ -442,6 +449,8 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, char*text; std::list*perm_strings; + std::list*identifiers; + std::list*port_list; std::vector* tf_ports; @@ -655,10 +664,10 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym %type udp_input_list udp_sequ_entry udp_comb_entry -%type udp_input_declaration_list +%type udp_input_declaration_list %type udp_entry_list udp_comb_entry_list udp_sequ_entry_list %type udp_body -%type udp_port_list +%type udp_port_list %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt @@ -668,8 +677,9 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, %type event_variable label_opt class_declaration_endlabel_opt %type block_identifier_opt %type identifier_name -%type event_variable_list -%type list_of_identifiers loop_variables +%type event_variable_list +%type list_of_identifiers +%type loop_variables %type list_of_port_identifiers list_of_variable_port_identifiers %type net_decl_assigns @@ -1773,7 +1783,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ listassign_list; decl_assignment_t*tmp_assign = new decl_assignment_t; - tmp_assign->name = lex_strings.make($5); + tmp_assign->name = { lex_strings.make($5), @5.lexical_pos }; assign_list.push_back(tmp_assign); pform_make_var(@5, &assign_list, $4); } @@ -1916,7 +1926,7 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ } decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); + tmp->name = { lex_strings.make($1), @1.lexical_pos }; if ($2) { tmp->index = *$2; delete $2; @@ -2500,7 +2510,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ NetNet::PortType use_port_type = $1; if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($3 == 0))) use_port_type = port_declaration_context.port_type; - list* port_list = make_port_list($4, $5, 0); + list* port_list = make_port_list($4, @4.lexical_pos, $5, 0); if (use_port_type == NetNet::PIMPLICIT) { yyerror(@1, "error: Missing task/function port direction."); @@ -4486,23 +4496,23 @@ hierarchy_identifier non-hierarchical names separated by ',' characters. */ list_of_identifiers : IDENTIFIER - { $$ = list_from_identifier($1); } + { $$ = list_from_identifier($1, @1.lexical_pos); } | list_of_identifiers ',' IDENTIFIER - { $$ = list_from_identifier($1, $3); } + { $$ = list_from_identifier($1, $3, @3.lexical_pos); } ; list_of_port_identifiers : IDENTIFIER dimensions_opt - { $$ = make_port_list($1, $2, 0); } + { $$ = make_port_list($1, @1.lexical_pos, $2, 0); } | list_of_port_identifiers ',' IDENTIFIER dimensions_opt - { $$ = make_port_list($1, $3, $4, 0); } + { $$ = make_port_list($1, $3, @3.lexical_pos, $4, 0); } ; list_of_variable_port_identifiers : IDENTIFIER dimensions_opt initializer_opt - { $$ = make_port_list($1, $2, $3); } + { $$ = make_port_list($1, @1.lexical_pos, $2, $3); } | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt initializer_opt - { $$ = make_port_list($1, $3, $4, $5); } + { $$ = make_port_list($1, $3, @3.lexical_pos, $4, $5); } ; @@ -5421,7 +5431,7 @@ generate_block net_decl_assign : IDENTIFIER '=' expression { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); + tmp->name = { lex_strings.make($1), @1.lexical_pos }; tmp->expr.reset($3); delete[]$1; $$ = tmp; @@ -5894,7 +5904,7 @@ dimensions net_variable : IDENTIFIER dimensions_opt - { perm_string name = lex_strings.make($1); + { pform_ident_t name = { lex_strings.make($1), @1.lexical_pos }; $$ = pform_makewire(@1, name, NetNet::IMPLICIT, $2); delete [] $1; } @@ -5924,9 +5934,9 @@ event_variable event_variable_list : event_variable - { $$ = list_from_identifier($1); } + { $$ = list_from_identifier($1, @1.lexical_pos); } | event_variable_list ',' event_variable - { $$ = list_from_identifier($1, $3); } + { $$ = list_from_identifier($1, $3, @3.lexical_pos); } ; specify_item @@ -7289,17 +7299,9 @@ udp_port_decls udp_port_list : IDENTIFIER - { std::list*tmp = new std::list; - tmp->push_back(lex_strings.make($1)); - delete[]$1; - $$ = tmp; - } + { $$ = list_from_identifier($1, @1.lexical_pos); } | udp_port_list ',' IDENTIFIER - { std::list*tmp = $1; - tmp->push_back(lex_strings.make($3)); - delete[]$3; - $$ = tmp; - } + { $$ = list_from_identifier($1, $3, @3.lexical_pos); } ; udp_reg_opt @@ -7308,17 +7310,9 @@ udp_reg_opt udp_input_declaration_list : K_input IDENTIFIER - { std::list*tmp = new std::list; - tmp->push_back(lex_strings.make($2)); - $$ = tmp; - delete[]$2; - } + { $$ = list_from_identifier($2, @2.lexical_pos); } | udp_input_declaration_list ',' K_input IDENTIFIER - { std::list*tmp = $1; - tmp->push_back(lex_strings.make($4)); - $$ = tmp; - delete[]$4; - } + { $$ = list_from_identifier($1, $4, @4.lexical_pos); } ; udp_primitive @@ -7346,7 +7340,7 @@ udp_primitive udp_body K_endprimitive label_opt { perm_string tmp2 = lex_strings.make($2); - perm_string tmp6 = lex_strings.make($6); + pform_ident_t tmp6 = { lex_strings.make($6) , @6.lexical_pos }; pform_make_udp(@2, tmp2, $5, tmp6, $7, $9, $12); check_end_label(@14, "primitive", $2, $14); delete[]$2; diff --git a/pform.cc b/pform.cc index 0311ad731..2678163f5 100644 --- a/pform.cc +++ b/pform.cc @@ -969,7 +969,7 @@ void pform_make_foreach_declarations(const struct vlltype&loc, if (cur->nil()) continue; decl_assignment_t*tmp_assign = new decl_assignment_t; - tmp_assign->name = lex_strings.make(*cur); + tmp_assign->name = { lex_strings.make(*cur), 0 }; assign_list.push_back(tmp_assign); } @@ -1478,19 +1478,19 @@ void pform_endmodule(const char*name, bool inside_celldefine, pform_pop_scope(); } -void pform_genvars(const struct vlltype&li, list*names) +void pform_genvars(const struct vlltype&li, list*names) { - list::const_iterator cur; + list::const_iterator cur; for (cur = names->begin(); cur != names->end() ; *cur++) { PGenvar*genvar = new PGenvar(); FILE_NAME(genvar, li); if (pform_cur_generate) { - add_local_symbol(pform_cur_generate, *cur, genvar); - pform_cur_generate->genvars[*cur] = genvar; + add_local_symbol(pform_cur_generate, cur->first, genvar); + pform_cur_generate->genvars[cur->first] = genvar; } else { - add_local_symbol(pform_cur_module.front(), *cur, genvar); - pform_cur_module.front()->genvars[*cur] = genvar; + add_local_symbol(pform_cur_module.front(), cur->first, genvar); + pform_cur_module.front()->genvars[cur->first] = genvar; } } @@ -1855,7 +1855,7 @@ static void process_udp_table(PUdp*udp, list*table, } void pform_make_udp(const struct vlltype&loc, perm_string name, - list*parms, vector*decl, + list*parms, vector*decl, list*table, Statement*init_expr) { unsigned local_errors = 0; @@ -1896,13 +1896,13 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, PWire* created by an input or output declaration. */ std::vector pins(parms->size()); std::vector pin_names(parms->size()); - { list::iterator cur; + { list::iterator cur; unsigned idx; for (cur = parms->begin(), idx = 0 ; cur != parms->end() ; ++ idx, ++ cur) { - pins[idx] = defs[*cur]; - pin_names[idx] = *cur; + pins[idx] = defs[cur->first]; + pin_names[idx] = cur->first; } } @@ -2048,27 +2048,27 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, } void pform_make_udp(const struct vlltype&loc, perm_string name, - bool synchronous_flag, perm_string out_name, - PExpr*init_expr, list*parms, + bool synchronous_flag, const pform_ident_t&out_name, + PExpr*init_expr, list*parms, list*table) { std::vector pins(parms->size() + 1); /* Make the PWire for the output port. */ - pins[0] = new PWire(out_name, loc.lexical_pos, + pins[0] = new PWire(out_name.first, out_name.second, synchronous_flag? NetNet::REG : NetNet::WIRE, NetNet::POUTPUT); FILE_NAME(pins[0], loc); /* Make the PWire objects for the input ports. */ - { list::iterator cur; + { list::iterator cur; unsigned idx; for (cur = parms->begin(), idx = 1 ; cur != parms->end() ; idx += 1, ++ cur) { ivl_assert(loc, idx < pins.size()); - pins[idx] = new PWire(*cur, loc.lexical_pos, NetNet::WIRE, + pins[idx] = new PWire(cur->first, cur->second, NetNet::WIRE, NetNet::PINPUT); FILE_NAME(pins[idx], loc); } @@ -2151,21 +2151,19 @@ static void pform_set_net_range(PWire *wire, * This is invoked to make a named event. This is the declaration of * the event, and not necessarily the use of it. */ -static void pform_make_event(const struct vlltype&loc, perm_string name) +static void pform_make_event(const struct vlltype&loc, const pform_ident_t&name) { - PEvent*event = new PEvent(name, loc.lexical_pos); + PEvent*event = new PEvent(name.first, name.second); FILE_NAME(event, loc); - add_local_symbol(lexical_scope, name, event); - lexical_scope->events[name] = event; + add_local_symbol(lexical_scope, name.first, event); + lexical_scope->events[name.first] = event; } -void pform_make_events(const struct vlltype&loc, list*names) +void pform_make_events(const struct vlltype&loc, const list*names) { - list::iterator cur; - for (cur = names->begin() ; cur != names->end() ; ++ cur ) { - perm_string txt = *cur; - pform_make_event(loc, txt); + for (auto cur = names->begin() ; cur != names->end() ; ++ cur ) { + pform_make_event(loc, *cur); } delete names; @@ -2476,8 +2474,8 @@ void pform_make_pgassign_list(const struct vlltype&loc, * This syntax is not part of the IEEE1364-1995 standard, but is * approved by OVI as enhancement BTF-B14. */ -void pform_make_var_init(const struct vlltype&li, - perm_string name, PExpr*expr) +void pform_make_var_init(const struct vlltype&li, const pform_ident_t&name, + PExpr*expr) { if (! pform_at_module_level() && !gn_system_verilog()) { VLerror(li, "error: Variable declaration assignments are only " @@ -2486,7 +2484,7 @@ void pform_make_var_init(const struct vlltype&li, return; } - PEIdent*lval = new PEIdent(name, li.lexical_pos); + PEIdent*lval = new PEIdent(name.first, name.second); FILE_NAME(lval, li); PAssign*ass = new PAssign(lval, expr, !gn_system_verilog(), true); FILE_NAME(ass, li); @@ -2514,8 +2512,10 @@ void pform_make_var_init(const struct vlltype&li, */ -static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name, - NetNet::Type type, NetNet::PortType ptype, +static PWire* pform_get_or_make_wire(const struct vlltype&li, + const pform_ident_t&name, + NetNet::Type type, + NetNet::PortType ptype, PWSRType rt) { PWire *cur = 0; @@ -2523,7 +2523,7 @@ static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name, // If this is not a full declaration check if there is already a signal // with the same name that can be extended. if (rt != SR_BOTH) - cur = pform_get_wire_in_scope(name); + cur = pform_get_wire_in_scope(name.first); // If the wire already exists but isn't yet fully defined, // carry on adding details. @@ -2547,10 +2547,10 @@ static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name, // to the scope. Do not delete the old wire - it will // remain in the local symbol map. - cur = new PWire(name, li.lexical_pos, type, ptype, rt); + cur = new PWire(name.first, name.second, type, ptype, rt); FILE_NAME(cur, li); - pform_put_wire_in_scope(name, cur); + pform_put_wire_in_scope(name.first, cur); return cur; } @@ -2567,7 +2567,7 @@ static PWire* pform_get_or_make_wire(const struct vlltype&li, perm_string name, * as is done for the old method. */ void pform_module_define_port(const struct vlltype&li, - perm_string name, + const pform_ident_t&name, NetNet::PortType port_kind, NetNet::Type type, data_type_t*vtype, @@ -2621,11 +2621,10 @@ void pform_module_define_port(const struct vlltype&li, * the variable/net. Other forms of pform_makewire ultimately call * this one to create the wire and stash it. */ -PWire *pform_makewire(const vlltype&li, perm_string name, NetNet::Type type, - std::list *indices) +PWire *pform_makewire(const vlltype&li, const pform_ident_t&name, + NetNet::Type type, std::list *indices) { - PWire*cur = pform_get_or_make_wire(li, name, type, NetNet::NOT_A_PORT, - SR_NET); + PWire*cur = pform_get_or_make_wire(li, name, type, NetNet::NOT_A_PORT, SR_NET); ivl_assert(li, cur); if (indices && !indices->empty()) @@ -2666,7 +2665,8 @@ void pform_makewire(const struct vlltype&li, if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { pform_make_var_init(li, first->name, expr); } else { - PEIdent*lval = new PEIdent(first->name, li.lexical_pos); + PEIdent*lval = new PEIdent(first->name.first, + first->name.second); FILE_NAME(lval, li); PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); FILE_NAME(ass, li); @@ -2735,10 +2735,8 @@ vector*pform_make_task_ports(const struct vlltype&loc, for (list::iterator cur = ports->begin(); cur != ports->end(); ++cur) { - const perm_string &name = cur->name; - - PWire*curw = pform_get_or_make_wire(loc, name, NetNet::IMPLICIT_REG, - pt, rt); + PWire*curw = pform_get_or_make_wire(loc, cur->name, + NetNet::IMPLICIT_REG, pt, rt); if (rt == SR_BOTH) curw->set_data_type(vtype); @@ -3170,8 +3168,7 @@ void pform_set_port_type(const struct vlltype&li, ; cur != ports->end() ; ++ cur ) { PWire *wire = pform_get_or_make_wire(li, cur->name, - NetNet::IMPLICIT, pt, - SR_PORT); + NetNet::IMPLICIT, pt, SR_PORT); pform_set_net_range(wire, vt, SR_PORT, attr); if (cur->udims) { @@ -3235,15 +3232,14 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, delete wires; } -vector* pform_make_udp_input_ports(list*names) +vector* pform_make_udp_input_ports(list*names) { vector*out = new vector(names->size()); unsigned idx = 0; - for (list::iterator cur = names->begin() + for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { - perm_string txt = *cur; - PWire*pp = new PWire(txt, /* FIXME */ 0, + PWire*pp = new PWire(cur->first, cur->second, NetNet::IMPLICIT, NetNet::PINPUT); (*out)[idx] = pp; diff --git a/pform.h b/pform.h index bb3dabfef..f0bbd63f6 100644 --- a/pform.h +++ b/pform.h @@ -151,7 +151,7 @@ extern void pform_set_scope_timescale(const struct vlltype&loc); in an ansi style or non-ansi style declaration. In this case, we have everything needed to define the port, all in one place. */ extern void pform_module_define_port(const struct vlltype&li, - perm_string name, + const pform_ident_t&name, NetNet::PortType, NetNet::Type type, data_type_t*vtype, @@ -186,14 +186,14 @@ extern void pform_end_class_declaration(const struct vlltype&loc); extern bool pform_in_class(); extern void pform_make_udp(const struct vlltype&loc, perm_string name, - std::list*parms, + std::list*parms, std::vector*decl, std::list*table, Statement*init); extern void pform_make_udp(const struct vlltype&loc, perm_string name, - bool sync_flag, perm_string out_name, + bool sync_flag, const pform_ident_t&out_name, PExpr*sync_init, - std::list*parms, + std::list*parms, std::list*table); /* * Package related functions. @@ -272,7 +272,7 @@ extern verinum* pform_verinum_with_size(verinum*s, verinum*val, * This function takes the list of names as new genvars to declare in * the current module or generate scope. */ -extern void pform_genvars(const struct vlltype&li, std::list*names); +extern void pform_genvars(const struct vlltype&li, std::list*names); /* * This flag is set by the parser to indicate the current generate block @@ -338,7 +338,8 @@ extern PForeach* pform_make_foreach(const struct vlltype&loc, * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. */ -extern PWire *pform_makewire(const struct vlltype&li, perm_string name, +extern PWire *pform_makewire(const struct vlltype&li, + const pform_ident_t&name, NetNet::Type type, std::list *indices); @@ -360,7 +361,8 @@ extern void pform_make_var(const struct vlltype&loc, bool is_const = false); extern void pform_make_var_init(const struct vlltype&li, - perm_string name, PExpr*expr); + const pform_ident_t&name, + PExpr*expr); /* This function is used when we have an incomplete port definition in a non-ansi style declaration. Look up the names of the wires, and set @@ -460,10 +462,10 @@ extern PProcess* pform_make_behavior(ivl_process_type_t, Statement*, std::list*attr); extern void pform_mc_translate_on(bool flag); -extern std::vector* pform_make_udp_input_ports(std::list*); +extern std::vector* pform_make_udp_input_ports(std::list*); extern void pform_make_events(const struct vlltype&loc, - std::list*names); + const std::list*names); /* * The makegate function creates a new gate (which need not have a * name) and connects it to the specified wires. @@ -537,7 +539,7 @@ extern void pform_discipline_potential(const struct vlltype&loc, const char*name extern void pform_discipline_flow(const struct vlltype&loc, const char*name); extern void pform_attach_discipline(const struct vlltype&loc, - ivl_discipline_t discipline, std::list*names); + ivl_discipline_t discipline, std::list*names); extern void pform_dump(std::ostream&out, const ivl_nature_s*); extern void pform_dump(std::ostream&out, const ivl_discipline_s*); diff --git a/pform_disciplines.cc b/pform_disciplines.cc index 830222ab4..19cef6aa3 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -189,12 +189,12 @@ void pform_end_discipline(const struct vlltype&loc) * in the current lexical scope. */ void pform_attach_discipline(const struct vlltype&loc, - ivl_discipline_t discipline, list*names) + ivl_discipline_t discipline, list*names) { - for (list::iterator cur = names->begin() + for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { - PWire* cur_net = pform_get_wire_in_scope(*cur); + PWire* cur_net = pform_get_wire_in_scope(cur->first); if (cur_net == 0) { /* Not declared yet, declare it now. */ cur_net = pform_makewire(loc, *cur, NetNet::WIRE, 0); diff --git a/pform_dump.cc b/pform_dump.cc index 1a43caaa5..9d714c3b6 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2023 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -374,7 +374,7 @@ void struct_member_t::pform_dump(ostream&out, unsigned indent) const for (list::iterator cur = names->begin() ; cur != names->end() ; ++cur) { decl_assignment_t*curp = *cur; - out << " " << curp->name; + out << " " << curp->name.first; } out << ";" << endl; } diff --git a/pform_pclass.cc b/pform_pclass.cc index fc3c19709..e9276a49a 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -86,12 +86,12 @@ void pform_class_property(const struct vlltype&loc, FILE_NAME(use_type, loc); } - pform_cur_class->type->properties[curp->name] + pform_cur_class->type->properties[curp->name.first] = class_type_t::prop_info_t(property_qual,use_type); - FILE_NAME(&pform_cur_class->type->properties[curp->name], loc); + FILE_NAME(&pform_cur_class->type->properties[curp->name.first], loc); if (PExpr*rval = curp->expr.release()) { - PExpr*lval = new PEIdent(curp->name, loc.lexical_pos); + PExpr*lval = new PEIdent(curp->name.first, curp->name.second); FILE_NAME(lval, loc); PAssign*tmp = new PAssign(lval, rval); FILE_NAME(tmp, loc); @@ -110,7 +110,7 @@ void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net) return; list*this_name = new list; - this_name->push_back(pform_port_t(perm_string::literal(THIS_TOKEN), 0, 0)); + this_name->push_back(pform_port_t({ perm_string::literal(THIS_TOKEN), 0 }, 0, 0)); vector*this_port = pform_make_task_ports(loc, NetNet::PINPUT, pform_cur_class->type, diff --git a/pform_types.h b/pform_types.h index fb7a03f8a..c35926662 100644 --- a/pform_types.h +++ b/pform_types.h @@ -49,6 +49,12 @@ class netclass_t; class netenum_t; typedef named named_pexpr_t; +/* + * The pform_ident_t holds the identifier name and its lexical position + * (the lexical_pos supplied by the scanner). + */ +typedef std::pair pform_ident_t; + /* * The pform_range_t holds variable dimensions for type * declarations. The two expressions are interpreted as the first and @@ -89,11 +95,11 @@ struct lgate : public LineInfo { * declarations. */ struct pform_port_t { - pform_port_t(perm_string n, std::list*ud, PExpr*e) + pform_port_t(pform_ident_t n, std::list*ud, PExpr*e) : name(n), udims(ud), expr(e) { } ~pform_port_t() { } - perm_string name; + pform_ident_t name; std::list*udims; PExpr*expr; }; @@ -130,7 +136,7 @@ struct name_component_t { }; struct decl_assignment_t { - perm_string name; + pform_ident_t name; std::listindex; std::unique_ptr expr; }; From 649fbb9a594ef4bb5c63ab790c3d9ed76cbebcf0 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 19 Feb 2024 10:02:40 +0000 Subject: [PATCH 06/12] Modify symbol_search() to only return declared nets and named events. This only applies to simple identifiers. Only return a match if the lexical position of the identifier being searched is later in the source text than the lexical position of a matching symbol. --- PExpr.cc | 2 +- elab_expr.cc | 10 +++++----- elab_lval.cc | 2 +- elab_net.cc | 6 +++--- elaborate.cc | 10 +++++----- netmisc.h | 5 +++-- symbol_search.cc | 41 +++++++++++++++++++++++------------------ 7 files changed, 41 insertions(+), 35 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index db9667877..35f0ed2ef 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -440,7 +440,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) bool PEIdent::has_aa_term(Design*des, NetScope*scope) const { symbol_search_results sr; - if (!symbol_search(this, des, scope, path_, &sr)) + if (!symbol_search(this, des, scope, path_, lexical_pos_, &sr)) return false; // Class properties are not considered automatic since a non-blocking diff --git a/elab_expr.cc b/elab_expr.cc index 902f1605a..fd6954b37 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1731,7 +1731,7 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, // Search for the symbol. This should turn up a scope. symbol_search_results search_results; - bool search_flag = symbol_search(this, des, scope, path_, &search_results); + bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results); if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::test_width: " @@ -2843,7 +2843,7 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope, // Search for the symbol. This should turn up a scope. symbol_search_results search_results; - bool search_flag = symbol_search(this, des, scope, path_, &search_results); + bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results); if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::elaborate_expr: " @@ -4334,7 +4334,7 @@ ivl_type_t PEIdent::resolve_type_(Design *des, const symbol_search_results &sr, unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) { symbol_search_results sr; - bool found_symbol = symbol_search(this, des, scope, path_, &sr); + bool found_symbol = symbol_search(this, des, scope, path_, lexical_pos_, &sr); // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the @@ -4490,7 +4490,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, bool need_const = NEED_CONST & flags; symbol_search_results sr; - symbol_search(this, des, scope, path_, &sr); + symbol_search(this, des, scope, path_, lexical_pos_, &sr); if (!sr.net) { cerr << get_fileline() << ": error: Unable to bind variable `" @@ -4680,7 +4680,7 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, // a net called "b" in the scope "main.a" and with a member // named "c". symbol_search() handles this for us. symbol_search_results sr; - symbol_search(this, des, scope, path_, &sr); + symbol_search(this, des, scope, path_, lexical_pos_, &sr); // If the identifier name is a parameter name, then return // the parameter value. diff --git a/elab_lval.cc b/elab_lval.cc index 81c12a6c0..71054a72e 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -174,7 +174,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } symbol_search_results sr; - symbol_search(this, des, scope, path_, &sr); + symbol_search(this, des, scope, path_, lexical_pos_, &sr); NetNet *reg = sr.net; pform_name_t &member_path = sr.path_tail; diff --git a/elab_net.cc b/elab_net.cc index 388f01491..0ae06bf58 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -503,7 +503,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, ivl_assert(*this, scope); symbol_search_results sr; - symbol_search(this, des, scope, path_.name, &sr); + symbol_search(this, des, scope, path_.name, lexical_pos_, &sr); if (sr.eve != 0) { cerr << get_fileline() << ": error: named events (" << path_ @@ -1113,7 +1113,7 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const { symbol_search_results sr; - symbol_search(this, des, scope, path_, &sr); + symbol_search(this, des, scope, path_, lexical_pos_, &sr); if (!sr.net) { cerr << get_fileline() << ": error: Net " << path_ << " is not defined in this context." << endl; @@ -1138,7 +1138,7 @@ bool PEIdent::is_collapsible_net(Design*des, NetScope*scope, ivl_assert(*this, scope); symbol_search_results sr; - symbol_search(this, des, scope, path_.name, &sr); + symbol_search(this, des, scope, path_.name, lexical_pos_, &sr); if (sr.eve != 0) return false; diff --git a/elaborate.cc b/elaborate.cc index 928032db6..45c40bad9 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1271,7 +1271,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const pform_name_t path_; path_.push_back(name_component_t(rmod->ports[j]->name)); symbol_search_results sr; - symbol_search(this, des, scope, path_, &sr); + symbol_search(this, des, scope, path_, UINT_MAX, &sr); if (sr.net != 0) { pins[j] = new PEIdent(rmod->ports[j]->name, UINT_MAX, true); pins[j]->set_lineno(get_lineno()); @@ -3825,7 +3825,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, // (internally represented as "@") is handled by there being a // "this" object in the instance scope. symbol_search_results sr; - symbol_search(this, des, scope, use_path, &sr); + symbol_search(this, des, scope, use_path, UINT_MAX, &sr); NetNet*net = sr.net; if (net == 0) @@ -4908,7 +4908,7 @@ cerr << endl; if (PEIdent*id = dynamic_cast(expr_[idx]->expr())) { symbol_search_results sr; - symbol_search(this, des, scope, id->path(), &sr); + symbol_search(this, des, scope, id->path(), id->lexical_pos(), &sr); if (sr.scope && sr.eve) { wa->add_event(sr.eve); @@ -6038,7 +6038,7 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const ivl_assert(*this, scope); symbol_search_results sr; - if (!symbol_search(this, des, scope, event_, &sr)) { + if (!symbol_search(this, des, scope, event_, UINT_MAX, &sr)) { cerr << get_fileline() << ": error: event <" << event_ << ">" << " not found." << endl; des->errors += 1; @@ -6062,7 +6062,7 @@ NetProc* PNBTrigger::elaborate(Design*des, NetScope*scope) const ivl_assert(*this, scope); symbol_search_results sr; - if (!symbol_search(this, des, scope, event_, &sr)) { + if (!symbol_search(this, des, scope, event_, UINT_MAX, &sr)) { cerr << get_fileline() << ": error: event <" << event_ << ">" << " not found." << endl; des->errors += 1; diff --git a/netmisc.h b/netmisc.h index d9da5af76..0f87fee88 100644 --- a/netmisc.h +++ b/netmisc.h @@ -106,11 +106,12 @@ static inline bool test_function_return_value(const symbol_search_results&search } extern bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, - pform_name_t path, struct symbol_search_results*res, + pform_name_t path, unsigned lexical_pos, + struct symbol_search_results*res, NetScope*start_scope = nullptr, bool prefix_scope = false); extern bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, - const pform_scoped_name_t &path, + const pform_scoped_name_t &path, unsigned lexical_pos, struct symbol_search_results*res); /* diff --git a/symbol_search.cc b/symbol_search.cc index d96f2a5f0..704a03d8e 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2024 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -38,7 +38,8 @@ using namespace std; */ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, - pform_name_t path, struct symbol_search_results*res, + pform_name_t path, unsigned lexical_pos, + struct symbol_search_results*res, NetScope*start_scope, bool prefix_scope) { assert(scope); @@ -68,8 +69,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, // recursively. Ideally, the result is a scope that we search // for the tail key, but there are other special cases as well. if (! path.empty()) { - bool flag = symbol_search(li, des, scope, path, res, start_scope, - prefix_scope); + bool flag = symbol_search(li, des, scope, path, lexical_pos, + res, start_scope, prefix_scope); if (! flag) return false; @@ -162,20 +163,24 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, } if (NetNet*net = scope->find_signal(path_tail.name)) { - path.push_back(path_tail); - res->scope = scope; - res->net = net; - res->type = net->net_type(); - res->path_head = path; - return true; + if (prefix_scope || (net->lexical_pos() <= lexical_pos)) { + path.push_back(path_tail); + res->scope = scope; + res->net = net; + res->type = net->net_type(); + res->path_head = path; + return true; + } } if (NetEvent*eve = scope->find_event(path_tail.name)) { - path.push_back(path_tail); - res->scope = scope; - res->eve = eve; - res->path_head = path; - return true; + if (prefix_scope || (eve->lexical_pos() <= lexical_pos)) { + path.push_back(path_tail); + res->scope = scope; + res->eve = eve; + res->path_head = path; + return true; + } } if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->type)) { @@ -310,7 +315,7 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, } bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, - const pform_scoped_name_t &path, + const pform_scoped_name_t &path, unsigned lexical_pos, struct symbol_search_results *res) { NetScope *search_scope = scope; @@ -323,6 +328,6 @@ bool symbol_search(const LineInfo *li, Design *des, NetScope *scope, prefix_scope = true; } - return symbol_search(li, des, search_scope, path.name, res, search_scope, - prefix_scope); + return symbol_search(li, des, search_scope, path.name, lexical_pos, + res, search_scope, prefix_scope); } From cd76bd237123b879e5f29af1a15ffb3d45af1319 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 19 Feb 2024 10:22:31 +0000 Subject: [PATCH 07/12] Fix tests that used variables/nets before declaring them. The sdf_interconnect tests just need the code reordering. The pr1909940 tests were written to test use before declaration, so now need to be CE tests. --- ivtest/ivltests/sdf_interconnect1.v | 7 +++---- ivtest/ivltests/sdf_interconnect2.v | 7 +++---- ivtest/ivltests/sdf_interconnect3.v | 7 +++---- ivtest/ivltests/sdf_interconnect4.v | 7 +++---- ivtest/regress-ivl1.list | 4 ---- ivtest/regress-vlg.list | 2 ++ 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/ivtest/ivltests/sdf_interconnect1.v b/ivtest/ivltests/sdf_interconnect1.v index 91f500539..7f8f44c73 100644 --- a/ivtest/ivltests/sdf_interconnect1.v +++ b/ivtest/ivltests/sdf_interconnect1.v @@ -42,14 +42,14 @@ endmodule module top; + reg a; + wire b; + initial begin $sdf_annotate("ivltests/sdf_interconnect1.sdf", my_design_inst); $monitor("time=%0t a=%h b=%h", $realtime, a, b); end - reg a; - wire b; - initial begin #5; a <= 1'b0; @@ -65,4 +65,3 @@ module top; ); endmodule - diff --git a/ivtest/ivltests/sdf_interconnect2.v b/ivtest/ivltests/sdf_interconnect2.v index c35523a41..2627398c5 100644 --- a/ivtest/ivltests/sdf_interconnect2.v +++ b/ivtest/ivltests/sdf_interconnect2.v @@ -44,14 +44,14 @@ endmodule module top; + reg a; + wire b; + initial begin $sdf_annotate("ivltests/sdf_interconnect2.sdf", my_design_inst); $monitor("time=%0t a=%h b=%h", $realtime, a, b); end - reg a; - wire b; - initial begin #5; a <= 1'b0; @@ -67,4 +67,3 @@ module top; ); endmodule - diff --git a/ivtest/ivltests/sdf_interconnect3.v b/ivtest/ivltests/sdf_interconnect3.v index fc501f641..203cc4656 100644 --- a/ivtest/ivltests/sdf_interconnect3.v +++ b/ivtest/ivltests/sdf_interconnect3.v @@ -87,14 +87,14 @@ endmodule module top; + reg a, b, c; + wire d; + initial begin $sdf_annotate("ivltests/sdf_interconnect3.sdf", my_design_inst); $monitor("time=%0t a=%h b=%h c=%h d=%h", $realtime, a, b, c, d); end - reg a, b, c; - wire d; - initial begin #10; a <= 1'b0; @@ -140,4 +140,3 @@ module top; ); endmodule - diff --git a/ivtest/ivltests/sdf_interconnect4.v b/ivtest/ivltests/sdf_interconnect4.v index 918a34a98..5b6e1be37 100644 --- a/ivtest/ivltests/sdf_interconnect4.v +++ b/ivtest/ivltests/sdf_interconnect4.v @@ -41,14 +41,14 @@ endmodule module top; + reg [2:0] a; + wire [2:0] b; + initial begin $sdf_annotate("ivltests/sdf_interconnect4.sdf", my_design_inst); $monitor("time=%0t a=%b b=%b", $realtime, a, b); end - reg [2:0] a; - wire [2:0] b; - initial begin #5; a <= 3'b000; @@ -64,4 +64,3 @@ module top; ); endmodule - diff --git a/ivtest/regress-ivl1.list b/ivtest/regress-ivl1.list index 7ba05aba8..af0a5b3e5 100644 --- a/ivtest/regress-ivl1.list +++ b/ivtest/regress-ivl1.list @@ -286,10 +286,6 @@ sv_deferred_assume2 CE,-g2009 ivltests gold=sv_deferred_assume2.gold # Icarus deviations #------------------------------------------------------------------------------ -# Icarus still allows (implicit) declaration after use in some circumstances. -pr1909940 normal ivltests -pr1909940b normal ivltests - # Icarus allows hierarchical references to unnamed generate blocks. # We should add a warning about this, as it's not strictly allowed. unnamed_generate_block normal ivltests gold=unnamed_generate_block.gold diff --git a/ivtest/regress-vlg.list b/ivtest/regress-vlg.list index 8dd34a0fa..19ece7d66 100644 --- a/ivtest/regress-vlg.list +++ b/ivtest/regress-vlg.list @@ -1106,6 +1106,8 @@ pr1903324 normal ivltests pr1903343 normal ivltests gold=pr1903343.gold pr1903520 normal ivltests pr1907192 normal ivltests +pr1909940 CE ivltests +pr1909940b CE ivltests pr1912843 normal ivltests pr1913918a normal ivltests pr1913918b normal ivltests From 1c289484841e08e60d20dbfc8b0eef44f517e346 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 19 Feb 2024 10:30:32 +0000 Subject: [PATCH 08/12] Pass lexical position information to PTrigger and PNBTrigger objects. --- Statement.cc | 10 +++++----- Statement.h | 8 +++++--- elaborate.cc | 4 ++-- parse.y | 12 ++++++------ pform.cc | 9 +++++---- pform.h | 5 +++-- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Statement.cc b/Statement.cc index 1dda37940..16307804a 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -396,8 +396,8 @@ PReturn::~PReturn() delete expr_; } -PTrigger::PTrigger(PPackage*pkg, const pform_name_t&ev) -: event_(pkg, ev) +PTrigger::PTrigger(PPackage*pkg, const pform_name_t&ev, unsigned lexical_pos) +: event_(pkg, ev), lexical_pos_(lexical_pos) { } @@ -405,8 +405,8 @@ PTrigger::~PTrigger() { } -PNBTrigger::PNBTrigger(const pform_name_t&ev, PExpr*dly) -: event_(ev), dly_(dly) +PNBTrigger::PNBTrigger(const pform_name_t&ev, unsigned lexical_pos, PExpr*dly) +: event_(ev), lexical_pos_(lexical_pos), dly_(dly) { } diff --git a/Statement.h b/Statement.h index d540fb881..c0c5e23e5 100644 --- a/Statement.h +++ b/Statement.h @@ -1,7 +1,7 @@ #ifndef IVL_Statement_H #define IVL_Statement_H /* - * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -599,7 +599,7 @@ class PReturn : public Statement { class PTrigger : public Statement { public: - explicit PTrigger(PPackage*pkg, const pform_name_t&ev); + explicit PTrigger(PPackage*pkg, const pform_name_t&ev, unsigned lexical_pos); ~PTrigger(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -607,11 +607,12 @@ class PTrigger : public Statement { private: pform_scoped_name_t event_; + unsigned lexical_pos_; }; class PNBTrigger : public Statement { public: - explicit PNBTrigger(const pform_name_t&ev, PExpr*dly); + explicit PNBTrigger(const pform_name_t&ev, unsigned lexical_pos, PExpr*dly); ~PNBTrigger(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -619,6 +620,7 @@ class PNBTrigger : public Statement { private: pform_name_t event_; + unsigned lexical_pos_; PExpr*dly_; }; diff --git a/elaborate.cc b/elaborate.cc index 45c40bad9..b1d6edda3 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -6038,7 +6038,7 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const ivl_assert(*this, scope); symbol_search_results sr; - if (!symbol_search(this, des, scope, event_, UINT_MAX, &sr)) { + if (!symbol_search(this, des, scope, event_, lexical_pos_, &sr)) { cerr << get_fileline() << ": error: event <" << event_ << ">" << " not found." << endl; des->errors += 1; @@ -6062,7 +6062,7 @@ NetProc* PNBTrigger::elaborate(Design*des, NetScope*scope) const ivl_assert(*this, scope); symbol_search_results sr; - if (!symbol_search(this, des, scope, event_, UINT_MAX, &sr)) { + if (!symbol_search(this, des, scope, event_, lexical_pos_, &sr)) { cerr << get_fileline() << ": error: event <" << event_ << ">" << " not found." << endl; des->errors += 1; diff --git a/parse.y b/parse.y index 9128f29e5..f7bf42aef 100644 --- a/parse.y +++ b/parse.y @@ -6766,35 +6766,35 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } | K_TRIGGER hierarchy_identifier ';' - { PTrigger*tmp = pform_new_trigger(@2, 0, *$2); + { PTrigger*tmp = pform_new_trigger(@2, 0, *$2, @2.lexical_pos); delete $2; $$ = tmp; } | K_TRIGGER package_scope hierarchy_identifier { lex_in_package_scope(0); - PTrigger*tmp = pform_new_trigger(@3, $2, *$3); + PTrigger*tmp = pform_new_trigger(@3, $2, *$3, @3.lexical_pos); delete $3; $$ = tmp; } /* FIXME: Does this need support for package resolution like above? */ | K_NB_TRIGGER hierarchy_identifier ';' - { PNBTrigger*tmp = pform_new_nb_trigger(@2, 0, *$2); + { PNBTrigger*tmp = pform_new_nb_trigger(@2, 0, *$2, @2.lexical_pos); delete $2; $$ = tmp; } | K_NB_TRIGGER delay1 hierarchy_identifier ';' - { PNBTrigger*tmp = pform_new_nb_trigger(@3, $2, *$3); + { PNBTrigger*tmp = pform_new_nb_trigger(@3, $2, *$3, @3.lexical_pos); delete $3; $$ = tmp; } | K_NB_TRIGGER event_control hierarchy_identifier ';' - { PNBTrigger*tmp = pform_new_nb_trigger(@3, 0, *$3); + { PNBTrigger*tmp = pform_new_nb_trigger(@3, 0, *$3, @3.lexical_pos); delete $3; $$ = tmp; yywarn(@1, "sorry: ->> with event control is not currently supported."); } | K_NB_TRIGGER K_repeat '(' expression ')' event_control hierarchy_identifier ';' - { PNBTrigger*tmp = pform_new_nb_trigger(@7, 0, *$7); + { PNBTrigger*tmp = pform_new_nb_trigger(@7, 0, *$7, @7.lexical_pos); delete $7; $$ = tmp; yywarn(@1, "sorry: ->> with repeat event control is not currently supported."); diff --git a/pform.cc b/pform.cc index 2678163f5..d57d0ed01 100644 --- a/pform.cc +++ b/pform.cc @@ -712,19 +712,20 @@ PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) } PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, - const pform_name_t&name) + const pform_name_t&name, unsigned lexical_pos) { if (gn_system_verilog()) check_potential_imports(loc, name.front().name, false); - PTrigger*tmp = new PTrigger(pkg, name); + PTrigger*tmp = new PTrigger(pkg, name, lexical_pos); FILE_NAME(tmp, loc); return tmp; } PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc, const list*dly, - const pform_name_t&name) + const pform_name_t&name, + unsigned lexical_pos) { if (gn_system_verilog()) check_potential_imports(loc, name.front().name, false); @@ -735,7 +736,7 @@ PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc, tmp_dly = dly->front(); } - PNBTrigger*tmp = new PNBTrigger(name, tmp_dly); + PNBTrigger*tmp = new PNBTrigger(name, lexical_pos, tmp_dly); FILE_NAME(tmp, loc); return tmp; } diff --git a/pform.h b/pform.h index f0bbd63f6..127f503f1 100644 --- a/pform.h +++ b/pform.h @@ -230,10 +230,11 @@ extern void pform_add_modport_port(const struct vlltype&loc, extern PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name); extern PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, - const pform_name_t&name); + const pform_name_t&name, unsigned lexical_pos); extern PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc, const std::list*dly, - const pform_name_t&name); + const pform_name_t&name, + unsigned lexical_pos); /* * Enter/exit name scopes. The push_scope function pushes the scope From 76a9d38d87fcc039f58d6eabcdc657e1b9186649 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 19 Feb 2024 11:48:00 +0000 Subject: [PATCH 09/12] Add check for parameters used before they are declared. --- PScope.h | 4 +++- net_scope.cc | 15 +++++++++++++-- netlist.h | 4 ++++ pform.cc | 1 + symbol_search.cc | 12 +++++++----- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/PScope.h b/PScope.h index 9fd41a461..03bc4f2e3 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ #ifndef IVL_PScope_H #define IVL_PScope_H /* - * Copyright (c) 2008-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2024 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -121,6 +121,8 @@ class LexicalScope { bool overridable; // Whether the parameter is a type parameter bool type_flag = false; + // The lexical position of the declaration + unsigned lexical_pos = 0; SymbolType symbol_type() const; }; diff --git a/net_scope.cc b/net_scope.cc index 9fac014e8..76d29c601 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2021 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2024 Stephen Williams (steve@icarus.com) * Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch) * * This source code is free software; you can redistribute it @@ -280,6 +280,7 @@ void NetScope::set_parameter(perm_string key, bool is_annotatable, ref.local_flag = param.local_flag; ref.overridable = param.overridable; ref.type_flag = param.type_flag; + ref.lexical_pos = param.lexical_pos; ivl_assert(param, !ref.range); ref.range = range_list; ref.val = 0; @@ -449,6 +450,17 @@ LineInfo NetScope::get_parameter_line_info(perm_string key) const return LineInfo(); } +unsigned NetScope::get_parameter_lexical_pos(perm_string key) const +{ + map::const_iterator idx; + + idx = parameters.find(key); + if (idx != parameters.end()) return idx->second.lexical_pos; + + // If we get here, assume an enumeration value. + return 0; +} + void NetScope::print_type(ostream&stream) const { switch (type_) { @@ -879,4 +891,3 @@ void NetScope::add_tie_lo(Design*des) connect(sig->pin(0), tie_lo_->pin(0)); } } - diff --git a/netlist.h b/netlist.h index 79e158baa..d2a039e44 100644 --- a/netlist.h +++ b/netlist.h @@ -1243,6 +1243,8 @@ class NetScope : public Definitions, public Attrib { bool overridable = false; // Is it a type parameter bool type_flag = false; + // The lexical position of the declaration + unsigned lexical_pos = 0; // range constraints struct range_t*range; @@ -1261,6 +1263,8 @@ class NetScope : public Definitions, public Attrib { LineInfo get_parameter_line_info(perm_string name) const; + unsigned get_parameter_lexical_pos(perm_string name) const; + /* Module instance arrays are collected here for access during the multiple elaboration passes. */ typedef std::vector scope_vec_t; diff --git a/pform.cc b/pform.cc index d57d0ed01..99714f3af 100644 --- a/pform.cc +++ b/pform.cc @@ -2953,6 +2953,7 @@ void pform_set_parameter(const struct vlltype&loc, parm->local_flag = is_local; parm->overridable = overridable; parm->type_flag = is_type; + parm->lexical_pos = loc.lexical_pos; scope->parameters[name] = parm; diff --git a/symbol_search.cc b/symbol_search.cc index 704a03d8e..5db3405a6 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -184,11 +184,13 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, } if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->type)) { - path.push_back(path_tail); - res->scope = scope; - res->par_val = par; - res->path_head = path; - return true; + if (prefix_scope || (scope->get_parameter_lexical_pos(path_tail.name) <= lexical_pos)) { + path.push_back(path_tail); + res->scope = scope; + res->par_val = par; + res->path_head = path; + return true; + } } // Static items are just normal signals and are found above. From f1bf6a7a55c14fe6ef84b845c70807b49a51bd2f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 19 Feb 2024 18:41:33 +0000 Subject: [PATCH 10/12] Mark the vhdl_fa4_test4 as NI. The VHDL pre-processor is generating illegal code for this test case (using localparam values before they are declared). --- ivtest/regress-vhdl.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivtest/regress-vhdl.list b/ivtest/regress-vhdl.list index 87089687f..3d94f9e8b 100644 --- a/ivtest/regress-vhdl.list +++ b/ivtest/regress-vhdl.list @@ -108,7 +108,7 @@ vhdl_generic_eval normal,-g2005-sv,ivltests/vhdl_generic_eval.vhd ivltests vhdl_fa4_test1 normal,-g2005-sv,ivltests/vhdl_fa4_test1.vhd ivltests vhdl_fa4_test2 normal,-g2005-sv,ivltests/vhdl_fa4_test2.vhd ivltests vhdl_fa4_test3 normal,-g2005-sv,ivltests/vhdl_fa4_test3.vhd ivltests -vhdl_fa4_test4 normal,-g2005-sv,ivltests/vhdl_fa4_test4.vhd ivltests +vhdl_fa4_test4 NI ivltests vhdl_file_open normal,-g2005-sv,ivltests/vhdl_file_open.vhd ivltests vhdl_generic_default normal,-g2005-sv,ivltests/vhdl_generic_default.vhd ivltests vhdl_init normal,-g2005-sv,ivltests/vhdl_init.vhd ivltests From d043c1fa4489a36954a94938ec3968f69488238f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 19 Feb 2024 19:44:53 +0000 Subject: [PATCH 11/12] Add regression tests for declare before use. --- .../decl_before_use1-iverilog-stderr.gold | 3 +++ .../decl_before_use2-iverilog-stderr.gold | 3 +++ .../decl_before_use3-iverilog-stderr.gold | 2 ++ .../decl_before_use4-iverilog-stderr.gold | 3 +++ .../decl_before_use5-iverilog-stderr.gold | 2 ++ ivtest/ivltests/decl_before_use1.v | 11 ++++++++++ ivtest/ivltests/decl_before_use2.v | 12 +++++++++++ ivtest/ivltests/decl_before_use3.v | 10 ++++++++++ ivtest/ivltests/decl_before_use4.v | 12 +++++++++++ ivtest/ivltests/decl_before_use5.v | 10 ++++++++++ ivtest/ivltests/decl_before_use6.v | 20 +++++++++++++++++++ ivtest/regress-vvp.list | 6 ++++++ ivtest/vvp_tests/decl_before_use1.json | 6 ++++++ ivtest/vvp_tests/decl_before_use2.json | 6 ++++++ ivtest/vvp_tests/decl_before_use3.json | 6 ++++++ ivtest/vvp_tests/decl_before_use4.json | 6 ++++++ ivtest/vvp_tests/decl_before_use5.json | 6 ++++++ ivtest/vvp_tests/decl_before_use6.json | 5 +++++ 18 files changed, 129 insertions(+) create mode 100644 ivtest/gold/decl_before_use1-iverilog-stderr.gold create mode 100644 ivtest/gold/decl_before_use2-iverilog-stderr.gold create mode 100644 ivtest/gold/decl_before_use3-iverilog-stderr.gold create mode 100644 ivtest/gold/decl_before_use4-iverilog-stderr.gold create mode 100644 ivtest/gold/decl_before_use5-iverilog-stderr.gold create mode 100644 ivtest/ivltests/decl_before_use1.v create mode 100644 ivtest/ivltests/decl_before_use2.v create mode 100644 ivtest/ivltests/decl_before_use3.v create mode 100644 ivtest/ivltests/decl_before_use4.v create mode 100644 ivtest/ivltests/decl_before_use5.v create mode 100644 ivtest/ivltests/decl_before_use6.v create mode 100644 ivtest/vvp_tests/decl_before_use1.json create mode 100644 ivtest/vvp_tests/decl_before_use2.json create mode 100644 ivtest/vvp_tests/decl_before_use3.json create mode 100644 ivtest/vvp_tests/decl_before_use4.json create mode 100644 ivtest/vvp_tests/decl_before_use5.json create mode 100644 ivtest/vvp_tests/decl_before_use6.json diff --git a/ivtest/gold/decl_before_use1-iverilog-stderr.gold b/ivtest/gold/decl_before_use1-iverilog-stderr.gold new file mode 100644 index 000000000..4ac31fc85 --- /dev/null +++ b/ivtest/gold/decl_before_use1-iverilog-stderr.gold @@ -0,0 +1,3 @@ +ivltests/decl_before_use1.v:4: error: Could not find variable ``v'' in ``test'' +ivltests/decl_before_use1.v:5: error: Unable to bind wire/reg/memory `v' in `test' +2 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use2-iverilog-stderr.gold b/ivtest/gold/decl_before_use2-iverilog-stderr.gold new file mode 100644 index 000000000..b9c66eb78 --- /dev/null +++ b/ivtest/gold/decl_before_use2-iverilog-stderr.gold @@ -0,0 +1,3 @@ +ivltests/decl_before_use2.v:3: error: Net w is not defined in this context. +ivltests/decl_before_use2.v:6: error: Unable to bind wire/reg/memory `w' in `test' +2 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use3-iverilog-stderr.gold b/ivtest/gold/decl_before_use3-iverilog-stderr.gold new file mode 100644 index 000000000..cca909053 --- /dev/null +++ b/ivtest/gold/decl_before_use3-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/decl_before_use3.v:4: error: event not found. +1 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use4-iverilog-stderr.gold b/ivtest/gold/decl_before_use4-iverilog-stderr.gold new file mode 100644 index 000000000..0fea6bfee --- /dev/null +++ b/ivtest/gold/decl_before_use4-iverilog-stderr.gold @@ -0,0 +1,3 @@ +ivltests/decl_before_use4.v:4: error: Unable to bind wire/reg/memory `e' in `test' +ivltests/decl_before_use4.v:4: error: Failed to evaluate event expression 'e'. +2 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use5-iverilog-stderr.gold b/ivtest/gold/decl_before_use5-iverilog-stderr.gold new file mode 100644 index 000000000..732e678fd --- /dev/null +++ b/ivtest/gold/decl_before_use5-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/decl_before_use5.v:4: error: Unable to bind wire/reg/memory `w' in `test' +1 error(s) during elaboration. diff --git a/ivtest/ivltests/decl_before_use1.v b/ivtest/ivltests/decl_before_use1.v new file mode 100644 index 000000000..8f338b72a --- /dev/null +++ b/ivtest/ivltests/decl_before_use1.v @@ -0,0 +1,11 @@ +module test(); + +initial begin + v = 1; + $display("%b", v); + $display("FAILED"); +end + +reg v; + +endmodule diff --git a/ivtest/ivltests/decl_before_use2.v b/ivtest/ivltests/decl_before_use2.v new file mode 100644 index 000000000..3eeb619c3 --- /dev/null +++ b/ivtest/ivltests/decl_before_use2.v @@ -0,0 +1,12 @@ +module test(); + +assign w = 1; + +initial begin + $display("%b", w); + $display("FAILED"); +end + +wire [7:0] w; + +endmodule diff --git a/ivtest/ivltests/decl_before_use3.v b/ivtest/ivltests/decl_before_use3.v new file mode 100644 index 000000000..8fed35387 --- /dev/null +++ b/ivtest/ivltests/decl_before_use3.v @@ -0,0 +1,10 @@ +module test(); + +initial begin + ->e; + $display("FAILED"); +end + +event e; + +endmodule diff --git a/ivtest/ivltests/decl_before_use4.v b/ivtest/ivltests/decl_before_use4.v new file mode 100644 index 000000000..8daa94218 --- /dev/null +++ b/ivtest/ivltests/decl_before_use4.v @@ -0,0 +1,12 @@ +module test(); + +initial begin + @(e); + $display("FAILED"); +end + +event e; + +initial ->e; + +endmodule diff --git a/ivtest/ivltests/decl_before_use5.v b/ivtest/ivltests/decl_before_use5.v new file mode 100644 index 000000000..cb92f23a0 --- /dev/null +++ b/ivtest/ivltests/decl_before_use5.v @@ -0,0 +1,10 @@ +module test(); + +initial begin + $display("%b", w); + $display("FAILED"); +end + +localparam w = 8'hAA; + +endmodule diff --git a/ivtest/ivltests/decl_before_use6.v b/ivtest/ivltests/decl_before_use6.v new file mode 100644 index 000000000..36770556d --- /dev/null +++ b/ivtest/ivltests/decl_before_use6.v @@ -0,0 +1,20 @@ +module test(); + +localparam w = 8; + +task t; + reg [w:1] v; + localparam w = 2; + begin + v = 8'hAA; + $display("%b", v); + if (v === 8'hAA) + $display("PASSED"); + else + $display("FAILED"); + end +endtask; + +initial t; + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index eada3433a..7d8711ec4 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -60,6 +60,12 @@ constfunc17 vvp_tests/constfunc17.json constfunc18 vvp_tests/constfunc18.json constfunc19 vvp_tests/constfunc19.json constfunc20 vvp_tests/constfunc20.json +decl_before_use1 vvp_tests/decl_before_use1.json +decl_before_use2 vvp_tests/decl_before_use2.json +decl_before_use3 vvp_tests/decl_before_use3.json +decl_before_use4 vvp_tests/decl_before_use4.json +decl_before_use5 vvp_tests/decl_before_use5.json +decl_before_use6 vvp_tests/decl_before_use6.json delayed_sfunc vvp_tests/delayed_sfunc.json dffsynth vvp_tests/dffsynth.json dffsynth-S vvp_tests/dffsynth-S.json diff --git a/ivtest/vvp_tests/decl_before_use1.json b/ivtest/vvp_tests/decl_before_use1.json new file mode 100644 index 000000000..e3452b26a --- /dev/null +++ b/ivtest/vvp_tests/decl_before_use1.json @@ -0,0 +1,6 @@ + +{ + "type" : "CE", + "source" : "decl_before_use1.v", + "gold" : "decl_before_use1" +} diff --git a/ivtest/vvp_tests/decl_before_use2.json b/ivtest/vvp_tests/decl_before_use2.json new file mode 100644 index 000000000..07ec7d5f1 --- /dev/null +++ b/ivtest/vvp_tests/decl_before_use2.json @@ -0,0 +1,6 @@ + +{ + "type" : "CE", + "source" : "decl_before_use2.v", + "gold" : "decl_before_use2" +} diff --git a/ivtest/vvp_tests/decl_before_use3.json b/ivtest/vvp_tests/decl_before_use3.json new file mode 100644 index 000000000..0fa1baa38 --- /dev/null +++ b/ivtest/vvp_tests/decl_before_use3.json @@ -0,0 +1,6 @@ + +{ + "type" : "CE", + "source" : "decl_before_use3.v", + "gold" : "decl_before_use3" +} diff --git a/ivtest/vvp_tests/decl_before_use4.json b/ivtest/vvp_tests/decl_before_use4.json new file mode 100644 index 000000000..4c367891b --- /dev/null +++ b/ivtest/vvp_tests/decl_before_use4.json @@ -0,0 +1,6 @@ + +{ + "type" : "CE", + "source" : "decl_before_use4.v", + "gold" : "decl_before_use4" +} diff --git a/ivtest/vvp_tests/decl_before_use5.json b/ivtest/vvp_tests/decl_before_use5.json new file mode 100644 index 000000000..36e14fe11 --- /dev/null +++ b/ivtest/vvp_tests/decl_before_use5.json @@ -0,0 +1,6 @@ + +{ + "type" : "CE", + "source" : "decl_before_use5.v", + "gold" : "decl_before_use5" +} diff --git a/ivtest/vvp_tests/decl_before_use6.json b/ivtest/vvp_tests/decl_before_use6.json new file mode 100644 index 000000000..17376ea6f --- /dev/null +++ b/ivtest/vvp_tests/decl_before_use6.json @@ -0,0 +1,5 @@ + +{ + "type" : "normal", + "source" : "decl_before_use6.v" +} From f08ff895af2919824e9e0ae22434fff5a7005c47 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 25 Feb 2024 16:12:31 +0000 Subject: [PATCH 12/12] Add informational messages that point to declaration after use. --- elab_expr.cc | 12 +++++++++++- elab_lval.cc | 5 +++++ elab_net.cc | 10 ++++++++++ elaborate.cc | 10 ++++++++++ ivtest/gold/decl_before_use1-iverilog-stderr.gold | 1 + ivtest/gold/decl_before_use2-iverilog-stderr.gold | 1 + ivtest/gold/decl_before_use3-iverilog-stderr.gold | 1 + ivtest/gold/decl_before_use4-iverilog-stderr.gold | 1 + netmisc.h | 6 ++++++ symbol_search.cc | 6 ++++++ 10 files changed, 52 insertions(+), 1 deletion(-) diff --git a/elab_expr.cc b/elab_expr.cc index fd6954b37..12967412a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2023 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2024 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -4495,6 +4495,11 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, if (!sr.net) { cerr << get_fileline() << ": error: Unable to bind variable `" << path_ << "' in `" << scope_path(scope) << "'" << endl; + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } des->errors++; return nullptr; } @@ -5016,6 +5021,11 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, << "' is being used as a constant function, so may " "only reference local variables." << endl; } + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } des->errors += 1; return 0; } diff --git a/elab_lval.cc b/elab_lval.cc index 71054a72e..bc6ae087e 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -193,6 +193,11 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, cerr << get_fileline() << ": error: Could not find variable ``" << path_ << "'' in ``" << scope_path(scope) << "''" << endl; + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } } des->errors += 1; return 0; diff --git a/elab_net.cc b/elab_net.cc index 0ae06bf58..7d0024192 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -520,6 +520,11 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, if (sig == 0) { cerr << get_fileline() << ": error: Net " << path_ << " is not defined in this context." << endl; + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } des->errors += 1; return 0; } @@ -1117,6 +1122,11 @@ NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const if (!sr.net) { cerr << get_fileline() << ": error: Net " << path_ << " is not defined in this context." << endl; + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } des->errors += 1; return nullptr; } diff --git a/elaborate.cc b/elaborate.cc index b1d6edda3..410e30eff 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -6041,6 +6041,11 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const if (!symbol_search(this, des, scope, event_, lexical_pos_, &sr)) { cerr << get_fileline() << ": error: event <" << event_ << ">" << " not found." << endl; + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } des->errors += 1; return 0; } @@ -6065,6 +6070,11 @@ NetProc* PNBTrigger::elaborate(Design*des, NetScope*scope) const if (!symbol_search(this, des, scope, event_, lexical_pos_, &sr)) { cerr << get_fileline() << ": error: event <" << event_ << ">" << " not found." << endl; + if (sr.decl_after_use) { + cerr << sr.decl_after_use->get_fileline() << ": : " + "A symbol with that name was declared here. " + "Check for declaration after use." << endl; + } des->errors += 1; return 0; } diff --git a/ivtest/gold/decl_before_use1-iverilog-stderr.gold b/ivtest/gold/decl_before_use1-iverilog-stderr.gold index 4ac31fc85..bde09a416 100644 --- a/ivtest/gold/decl_before_use1-iverilog-stderr.gold +++ b/ivtest/gold/decl_before_use1-iverilog-stderr.gold @@ -1,3 +1,4 @@ ivltests/decl_before_use1.v:4: error: Could not find variable ``v'' in ``test'' +ivltests/decl_before_use1.v:9: : A symbol with that name was declared here. Check for declaration after use. ivltests/decl_before_use1.v:5: error: Unable to bind wire/reg/memory `v' in `test' 2 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use2-iverilog-stderr.gold b/ivtest/gold/decl_before_use2-iverilog-stderr.gold index b9c66eb78..40091a707 100644 --- a/ivtest/gold/decl_before_use2-iverilog-stderr.gold +++ b/ivtest/gold/decl_before_use2-iverilog-stderr.gold @@ -1,3 +1,4 @@ ivltests/decl_before_use2.v:3: error: Net w is not defined in this context. +ivltests/decl_before_use2.v:10: : A symbol with that name was declared here. Check for declaration after use. ivltests/decl_before_use2.v:6: error: Unable to bind wire/reg/memory `w' in `test' 2 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use3-iverilog-stderr.gold b/ivtest/gold/decl_before_use3-iverilog-stderr.gold index cca909053..b42d51989 100644 --- a/ivtest/gold/decl_before_use3-iverilog-stderr.gold +++ b/ivtest/gold/decl_before_use3-iverilog-stderr.gold @@ -1,2 +1,3 @@ ivltests/decl_before_use3.v:4: error: event not found. +ivltests/decl_before_use3.v:8: : A symbol with that name was declared here. Check for declaration after use. 1 error(s) during elaboration. diff --git a/ivtest/gold/decl_before_use4-iverilog-stderr.gold b/ivtest/gold/decl_before_use4-iverilog-stderr.gold index 0fea6bfee..1a6e3ebe3 100644 --- a/ivtest/gold/decl_before_use4-iverilog-stderr.gold +++ b/ivtest/gold/decl_before_use4-iverilog-stderr.gold @@ -1,3 +1,4 @@ ivltests/decl_before_use4.v:4: error: Unable to bind wire/reg/memory `e' in `test' +ivltests/decl_before_use4.v:8: : A symbol with that name was declared here. Check for declaration after use. ivltests/decl_before_use4.v:4: error: Failed to evaluate event expression 'e'. 2 error(s) during elaboration. diff --git a/netmisc.h b/netmisc.h index 0f87fee88..5ae10d6f9 100644 --- a/netmisc.h +++ b/netmisc.h @@ -49,6 +49,7 @@ struct symbol_search_results { par_val = 0; type = 0; eve = 0; + decl_after_use = 0; } inline bool is_scope() const { @@ -78,6 +79,11 @@ struct symbol_search_results { ivl_type_t type; // If this is a named event, ... NetEvent*eve; + // If a symbol was located but skipped because its lexical position + // is after the lexical position of the name being searched, it is + // stored here. If more than one such symbol is found, the first + // one is retained. + const LineInfo*decl_after_use; // Store bread crumbs of the search here. The path_tail is the parts // of the original path that were not found, or are after an object diff --git a/symbol_search.cc b/symbol_search.cc index 5db3405a6..8479ff268 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -170,6 +170,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, res->type = net->net_type(); res->path_head = path; return true; + } else if (!res->decl_after_use) { + res->decl_after_use = net; } } @@ -180,6 +182,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, res->eve = eve; res->path_head = path; return true; + } else if (!res->decl_after_use) { + res->decl_after_use = eve; } } @@ -190,6 +194,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, res->par_val = par; res->path_head = path; return true; + } else if (!res->decl_after_use) { + res->decl_after_use = par; } }