diff --git a/Makefile.in b/Makefile.in index 437cec911..986427846 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..993a8c0df 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 @@ -97,7 +97,7 @@ class Module : public PScopeExtra, public LineInfo { /* 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 @@ -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/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/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..21f751601 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" @@ -61,6 +61,24 @@ 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; + + // 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; @@ -79,7 +97,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,9 +108,11 @@ class LexicalScope { PExpr*expr; // If there are range constraints, list them here range_t*range; + + SymbolType symbol_type() const; }; - mapparameters; - maplocalparams; + mapparameters; + maplocalparams; // Defined types in the scope. maptypedefs; @@ -100,10 +120,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/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 cb32e6954..e5f5f169e 100644 --- a/Statement.cc +++ b/Statement.cc @@ -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()) { @@ -411,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 78963dc93..ae5e162b6 100644 --- a/Statement.h +++ b/Statement.h @@ -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_; @@ -561,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/elab_scope.cc b/elab_scope.cc index 5799c924a..b3b008b92 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 @@ -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,32 @@ 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() - << ": 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() - << ": 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() - << ": 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); } } @@ -556,6 +529,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->explicit_imports); if (debug_scopes) { cerr << cur->second->get_fileline() << ": elaborate_scope_class: " @@ -574,6 +548,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->explicit_imports); if (debug_scopes) { cerr << cur->second->get_fileline() << ": elaborate_scope_class: " @@ -644,6 +619,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->explicit_imports); if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_task: " @@ -661,39 +637,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); } @@ -706,6 +649,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->explicit_imports); if (debug_scopes) { cerr << task->get_fileline() << ": elaborate_scope_func: " @@ -723,40 +667,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); } @@ -815,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; } @@ -1013,56 +924,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; @@ -1093,6 +954,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(&explicit_imports); // Set in the scope a localparam for the value of the // genvar within this instance of the generate @@ -1169,45 +1031,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)") @@ -1228,6 +1051,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(&explicit_imports); elaborate_subscope_(des, scope); @@ -1311,44 +1135,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_) { @@ -1368,6 +1154,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(&explicit_imports); + item->elaborate_subscope_(des, scope); return true; @@ -1376,46 +1164,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; @@ -1423,6 +1171,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(&explicit_imports); elaborate_subscope_(des, scope); @@ -1554,36 +1303,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. @@ -1728,6 +1447,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->explicit_imports); for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1) my_scope->attribute(attrib_list[adx].key, attrib_list[adx].val); @@ -1809,36 +1529,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); @@ -1909,37 +1601,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 @@ -1952,6 +1613,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(&explicit_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..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 @@ -1214,7 +1176,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 166848767..0875929f3 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4322,7 +4322,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); @@ -4368,8 +4374,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; } @@ -5348,11 +5355,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) { @@ -6609,6 +6622,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->explicit_imports); set_scope_timescale(des, scope, unit); elaborator_work_item_t*es = new elaborate_package_t(des, scope, unit); @@ -6633,6 +6647,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->explicit_imports); set_scope_timescale(des, scope, pac->second); elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second); @@ -6674,6 +6689,7 @@ Design* elaborate(listroots) // Collect some basic properties of this scope from the // Module definition. scope->set_line(rmod); + 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/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 b25b03941..6b85a5a2a 100644 --- a/netlist.h +++ b/netlist.h @@ -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/parse.y b/parse.y index 5337496df..eb10d6b72 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; } @@ -1056,6 +1058,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 */ @@ -1103,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; @@ -1422,8 +1428,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; @@ -1436,7 +1441,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); @@ -1484,8 +1489,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); @@ -1989,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 @@ -2547,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. */ @@ -3176,7 +3185,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); @@ -3559,7 +3569,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; @@ -3612,7 +3623,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; @@ -4508,7 +4519,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; @@ -5048,29 +5059,27 @@ 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 - | package_import_declaration - /* 1364-2001 and later allow specparam declarations outside specify blocks. */ | attribute_list_opt K_specparam @@ -5162,9 +5171,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 @@ -5185,7 +5194,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); } ; @@ -5318,7 +5327,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; } @@ -6260,8 +6270,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 @@ -6295,8 +6304,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 @@ -6333,8 +6341,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 @@ -6369,8 +6376,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 @@ -6408,12 +6414,18 @@ statement_item /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_TRIGGER hierarchy_identifier ';' - { PTrigger*tmp = new PTrigger(*$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/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 000cfd1c7..957addd3e 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; @@ -400,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); } @@ -423,6 +439,89 @@ 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, bool tf_call, bool make_explicit) +{ + 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 (found_pkg && make_explicit) { + 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; + 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, bool tf_call) +{ + 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, tf_call, true)) + 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 +615,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 +659,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 +694,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; @@ -642,7 +707,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); @@ -656,26 +722,34 @@ 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; return block; } /* - * Create a new identifier. Check if this is an imported name. + * 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) { - LexicalScope*scope = pform_peek_scope(); - map::const_iterator pkg = scope->imports.find(name.front().name); - if (pkg == scope->imports.end()) - return new PEIdent(name); + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, false); - // XXXX For now, do not support indexed imported names. - assert(name.back().index.size() == 0); + return new PEIdent(name); +} - return new PEIdent(pkg->second, name); +PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg, + const pform_name_t&name) +{ + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, false); + + PTrigger*tmp = new PTrigger(pkg, name); + FILE_NAME(tmp, loc); + return tmp; } PGenerate* pform_parent_generate(void) @@ -729,15 +803,33 @@ 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; } 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); } -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) { @@ -745,15 +837,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); @@ -773,17 +861,24 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::listtypedefs[name]; ivl_assert(*data_type, ref == 0); ref = data_type; - if (enum_type_t*enum_type = dynamic_cast(data_type)) { + if (enum_type_t*enum_type = dynamic_cast(data_type)) pform_put_enum_type_in_scope(enum_type); - } } -data_type_t* pform_test_type_identifier(const char*txt) +void pform_set_type_referenced(const struct vlltype&loc, const char*name) +{ + perm_string lex_name = lex_strings.make(name); + check_potential_imports(loc, lex_name, false); +} + +data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) { perm_string name = lex_strings.make(txt); @@ -798,8 +893,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()) @@ -813,6 +908,16 @@ 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, false, 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(); } while (cur_scope); @@ -841,29 +946,10 @@ 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); - } + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, true); + PECallFunction*tmp = new PECallFunction(name, parms); FILE_NAME(tmp, loc); return tmp; } @@ -872,26 +958,10 @@ 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); - } + if (gn_system_verilog()) + check_potential_imports(loc, name.front().name, true); + PCallTask*tmp = new PCallTask(name, parms); FILE_NAME(tmp, loc); return tmp; } @@ -1273,6 +1343,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 @@ -1356,31 +1428,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; @@ -1423,6 +1484,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) @@ -1431,7 +1494,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; @@ -1465,6 +1528,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()); } /* @@ -1487,6 +1552,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); } /* @@ -1528,14 +1597,36 @@ 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); + } + + 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() +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 @@ -2024,18 +2115,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; } @@ -2089,10 +2172,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, @@ -2169,10 +2255,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); } @@ -2214,11 +2303,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); } @@ -2554,20 +2645,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; } @@ -3021,63 +3107,33 @@ 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]; - 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; + 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())) + if ((dynamic_cast(scope)) && (scope == pform_cur_module.front())) pform_cur_module.front()->param_names.push_back(name); } @@ -3090,58 +3146,30 @@ 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]; - 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; + parm->signed_flag = signed_flag; + parm->range = 0; } void pform_set_specparam(const struct vlltype&loc, perm_string name, @@ -3151,55 +3179,30 @@ 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 = new Module::param_expr_t(); + FILE_NAME(parm, loc); - Module::param_expr_t&parm = pform_cur_module.front()->specparams[name]; - FILE_NAME(&parm, loc); + add_local_symbol(scope, name, parm); + pform_cur_module.front()->specparams[name] = parm; - parm.expr = expr; + 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; + parm->signed_flag = false; + parm->range = 0; } void pform_set_defparam(const pform_name_t&name, PExpr*expr) @@ -3621,12 +3624,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 2b9c04f23..aba405ad0 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 @@ -246,7 +246,10 @@ 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); + +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 @@ -274,7 +277,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); @@ -299,7 +303,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 @@ -311,9 +315,10 @@ 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. 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, 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; } 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); } } 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; }; /* 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);