From 55219773fdb05ada7731d3ef602fad6a045ebea9 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 21 Sep 2019 23:09:48 +0100 Subject: [PATCH 01/16] Allow nested scopes to use their parent's imports. --- elab_scope.cc | 13 ++++++++++++- elab_sig.cc | 2 +- elaborate.cc | 5 ++++- net_design.cc | 23 ++++++++++++++++++++--- net_scope.cc | 30 +++++++++++++++++++++++++++--- netlist.h | 10 ++++++++-- symbol_search.cc | 7 ++++++- 7 files changed, 78 insertions(+), 12 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index cfbc2a50d..bb3592d2d 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -542,6 +542,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // Task methods are always automatic... method_scope->is_auto(true); method_scope->set_line(cur->second); + method_scope->add_imports(&cur->second->imports); if (debug_scopes) { cerr << cur->second->get_fileline() << ": elaborate_scope_class: " @@ -560,6 +561,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // Function methods are always automatic... method_scope->is_auto(true); method_scope->set_line(cur->second); + method_scope->add_imports(&cur->second->imports); if (debug_scopes) { cerr << cur->second->get_fileline() << ": elaborate_scope_class: " @@ -630,6 +632,7 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task) NetScope*task_scope = new NetScope(scope, use_name, NetScope::TASK); task_scope->is_auto(task->is_auto()); task_scope->set_line(task); + task_scope->add_imports(&task->imports); if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_task: " @@ -692,6 +695,7 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task) NetScope*task_scope = new NetScope(scope, use_name, NetScope::FUNC); task_scope->is_auto(task->is_auto()); task_scope->set_line(task); + task_scope->add_imports(&task->imports); if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_func: " @@ -1065,6 +1069,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); + scope->add_imports(&imports); // Set in the scope a localparam for the value of the // genvar within this instance of the generate @@ -1200,6 +1205,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else // for myself. That is what I will pass to the subscope. NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); + scope->add_imports(&imports); elaborate_subscope_(des, scope); @@ -1340,6 +1346,8 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); + scope->add_imports(&imports); + item->elaborate_subscope_(des, scope); return true; @@ -1395,6 +1403,7 @@ bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container) NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); + scope->add_imports(&imports); elaborate_subscope_(des, scope); @@ -1700,6 +1709,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s my_scope->set_line(get_file(), mod->get_file(), get_lineno(), mod->get_lineno()); my_scope->set_module_name(mod->mod_name()); + my_scope->add_imports(&mod->imports); for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1) my_scope->attribute(attrib_list[adx].key, attrib_list[adx].val); @@ -1924,6 +1934,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const : NetScope::BEGIN_END); my_scope->set_line(get_file(), get_lineno()); my_scope->is_auto(scope->is_auto()); + my_scope->add_imports(&imports); // Scan the parameters in the scope, and store the information // needed to evaluate the parameter expressions. diff --git a/elab_sig.cc b/elab_sig.cc index 4b64ff901..885a9253d 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1214,7 +1214,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } else if (enum_type_t*enum_type = dynamic_cast(set_data_type_)) { list::const_iterator sample_name = enum_type->names->begin(); - const netenum_t*use_enum = scope->find_enumeration_for_name(sample_name->name); + const netenum_t*use_enum = scope->find_enumeration_for_name(des, sample_name->name); if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype diff --git a/elaborate.cc b/elaborate.cc index 1feb9e62c..0185c3031 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -6528,6 +6528,7 @@ Design* elaborate(listroots) PPackage*unit = pform_units[i]; NetScope*scope = des->make_package_scope(unit->pscope_name(), 0, true); scope->set_line(unit); + scope->add_imports(&unit->imports); set_scope_timescale(des, scope, unit); elaborator_work_item_t*es = new elaborate_package_t(des, scope, unit); @@ -6552,6 +6553,7 @@ Design* elaborate(listroots) NetScope*unit_scope = unit_scopes[pac->second->parent_scope()]; NetScope*scope = des->make_package_scope(pac->first, unit_scope, false); scope->set_line(pac->second); + scope->add_imports(&pac->second->imports); set_scope_timescale(des, scope, pac->second); elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second); @@ -6593,6 +6595,7 @@ Design* elaborate(listroots) // Collect some basic properties of this scope from the // Module definition. scope->set_line(rmod); + scope->add_imports(&rmod->imports); set_scope_timescale(des, scope, rmod); // Save this scope, along with its definition, in the diff --git a/net_design.cc b/net_design.cc index b071469e2..6dc0bced0 100644 --- a/net_design.cc +++ b/net_design.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2019 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 @@ -244,7 +244,13 @@ NetScope* Design::find_scope_(NetScope*scope, const std::list&path, /* Up references may match module name */ } else { - scope = scope->child( key ); + NetScope*found_scope = scope->child(key); + if (found_scope == 0) { + found_scope = scope->find_import(this, key.peek_name()); + if (found_scope) + found_scope = found_scope->child(key); + } + scope = found_scope; if (scope == 0) break; } tmp.pop_front(); @@ -319,7 +325,13 @@ NetScope* Design::find_scope_(NetScope*scope, const hname_t&path, /* Up references may match module name */ return scope; } - return scope->child( path ); + NetScope*found_scope = scope->child(path); + if (found_scope == 0) { + found_scope = scope->find_import(this, path.peek_name()); + if (found_scope) + found_scope = found_scope->child(path); + } + return found_scope; } /* @@ -864,6 +876,11 @@ NetNet* Design::find_signal(NetScope*scope, pform_name_t path) if (NetNet*net = scope->find_signal(key)) return net; + if (NetScope*import_scope = scope->find_import(this, key)) { + scope = import_scope; + continue; + } + if (scope->type() == NetScope::MODULE) break; diff --git a/net_scope.cc b/net_scope.cc index 006cbd5c2..480edf3b4 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2019 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 @@ -25,6 +25,7 @@ # include "netclass.h" # include "netenum.h" # include "netvector.h" +# include "PPackage.h" # include # include # include @@ -117,6 +118,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, NetScope*in_u : type_(t), name_(n), nested_module_(nest), program_block_(program), is_interface_(interface), is_unit_(compilation_unit), unit_(in_unit), up_(up) { + imports_ = 0; events_ = 0; lcounter_ = 0; is_auto_ = false; @@ -205,16 +207,38 @@ void NetScope::set_line(perm_string file, perm_string def_file, def_lineno_ = def_lineno; } +void NetScope::add_imports(const map*imports) +{ + if (!imports->empty()) + imports_ = imports; +} + +NetScope*NetScope::find_import(const Design*des, perm_string name) +{ + if (imports_ == 0) + return 0; + + map::const_iterator cur = imports_->find(name); + if (cur != imports_->end()) { + return des->find_package(cur->second->pscope_name()); + } else + return 0; +} + /* * Look for the enumeration in the current scope and any parent scopes. */ -const netenum_t*NetScope::find_enumeration_for_name(perm_string name) +const netenum_t*NetScope::find_enumeration_for_name(const Design*des, perm_string name) { NetScope *cur_scope = this; while (cur_scope) { NetEConstEnum*tmp = cur_scope->enum_names_[name]; if (tmp) break; - cur_scope = cur_scope->parent(); + NetScope*import_scope = cur_scope->find_import(des, name); + if (import_scope) + cur_scope = import_scope; + else + cur_scope = cur_scope->parent(); if (cur_scope == 0) cur_scope = unit_; } diff --git a/netlist.h b/netlist.h index 31cfc889e..17602388e 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ #ifndef IVL_netlist_H #define IVL_netlist_H /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -77,6 +77,7 @@ class NetEvWait; class PClass; class PExpr; class PFunction; +class PPackage; class PTaskFunc; struct enum_type_t; class netclass_t; @@ -942,9 +943,12 @@ class NetScope : public Definitions, public Attrib { if a unique name couldn't be generated. */ bool auto_name(const char* prefix, char pad, const char* suffix); + void add_imports(const map*imports); + NetScope*find_import(const Design*des, perm_string name); + /* Routine to search for the enumeration given a name. It basically * does what enumeration_for_name() does but searched the hierarchy. */ - const netenum_t*find_enumeration_for_name(perm_string name); + const netenum_t*find_enumeration_for_name(const Design*des, perm_string name); /* Parameters exist within a scope, and these methods allow one to manipulate the set. In these cases, the name is the @@ -1269,6 +1273,8 @@ class NetScope : public Definitions, public Attrib { signed char time_unit_, time_prec_; bool time_from_timescale_; + const map*imports_; + NetEvent *events_; map genvars_; diff --git a/symbol_search.cc b/symbol_search.cc index 8b8e22239..527ebe6c5 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -132,6 +132,11 @@ static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, return true; } + if (NetScope*import_scope = scope->find_import(des, path_tail.name)) { + scope = import_scope; + continue; + } + if (recurse_flag) { bool flag = false; hname_t path_item = eval_path_component(des, start_scope, path_tail, flag); From 269ec2f0425b416e2e19303a8414ae5d31508658 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 22 Sep 2019 09:16:10 +0100 Subject: [PATCH 02/16] Remove redundant checks for package imports during parsing. The find_* and symbol_search functions now handle this. --- pform.cc | 57 ++++---------------------------------------------------- pform.h | 5 ++--- 2 files changed, 6 insertions(+), 56 deletions(-) diff --git a/pform.cc b/pform.cc index 000cfd1c7..4b26f8c82 100644 --- a/pform.cc +++ b/pform.cc @@ -663,19 +663,11 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) } /* - * Create a new identifier. Check if this is an imported name. + * Create a new identifier. */ PEIdent* pform_new_ident(const pform_name_t&name) { - LexicalScope*scope = pform_peek_scope(); - map::const_iterator pkg = scope->imports.find(name.front().name); - if (pkg == scope->imports.end()) - return new PEIdent(name); - - // XXXX For now, do not support indexed imported names. - assert(name.back().index.size() == 0); - - return new PEIdent(pkg->second, name); + return new PEIdent(name); } PGenerate* pform_parent_generate(void) @@ -841,29 +833,7 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list&parms) { - PECallFunction*tmp = 0; - - // First try to get the function name from a package. Check - // the imports, and if the name is there, make the function as - // a package member. - do { - if (name.size() != 1) - break; - - perm_string use_name = peek_tail_name(name); - - map::iterator cur_pkg; - cur_pkg = lexical_scope->imports.find(use_name); - if (cur_pkg == lexical_scope->imports.end()) - break; - - tmp = new PECallFunction(cur_pkg->second, use_name, parms); - } while(0); - - if (tmp == 0) { - tmp = new PECallFunction(name, parms); - } - + PECallFunction*tmp = new PECallFunction(name, parms); FILE_NAME(tmp, loc); return tmp; } @@ -872,26 +842,7 @@ PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, const list&parms) { - PCallTask*tmp = 0; - - do { - if (name.size() != 1) - break; - - perm_string use_name = peek_tail_name(name); - - map::iterator cur_pkg; - cur_pkg = lexical_scope->imports.find(use_name); - if (cur_pkg == lexical_scope->imports.end()) - break; - - tmp = new PCallTask(cur_pkg->second, name, parms); - } while (0); - - if (tmp == 0) { - tmp = new PCallTask(name, parms); - } - + PCallTask*tmp = new PCallTask(name, parms); FILE_NAME(tmp, loc); return tmp; } diff --git a/pform.h b/pform.h index 2b9c04f23..3c9c0e9ea 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_H #define IVL_pform_H /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -312,8 +312,7 @@ extern void pform_set_typedef(perm_string name, data_type_t*data_type, std::list*unp_ranges); /* - * This function makes a PECallFunction of the named function. Decide - * if this function is in the scope or is imported from a package. + * This function makes a PECallFunction of the named function. */ extern PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, From b88d91c6177050968f0ca8aa1df9cce3205f6a20 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 23 Sep 2019 23:17:31 +0100 Subject: [PATCH 03/16] Create new base class for all named items that can be added to a scope. Provide a helper function to identify the derived classes when reporting errors. --- Makefile.in | 6 +-- Module.cc | 12 ++++- Module.h | 8 ++-- PClass.cc | 7 ++- PClass.h | 8 ++-- PEvent.cc | 6 ++- PEvent.h | 8 ++-- PFunction.cc | 7 ++- PGate.cc | 7 ++- PGate.h | 8 ++-- PGenerate.cc | 7 ++- PGenerate.h | 8 ++-- PModport.cc | 7 ++- PModport.h | 8 ++-- PNamedItem.cc | 116 +++++++++++++++++++++++++++++++++++++++++++++++++ PNamedItem.h | 57 ++++++++++++++++++++++++ PScope.cc | 7 ++- PScope.h | 8 ++-- PTask.cc | 7 ++- PTask.h | 10 +++-- PWire.cc | 14 +++++- PWire.h | 8 ++-- Statement.cc | 7 ++- Statement.h | 8 ++-- pform_types.cc | 17 +++++++- pform_types.h | 12 +++-- 26 files changed, 330 insertions(+), 48 deletions(-) create mode 100644 PNamedItem.cc create mode 100644 PNamedItem.h diff --git a/Makefile.in b/Makefile.in index fff9534e5..dd9448b03 100644 --- a/Makefile.in +++ b/Makefile.in @@ -118,9 +118,9 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ pform_disciplines.o pform_dump.o pform_package.o pform_pclass.o \ pform_class_type.o pform_string_type.o pform_struct_type.o pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ - Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \ - PGenerate.o PModport.o PPackage.o PScope.o PSpec.o PTask.o PUdp.o \ - PFunction.o PWire.o Statement.o AStatement.o $M $(FF) $(TT) + Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PFunction.o \ + PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o \ + PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT) all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true diff --git a/Module.cc b/Module.cc index c5980637e..a7e5183bc 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -122,3 +122,13 @@ const list& Module::get_gates() const { return gates_; } + +PNamedItem::SymbolType Module::symbol_type() const +{ + if (program_block) + return PROGRAM; + if (is_interface) + return INTERFACE; + + return MODULE; +} diff --git a/Module.h b/Module.h index 411c99f9f..48c83af88 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef IVL_Module_H #define IVL_Module_H /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -28,7 +28,7 @@ # include "HName.h" # include "named.h" # include "PScope.h" -# include "LineInfo.h" +# include "PNamedItem.h" # include "netlist.h" # include "pform_types.h" class PExpr; @@ -54,7 +54,7 @@ class NetScope; * these containers as well. */ -class Module : public PScopeExtra, public LineInfo { +class Module : public PScopeExtra, public PNamedItem { /* The module ports are in general a vector of port_t objects. Each port has a name and an ordered list of @@ -160,6 +160,8 @@ class Module : public PScopeExtra, public LineInfo { bool elaborate_sig(Design*, NetScope*scope) const; + SymbolType symbol_type() const; + private: void dump_specparams_(ostream&out, unsigned indent) const; list gates_; diff --git a/PClass.cc b/PClass.cc index ba44d754a..0964e4951 100644 --- a/PClass.cc +++ b/PClass.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2019 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 @@ -28,3 +28,8 @@ PClass::PClass(perm_string name, LexicalScope*parent) PClass::~PClass() { } + +PNamedItem::SymbolType PClass::symbol_type() const +{ + return CLASS; +} diff --git a/PClass.h b/PClass.h index e5dc1d8a2..55a3b7048 100644 --- a/PClass.h +++ b/PClass.h @@ -1,7 +1,7 @@ #ifndef IVL_PClass_H #define IVL_PClass_H /* - * Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2019 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 @@ -20,7 +20,7 @@ */ # include "PScope.h" -# include "LineInfo.h" +# include "PNamedItem.h" # include "StringHeap.h" # include @@ -32,7 +32,7 @@ class PChainConstructor; * collected. */ -class PClass : public PScopeExtra, public LineInfo { +class PClass : public PScopeExtra, public PNamedItem { public: explicit PClass (perm_string name, LexicalScope*parent); @@ -40,6 +40,8 @@ class PClass : public PScopeExtra, public LineInfo { void dump(std::ostream&out, unsigned indent) const; + SymbolType symbol_type() const; + public: class_type_t*type; }; diff --git a/PEvent.cc b/PEvent.cc index 0f2426404..9bf56ea5b 100644 --- a/PEvent.cc +++ b/PEvent.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2019 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 @@ -35,3 +35,7 @@ perm_string PEvent::name() const return name_; } +PNamedItem::SymbolType PEvent::symbol_type() const +{ + return EVENT; +} diff --git a/PEvent.h b/PEvent.h index 11836d295..ba5bb668b 100644 --- a/PEvent.h +++ b/PEvent.h @@ -1,7 +1,7 @@ #ifndef IVL_PEvent_H #define IVL_PEvent_H /* - * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2019 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 @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -# include "LineInfo.h" +# include "PNamedItem.h" # include "StringHeap.h" # include @@ -31,7 +31,7 @@ class NetScope; * are declared in Verilog as ``event foo;'' The name passed to the * constructor is the "foo" part of the declaration. */ -class PEvent : public LineInfo { +class PEvent : public PNamedItem { public: // The name is a perm-allocated string. It is the simple name @@ -43,6 +43,8 @@ class PEvent : public LineInfo { void elaborate_scope(Design*des, NetScope*scope) const; + SymbolType symbol_type() const; + private: perm_string name_; diff --git a/PFunction.cc b/PFunction.cc index a5dc8f351..215cc5170 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 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 @@ -83,3 +83,8 @@ PChainConstructor* PFunction::extract_chain_constructor() return res; } + +PNamedItem::SymbolType PFunction::symbol_type() const +{ + return FUNCTION; +} diff --git a/PGate.cc b/PGate.cc index 56fd7578c..0429b4690 100644 --- a/PGate.cc +++ b/PGate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 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 @@ -117,6 +117,11 @@ unsigned PGate::delay_count() const return delay_.delay_count(); } +PNamedItem::SymbolType PGate::symbol_type() const +{ + return INSTANCE; +} + PGAssign::PGAssign(list*pins) : PGate(perm_string(), pins) { diff --git a/PGate.h b/PGate.h index ee6f10f79..1f5ce5752 100644 --- a/PGate.h +++ b/PGate.h @@ -1,7 +1,7 @@ #ifndef IVL_PGate_H #define IVL_PGate_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -22,7 +22,7 @@ # include "svector.h" # include "StringHeap.h" # include "named.h" -# include "LineInfo.h" +# include "PNamedItem.h" # include "PDelays.h" # include "netlist.h" # include @@ -47,7 +47,7 @@ class Module; * single strength pair. There is a strength of the 0 drive, and a * strength of the 1 drive. */ -class PGate : public LineInfo { +class PGate : public PNamedItem { public: explicit PGate(perm_string name, list*pins, @@ -88,6 +88,8 @@ class PGate : public LineInfo { virtual void elaborate_scope(Design*des, NetScope*sc) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const; + SymbolType symbol_type() const; + protected: const vector& get_pins() const { return pins_; } diff --git a/PGenerate.cc b/PGenerate.cc index 5e99f1a6e..919b74f87 100644 --- a/PGenerate.cc +++ b/PGenerate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-2019 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 @@ -112,3 +112,8 @@ ostream& operator << (ostream&out, PGenerate::scheme_t type) } return out; } + +PNamedItem::SymbolType PGenerate::symbol_type() const +{ + return GENBLOCK; +} diff --git a/PGenerate.h b/PGenerate.h index 45a37e13d..c08f9cb8b 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -1,7 +1,7 @@ #ifndef IVL_PGenerate_H #define IVL_PGenerate_H /* - * Copyright (c) 2006-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-2019 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 @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -# include "LineInfo.h" +# include "PNamedItem.h" # include "StringHeap.h" # include "HName.h" # include "PScope.h" @@ -50,7 +50,7 @@ class PWire; * The parent points to the GS_CASE that contains this item. * the loop_test is compared with the parent->loop_test expression. */ -class PGenerate : public LineInfo, public LexicalScope { +class PGenerate : public PNamedItem, public LexicalScope { public: explicit PGenerate(LexicalScope*parent, unsigned id_number); @@ -107,6 +107,8 @@ class PGenerate : public LineInfo, public LexicalScope { void dump(ostream&out, unsigned indent) const; + SymbolType symbol_type() const; + private: bool generate_scope_loop_(Design*des, NetScope*container); bool generate_scope_condit_(Design*des, NetScope*container, bool else_flag); diff --git a/PModport.cc b/PModport.cc index 8ce774088..969a49c09 100644 --- a/PModport.cc +++ b/PModport.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2015-2019 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 @@ -29,3 +29,8 @@ PModport::PModport(perm_string n) PModport::~PModport() { } + +PNamedItem::SymbolType PModport::symbol_type() const +{ + return MODPORT; +} diff --git a/PModport.h b/PModport.h index 339154784..417d0b523 100644 --- a/PModport.h +++ b/PModport.h @@ -1,7 +1,7 @@ #ifndef IVL_PModport_H #define IVL_PModport_H /* - * Copyright (c) 2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2015-2019 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 @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -# include "LineInfo.h" +# include "PNamedItem.h" # include "PScope.h" # include "StringHeap.h" # include "netlist.h" @@ -28,7 +28,7 @@ /* * The PModport class represents a parsed SystemVerilog modport list. */ -class PModport : public LineInfo { +class PModport : public PNamedItem { public: // The name is a perm-allocated string. It is the simple name @@ -41,6 +41,8 @@ class PModport : public LineInfo { typedef pair simple_port_t; map simple_ports; + SymbolType symbol_type() const; + private: perm_string name_; diff --git a/PNamedItem.cc b/PNamedItem.cc new file mode 100644 index 000000000..70c33a7ca --- /dev/null +++ b/PNamedItem.cc @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2019 Martin Whitaker (icarus@martin-whitaker.me.uk) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "PNamedItem.h" +# include + +PNamedItem::PNamedItem() +{ +} + +PNamedItem::~PNamedItem() +{ +} + +PNamedItem::SymbolType PNamedItem::symbol_type() const +{ + return ANY; +} + +std::ostream& operator << (std::ostream&o, PNamedItem::SymbolType st) +{ + switch (st) { + case PNamedItem::ANY: + o << "a symbol"; + break; + case PNamedItem::PARAM: + o << "a parameter"; + break; + case PNamedItem::NET: + o << "a net"; + break; + case PNamedItem::VAR: + o << "a variable"; + break; + case PNamedItem::GENVAR: + o << "a genvar"; + break; + case PNamedItem::EVENT: + o << "an event"; + break; + case PNamedItem::TYPE: + o << "a type"; + break; + case PNamedItem::ENUM: + o << "an enum type or value"; + break; + case PNamedItem::CLASS: + o << "a class"; + break; + case PNamedItem::FUNCTION: + o << "a function"; + break; + case PNamedItem::TASK: + o << "a task"; + break; + case PNamedItem::BLOCK: + o << "a named block"; + break; + case PNamedItem::GENBLOCK: + o << "a generate block"; + break; + case PNamedItem::MODPORT: + o << "a modport"; + break; + case PNamedItem::PACKAGE: + o << "a package"; + break; + case PNamedItem::MODULE: + o << "a module"; + break; + case PNamedItem::PROGRAM: + o << "a program"; + break; + case PNamedItem::INTERFACE: + o << "an interface"; + break; + case PNamedItem::PRIMITIVE: + o << "a primitive"; + break; + case PNamedItem::INSTANCE: + o << "an instance name"; + break; + default: + break; + } + return o; +} + +PGenvar::PGenvar() +{ +} + +PGenvar::~PGenvar() +{ +} + +PNamedItem::SymbolType PGenvar::symbol_type() const +{ + return GENVAR; +} diff --git a/PNamedItem.h b/PNamedItem.h new file mode 100644 index 000000000..0b6e791ea --- /dev/null +++ b/PNamedItem.h @@ -0,0 +1,57 @@ +#ifndef IVL_PNamedItem_H +#define IVL_PNamedItem_H +/* + * Copyright (c) 2019 Martin Whitaker (icarus@martin-whitaker.me.uk) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "LineInfo.h" + +/* + * The PNamedItem class is the base class for all items that can be added + * to a scope's local symbol map. + */ +class PNamedItem : virtual public LineInfo { + + public: + enum SymbolType { ANY, PARAM, NET, VAR, GENVAR, EVENT, TYPE, ENUM, + CLASS, FUNCTION, TASK, BLOCK, GENBLOCK, MODPORT, + PACKAGE, MODULE, PROGRAM, INTERFACE, PRIMITIVE, + INSTANCE }; + + explicit PNamedItem(); + virtual ~PNamedItem(); + + virtual SymbolType symbol_type() const; +}; + +extern std::ostream& operator << (std::ostream&, PNamedItem::SymbolType); + +/* + * The PGenvar class represents a genvar. This is only used to represent + * genvar in a scope's local symbol map. + */ +class PGenvar : public PNamedItem { + + public: + explicit PGenvar(); + virtual ~PGenvar(); + + SymbolType symbol_type() const; +}; + +#endif /* IVL_PNamedItem_H */ diff --git a/PScope.cc b/PScope.cc index c0738cc29..787dbf88d 100644 --- a/PScope.cc +++ b/PScope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2019 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 @@ -33,6 +33,11 @@ PWire* LexicalScope::wires_find(perm_string name) return (*cur).second; } +PNamedItem::SymbolType LexicalScope::param_expr_t::symbol_type() const +{ + return PARAM; +} + PScope::PScope(perm_string n, LexicalScope*parent) : LexicalScope(parent), name_(n) { diff --git a/PScope.h b/PScope.h index 24674d6df..9f339a5b2 100644 --- a/PScope.h +++ b/PScope.h @@ -1,7 +1,7 @@ #ifndef IVL_PScope_H #define IVL_PScope_H /* - * Copyright (c) 2008-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2019 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 @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -# include "LineInfo.h" +# include "PNamedItem.h" # include "StringHeap.h" # include "pform_types.h" # include "ivl_target.h" @@ -79,7 +79,7 @@ class LexicalScope { /* The scope has parameters that are evaluated when the scope is elaborated. During parsing, I put the parameters into this map. */ - struct param_expr_t : public LineInfo { + 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; @@ -90,6 +90,8 @@ class LexicalScope { PExpr*expr; // If there are range constraints, list them here range_t*range; + + SymbolType symbol_type() const; }; mapparameters; maplocalparams; diff --git a/PTask.cc b/PTask.cc index 93f8ba10f..bb008ad23 100644 --- a/PTask.cc +++ b/PTask.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 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 @@ -73,3 +73,8 @@ void PTask::set_statement(Statement*s) assert(statement_ == 0); statement_ = s; } + +PNamedItem::SymbolType PTask::symbol_type() const +{ + return TASK; +} diff --git a/PTask.h b/PTask.h index 4c1899d04..1d328ed6c 100644 --- a/PTask.h +++ b/PTask.h @@ -1,7 +1,7 @@ #ifndef IVL_PTask_H #define IVL_PTask_H /* - * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 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 @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -# include "LineInfo.h" # include "PScope.h" +# include "PNamedItem.h" # include "StringHeap.h" # include # include @@ -35,7 +35,7 @@ class Statement; class PExpr; -class PTaskFunc : public PScope, public LineInfo { +class PTaskFunc : public PScope, public PNamedItem { public: PTaskFunc(perm_string name, LexicalScope*parent); @@ -99,6 +99,8 @@ class PTask : public PTaskFunc { void dump(ostream&, unsigned) const; + SymbolType symbol_type() const; + private: Statement*statement_; bool is_auto_; @@ -148,6 +150,8 @@ class PFunction : public PTaskFunc { void dump(ostream&, unsigned) const; + SymbolType symbol_type() const; + private: data_type_t* return_type_; Statement *statement_; diff --git a/PWire.cc b/PWire.cc index 79db562eb..524f18b44 100644 --- a/PWire.cc +++ b/PWire.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 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 @@ -283,3 +283,15 @@ ivl_discipline_t PWire::get_discipline(void) const { return discipline_; } + +PNamedItem::SymbolType PWire::symbol_type() const +{ + switch (type_) { + case NetNet::IMPLICIT_REG: + case NetNet::INTEGER: + case NetNet::REG: + return VAR; + default: + return NET; + } +} diff --git a/PWire.h b/PWire.h index d003d445b..a588797f8 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ #ifndef IVL_PWire_H #define IVL_PWire_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -20,7 +20,7 @@ */ # include "netlist.h" -# include "LineInfo.h" +# include "PNamedItem.h" # include # include # include "StringHeap.h" @@ -51,7 +51,7 @@ enum PWSRType {SR_PORT, SR_NET, SR_BOTH}; * from that perspective, sub-scopes within the module are a part of * the wire name. */ -class PWire : public LineInfo { +class PWire : public PNamedItem { public: PWire(perm_string name, @@ -93,6 +93,8 @@ class PWire : public LineInfo { NetNet* elaborate_sig(Design*, NetScope*scope) const; + SymbolType symbol_type() const; + private: perm_string name_; NetNet::Type type_; diff --git a/Statement.cc b/Statement.cc index 92a87a12d..696ef44bd 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -158,6 +158,11 @@ void PBlock::push_statement_front(Statement*that) list_[0] = that; } +PNamedItem::SymbolType PBlock::symbol_type() const +{ + return BLOCK; +} + PCallTask::PCallTask(const pform_name_t&n, const list&p) : package_(0), path_(n), parms_(p.size()) { diff --git a/Statement.h b/Statement.h index 30f3b8229..91ed3828d 100644 --- a/Statement.h +++ b/Statement.h @@ -1,7 +1,7 @@ #ifndef IVL_Statement_H #define IVL_Statement_H /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -75,7 +75,7 @@ class PProcess : public LineInfo { * fact, the Statement class is abstract and represents all the * possible kinds of statements that exist in Verilog. */ -class Statement : public LineInfo { +class Statement : virtual public LineInfo { public: Statement() { } @@ -170,7 +170,7 @@ class PAssignNB : public PAssign_ { * statements before constructing this object, so it knows a priori * what is contained. */ -class PBlock : public PScope, public Statement { +class PBlock : public PScope, public Statement, public PNamedItem { public: enum BL_TYPE { BL_SEQ, BL_PAR, BL_JOIN_NONE, BL_JOIN_ANY }; @@ -205,6 +205,8 @@ class PBlock : public PScope, public Statement { virtual void elaborate_scope(Design*des, NetScope*scope) const; virtual void elaborate_sig(Design*des, NetScope*scope) const; + SymbolType symbol_type() const; + private: BL_TYPE bl_type_; std::vectorlist_; diff --git a/pform_types.cc b/pform_types.cc index 8d8d430d0..72f312619 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2019 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 @@ -24,6 +24,11 @@ data_type_t::~data_type_t() { } +PNamedItem::SymbolType data_type_t::symbol_type() const +{ + return TYPE; +} + string_type_t::~string_type_t() { } @@ -44,3 +49,13 @@ ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const } atom2_type_t size_type (32, true); + +PNamedItem::SymbolType enum_type_t::symbol_type() const +{ + return ENUM; +} + +PNamedItem::SymbolType class_type_t::symbol_type() const +{ + return CLASS; +} diff --git a/pform_types.h b/pform_types.h index 92061527e..a7aaaad13 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_types_H #define IVL_pform_types_H /* - * Copyright (c) 2007-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2019 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,7 +21,7 @@ // This for the perm_string type. # include "StringHeap.h" -# include "LineInfo.h" +# include "PNamedItem.h" # include "verinum.h" # include "named.h" # include "netstruct.h" @@ -137,7 +137,7 @@ struct pform_tf_port_t { * "data_type" rule in the parse rule. We make the type virtual so * that dynamic types will work. */ -class data_type_t : public LineInfo { +class data_type_t : public PNamedItem { public: inline explicit data_type_t() { } virtual ~data_type_t() = 0; @@ -149,6 +149,8 @@ class data_type_t : public LineInfo { ivl_type_s* elaborate_type(Design*des, NetScope*scope); + virtual SymbolType symbol_type() const; + private: // Elaborate the type to an ivl_type_s type. virtual ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; @@ -171,6 +173,8 @@ struct enum_type_t : public data_type_t { // Return the elaborated version of the type. virtual ivl_type_s*elaborate_type_raw(Design*des, NetScope*scope) const; + SymbolType symbol_type() const; + ivl_variable_type_t base_type; bool signed_flag; bool integer_flag; // True if "integer" was used @@ -335,6 +339,8 @@ struct class_type_t : public data_type_t { // type. The elaborate_type_raw() method uses this pointer, // and it is used in some other situations as well. netclass_t* save_elaborated_type; + + virtual SymbolType symbol_type() const; }; /* From d3bced57cce251eb8f490be51807c55e33537a5a Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 26 Sep 2019 23:35:57 +0100 Subject: [PATCH 04/16] Correctly handle explicit and wildcard package imports. Explicit imports should always conflict with local declarations using the same name. Wildcard imports only conflict if they are referenced before a local declaration with the same name. This also unifies the detection of identifier conflicts. --- PScope.h | 16 +- elab_scope.cc | 20 +-- elaborate.cc | 6 +- lexor.lex | 6 +- parse.y | 20 +-- parse_misc.h | 4 +- pform.cc | 403 +++++++++++++++++++++++------------------------ pform.h | 4 +- pform_package.cc | 112 +++++-------- 9 files changed, 278 insertions(+), 313 deletions(-) diff --git a/PScope.h b/PScope.h index 9f339a5b2..1c0760ad5 100644 --- a/PScope.h +++ b/PScope.h @@ -61,6 +61,18 @@ class LexicalScope { lifetime_t default_lifetime; + // Symbols that are defined or declared in this scope. + std::maplocal_symbols; + + // Symbols that are explicitly imported. Bind the imported name + // to the package from which the name is imported. + std::mapexplicit_imports; + + // Packages that are wildcard imported. When identifiers from + // these packages are referenced, they will be added to the + // explicit imports (IEEE 1800-2012 26.3). + std::setpotential_imports; + struct range_t { // True if this is an exclude bool exclude_flag; @@ -102,10 +114,6 @@ class LexicalScope { // Named events in the scope. mapevents; - // Symbols that are imported. Bind the imported name to the - // package from which the name is imported. - std::mapimports; - // Nets and variables (wires) in the scope mapwires; PWire* wires_find(perm_string name); diff --git a/elab_scope.cc b/elab_scope.cc index bb3592d2d..4afd4b680 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -542,7 +542,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // Task methods are always automatic... method_scope->is_auto(true); method_scope->set_line(cur->second); - method_scope->add_imports(&cur->second->imports); + method_scope->add_imports(&cur->second->explicit_imports); if (debug_scopes) { cerr << cur->second->get_fileline() << ": elaborate_scope_class: " @@ -561,7 +561,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // Function methods are always automatic... method_scope->is_auto(true); method_scope->set_line(cur->second); - method_scope->add_imports(&cur->second->imports); + method_scope->add_imports(&cur->second->explicit_imports); if (debug_scopes) { cerr << cur->second->get_fileline() << ": elaborate_scope_class: " @@ -632,7 +632,7 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task) NetScope*task_scope = new NetScope(scope, use_name, NetScope::TASK); task_scope->is_auto(task->is_auto()); task_scope->set_line(task); - task_scope->add_imports(&task->imports); + task_scope->add_imports(&task->explicit_imports); if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_task: " @@ -695,7 +695,7 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task) NetScope*task_scope = new NetScope(scope, use_name, NetScope::FUNC); task_scope->is_auto(task->is_auto()); task_scope->set_line(task); - task_scope->add_imports(&task->imports); + task_scope->add_imports(&task->explicit_imports); if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_func: " @@ -1069,7 +1069,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); - scope->add_imports(&imports); + scope->add_imports(&explicit_imports); // Set in the scope a localparam for the value of the // genvar within this instance of the generate @@ -1205,7 +1205,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else // for myself. That is what I will pass to the subscope. NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); - scope->add_imports(&imports); + scope->add_imports(&explicit_imports); elaborate_subscope_(des, scope); @@ -1346,7 +1346,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); - scope->add_imports(&imports); + scope->add_imports(&explicit_imports); item->elaborate_subscope_(des, scope); @@ -1403,7 +1403,7 @@ bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container) NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK); scope->set_line(get_file(), get_lineno()); - scope->add_imports(&imports); + scope->add_imports(&explicit_imports); elaborate_subscope_(des, scope); @@ -1709,7 +1709,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s my_scope->set_line(get_file(), mod->get_file(), get_lineno(), mod->get_lineno()); my_scope->set_module_name(mod->mod_name()); - my_scope->add_imports(&mod->imports); + my_scope->add_imports(&mod->explicit_imports); for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1) my_scope->attribute(attrib_list[adx].key, attrib_list[adx].val); @@ -1934,7 +1934,7 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const : NetScope::BEGIN_END); my_scope->set_line(get_file(), get_lineno()); my_scope->is_auto(scope->is_auto()); - my_scope->add_imports(&imports); + my_scope->add_imports(&explicit_imports); // Scan the parameters in the scope, and store the information // needed to evaluate the parameter expressions. diff --git a/elaborate.cc b/elaborate.cc index 0185c3031..61ea115f4 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -6528,7 +6528,7 @@ Design* elaborate(listroots) PPackage*unit = pform_units[i]; NetScope*scope = des->make_package_scope(unit->pscope_name(), 0, true); scope->set_line(unit); - scope->add_imports(&unit->imports); + scope->add_imports(&unit->explicit_imports); set_scope_timescale(des, scope, unit); elaborator_work_item_t*es = new elaborate_package_t(des, scope, unit); @@ -6553,7 +6553,7 @@ Design* elaborate(listroots) NetScope*unit_scope = unit_scopes[pac->second->parent_scope()]; NetScope*scope = des->make_package_scope(pac->first, unit_scope, false); scope->set_line(pac->second); - scope->add_imports(&pac->second->imports); + scope->add_imports(&pac->second->explicit_imports); set_scope_timescale(des, scope, pac->second); elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second); @@ -6595,7 +6595,7 @@ Design* elaborate(listroots) // Collect some basic properties of this scope from the // Module definition. scope->set_line(rmod); - scope->add_imports(&rmod->imports); + scope->add_imports(&rmod->explicit_imports); set_scope_timescale(des, scope, rmod); // Save this scope, along with its definition, in the diff --git a/lexor.lex b/lexor.lex index 37c3e0207..d5cad1f7b 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -362,7 +362,7 @@ TU [munpf] /* If this identifier names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { - if (data_type_t*type = pform_test_type_identifier(yylval.text)) { + if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) { yylval.type_identifier.text = yylval.text; yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; @@ -383,7 +383,7 @@ TU [munpf] } } if (gn_system_verilog()) { - if (data_type_t*type = pform_test_type_identifier(yylval.text)) { + if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) { yylval.type_identifier.text = yylval.text; yylval.type_identifier.type = type; return TYPE_IDENTIFIER; diff --git a/parse.y b/parse.y index ce8e18b3b..28154625a 100644 --- a/parse.y +++ b/parse.y @@ -1428,7 +1428,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ { pform_name_t tmp_hident; tmp_hident.push_back(name_component_t(lex_strings.make($4))); - PEIdent*tmp_ident = pform_new_ident(tmp_hident); + PEIdent*tmp_ident = pform_new_ident(@4, tmp_hident); FILE_NAME(tmp_ident, @4); PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13); @@ -3604,7 +3604,7 @@ expr_primary indexed arrays and part selects */ | hierarchy_identifier - { PEIdent*tmp = pform_new_ident(*$1); + { PEIdent*tmp = pform_new_ident(@1, *$1); FILE_NAME(tmp, @1); $$ = tmp; delete $1; @@ -4500,7 +4500,7 @@ atom2_type rule to reflect the rules for assignment l-values. */ lpvalue : hierarchy_identifier - { PEIdent*tmp = pform_new_ident(*$1); + { PEIdent*tmp = pform_new_ident(@1, *$1); FILE_NAME(tmp, @1); $$ = tmp; delete $1; @@ -5040,24 +5040,24 @@ module_item IDENTIFIER '=' expression ')' { pform_start_generate_for(@1, $3, $5, $7, $9, $11); } generate_block - { pform_endgenerate(); } + { pform_endgenerate(false); } | generate_if generate_block_opt K_else { pform_start_generate_else(@1); } generate_block - { pform_endgenerate(); } + { pform_endgenerate(true); } | generate_if generate_block_opt %prec less_than_K_else - { pform_endgenerate(); } + { pform_endgenerate(true); } | K_case '(' expression ')' { pform_start_generate_case(@1, $3); } generate_case_items K_endcase - { pform_endgenerate(); } + { pform_endgenerate(true); } | modport_declaration @@ -5154,9 +5154,9 @@ generate_case_items generate_case_item : expression_list_proper ':' { pform_generate_case_item(@1, $1); } generate_block_opt - { pform_endgenerate(); } + { pform_endgenerate(false); } | K_default ':' { pform_generate_case_item(@1, 0); } generate_block_opt - { pform_endgenerate(); } + { pform_endgenerate(false); } ; generate_item @@ -5177,7 +5177,7 @@ generate_item warn_count += 1; cerr << @1 << ": warning: Anachronistic use of named begin/end to surround generate schemes." << endl; } - pform_endgenerate(); + pform_endgenerate(false); } ; diff --git a/parse_misc.h b/parse_misc.h index 05c35fb01..58f5aea98 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-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2019 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 @@ -88,7 +88,7 @@ extern void lex_in_package_scope(PPackage*pkg); * parser detects typedefs and marks the typedef'ed identifiers as * type names. */ -extern data_type_t* pform_test_type_identifier(const char*txt); +extern data_type_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt); extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt); extern bool pform_test_type_identifier_local(perm_string txt); diff --git a/pform.cc b/pform.cc index 4b26f8c82..d6b41f3d3 100644 --- a/pform.cc +++ b/pform.cc @@ -349,6 +349,13 @@ static unsigned scope_generate_counter = 1; always within a module. */ static PGenerate*pform_cur_generate = 0; + /* Blocks within the same conditional generate construct may have + the same name. Here we collect the set of names used in each + construct, so they can be added to the local scope without + conflicting with each other. Generate constructs may nest, so + we need a stack. */ +static list> conditional_block_names; + /* This tracks the current modport list being processed. This is always within an interface. */ static PModport*pform_cur_modport = 0; @@ -423,6 +430,87 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) return scopex; } +static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*item) +{ + assert(scope); + + // Check for conflict with another local symbol. + map::const_iterator cur_sym + = scope->local_symbols.find(name); + if (cur_sym != scope->local_symbols.end()) { + cerr << item->get_fileline() << ": error: " + "'" << name << "' has already been declared " + "in this scope." << endl; + cerr << cur_sym->second->get_fileline() << ": : " + "It was declared here as " + << cur_sym->second->symbol_type() << "." << endl; + error_count += 1; + return; + } + + // Check for conflict with an explicit import. + map::const_iterator cur_pkg + = scope->explicit_imports.find(name); + if (cur_pkg != scope->explicit_imports.end()) { + cerr << item->get_fileline() << ": error: " + "'" << name << "' has already been " + "imported into this scope from package '" + << cur_pkg->second->pscope_name() << "'." << endl; + error_count += 1; + return; + } + + scope->local_symbols[name] = item; +} + +static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*scope, + perm_string name, PNamedItem::SymbolType st) +{ + assert(scope); + + PPackage*found_pkg = 0; + for (set::const_iterator cur_pkg = scope->potential_imports.begin(); + cur_pkg != scope->potential_imports.end(); ++cur_pkg) { + PPackage*search_pkg = *cur_pkg; + map::const_iterator cur_sym + = search_pkg->local_symbols.find(name); + if (cur_sym != search_pkg->local_symbols.end()) { + if (st != PNamedItem::ANY && st != cur_sym->second->symbol_type()) + continue; + + if (found_pkg) { + cerr << loc.get_fileline() << ": error: " + "Ambiguous use of '" << name << "'. " + "It is exported by both '" + << found_pkg->pscope_name() + << "' and by '" + << search_pkg->pscope_name() + << "'." << endl; + error_count += 1; + } else { + found_pkg = search_pkg; + scope->explicit_imports[name] = found_pkg; + } + } + } + return found_pkg; +} + +static void check_potential_imports(const struct vlltype&loc, perm_string name) +{ + LexicalScope*scope = lexical_scope; + while (scope) { + if (scope->local_symbols.find(name) != scope->local_symbols.end()) + return; + if (scope->explicit_imports.find(name) != scope->explicit_imports.end()) + return; + if (find_potential_import(loc, scope, name, PNamedItem::ANY)) + return; + + scope = scope->parent_scope(); + } +} + /* * Set the local time unit/precision. This version is used for setting * the time scale for design elements (modules, packages, etc.) and is @@ -516,12 +604,6 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name, pform_set_scope_timescale(class_scope, scopex); - if (scopex->classes.find(name) != scopex->classes.end()) { - cerr << class_scope->get_fileline() << ": error: duplicate " - "definition for class '" << name << "' in '" - << scopex->pscope_name() << "'." << endl; - error_count += 1; - } scopex->classes[name] = class_scope; scopex->classes_lexical .push_back(class_scope); @@ -566,25 +648,11 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, pform_set_scope_timescale(task, scopex); if (pform_cur_generate) { - // Check if the task is already in the dictionary. - if (pform_cur_generate->tasks.find(task->pscope_name()) != - pform_cur_generate->tasks.end()) { - cerr << task->get_fileline() << ": error: duplicate " - "definition for task '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "' (generate)." - << endl; - error_count += 1; - } - pform_cur_generate->tasks[task->pscope_name()] = task; + add_local_symbol(pform_cur_generate, task_name, task); + pform_cur_generate->tasks[task_name] = task; } else { - // Check if the task is already in the dictionary. - if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) { - cerr << task->get_fileline() << ": error: duplicate " - "definition for task '" << name << "' in '" - << scopex->pscope_name() << "'." << endl; - error_count += 1; - } - scopex->tasks[task->pscope_name()] = task; + add_local_symbol(scopex, task_name, task); + scopex->tasks[task_name] = task; } lexical_scope = task; @@ -615,26 +683,12 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, pform_set_scope_timescale(func, scopex); if (pform_cur_generate) { - // Check if the function is already in the dictionary. - if (pform_cur_generate->funcs.find(func->pscope_name()) != - pform_cur_generate->funcs.end()) { - cerr << func->get_fileline() << ": error: duplicate " - "definition for function '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "' (generate)." - << endl; - error_count += 1; - } - pform_cur_generate->funcs[func->pscope_name()] = func; + add_local_symbol(pform_cur_generate, func_name, func); + pform_cur_generate->funcs[func_name] = func; } else { - // Check if the function is already in the dictionary. - if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) { - cerr << func->get_fileline() << ": error: duplicate " - "definition for function '" << name << "' in '" - << scopex->pscope_name() << "'." << endl; - error_count += 1; - } - scopex->funcs[func->pscope_name()] = func; + add_local_symbol(scopex, func_name, func); + scopex->funcs[func_name] = func; } lexical_scope = func; @@ -657,6 +711,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) PBlock*block = new PBlock(block_name, lexical_scope, bt); block->default_lifetime = find_lifetime(LexicalScope::INHERITED); + if (name) add_local_symbol(lexical_scope, block_name, block); lexical_scope = block; return block; @@ -665,8 +720,11 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) /* * Create a new identifier. */ -PEIdent* pform_new_ident(const pform_name_t&name) +PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) { + if (gn_system_verilog() && name.size() == 1) + check_potential_imports(loc, name.back().name); + return new PEIdent(name); } @@ -721,6 +779,7 @@ PWire*pform_get_wire_in_scope(perm_string name) static void pform_put_wire_in_scope(perm_string name, PWire*net) { + add_local_symbol(lexical_scope, name, net); lexical_scope->wires[name] = net; } @@ -729,7 +788,7 @@ static void pform_put_enum_type_in_scope(enum_type_t*enum_set) lexical_scope->enum_sets.insert(enum_set); } -PWire*pform_get_make_wire_in_scope(const struct vlltype&li, perm_string name, +PWire*pform_get_make_wire_in_scope(const struct vlltype&, perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) { @@ -737,15 +796,11 @@ PWire*pform_get_make_wire_in_scope(const struct vlltype&li, perm_string name, // If the wire already exists and is fully defined, this // must be a redeclaration. Start again with a new wire. - if (cur && cur->get_data_type() != IVL_VT_NO_TYPE) { - LineInfo tloc; - FILE_NAME(&tloc, li); - cerr << tloc.get_fileline() << ": error: duplicate declaration " - "for net or variable '" << name << "'." << endl; - error_count += 1; - delete cur; + // The error will be reported when we add the new wire + // to the scope. Do not delete the old wire - it will + // remain in the local symbol map. + if (cur && cur->get_data_type() != IVL_VT_NO_TYPE) cur = 0; - } if (cur == 0) { cur = new PWire(name, net_type, port_type, vt_type); @@ -765,6 +820,8 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::listtypedefs[name]; ivl_assert(*data_type, ref == 0); @@ -772,10 +829,14 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::list(data_type)) { pform_put_enum_type_in_scope(enum_type); + + list::const_iterator cur; + for (cur = enum_type->names->begin(); cur != enum_type->names->end(); ++cur) + add_local_symbol(lexical_scope, cur->name, enum_type); } } -data_type_t* pform_test_type_identifier(const char*txt) +data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) { perm_string name = lex_strings.make(txt); @@ -790,8 +851,8 @@ data_type_t* pform_test_type_identifier(const char*txt) // the name has at least shadowed any other possible // meaning for this name. map::iterator cur_pkg; - cur_pkg = cur_scope->imports.find(name); - if (cur_pkg != cur_scope->imports.end()) { + cur_pkg = cur_scope->explicit_imports.find(name); + if (cur_pkg != cur_scope->explicit_imports.end()) { PPackage*pkg = cur_pkg->second; cur = pkg->typedefs.find(name); if (cur != pkg->typedefs.end()) @@ -805,6 +866,13 @@ data_type_t* pform_test_type_identifier(const char*txt) if (cur != cur_scope->typedefs.end()) return cur->second; + PPackage*pkg = find_potential_import(loc, cur_scope, name, PNamedItem::TYPE); + if (pkg) { + cur = pkg->typedefs.find(name); + if (cur != cur_scope->typedefs.end()) + return cur->second; + } + cur_scope = cur_scope->parent_scope(); } while (cur_scope); @@ -833,6 +901,9 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list&parms) { + if (gn_system_verilog() && name.size() == 1) + check_potential_imports(loc, name.back().name); + PECallFunction*tmp = new PECallFunction(name, parms); FILE_NAME(tmp, loc); return tmp; @@ -842,6 +913,9 @@ PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, const list&parms) { + if (gn_system_verilog() && name.size() == 1) + check_potential_imports(loc, name.back().name); + PCallTask*tmp = new PCallTask(name, parms); FILE_NAME(tmp, loc); return tmp; @@ -1224,6 +1298,8 @@ void pform_startmodule(const struct vlltype&loc, const char*name, allow_timeunit_decl = true; allow_timeprec_decl = true; + add_local_symbol(lexical_scope, lex_name, cur_module); + lexical_scope = cur_module; /* The generate scheme numbering starts with *1*, not @@ -1307,31 +1383,20 @@ void pform_endmodule(const char*name, bool inside_celldefine, pform_pop_scope(); } -static void pform_add_genvar(const struct vlltype&li, const perm_string&name, - map&genvars) -{ - LineInfo*lni = new LineInfo(); - FILE_NAME(lni, li); - if (genvars.find(name) != genvars.end()) { - cerr << lni->get_fileline() << ": error: genvar '" - << name << "' has already been declared." << endl; - cerr << genvars[name]->get_fileline() - << ": the previous declaration is here." << endl; - error_count += 1; - delete lni; - } else { - genvars[name] = lni; - } -} - void pform_genvars(const struct vlltype&li, list*names) { list::const_iterator cur; for (cur = names->begin(); cur != names->end() ; *cur++) { - if (pform_cur_generate) - pform_add_genvar(li, *cur, pform_cur_generate->genvars); - else - pform_add_genvar(li, *cur, pform_cur_module.front()->genvars); + 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; + } else { + add_local_symbol(pform_cur_module.front(), *cur, genvar); + pform_cur_module.front()->genvars[*cur] = genvar; + } } delete names; @@ -1374,6 +1439,8 @@ void pform_start_generate_if(const struct vlltype&li, PExpr*test) pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = test; pform_cur_generate->loop_step = 0; + + conditional_block_names.push_front(set()); } void pform_start_generate_else(const struct vlltype&li) @@ -1382,7 +1449,7 @@ void pform_start_generate_else(const struct vlltype&li) assert(pform_cur_generate->scheme_type == PGenerate::GS_CONDIT); PGenerate*cur = pform_cur_generate; - pform_endgenerate(); + pform_endgenerate(false); PGenerate*gen = new PGenerate(lexical_scope, scope_generate_counter++); lexical_scope = gen; @@ -1416,6 +1483,8 @@ void pform_start_generate_case(const struct vlltype&li, PExpr*expr) pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = expr; pform_cur_generate->loop_step = 0; + + conditional_block_names.push_front(set()); } /* @@ -1438,6 +1507,10 @@ void pform_start_generate_nblock(const struct vlltype&li, char*name) pform_cur_generate->scope_name = lex_strings.make(name); delete[]name; + + add_local_symbol(pform_cur_generate->parent_scope(), + pform_cur_generate->scope_name, + pform_cur_generate); } /* @@ -1479,14 +1552,31 @@ void pform_generate_block_name(char*name) { assert(pform_cur_generate != 0); assert(pform_cur_generate->scope_name == 0); - pform_cur_generate->scope_name = lex_strings.make(name); + perm_string scope_name = lex_strings.make(name); + pform_cur_generate->scope_name = scope_name; + + if (pform_cur_generate->scheme_type == PGenerate::GS_CONDIT + || pform_cur_generate->scheme_type == PGenerate::GS_ELSE + || pform_cur_generate->scheme_type == PGenerate::GS_CASE_ITEM) { + + if (conditional_block_names.front().count(scope_name)) + return; + + conditional_block_names.front().insert(scope_name); + } + + add_local_symbol(pform_cur_generate->parent_scope(), + scope_name, pform_cur_generate); } -void pform_endgenerate() +void pform_endgenerate(bool end_conditional) { assert(pform_cur_generate != 0); assert(! pform_cur_module.empty()); + if (end_conditional) + conditional_block_names.pop_front(); + // If there is no explicit block name then generate a temporary // name. This will be replaced by the correct name later, once // we know all the explicit names in the surrounding scope. If @@ -1975,18 +2065,10 @@ static void pform_set_net_range(list*names, */ static void pform_make_event(perm_string name, const char*fn, unsigned ln) { - // Check if the named event is already in the dictionary. - if (lexical_scope->events.find(name) != lexical_scope->events.end()) { - LineInfo tloc; - FILE_NAME(&tloc, fn, ln); - cerr << tloc.get_fileline() << ": error: duplicate definition " - "for named event '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "'." << endl; - error_count += 1; - } - PEvent*event = new PEvent(name); FILE_NAME(event, fn, ln); + + add_local_symbol(lexical_scope, name, event); lexical_scope->events[name] = event; } @@ -2040,10 +2122,13 @@ static void pform_makegate(PGBuiltin::Type type, cur->strength1(str.str1); FILE_NAME(cur, info.file, info.lineno); - if (pform_cur_generate) + if (pform_cur_generate) { + if (dev_name != "") add_local_symbol(pform_cur_generate, dev_name, cur); pform_cur_generate->add_gate(cur); - else + } else { + if (dev_name != "") add_local_symbol(pform_cur_module.front(), dev_name, cur); pform_cur_module.front()->add_gate(cur); + } } void pform_makegates(const struct vlltype&loc, @@ -2120,10 +2205,13 @@ static void pform_make_modgate(perm_string type, cur->set_parameters(overrides->by_order); } - if (pform_cur_generate) + if (pform_cur_generate) { + if (name != "") add_local_symbol(pform_cur_generate, name, cur); pform_cur_generate->add_gate(cur); - else + } else { + if (name != "") add_local_symbol(pform_cur_module.front(), name, cur); pform_cur_module.front()->add_gate(cur); + } pform_bind_attributes(cur->attributes, attr); } @@ -2165,11 +2253,13 @@ static void pform_make_modgate(perm_string type, cur->set_parameters(overrides->by_order); } - - if (pform_cur_generate) + if (pform_cur_generate) { + add_local_symbol(pform_cur_generate, name, cur); pform_cur_generate->add_gate(cur); - else + } else { + add_local_symbol(pform_cur_module.front(), name, cur); pform_cur_module.front()->add_gate(cur); + } pform_bind_attributes(cur->attributes, attr); } @@ -2505,20 +2595,15 @@ static PWire* pform_get_or_make_wire(const vlltype&li, perm_string name, // If the wire already exists and is fully defined, this // must be a redeclaration. Start again with a new wire. - if (cur) { - LineInfo tloc; - FILE_NAME(&tloc, li); - cerr << tloc.get_fileline() << ": error: duplicate declaration " - "for net or variable '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "'." << endl; - error_count += 1; - delete cur; - } + // The error will be reported when we add the new wire + // to the scope. Do not delete the old wire - it will + // remain in the local symbol map. cur = new PWire(name, type, ptype, dtype); FILE_NAME(cur, li.text, li.first_line); pform_put_wire_in_scope(name, cur); + return cur; } @@ -2972,38 +3057,6 @@ void pform_set_parameter(const struct vlltype&loc, VLerror("parameter declarations are not permitted in generate blocks"); return; } - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - assert(scopex); - - // Check if the parameter name is already in the dictionary. - if (scope->parameters.find(name) != scope->parameters.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: duplicate definition " - "for parameter '" << name << "' in '" - << scopex->pscope_name() << "'." << endl; - error_count += 1; - } - if (scope->localparams.find(name) != scope->localparams.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: localparam and " - << "parameter in '" << scopex->pscope_name() - << "' have the same name '" << name << "'." << endl; - error_count += 1; - } - // Only a Module scope has specparams. - if ((dynamic_cast (scope)) && - (scope == pform_cur_module.front()) && - (pform_cur_module.front()->specparams.find(name) != - pform_cur_module.front()->specparams.end())) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: specparam and " - "parameter in '" << scopex->pscope_name() - << "' have the same name '" << name << "'." << endl; - error_count += 1; - } assert(expr); Module::param_expr_t&parm = scope->parameters[name]; @@ -3026,9 +3079,10 @@ void pform_set_parameter(const struct vlltype&loc, parm.signed_flag = signed_flag; parm.range = value_range; + add_local_symbol(scope, name, &parm); + // Only a Module keeps the position of the parameter. - if ((dynamic_cast (scope)) && - (scope == pform_cur_module.front())) + if ((dynamic_cast(scope)) && (scope == pform_cur_module.front())) pform_cur_module.front()->param_names.push_back(name); } @@ -3041,37 +3095,6 @@ void pform_set_localparam(const struct vlltype&loc, VLerror(loc, "error: localparam declarations must be contained within a module."); return; } - PScopeExtra*scopex = find_nearest_scopex(lexical_scope); - assert(scopex); - - // Check if the localparam name is already in the dictionary. - if (scope->localparams.find(name) != scope->localparams.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: duplicate definition " - "for localparam '" << name << "' in '" - << scopex->pscope_name() << "'." << endl; - error_count += 1; - } - if (scope->parameters.find(name) != scope->parameters.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: parameter and " - << "localparam in '" << scopex->pscope_name() - << "' have the same name '" << name << "'." << endl; - error_count += 1; - } - - if ((! pform_cur_module.empty()) && - (scope == pform_cur_module.front()) && - (pform_cur_module.front()->specparams.find(name) != pform_cur_module.front()->specparams.end())) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: specparam and " - "localparam in '" << scopex->pscope_name() - << "' have the same name '" << name << "'." << endl; - error_count += 1; - } assert(expr); Module::param_expr_t&parm = scope->localparams[name]; @@ -3093,6 +3116,8 @@ void pform_set_localparam(const struct vlltype&loc, } parm.signed_flag = signed_flag; parm.range = 0; + + add_local_symbol(scope, name, &parm); } void pform_set_specparam(const struct vlltype&loc, perm_string name, @@ -3102,35 +3127,7 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name, Module*scope = pform_cur_module.front(); assert(scope == lexical_scope); - // Check if the specparam name is already in the dictionary. - if (pform_cur_module.front()->specparams.find(name) != - pform_cur_module.front()->specparams.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: duplicate definition " - "for specparam '" << name << "' in '" - << pform_cur_module.front()->mod_name() << "'." << endl; - error_count += 1; - } - if (scope->parameters.find(name) != scope->parameters.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: parameter and " - "specparam in '" << pform_cur_module.front()->mod_name() - << "' have the same name '" << name << "'." << endl; - error_count += 1; - } - if (scope->localparams.find(name) != scope->localparams.end()) { - LineInfo tloc; - FILE_NAME(&tloc, loc); - cerr << tloc.get_fileline() << ": error: localparam and " - "specparam in '" << pform_cur_module.front()->mod_name() - << "' have the same name '" << name << "'." << endl; - error_count += 1; - } - assert(expr); - Module::param_expr_t&parm = pform_cur_module.front()->specparams[name]; FILE_NAME(&parm, loc); @@ -3151,6 +3148,8 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name, } parm.signed_flag = false; parm.range = 0; + + add_local_symbol(scope, name, &parm); } void pform_set_defparam(const pform_name_t&name, PExpr*expr) @@ -3572,12 +3571,10 @@ void pform_start_modport_item(const struct vlltype&loc, const char*name) perm_string use_name = lex_strings.make(name); pform_cur_modport = new PModport(use_name); FILE_NAME(pform_cur_modport, loc); - if (scope->modports.find(use_name) != scope->modports.end()) { - cerr << loc << ": error: duplicate declaration for modport '" - << name << "' in '" << scope->mod_name() << "'." << endl; - error_count += 1; - } + + add_local_symbol(scope, use_name, pform_cur_modport); scope->modports[use_name] = pform_cur_modport; + delete[] name; } diff --git a/pform.h b/pform.h index 3c9c0e9ea..cd1fb5c88 100644 --- a/pform.h +++ b/pform.h @@ -246,7 +246,7 @@ extern void pform_add_modport_port(const struct vlltype&loc, * This creates an identifier aware of names that may have been * imported from other packages. */ -extern PEIdent* pform_new_ident(const pform_name_t&name); +extern PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name); /* * Enter/exit name scopes. The push_scope function pushes the scope @@ -299,7 +299,7 @@ extern void pform_start_generate_case(const struct vlltype&lp, PExpr*test); extern void pform_start_generate_nblock(const struct vlltype&lp, char*name); extern void pform_generate_case_item(const struct vlltype&lp, list*test); extern void pform_generate_block_name(char*name); -extern void pform_endgenerate(); +extern void pform_endgenerate(bool end_conditional); /* * This function returns the lexically containing generate scheme, if diff --git a/pform_package.cc b/pform_package.cc index 72ac9c6b3..22ec72c38 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2019 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -72,98 +72,58 @@ void pform_end_package_declaration(const struct vlltype&loc) * package is declared in pform ahead of time (it is) and that we can * simply transfer definitions to the current scope (we can). */ -void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident) +void pform_package_import(const struct vlltype&loc, PPackage*pkg, const char*ident) { LexicalScope*scope = pform_peek_scope(); if (ident) { perm_string use_ident = lex_strings.make(ident); - map::const_iterator cur - = pkg->parameters.find(use_ident); - if (cur != pkg->parameters.end()) { - scope->imports[cur->first] = pkg; + // Check that the requested symbol is available. + map::const_iterator cur_sym + = pkg->local_symbols.find(use_ident); + if (cur_sym == pkg->local_symbols.end()) { + cerr << loc.get_fileline() << ": error: " + "'" << use_ident << "' is not exported by '" + << pkg->pscope_name() << "'." << endl; + error_count += 1; return; } - cur = pkg->localparams.find(use_ident); - if (cur != pkg->localparams.end()) { - scope->imports[cur->first] = pkg; + // Check for conflict with local symbol. + cur_sym = scope->local_symbols.find(use_ident); + if (cur_sym != scope->local_symbols.end()) { + cerr << loc.get_fileline() << ": error: " + "'" << use_ident << "' has already been declared " + "in this scope." << endl; + cerr << cur_sym->second->get_fileline() << ": : " + "It was declared here as " + << cur_sym->second->symbol_type() << "." << endl; + error_count += 1; return; } - map::const_iterator tcur; - tcur = pkg->typedefs.find(use_ident); - if (tcur != pkg->typedefs.end()) { - scope->imports[tcur->first] = pkg; + // Check for conflict with previous import. + map::const_iterator cur_pkg + = scope->explicit_imports.find(use_ident); + if (cur_pkg != scope->explicit_imports.end()) { + if (cur_pkg->second != pkg) { + cerr << loc.get_fileline() << ": error: " + "'" << use_ident << "' has already been " + "imported into this scope from package '" + << cur_pkg->second->pscope_name() << "'." << endl; + error_count += 1; + } return; } - map::const_iterator fcur; - fcur = pkg->funcs.find(use_ident); - if (fcur != pkg->funcs.end()) { - scope->imports[fcur->first] = pkg; - return; - } - - map::const_iterator ttcur; - ttcur = pkg->tasks.find(use_ident); - if (ttcur != pkg->tasks.end()) { - scope->imports[ttcur->first] = pkg; - return; - } - - map::const_iterator wcur; - wcur = pkg->wires.find(use_ident); - if (wcur != pkg->wires.end()) { - scope->imports[wcur->first] = pkg; - return; - } - - ostringstream msg; - msg << "Symbol " << use_ident - << " not found in package " << pkg->pscope_name() << "." << ends; - VLerror(msg.str().c_str()); - return; + scope->explicit_imports[use_ident] = pkg; } else { - - // Handle the pkg::* case by importing everything from - // the package. - for (map::const_iterator cur = pkg->parameters.begin() - ; cur != pkg->parameters.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->localparams.begin() - ; cur != pkg->localparams.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->typedefs.begin() - ; cur != pkg->typedefs.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->funcs.begin() - ; cur != pkg->funcs.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (map::const_iterator cur = pkg->wires.begin() - ; cur != pkg->wires.end() ; ++cur) { - - scope->imports[cur->first] = pkg; - } - - for (set::const_iterator cur = pkg->enum_sets.begin() - ; cur != pkg->enum_sets.end() ; ++ cur) { - scope->enum_sets.insert(*cur); - } + set::const_iterator cur_pkg + = scope->potential_imports.find(pkg); + if (cur_pkg == scope->potential_imports.end()) + scope->potential_imports.insert(pkg); } } From 628f5645bfccc5275b99a1438f26310d2f8cd8ef Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 27 Sep 2019 00:29:46 +0100 Subject: [PATCH 05/16] Fix file/line reported for duplicate parameter declarations. We need to retain the old parameter information until we have reported the error. --- Module.h | 2 +- PScope.h | 4 +-- elab_scope.cc | 20 ++++++------- pform.cc | 77 ++++++++++++++++++++++++++------------------------- pform_dump.cc | 42 ++++++++++++++-------------- 5 files changed, 74 insertions(+), 71 deletions(-) diff --git a/Module.h b/Module.h index 48c83af88..993a8c0df 100644 --- a/Module.h +++ b/Module.h @@ -97,7 +97,7 @@ class Module : public PScopeExtra, public PNamedItem { /* specparams are simpler than other parameters, in that they can have a range, but not an explicit type. The restrictions are enforced by the parser. */ - mapspecparams; + mapspecparams; /* The module also has defparam assignments which don't create new parameters within the module, but may be used to set diff --git a/PScope.h b/PScope.h index 1c0760ad5..aa0eddf84 100644 --- a/PScope.h +++ b/PScope.h @@ -105,8 +105,8 @@ class LexicalScope { SymbolType symbol_type() const; }; - mapparameters; - maplocalparams; + mapparameters; + maplocalparams; // Defined types in the scope. maptypedefs; diff --git a/elab_scope.cc b/elab_scope.cc index 4afd4b680..5554a0768 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -63,7 +63,7 @@ void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope) des->set_precision(pscope->time_precision); } -typedef map::const_iterator mparm_it_t; +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, @@ -110,59 +110,59 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name, } static void collect_scope_parameters_(Design*des, NetScope*scope, - const map¶meters) + const map¶meters) { for (mparm_it_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur ) { // A parameter can not have the same name as a genvar. if (scope->find_genvar((*cur).first)) { - cerr << cur->second.get_fileline() + cerr << cur->second->get_fileline() << ": error: parameter and genvar in '" << scope->fullname() << "' have the same name '" << (*cur).first << "'." << endl; des->errors += 1; } - 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, - const map&localparams) + const map&localparams) { for (mparm_it_t cur = localparams.begin() ; cur != localparams.end() ; ++ cur ) { // A localparam can not have the same name as a genvar. if (scope->find_genvar((*cur).first)) { - cerr << cur->second.get_fileline() + cerr << cur->second->get_fileline() << ": error: localparam and genvar in '" << scope->fullname() << "' have the same name '" << (*cur).first << "'." << endl; des->errors += 1; } - 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, - const map&specparams) + const map&specparams) { for (mparm_it_t cur = specparams.begin() ; cur != specparams.end() ; ++ cur ) { // A specparam can not have the same name as a genvar. if (scope->find_genvar((*cur).first)) { - cerr << cur->second.get_fileline() + cerr << cur->second->get_fileline() << ": error: specparam and genvar in '" << scope->fullname() << "' have the same name '" << (*cur).first << "'." << endl; des->errors += 1; } - collect_parm_item_(des, scope, (*cur).first, (*cur).second, true, false); + collect_parm_item_(des, scope, cur->first, *(cur->second), true, false); } } diff --git a/pform.cc b/pform.cc index d6b41f3d3..c0a57ffcc 100644 --- a/pform.cc +++ b/pform.cc @@ -3059,27 +3059,28 @@ void pform_set_parameter(const struct vlltype&loc, } assert(expr); - Module::param_expr_t&parm = scope->parameters[name]; - FILE_NAME(&parm, loc); + Module::param_expr_t*parm = new Module::param_expr_t(); + FILE_NAME(parm, loc); - parm.expr = expr; + add_local_symbol(scope, name, parm); + scope->parameters[name] = parm; - parm.type = type; + 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; + parm->msb = rng.first; + parm->lsb = rng.second; } else { - parm.msb = 0; - parm.lsb = 0; + parm->msb = 0; + parm->lsb = 0; } - parm.signed_flag = signed_flag; - parm.range = value_range; - - add_local_symbol(scope, name, &parm); + parm->signed_flag = signed_flag; + parm->range = value_range; // Only a Module keeps the position of the parameter. if ((dynamic_cast(scope)) && (scope == pform_cur_module.front())) @@ -3097,27 +3098,28 @@ void pform_set_localparam(const struct vlltype&loc, } assert(expr); - Module::param_expr_t&parm = scope->localparams[name]; - FILE_NAME(&parm, loc); + Module::param_expr_t*parm = new Module::param_expr_t(); + FILE_NAME(parm, loc); - parm.expr = expr; + add_local_symbol(scope, name, parm); + scope->localparams[name] = parm; - parm.type = type; + 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; + parm->msb = rng.first; + parm->lsb = rng.second; } else { - parm.msb = 0; - parm.lsb = 0; + parm->msb = 0; + parm->lsb = 0; } - parm.signed_flag = signed_flag; - parm.range = 0; - - add_local_symbol(scope, name, &parm); + parm->signed_flag = signed_flag; + parm->range = 0; } void pform_set_specparam(const struct vlltype&loc, perm_string name, @@ -3128,28 +3130,29 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name, assert(scope == lexical_scope); assert(expr); - Module::param_expr_t&parm = pform_cur_module.front()->specparams[name]; - FILE_NAME(&parm, loc); + Module::param_expr_t*parm = new Module::param_expr_t(); + FILE_NAME(parm, loc); - parm.expr = expr; + add_local_symbol(scope, name, parm); + pform_cur_module.front()->specparams[name] = parm; + + parm->expr = expr; 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; + 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->type = IVL_VT_NO_TYPE; + parm->msb = 0; + parm->lsb = 0; } - parm.signed_flag = false; - parm.range = 0; - - add_local_symbol(scope, name, &parm); + parm->signed_flag = false; + parm->range = 0; } void pform_set_defparam(const pform_name_t&name, PExpr*expr) diff --git a/pform_dump.cc b/pform_dump.cc index 26a079786..97a6f13af 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1359,22 +1359,22 @@ void LexicalScope::dump_typedefs_(ostream&out, unsigned indent) const void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const { - typedef map::const_iterator parm_iter_t; + 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) + << (*cur).second->type << " "; + if ((*cur).second->signed_flag) out << "signed "; - if ((*cur).second.msb) - out << "[" << *(*cur).second.msb << ":" - << *(*cur).second.lsb << "] "; + if ((*cur).second->msb) + out << "[" << *(*cur).second->msb << ":" + << *(*cur).second->lsb << "] "; out << (*cur).first << " = "; - if ((*cur).second.expr) - out << *(*cur).second.expr; + if ((*cur).second->expr) + out << *(*cur).second->expr; else out << "/* ERROR */"; - for (LexicalScope::range_t*tmp = (*cur).second.range + for (LexicalScope::range_t*tmp = (*cur).second->range ; tmp ; tmp = tmp->next) { if (tmp->exclude_flag) out << " exclude "; @@ -1408,16 +1408,16 @@ void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const void LexicalScope::dump_localparams_(ostream&out, unsigned indent) const { - typedef map::const_iterator parm_iter_t; + typedef map::const_iterator parm_iter_t; 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->msb) + out << "[" << *(*cur).second->msb << ":" + << *(*cur).second->lsb << "] "; out << (*cur).first << " = "; - if ((*cur).second.expr) - out << *(*cur).second.expr << ";" << endl; + if ((*cur).second->expr) + out << *(*cur).second->expr << ";" << endl; else out << "/* ERROR */;" << endl; } @@ -1513,16 +1513,16 @@ void PClass::dump(ostream&out, unsigned indent) const void Module::dump_specparams_(ostream&out, unsigned indent) const { - typedef map::const_iterator parm_iter_t; + typedef map::const_iterator parm_iter_t; 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->msb) + out << "[" << *(*cur).second->msb << ":" + << *(*cur).second->lsb << "] "; out << (*cur).first << " = "; - if ((*cur).second.expr) - out << *(*cur).second.expr << ";" << endl; + if ((*cur).second->expr) + out << *(*cur).second->expr << ";" << endl; else out << "/* ERROR */;" << endl; } From 03c4c63df1223c0499e5bd9bc70315aa0c760b3c Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 27 Sep 2019 00:46:39 +0100 Subject: [PATCH 06/16] Fix file/line reported for duplicate named blocks. --- parse.y | 18 ++++++------------ pform.cc | 4 +++- pform.h | 3 ++- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/parse.y b/parse.y index 28154625a..822f02e83 100644 --- a/parse.y +++ b/parse.y @@ -1414,8 +1414,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ char for_block_name [64]; snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); for_counter += 1; - PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ); - FILE_NAME(tmp, @1); + PBlock*tmp = pform_push_block_scope(@1, for_block_name, PBlock::BL_SEQ); current_block_stack.push(tmp); listassign_list; @@ -1476,8 +1475,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter); foreach_counter += 1; - PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ); - FILE_NAME(tmp, @1); + PBlock*tmp = pform_push_block_scope(@1, for_block_name, PBlock::BL_SEQ); current_block_stack.push(tmp); pform_make_foreach_declarations(@1, $5); @@ -6252,8 +6250,7 @@ statement_item /* This is roughly statement_item in the LRM */ } /* In SystemVerilog an unnamed block can contain variable declarations. */ | K_begin - { PBlock*tmp = pform_push_block_scope(0, PBlock::BL_SEQ); - FILE_NAME(tmp, @1); + { PBlock*tmp = pform_push_block_scope(@1, 0, PBlock::BL_SEQ); current_block_stack.push(tmp); } block_item_decls_opt @@ -6287,8 +6284,7 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } | K_begin ':' IDENTIFIER - { PBlock*tmp = pform_push_block_scope($3, PBlock::BL_SEQ); - FILE_NAME(tmp, @1); + { PBlock*tmp = pform_push_block_scope(@1, $3, PBlock::BL_SEQ); current_block_stack.push(tmp); } block_item_decls_opt @@ -6325,8 +6321,7 @@ statement_item /* This is roughly statement_item in the LRM */ } /* In SystemVerilog an unnamed block can contain variable declarations. */ | K_fork - { PBlock*tmp = pform_push_block_scope(0, PBlock::BL_PAR); - FILE_NAME(tmp, @1); + { PBlock*tmp = pform_push_block_scope(@1, 0, PBlock::BL_PAR); current_block_stack.push(tmp); } block_item_decls_opt @@ -6361,8 +6356,7 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } | K_fork ':' IDENTIFIER - { PBlock*tmp = pform_push_block_scope($3, PBlock::BL_PAR); - FILE_NAME(tmp, @1); + { PBlock*tmp = pform_push_block_scope(@1, $3, PBlock::BL_PAR); current_block_stack.push(tmp); } block_item_decls_opt diff --git a/pform.cc b/pform.cc index c0a57ffcc..17ad83d60 100644 --- a/pform.cc +++ b/pform.cc @@ -696,7 +696,8 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, return func; } -PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) +PBlock* pform_push_block_scope(const struct vlltype&loc, char*name, + PBlock::BL_TYPE bt) { perm_string block_name; if (name) block_name = lex_strings.make(name); @@ -710,6 +711,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) } PBlock*block = new PBlock(block_name, lexical_scope, bt); + FILE_NAME(block, loc); block->default_lifetime = find_lifetime(LexicalScope::INHERITED); if (name) add_local_symbol(lexical_scope, block_name, block); lexical_scope = block; diff --git a/pform.h b/pform.h index cd1fb5c88..f538e58a7 100644 --- a/pform.h +++ b/pform.h @@ -274,7 +274,8 @@ extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, extern PFunction*pform_push_function_scope(const struct vlltype&loc, const char*name, LexicalScope::lifetime_t lifetime); -extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); +extern PBlock*pform_push_block_scope(const struct vlltype&loc, char*name, + PBlock::BL_TYPE tt); extern void pform_put_behavior_in_scope(AProcess*proc); From 2ae910750b2c9fd417899cb4563f996b07323bce Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 27 Sep 2019 20:04:09 +0100 Subject: [PATCH 07/16] Put generate case item block names in correct scope. The compiler creates an artificial scope around the case items. We need to add the block names to the real containing scope. --- pform.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pform.cc b/pform.cc index 17ad83d60..fa44f4a28 100644 --- a/pform.cc +++ b/pform.cc @@ -1567,8 +1567,13 @@ void pform_generate_block_name(char*name) conditional_block_names.front().insert(scope_name); } - add_local_symbol(pform_cur_generate->parent_scope(), - scope_name, pform_cur_generate); + LexicalScope*parent_scope = pform_cur_generate->parent_scope(); + assert(parent_scope); + if (pform_cur_generate->scheme_type == PGenerate::GS_CASE_ITEM) + // Skip over the PGenerate::GS_CASE container. + parent_scope = parent_scope->parent_scope(); + + add_local_symbol(parent_scope, scope_name, pform_cur_generate); } void pform_endgenerate(bool end_conditional) From 439688fa461da2fbba77059d00a1dd1ab28fe68f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 27 Sep 2019 21:29:50 +0100 Subject: [PATCH 08/16] Add anonymous enums to the scope local symbols. --- pform.cc | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/pform.cc b/pform.cc index fa44f4a28..0cd341133 100644 --- a/pform.cc +++ b/pform.cc @@ -787,6 +787,23 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net) static void pform_put_enum_type_in_scope(enum_type_t*enum_set) { + if (lexical_scope->enum_sets.count(enum_set)) + return; + + set enum_names; + list::const_iterator cur; + for (cur = enum_set->names->begin(); cur != enum_set->names->end(); ++cur) { + if (enum_names.count(cur->name)) { + cerr << enum_set->get_fileline() << ": error: " + "Duplicate enumeration name '" + << cur->name << "'." << endl; + error_count += 1; + } else { + add_local_symbol(lexical_scope, cur->name, enum_set); + enum_names.insert(cur->name); + } + } + lexical_scope->enum_sets.insert(enum_set); } @@ -829,13 +846,8 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::list(data_type)) { + if (enum_type_t*enum_type = dynamic_cast(data_type)) pform_put_enum_type_in_scope(enum_type); - - list::const_iterator cur; - for (cur = enum_type->names->begin(); cur != enum_type->names->end(); ++cur) - add_local_symbol(lexical_scope, cur->name, enum_type); - } } data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) From e73da43cc1093ea4f95e8879b9e474012319d96c Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 27 Sep 2019 22:08:58 +0100 Subject: [PATCH 09/16] Remove obsolete checks for name collisions during elaboration. This is now handled by the parser. --- elab_scope.cc | 352 +------------------------------------------------- elab_sig.cc | 38 ------ 2 files changed, 1 insertion(+), 389 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 5554a0768..b69bdc9f2 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -115,15 +115,6 @@ static void collect_scope_parameters_(Design*des, NetScope*scope, for (mparm_it_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur ) { - // A parameter can not have the same name as a genvar. - if (scope->find_genvar((*cur).first)) { - cerr << cur->second->get_fileline() - << ": error: parameter and genvar in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - collect_parm_item_(des, scope, cur->first, *(cur->second), false, false); } } @@ -134,15 +125,6 @@ static void collect_scope_localparams_(Design*des, NetScope*scope, for (mparm_it_t cur = localparams.begin() ; cur != localparams.end() ; ++ cur ) { - // A localparam can not have the same name as a genvar. - if (scope->find_genvar((*cur).first)) { - cerr << cur->second->get_fileline() - << ": error: localparam and genvar in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - collect_parm_item_(des, scope, cur->first, *(cur->second), false, true); } } @@ -153,15 +135,6 @@ static void collect_scope_specparams_(Design*des, NetScope*scope, for (mparm_it_t cur = specparams.begin() ; cur != specparams.end() ; ++ cur ) { - // A specparam can not have the same name as a genvar. - if (scope->find_genvar((*cur).first)) { - cerr << cur->second->get_fileline() - << ": error: specparam and genvar in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - collect_parm_item_(des, scope, cur->first, *(cur->second), true, false); } } @@ -650,39 +623,6 @@ static void elaborate_scope_tasks(Design*des, NetScope*scope, for (tasks_it_t cur = tasks.begin() ; cur != tasks.end() ; ++ cur ) { - hname_t use_name( (*cur).first ); - // A task can not have the same name as another scope object. - const NetScope *child = scope->child(use_name); - if (child) { - cerr << cur->second->get_fileline() << ": error: task and "; - child->print_type(cerr); - cerr << " in '" << scope->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - continue; - } - - // A task can not have the same name as a genvar. - if (scope->find_genvar((*cur).first)) { - cerr << cur->second->get_fileline() - << ": error: task and genvar in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - - // A task can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = scope->get_parameter(des, (*cur).first, - ex_msb, ex_lsb); - if (parm) { - cerr << cur->second->get_fileline() - << ": error: task and parameter in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - elaborate_scope_task(des, scope, cur->second); } @@ -713,40 +653,6 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope, for (funcs_it_t cur = funcs.begin() ; cur != funcs.end() ; ++ cur ) { - hname_t use_name( (*cur).first ); - // A function can not have the same name as another scope object. - const NetScope *child = scope->child(use_name); - if (child) { - cerr << cur->second->get_fileline() - << ": error: function and "; - child->print_type(cerr); - cerr << " in '" << scope->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - continue; - } - - // A function can not have the same name as a genvar. - if (scope->find_genvar((*cur).first)) { - cerr << cur->second->get_fileline() - << ": error: function and genvar in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - - // A function can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = scope->get_parameter(des, (*cur).first, - ex_msb, ex_lsb); - if (parm) { - cerr << cur->second->get_fileline() - << ": error: function and parameter in '" - << scope->fullname() << "' have the same name '" - << (*cur).first << "'." << endl; - des->errors += 1; - } - elaborate_scope_func(des, scope, cur->second); } @@ -989,56 +895,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) return false; } - // Check the generate block name. - - // A generate "loop" can not have the same name as another - // scope object. Find any scope with this name, not just an - // exact match scope. - const NetScope *child = container->child_byname(scope_name); - if (child) { - cerr << get_fileline() << ": error: generate \"loop\" and "; - child->print_type(cerr); - cerr << " in '" << container->fullname() - << "' have the same name '" << scope_name << "'." << endl; - des->errors += 1; - return false; - } - - // A generate "loop" can not have the same name as a genvar. - if (container->find_genvar(scope_name)) { - cerr << get_fileline() << ": error: generate \"loop\" and " - "genvar in '" << container->fullname() - << "' have the same name '" << scope_name << "'." << endl; - des->errors += 1; - } - - // A generate "loop" can not have the same name as a named event. - const NetEvent *event = container->find_event(scope_name); - if (event) { - cerr << get_fileline() << ": error: generate \"loop\" and " - "named event in '" << container->fullname() - << "' have the same name '" << scope_name << "'." << endl; - des->errors += 1; - } - - // A generate "loop" can not have the same name as a parameter. - const NetExpr*tmsb; - const NetExpr*tlsb; - const NetExpr*texpr = container->get_parameter(des, scope_name, - tmsb, tlsb); - if (texpr != 0) { - cerr << get_fileline() << ": error: generate \"loop\" and " - "parameter in '" << container->fullname() - << "' have the same name '" << scope_name << "'." << endl; - des->errors += 1; - } - - // These have all been checked so we just need to skip the actual - // generation for these name conflicts. Not skipping these two will - // cause the compiler to have problems (assert, inf. loop, etc.). - if (container->get_parameter(des, loop_index, tmsb, tlsb)) return false; - if (container->find_event(loop_index)) return false; - genvar = init->value().as_long(); delete init_ex; @@ -1146,45 +1002,6 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else } hname_t use_name (scope_name); - // A generate "if" can not have the same name as another scope object. - const NetScope *child = container->child(use_name); - if (child) { - cerr << get_fileline() << ": error: generate \"if\" and "; - child->print_type(cerr); - cerr << " in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - return false; - } - - // A generate "if" can not have the same name as a genvar. - if (container->find_genvar(scope_name)) { - cerr << get_fileline() << ": error: generate \"if\" and " - "genvar in '" << container->fullname() - << "' have the same name '" << scope_name << "'." << endl; - des->errors += 1; - } - - // A generate "if" can not have the same name as a named event. - const NetEvent *event = container->find_event(scope_name); - if (event) { - cerr << get_fileline() << ": error: generate \"if\" and " - "named event in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - - // A generate "if" can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = container->get_parameter(des, scope_name, - ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: generate \"if\" and " - "parameter in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - if (debug_scopes) cerr << get_fileline() << ": debug: Generate condition " << (else_flag? "(else)" : "(if)") @@ -1289,44 +1106,6 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) // The name of the scope to generate, whatever that item is. hname_t use_name (item->scope_name); - // A generate "case" can not have the same name as another scope object. - const NetScope *child = container->child(use_name); - if (child) { - cerr << get_fileline() << ": error: generate \"case\" and "; - child->print_type(cerr); - cerr << " in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - return false; - } - - // A generate "case" can not have the same name as a genvar. - if (container->find_genvar(item->scope_name)) { - cerr << get_fileline() << ": error: generate \"case\" and " - "genvar in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - - // A generate "case" can not have the same name as a named event. - const NetEvent *event = container->find_event(item->scope_name); - if (event) { - cerr << get_fileline() << ": error: generate \"case\" and " - "named event in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - - // A generate "case" can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = container->get_parameter(des, item->scope_name, - ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: generate \"case\" and " - "parameter in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } item->probe_for_direct_nesting_(); if (item->direct_nested_) { @@ -1356,46 +1135,6 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container) bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container) { hname_t use_name (scope_name); - // A generate "block" can not have the same name as another scope - // object. - const NetScope *child = container->child(use_name); - if (child) { - cerr << get_fileline() << ": error: generate \"block\" and "; - child->print_type(cerr); - cerr << " in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - return false; - } - - // A generate "block" can not have the same name as a genvar. - if (container->find_genvar(scope_name)) { - cerr << get_fileline() << ": error: generate \"block\" and " - "genvar in '" << container->fullname() - << "' have the same name '" << scope_name << "'." << endl; - des->errors += 1; - } - - // A generate "block" can not have the same name as a named event. - const NetEvent *event = container->find_event(scope_name); - if (event) { - cerr << get_fileline() << ": error: generate \"block\" and " - "named event in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - - // A generate "block" can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = container->get_parameter(des, scope_name, - ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: generate \"block\" and " - "parameter in '" << container->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - if (debug_scopes) cerr << get_fileline() << ": debug: Generate named block " << ": Generate scope=" << use_name << endl; @@ -1535,36 +1274,6 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const // Missing module instance names have already been rejected. assert(get_name() != ""); - // A module instance can not have the same name as another scope object. - const NetScope *child = sc->child(hname_t(get_name())); - if (child) { - cerr << get_fileline() << ": error: module <" << mod->mod_name() - << "> instance and "; - child->print_type(cerr); - cerr << " in '" << sc->fullname() - << "' have the same name '" << get_name() << "'." << endl; - des->errors += 1; - return; - } - - // A module instance can not have the same name as a genvar. - if (sc->find_genvar(get_name())) { - cerr << get_fileline() << ": error: module <" << mod->mod_name() - << "> instance and genvar in '" << sc->fullname() - << "' have the same name '" << get_name() << "'." << endl; - des->errors += 1; - } - - // A module instance can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = sc->get_parameter(des, get_name(), ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: module <" << mod->mod_name() - << "> instance and parameter in '" << sc->fullname() - << "' have the same name '" << get_name() << "'." << endl; - des->errors += 1; - } - // check for recursive instantiation by scanning the current // scope and its parents. Look for a module instantiation of // the same module, but farther up in the scope. @@ -1791,36 +1500,8 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s * no hierarchy, but neither does the NetEvent, until it is stored in * the NetScope object. */ -void PEvent::elaborate_scope(Design*des, NetScope*scope) const +void PEvent::elaborate_scope(Design*, NetScope*scope) const { - // A named event can not have the same name as another scope object. - const NetScope *child = scope->child(hname_t(name_)); - if (child) { - cerr << get_fileline() << ": error: named event and "; - child->print_type(cerr); - cerr << " in '" << scope->fullname() - << "' have the same name '" << name_ << "'." << endl; - des->errors += 1; - } - - // A named event can not have the same name as a genvar. - if (scope->find_genvar(name_)) { - cerr << get_fileline() << ": error: named event and " - << "genvar in '" << scope->fullname() - << "' have the same name '" << name_ << "'." << endl; - des->errors += 1; - } - - // A named event can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = scope->get_parameter(des, name_, ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: named event and " - << "parameter in '" << scope->fullname() - << "' have the same name '" << name_ << "'." << endl; - des->errors += 1; - } - NetEvent*ev = new NetEvent(name_); ev->set_line(*this); scope->add_event(ev); @@ -1891,37 +1572,6 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const if (pscope_name() != 0) { hname_t use_name(pscope_name()); - // A named block can not have the same name as another scope - // object. - const NetScope *child = scope->child(use_name); - if (child) { - cerr << get_fileline() << ": error: named block and "; - child->print_type(cerr); - cerr << " in '" << scope->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - return; - } - - // A named block can not have the same name as a genvar. - if (scope->find_genvar(pscope_name())) { - cerr << get_fileline() << ": error: named block and " - "genvar in '" << scope->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - - // A named block can not have the same name as a parameter. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = scope->get_parameter(des, pscope_name(), - ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: named block and " - "parameter in '" << scope->fullname() - << "' have the same name '" << use_name << "'." << endl; - des->errors += 1; - } - if (debug_scopes) cerr << get_fileline() << ": debug: " << "Elaborate block scope " << use_name diff --git a/elab_sig.cc b/elab_sig.cc index 885a9253d..4b50fc466 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -942,44 +942,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const des->errors += error_cnt_; - // A signal can not have the same name as a scope object. - const NetScope *child = scope->child_byname(name_); - if (child) { - cerr << get_fileline() << ": error: signal and "; - child->print_type(cerr); - cerr << " in '" << scope->fullname() - << "' have the same name '" << name_ << "'." << endl; - des->errors += 1; - } - // A signal can not have the same name as a genvar. - const LineInfo *genvar = scope->find_genvar(name_); - if (genvar) { - cerr << get_fileline() << ": error: signal and genvar in '" - << scope->fullname() << "' have the same name '" << name_ - << "'." << endl; - des->errors += 1; - } - // A signal can not have the same name as a parameter. Note - // that we treat enumeration literals similar to parameters, - // so if the name matches an enumeration literal, it will be - // caught here. - const NetExpr *ex_msb, *ex_lsb; - const NetExpr *parm = scope->get_parameter(des, name_, ex_msb, ex_lsb); - if (parm) { - cerr << get_fileline() << ": error: signal and parameter in '" - << scope->fullname() << "' have the same name '" << name_ - << "'." << endl; - des->errors += 1; - } - // A signal can not have the same name as a named event. - const NetEvent *event = scope->find_event(name_); - if (event) { - cerr << get_fileline() << ": error: signal and named event in '" - << scope->fullname() << "' have the same name '" << name_ - << "'." << endl; - des->errors += 1; - } - if (port_set_ || net_set_) { if (warn_implicit_dimensions From 1e26a808adeddce65ab822b2f9e400bc24449355 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 28 Sep 2019 20:59:12 +0100 Subject: [PATCH 10/16] Fix error message for failed elaboration of event expression. --- elaborate.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index bd950ba2f..4a06303c7 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4356,8 +4356,9 @@ cerr << endl; NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), -1); if (tmp == 0) { - expr_[idx]->dump(cerr); - cerr << endl; + cerr << get_fileline() << ": error: " + "Failed to evaluate event expression '" + << *expr_[idx] << "'." << endl; des->errors += 1; continue; } From b0142a6406c5093083f857b59bbf9d555e5ce3a2 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 28 Sep 2019 21:00:17 +0100 Subject: [PATCH 11/16] Add support for named events in packages. --- elab_scope.cc | 1 + parse.y | 8 ++++++-- pform.cc | 8 ++++++++ pform.h | 2 ++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 830d40003..b3b008b92 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -725,6 +725,7 @@ bool PPackage::elaborate_scope(Design*des, NetScope*scope) elaborate_scope_classes(des, scope, classes_lexical); elaborate_scope_funcs(des, scope, funcs); elaborate_scope_tasks(des, scope, tasks); + elaborate_scope_events_(des, scope, events); return true; } diff --git a/parse.y b/parse.y index 602981987..cc99dee27 100644 --- a/parse.y +++ b/parse.y @@ -1056,6 +1056,9 @@ data_declaration /* IEEE1800-2005: A.2.1.3 */ } pform_makewire(@2, 0, str_strength, $3, NetNet::IMPLICIT_REG, data_type); } + | attribute_list_opt K_event event_variable_list ';' + { if ($3) pform_make_events($3, @2.text, @2.first_line); + } ; data_type /* IEEE1800-2005: A.2.2.1 */ @@ -3174,7 +3177,8 @@ clocking_event_opt /* */ event_control /* A.K.A. clocking_event */ : '@' hierarchy_identifier - { PEIdent*tmpi = new PEIdent(*$2); + { PEIdent*tmpi = pform_new_ident(@2, *$2); + FILE_NAME(tmpi, @2); PEEvent*tmpe = new PEEvent(PEEvent::ANYEDGE, tmpi); PEventStatement*tmps = new PEventStatement(tmpe); FILE_NAME(tmps, @1); @@ -6403,7 +6407,7 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } | K_TRIGGER hierarchy_identifier ';' - { PTrigger*tmp = new PTrigger(*$2); + { PTrigger*tmp = pform_new_trigger(@2, *$2); FILE_NAME(tmp, @1); delete $2; $$ = tmp; diff --git a/pform.cc b/pform.cc index 0cd341133..18f829476 100644 --- a/pform.cc +++ b/pform.cc @@ -730,6 +730,14 @@ PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) return new PEIdent(name); } +PTrigger* pform_new_trigger(const struct vlltype&loc, const pform_name_t&name) +{ + if (gn_system_verilog() && name.size() == 1) + check_potential_imports(loc, name.back().name); + + return new PTrigger(name); +} + PGenerate* pform_parent_generate(void) { return pform_cur_generate; diff --git a/pform.h b/pform.h index f538e58a7..bf1cd629e 100644 --- a/pform.h +++ b/pform.h @@ -248,6 +248,8 @@ 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, const pform_name_t&name); + /* * Enter/exit name scopes. The push_scope function pushes the scope * name string onto the scope hierarchy. The pop pulls it off and From 12fe4f2bf34e7070a3cd74e5a61fdc12372e6ae4 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 29 Sep 2019 19:16:35 +0100 Subject: [PATCH 12/16] Fix handling of wildcard-imported types. Don't add them to the explicit imports until they are referenced legally. Stop searching when a matching name is found, even if it isn't a type name. --- parse.y | 18 ++++++++++++------ pform.cc | 23 +++++++++++++++-------- pform.h | 2 ++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/parse.y b/parse.y index cc99dee27..5186edf3b 100644 --- a/parse.y +++ b/parse.y @@ -819,12 +819,14 @@ class_declaration_endlabel_opt class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ : K_extends TYPE_IDENTIFIER - { $$.type = $2.type; + { pform_set_type_referenced(@2, $2.text); + $$.type = $2.type; $$.exprs= 0; delete[]$2.text; } | K_extends TYPE_IDENTIFIER '(' expression_list_with_nuls ')' - { $$.type = $2.type; + { pform_set_type_referenced(@2, $2.text); + $$.type = $2.type; $$.exprs = $4; delete[]$2.text; } @@ -1106,7 +1108,8 @@ data_type /* IEEE1800-2005: A.2.2.1 */ $$ = tmp; } | TYPE_IDENTIFIER dimensions_opt - { if ($2) { + { pform_set_type_referenced(@1, $1.text); + if ($2) { parray_type_t*tmp = new parray_type_t($1.type, $2); FILE_NAME(tmp, @1); $$ = tmp; @@ -1990,7 +1993,8 @@ simple_type_or_string /* IEEE1800-2005: A.2.2.1 */ $$ = tmp; } | TYPE_IDENTIFIER - { $$ = $1.type; + { pform_set_type_referenced(@1, $1.text); + $$ = $1.type; delete[]$1.text; } | PACKAGE_IDENTIFIER K_SCOPE_RES @@ -3561,7 +3565,8 @@ expr_primary_or_typename /* There are a few special cases (notably $bits argument) where the expression may be a type name. Let the elaborator sort this out. */ | TYPE_IDENTIFIER - { PETypename*tmp = new PETypename($1.type); + { pform_set_type_referenced(@1, $1.text); + PETypename*tmp = new PETypename($1.type); FILE_NAME(tmp,@1); $$ = tmp; delete[]$1.text; @@ -5320,7 +5325,8 @@ param_type param_active_type = IVL_VT_BOOL; } | TYPE_IDENTIFIER - { pform_set_param_from_type(@1, $1.type, $1.text, param_active_range, + { 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; } diff --git a/pform.cc b/pform.cc index 18f829476..df407724c 100644 --- a/pform.cc +++ b/pform.cc @@ -464,7 +464,7 @@ static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*it } static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*scope, - perm_string name, PNamedItem::SymbolType st) + perm_string name, bool make_explicit) { assert(scope); @@ -475,10 +475,7 @@ static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*sco map::const_iterator cur_sym = search_pkg->local_symbols.find(name); if (cur_sym != search_pkg->local_symbols.end()) { - if (st != PNamedItem::ANY && st != cur_sym->second->symbol_type()) - continue; - - if (found_pkg) { + if (found_pkg && make_explicit) { cerr << loc.get_fileline() << ": error: " "Ambiguous use of '" << name << "'. " "It is exported by both '" @@ -489,7 +486,8 @@ static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*sco error_count += 1; } else { found_pkg = search_pkg; - scope->explicit_imports[name] = found_pkg; + if (make_explicit) + scope->explicit_imports[name] = found_pkg; } } } @@ -504,7 +502,7 @@ static void check_potential_imports(const struct vlltype&loc, perm_string name) return; if (scope->explicit_imports.find(name) != scope->explicit_imports.end()) return; - if (find_potential_import(loc, scope, name, PNamedItem::ANY)) + if (find_potential_import(loc, scope, name, true)) return; scope = scope->parent_scope(); @@ -858,6 +856,12 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::listtypedefs.end()) return cur->second; - PPackage*pkg = find_potential_import(loc, cur_scope, name, PNamedItem::TYPE); + PPackage*pkg = find_potential_import(loc, cur_scope, name, false); if (pkg) { cur = pkg->typedefs.find(name); if (cur != cur_scope->typedefs.end()) return cur->second; + + // Not a type. Give up. + return 0; } cur_scope = cur_scope->parent_scope(); diff --git a/pform.h b/pform.h index bf1cd629e..18d514d85 100644 --- a/pform.h +++ b/pform.h @@ -314,6 +314,8 @@ extern PGenerate* pform_parent_generate(void); extern void pform_set_typedef(perm_string name, data_type_t*data_type, std::list*unp_ranges); +extern void pform_set_type_referenced(const struct vlltype&loc, const char*name); + /* * This function makes a PECallFunction of the named function. */ From c5c264400ee6f508060040090fee85bb845db9bc Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 29 Sep 2019 21:11:01 +0100 Subject: [PATCH 13/16] Add support for package scope resolution for named events. --- PExpr.h | 4 +++- Statement.cc | 4 ++-- Statement.h | 3 ++- elaborate.cc | 16 ++++++++++++++-- parse.y | 18 ++++++++++++------ pform.cc | 9 ++++++--- pform.h | 3 ++- 7 files changed, 41 insertions(+), 16 deletions(-) diff --git a/PExpr.h b/PExpr.h index 00588293b..fd91dc6a8 100644 --- a/PExpr.h +++ b/PExpr.h @@ -1,7 +1,7 @@ #ifndef IVL_PExpr_H #define IVL_PExpr_H /* - * Copyright (c) 1998-2016 Stephen Williams + * Copyright (c) 1998-2019 Stephen Williams * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -379,6 +379,8 @@ class PEIdent : public PExpr { virtual bool is_collapsible_net(Design*des, NetScope*scope) const; + const PPackage* package() const { return package_; } + const pform_name_t& path() const { return path_; } private: diff --git a/Statement.cc b/Statement.cc index 1e587758a..e5f5f169e 100644 --- a/Statement.cc +++ b/Statement.cc @@ -416,8 +416,8 @@ PReturn::~PReturn() delete expr_; } -PTrigger::PTrigger(const pform_name_t&e) -: event_(e) +PTrigger::PTrigger(PPackage*pkg, const pform_name_t&e) +: package_(pkg), event_(e) { } diff --git a/Statement.h b/Statement.h index 95d453195..ae5e162b6 100644 --- a/Statement.h +++ b/Statement.h @@ -563,13 +563,14 @@ class PReturn : public Statement { class PTrigger : public Statement { public: - explicit PTrigger(const pform_name_t&ev); + explicit PTrigger(PPackage*pkg, const pform_name_t&ev); ~PTrigger(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; private: + PPackage*package_; pform_name_t event_; }; diff --git a/elaborate.cc b/elaborate.cc index 4a06303c7..572c09f7d 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4310,7 +4310,13 @@ cerr << endl; const NetExpr*par = 0; NetEvent* eve = 0; - NetScope*found_in = symbol_search(this, des, scope, + NetScope*use_scope = scope; + if (id->package()) { + use_scope = des->find_package(id->package()->pscope_name()); + ivl_assert(*this, use_scope); + } + + NetScope*found_in = symbol_search(this, des, use_scope, id->path(), sig, par, eve); @@ -5337,11 +5343,17 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const { assert(scope); + NetScope*use_scope = scope; + if (package_) { + use_scope = des->find_package(package_->pscope_name()); + ivl_assert(*this, use_scope); + } + NetNet* sig = 0; const NetExpr*par = 0; NetEvent* eve = 0; - NetScope*found_in = symbol_search(this, des, scope, event_, + NetScope*found_in = symbol_search(this, des, use_scope, event_, sig, par, eve); if (found_in == 0) { diff --git a/parse.y b/parse.y index 5186edf3b..462508ad5 100644 --- a/parse.y +++ b/parse.y @@ -6412,12 +6412,18 @@ statement_item /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_TRIGGER hierarchy_identifier ';' - { PTrigger*tmp = pform_new_trigger(@2, *$2); - FILE_NAME(tmp, @1); - delete $2; - $$ = tmp; - } + | K_TRIGGER hierarchy_identifier ';' + { PTrigger*tmp = pform_new_trigger(@2, 0, *$2); + FILE_NAME(tmp, @1); + delete $2; + $$ = tmp; + } + | K_TRIGGER PACKAGE_IDENTIFIER K_SCOPE_RES hierarchy_identifier + { PTrigger*tmp = pform_new_trigger(@4, $2, *$4); + FILE_NAME(tmp, @1); + delete $4; + $$ = tmp; + } | procedural_assertion_statement { $$ = $1; } diff --git a/pform.cc b/pform.cc index df407724c..5f3f342fa 100644 --- a/pform.cc +++ b/pform.cc @@ -728,12 +728,15 @@ PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) return new PEIdent(name); } -PTrigger* pform_new_trigger(const struct vlltype&loc, const pform_name_t&name) +PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, + const pform_name_t&name) { - if (gn_system_verilog() && name.size() == 1) + if (gn_system_verilog() && pkg == 0 && name.size() == 1) check_potential_imports(loc, name.back().name); - return new PTrigger(name); + PTrigger*tmp = new PTrigger(pkg, name); + FILE_NAME(tmp, loc); + return tmp; } PGenerate* pform_parent_generate(void) diff --git a/pform.h b/pform.h index 18d514d85..aba405ad0 100644 --- a/pform.h +++ b/pform.h @@ -248,7 +248,8 @@ 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, const pform_name_t&name); +extern PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, + const pform_name_t&name); /* * Enter/exit name scopes. The push_scope function pushes the scope From 17f0dd7e6e3bb0706a3585841eb9189dd785a6ec Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 30 Sep 2019 20:59:05 +0100 Subject: [PATCH 14/16] Enable package imports in blocks. --- parse.y | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/parse.y b/parse.y index 462508ad5..eb10d6b72 100644 --- a/parse.y +++ b/parse.y @@ -2552,6 +2552,10 @@ block_item_decl | type_declaration + /* Blocks can have imports. */ + + | package_import_declaration + /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ @@ -5076,8 +5080,6 @@ module_item | modport_declaration - | package_import_declaration - /* 1364-2001 and later allow specparam declarations outside specify blocks. */ | attribute_list_opt K_specparam From 1fca7b41a44e109b67caa6b463b7cb37271b7c3f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Mon, 30 Sep 2019 21:01:30 +0100 Subject: [PATCH 15/16] Delay potential imports for task/function calls until end of scope. A local task/function definition takes precedence, even if it appears after the call. --- PScope.h | 6 ++++++ pform.cc | 39 ++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/PScope.h b/PScope.h index aa0eddf84..21f751601 100644 --- a/PScope.h +++ b/PScope.h @@ -73,6 +73,12 @@ class LexicalScope { // explicit imports (IEEE 1800-2012 26.3). std::setpotential_imports; + // A task or function call may reference a task or function defined + // later in the scope. So here we stash the potential imports for + // task and function calls. They will be added to the explicit + // imports if we don't find a local definition. + std::mappossible_imports; + struct range_t { // True if this is an exclude bool exclude_flag; diff --git a/pform.cc b/pform.cc index 5f3f342fa..3b9259b5b 100644 --- a/pform.cc +++ b/pform.cc @@ -407,8 +407,17 @@ LexicalScope* pform_peek_scope(void) void pform_pop_scope() { - assert(lexical_scope); - lexical_scope = lexical_scope->parent_scope(); + LexicalScope*scope = lexical_scope; + assert(scope); + + map::const_iterator cur; + for (cur = scope->possible_imports.begin(); cur != scope->possible_imports.end(); ++cur) { + if (scope->local_symbols.find(cur->first) == scope->local_symbols.end()) + scope->explicit_imports[cur->first] = cur->second; + } + scope->possible_imports.clear(); + + lexical_scope = scope->parent_scope(); assert(lexical_scope); } @@ -464,7 +473,7 @@ static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*it } static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*scope, - perm_string name, bool make_explicit) + perm_string name, bool tf_call, bool make_explicit) { assert(scope); @@ -486,15 +495,19 @@ static PPackage*find_potential_import(const struct vlltype&loc, LexicalScope*sco error_count += 1; } else { found_pkg = search_pkg; - if (make_explicit) - scope->explicit_imports[name] = found_pkg; + if (make_explicit) { + if (tf_call) + scope->possible_imports[name] = found_pkg; + else + scope->explicit_imports[name] = found_pkg; + } } } } return found_pkg; } -static void check_potential_imports(const struct vlltype&loc, perm_string name) +static void check_potential_imports(const struct vlltype&loc, perm_string name, bool tf_call) { LexicalScope*scope = lexical_scope; while (scope) { @@ -502,7 +515,7 @@ static void check_potential_imports(const struct vlltype&loc, perm_string name) return; if (scope->explicit_imports.find(name) != scope->explicit_imports.end()) return; - if (find_potential_import(loc, scope, name, true)) + if (find_potential_import(loc, scope, name, tf_call, true)) return; scope = scope->parent_scope(); @@ -723,7 +736,7 @@ PBlock* pform_push_block_scope(const struct vlltype&loc, char*name, PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) { if (gn_system_verilog() && name.size() == 1) - check_potential_imports(loc, name.back().name); + check_potential_imports(loc, name.back().name, false); return new PEIdent(name); } @@ -732,7 +745,7 @@ PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, const pform_name_t&name) { if (gn_system_verilog() && pkg == 0 && name.size() == 1) - check_potential_imports(loc, name.back().name); + check_potential_imports(loc, name.back().name, false); PTrigger*tmp = new PTrigger(pkg, name); FILE_NAME(tmp, loc); @@ -862,7 +875,7 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::listtypedefs.end()) return cur->second; - PPackage*pkg = find_potential_import(loc, cur_scope, name, false); + PPackage*pkg = find_potential_import(loc, cur_scope, name, false, false); if (pkg) { cur = pkg->typedefs.find(name); if (cur != cur_scope->typedefs.end()) @@ -934,7 +947,7 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc, const list&parms) { if (gn_system_verilog() && name.size() == 1) - check_potential_imports(loc, name.back().name); + check_potential_imports(loc, name.back().name, true); PECallFunction*tmp = new PECallFunction(name, parms); FILE_NAME(tmp, loc); @@ -946,7 +959,7 @@ PCallTask* pform_make_call_task(const struct vlltype&loc, const list&parms) { if (gn_system_verilog() && name.size() == 1) - check_potential_imports(loc, name.back().name); + check_potential_imports(loc, name.back().name, true); PCallTask*tmp = new PCallTask(name, parms); FILE_NAME(tmp, loc); From 1cc872be8cc7e5588277be4056d368e0509693b2 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 1 Oct 2019 08:46:11 +0100 Subject: [PATCH 16/16] Downward references may also activate potential imports. --- pform.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pform.cc b/pform.cc index 3b9259b5b..957addd3e 100644 --- a/pform.cc +++ b/pform.cc @@ -735,8 +735,8 @@ PBlock* pform_push_block_scope(const struct vlltype&loc, char*name, */ PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&name) { - if (gn_system_verilog() && name.size() == 1) - check_potential_imports(loc, name.back().name, false); + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, false); return new PEIdent(name); } @@ -744,8 +744,8 @@ 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) { - if (gn_system_verilog() && pkg == 0 && name.size() == 1) - check_potential_imports(loc, name.back().name, false); + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, false); PTrigger*tmp = new PTrigger(pkg, name); FILE_NAME(tmp, loc); @@ -946,8 +946,8 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list&parms) { - if (gn_system_verilog() && name.size() == 1) - check_potential_imports(loc, name.back().name, true); + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, true); PECallFunction*tmp = new PECallFunction(name, parms); FILE_NAME(tmp, loc); @@ -958,8 +958,8 @@ PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, const list&parms) { - if (gn_system_verilog() && name.size() == 1) - check_potential_imports(loc, name.back().name, true); + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, true); PCallTask*tmp = new PCallTask(name, parms); FILE_NAME(tmp, loc);