mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	Merge pull request #5135 from YosysHQ/emil/ast-ownership
ast, read_verilog: ownership in AST, use C++ styles for parser and lexer
This commit is contained in:
		
						commit
						fb024c4d55
					
				
					 28 changed files with 3685 additions and 3604 deletions
				
			
		
							
								
								
									
										2
									
								
								.github/actions/setup-build-env/action.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/actions/setup-build-env/action.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -8,7 +8,7 @@ runs:
 | 
			
		|||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        sudo apt-get update
 | 
			
		||||
        sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
 | 
			
		||||
        sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
 | 
			
		||||
 | 
			
		||||
    - name: Install macOS Dependencies
 | 
			
		||||
      if: runner.os == 'macOS'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								.github/workflows/extra-builds.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/extra-builds.yml
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -27,19 +27,20 @@ jobs:
 | 
			
		|||
        with:
 | 
			
		||||
          submodules: true
 | 
			
		||||
          persist-credentials: false
 | 
			
		||||
      - run: sudo apt-get install libfl-dev
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: make vcxsrc YOSYS_VER=latest
 | 
			
		||||
      - uses: actions/upload-artifact@v4
 | 
			
		||||
        with:
 | 
			
		||||
          name: vcxsrc
 | 
			
		||||
          path: yosys-win32-vcxsrc-latest.zip
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  vs-build:
 | 
			
		||||
    name: Visual Studio build
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
    needs: [vs-prep, pre_job]
 | 
			
		||||
    if: needs.pre_job.outputs.should_skip != 'true'
 | 
			
		||||
    steps:  
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/download-artifact@v4
 | 
			
		||||
        with:
 | 
			
		||||
          name: vcxsrc
 | 
			
		||||
| 
						 | 
				
			
			@ -68,9 +69,20 @@ jobs:
 | 
			
		|||
          WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
 | 
			
		||||
          if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
 | 
			
		||||
 | 
			
		||||
          FLEX_VER=2.6.4
 | 
			
		||||
          FLEX=flex-${FLEX_VER}
 | 
			
		||||
          FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz
 | 
			
		||||
          if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi
 | 
			
		||||
 | 
			
		||||
          mkdir -p flex-build
 | 
			
		||||
          (cd flex-build &&
 | 
			
		||||
            ../${FLEX}/configure --prefix=$(pwd)/../flex-prefix &&
 | 
			
		||||
            make &&
 | 
			
		||||
            make install)
 | 
			
		||||
 | 
			
		||||
          mkdir -p build
 | 
			
		||||
          cat > build/Makefile.conf <<END
 | 
			
		||||
          export PATH := $(pwd)/${WASI_SDK}/bin:${PATH}
 | 
			
		||||
          export PATH := $(pwd)/${WASI_SDK}/bin:$(pwd)/flex-prefix/bin:${PATH}
 | 
			
		||||
          WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
 | 
			
		||||
 | 
			
		||||
          CONFIG := wasi
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +92,8 @@ jobs:
 | 
			
		|||
          ENABLE_READLINE := 0
 | 
			
		||||
          ENABLE_PLUGINS := 0
 | 
			
		||||
          ENABLE_ZLIB := 0
 | 
			
		||||
 | 
			
		||||
          CXXFLAGS += -I$(pwd)/flex-prefix/include
 | 
			
		||||
          END
 | 
			
		||||
 | 
			
		||||
          make -C build -f ../Makefile CXX=clang -j$(nproc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -132,8 +132,8 @@ ifeq ($(ENABLE_PYOSYS),1)
 | 
			
		|||
CXXFLAGS += -I$(BREW_PREFIX)/boost/include
 | 
			
		||||
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib
 | 
			
		||||
endif
 | 
			
		||||
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
 | 
			
		||||
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib
 | 
			
		||||
CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include
 | 
			
		||||
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib
 | 
			
		||||
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
 | 
			
		||||
PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
 | 
			
		||||
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,10 +80,10 @@ recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
 | 
			
		|||
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
 | 
			
		||||
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
 | 
			
		||||
 | 
			
		||||
For example on Ubuntu Linux 16.04 LTS the following commands will install all
 | 
			
		||||
For example on Ubuntu Linux 22.04 LTS the following commands will install all
 | 
			
		||||
prerequisites for building yosys:
 | 
			
		||||
 | 
			
		||||
	$ sudo apt-get install build-essential clang lld bison flex \
 | 
			
		||||
	$ sudo apt-get install build-essential clang lld bison flex libfl-dev \
 | 
			
		||||
		libreadline-dev gawk tcl-dev libffi-dev git \
 | 
			
		||||
		graphviz xdot pkg-config python3 libboost-system-dev \
 | 
			
		||||
		libboost-python-dev libboost-filesystem-dev zlib1g-dev
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,18 +88,18 @@ Build prerequisites
 | 
			
		|||
^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
A C++ compiler with C++17 support is required as well as some standard tools
 | 
			
		||||
such as GNU Flex, GNU Bison, Make and Python.  Some additional tools: readline,
 | 
			
		||||
libffi, Tcl and zlib; are optional but enabled by default (see
 | 
			
		||||
such as GNU Flex, GNU Bison (>=3.8), Make, and Python (>=3.11). Some additional
 | 
			
		||||
tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see
 | 
			
		||||
:makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the
 | 
			
		||||
`show` command to display schematics.
 | 
			
		||||
 | 
			
		||||
Installing all prerequisites for Ubuntu 20.04:
 | 
			
		||||
Installing all prerequisites for Ubuntu 22.04:
 | 
			
		||||
 | 
			
		||||
.. code:: console
 | 
			
		||||
 | 
			
		||||
   sudo apt-get install gperf build-essential bison flex \
 | 
			
		||||
      libreadline-dev gawk tcl-dev libffi-dev git graphviz \
 | 
			
		||||
      xdot pkg-config python3 libboost-system-dev \
 | 
			
		||||
   sudo apt-get install gperf build-essential clang lld bison flex libfl-dev \
 | 
			
		||||
      libreadline-dev gawk tcl-dev libffi-dev git \
 | 
			
		||||
      graphviz xdot pkg-config python3 libboost-system-dev \
 | 
			
		||||
      libboost-python-dev libboost-filesystem-dev zlib1g-dev
 | 
			
		||||
 | 
			
		||||
Installing all prerequisites for macOS 13 (with Homebrew):
 | 
			
		||||
| 
						 | 
				
			
			@ -137,8 +137,9 @@ For Cygwin use the following command to install all prerequisites, or select the
 | 
			
		|||
   minimum required version of Python is 3.11.  This means that Cygwin is not
 | 
			
		||||
   compatible with many of the Python-based frontends.  While this does not
 | 
			
		||||
   currently prevent Yosys itself from working, no guarantees are made for
 | 
			
		||||
   continued support.  It is instead recommended to use Windows Subsystem for
 | 
			
		||||
   Linux (WSL) and follow the instructions for Ubuntu.
 | 
			
		||||
   continued support.  You may also need to specify `CXXSTD=gnu++17` to resolve
 | 
			
		||||
   missing `strdup` function when using gcc.  It is instead recommended to use
 | 
			
		||||
   Windows Subsystem for Linux (WSL) and follow the instructions for Ubuntu.
 | 
			
		||||
 | 
			
		||||
.. 
 | 
			
		||||
   For MSYS2 (MINGW64):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree.
 | 
			
		|||
The lexer does little more than identifying all keywords and literals recognised
 | 
			
		||||
by the Yosys Verilog frontend.
 | 
			
		||||
 | 
			
		||||
The lexer keeps track of the current location in the Verilog source code using
 | 
			
		||||
some global variables. These variables are used by the constructor of AST nodes
 | 
			
		||||
to annotate each node with the source code location it originated from.
 | 
			
		||||
The lexer keeps track of the current location in the Verilog source code with
 | 
			
		||||
a ``VerilogLexer::out_loc`` and uses it to construct parser-defined
 | 
			
		||||
symbol objects.
 | 
			
		||||
 | 
			
		||||
Finally the lexer identifies and handles special comments such as "``// synopsys
 | 
			
		||||
translate_off``" and "``// synopsys full_case``". (It is recommended to use
 | 
			
		||||
| 
						 | 
				
			
			@ -178,21 +178,22 @@ properties:
 | 
			
		|||
 | 
			
		||||
-  | Source code location
 | 
			
		||||
   | Each ``AST::AstNode`` is automatically annotated with the current source
 | 
			
		||||
     code location by the ``AST::AstNode`` constructor. It is stored in the
 | 
			
		||||
     ``std::string filename`` and ``int linenum`` member variables.
 | 
			
		||||
     code location by the ``AST::AstNode`` constructor. The ``location`` type
 | 
			
		||||
     is a manual reimplementation of the bison-provided location type. This
 | 
			
		||||
     type is defined at ``frontends/verilog/verilog_location.h``.
 | 
			
		||||
 | 
			
		||||
The ``AST::AstNode`` constructor can be called with up to two child nodes that
 | 
			
		||||
are automatically added to the list of child nodes for the new object. This
 | 
			
		||||
The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This
 | 
			
		||||
simplifies the creation of AST nodes for simple expressions a bit. For example
 | 
			
		||||
the bison code for parsing multiplications:
 | 
			
		||||
 | 
			
		||||
.. code:: none
 | 
			
		||||
   	:number-lines:
 | 
			
		||||
   :number-lines:
 | 
			
		||||
 | 
			
		||||
	basic_expr '*' attr basic_expr {
 | 
			
		||||
		$$ = new AstNode(AST_MUL, $1, $4);
 | 
			
		||||
		append_attr($$, $3);
 | 
			
		||||
	} |
 | 
			
		||||
   basic_expr TOK_ASTER attr basic_expr {
 | 
			
		||||
     $$ = std::make_unique<AstNode>(AST_MUL, std::move($1), std::move($4));
 | 
			
		||||
     SET_AST_NODE_LOC($$.get(), @1, @4);
 | 
			
		||||
     append_attr($$.get(), $3);
 | 
			
		||||
   } |
 | 
			
		||||
 | 
			
		||||
The generated AST data structure is then passed directly to the AST frontend
 | 
			
		||||
that performs the actual conversion to RTLIL.
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +205,7 @@ tree respectively.
 | 
			
		|||
Transforming AST to RTLIL
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
The AST Frontend converts a set of modules in AST representation to modules in
 | 
			
		||||
The AST frontend converts a set of modules in AST representation to modules in
 | 
			
		||||
RTLIL representation and adds them to the current design. This is done in two
 | 
			
		||||
steps: simplification and RTLIL generation.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,9 +38,7 @@ using namespace AST_INTERNAL;
 | 
			
		|||
 | 
			
		||||
// instantiate global variables (public API)
 | 
			
		||||
namespace AST {
 | 
			
		||||
	std::string current_filename;
 | 
			
		||||
	void (*set_line_num)(int) = NULL;
 | 
			
		||||
	int (*get_line_num)() = NULL;
 | 
			
		||||
	bool sv_mode_but_global_and_used_for_literally_one_condition;
 | 
			
		||||
	unsigned long long astnodes = 0;
 | 
			
		||||
	unsigned long long astnode_count() { return astnodes; }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +191,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
 | 
			
		|||
	if (attributes.count(id) == 0)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	AstNode *attr = attributes.at(id);
 | 
			
		||||
	auto& attr = attributes.at(id);
 | 
			
		||||
	if (attr->type != AST_CONSTANT)
 | 
			
		||||
		attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str());
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +200,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
 | 
			
		|||
 | 
			
		||||
// create new node (AstNode constructor)
 | 
			
		||||
// (the optional child arguments make it easier to create AST trees)
 | 
			
		||||
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4)
 | 
			
		||||
AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_ptr<AstNode> child2, std::unique_ptr<AstNode> child3, std::unique_ptr<AstNode> child4)
 | 
			
		||||
{
 | 
			
		||||
	static unsigned int hashidx_count = 123456789;
 | 
			
		||||
	hashidx_count = mkhash_xorshift(hashidx_count);
 | 
			
		||||
| 
						 | 
				
			
			@ -210,7 +208,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
 | 
			
		|||
	astnodes++;
 | 
			
		||||
 | 
			
		||||
	this->type = type;
 | 
			
		||||
	filename = current_filename;
 | 
			
		||||
	location = loc;
 | 
			
		||||
	is_input = false;
 | 
			
		||||
	is_output = false;
 | 
			
		||||
	is_reg = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -240,56 +238,73 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
 | 
			
		|||
	in_param = false;
 | 
			
		||||
 | 
			
		||||
	if (child1)
 | 
			
		||||
		children.push_back(child1);
 | 
			
		||||
		children.push_back(std::move(child1));
 | 
			
		||||
	if (child2)
 | 
			
		||||
		children.push_back(child2);
 | 
			
		||||
		children.push_back(std::move(child2));
 | 
			
		||||
	if (child3)
 | 
			
		||||
		children.push_back(child3);
 | 
			
		||||
		children.push_back(std::move(child3));
 | 
			
		||||
	if (child4)
 | 
			
		||||
		children.push_back(child4);
 | 
			
		||||
		children.push_back(std::move(child4));
 | 
			
		||||
 | 
			
		||||
	fixup_hierarchy_flags();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a (deep recursive) copy of a node
 | 
			
		||||
AstNode *AstNode::clone() const
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::clone() const
 | 
			
		||||
{
 | 
			
		||||
	AstNode *that = new AstNode;
 | 
			
		||||
	*that = *this;
 | 
			
		||||
	for (auto &it : that->children)
 | 
			
		||||
		it = it->clone();
 | 
			
		||||
	for (auto &it : that->attributes)
 | 
			
		||||
		it.second = it.second->clone();
 | 
			
		||||
 | 
			
		||||
	that->set_in_lvalue_flag(false);
 | 
			
		||||
	that->set_in_param_flag(false);
 | 
			
		||||
	that->fixup_hierarchy_flags(); // fixup to set flags on cloned children
 | 
			
		||||
	auto that = std::make_unique<AstNode>(this->location, this->type);
 | 
			
		||||
	cloneInto(*that.get());
 | 
			
		||||
	return that;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a (deep recursive) copy of a node use 'other' as target root node
 | 
			
		||||
void AstNode::cloneInto(AstNode *other) const
 | 
			
		||||
void AstNode::cloneInto(AstNode &other) const
 | 
			
		||||
{
 | 
			
		||||
	AstNode *tmp = clone();
 | 
			
		||||
	tmp->in_lvalue_from_above = other->in_lvalue_from_above;
 | 
			
		||||
	tmp->in_param_from_above = other->in_param_from_above;
 | 
			
		||||
	other->delete_children();
 | 
			
		||||
	*other = *tmp;
 | 
			
		||||
	tmp->children.clear();
 | 
			
		||||
	tmp->attributes.clear();
 | 
			
		||||
	other->fixup_hierarchy_flags();
 | 
			
		||||
	delete tmp;
 | 
			
		||||
	other.type = type;
 | 
			
		||||
	other.str = str;
 | 
			
		||||
	other.bits = bits;
 | 
			
		||||
	other.is_input = is_input;
 | 
			
		||||
	other.is_output = is_output;
 | 
			
		||||
	other.is_reg = is_reg;
 | 
			
		||||
	other.is_logic = is_logic;
 | 
			
		||||
	other.is_signed = is_signed;
 | 
			
		||||
	other.is_string = is_string;
 | 
			
		||||
	other.is_wand = is_wand;
 | 
			
		||||
	other.is_wor = is_wor;
 | 
			
		||||
	other.range_valid = range_valid;
 | 
			
		||||
	other.range_swapped = range_swapped;
 | 
			
		||||
	other.was_checked = was_checked;
 | 
			
		||||
	other.is_unsized = is_unsized;
 | 
			
		||||
	other.is_custom_type = is_custom_type;
 | 
			
		||||
	other.port_id = port_id,
 | 
			
		||||
	other.range_left = range_left,
 | 
			
		||||
	other.range_right = range_right;
 | 
			
		||||
	other.integer = integer;
 | 
			
		||||
	other.realvalue = realvalue;
 | 
			
		||||
	other.is_enum = is_enum;
 | 
			
		||||
	other.dimensions = dimensions;
 | 
			
		||||
	other.unpacked_dimensions = unpacked_dimensions;
 | 
			
		||||
	other.id2ast = id2ast;
 | 
			
		||||
	other.basic_prep = basic_prep;
 | 
			
		||||
	other.lookahead = lookahead;
 | 
			
		||||
	other.location = location;
 | 
			
		||||
	other.in_lvalue = in_lvalue;
 | 
			
		||||
	other.in_param = in_param;
 | 
			
		||||
	// Keep in_lvalue_from_above and in_param_from_above untouched
 | 
			
		||||
 | 
			
		||||
	other.delete_children();
 | 
			
		||||
	for (auto& child : this->children)
 | 
			
		||||
		other.children.push_back(child->clone());
 | 
			
		||||
	for (auto& [key, val] : this->attributes)
 | 
			
		||||
		other.attributes[key] = (val->clone());
 | 
			
		||||
	 // fixup to set flags on cloned children
 | 
			
		||||
	other.fixup_hierarchy_flags();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// delete all children in this node
 | 
			
		||||
void AstNode::delete_children()
 | 
			
		||||
{
 | 
			
		||||
	for (auto &it : children)
 | 
			
		||||
		delete it;
 | 
			
		||||
	children.clear();
 | 
			
		||||
 | 
			
		||||
	for (auto &it : attributes)
 | 
			
		||||
		delete it.second;
 | 
			
		||||
	attributes.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -424,18 +439,18 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
	{
 | 
			
		||||
	case AST_MODULE:
 | 
			
		||||
		fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str());
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (const auto& child : children)
 | 
			
		||||
			if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
 | 
			
		||||
				fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str());
 | 
			
		||||
				first = false;
 | 
			
		||||
			}
 | 
			
		||||
		fprintf(f, ");\n");
 | 
			
		||||
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (const auto& child : children)
 | 
			
		||||
			if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM)
 | 
			
		||||
				child->dumpVlog(f, indent + "  ");
 | 
			
		||||
			else
 | 
			
		||||
				rem_children1.push_back(child);
 | 
			
		||||
				rem_children1.push_back(child.get());
 | 
			
		||||
 | 
			
		||||
		for (auto child : rem_children1)
 | 
			
		||||
			if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY)
 | 
			
		||||
| 
						 | 
				
			
			@ -471,7 +486,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
			fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str());
 | 
			
		||||
		if (is_signed)
 | 
			
		||||
			fprintf(f, " signed");
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			fprintf(f, " ");
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -487,7 +502,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
		fprintf(f, "%s" "memory", indent.c_str());
 | 
			
		||||
		if (is_signed)
 | 
			
		||||
			fprintf(f, " signed");
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			fprintf(f, " ");
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
			if (first)
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +516,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
	if (0) { case AST_MEMINIT: txt = "@meminit@";  }
 | 
			
		||||
	if (0) { case AST_MEMWR:   txt = "@memwr@";  }
 | 
			
		||||
		fprintf(f, "%s%s", indent.c_str(), txt.c_str());
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			fprintf(f, first ? "(" : ", ");
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
			first = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -518,7 +533,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
			else
 | 
			
		||||
				fprintf(f, "[%d:%d]", range_left, range_right);
 | 
			
		||||
		} else {
 | 
			
		||||
			for (auto child : children) {
 | 
			
		||||
			for (const auto& child : children) {
 | 
			
		||||
				fprintf(f, "%c", first ? '[' : ':');
 | 
			
		||||
				child->dumpVlog(f, "");
 | 
			
		||||
				first = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -528,13 +543,13 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
		break;
 | 
			
		||||
 | 
			
		||||
	case AST_MULTIRANGE:
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (const auto& child : children)
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case AST_ALWAYS:
 | 
			
		||||
		fprintf(f, "%s" "always @", indent.c_str());
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
 | 
			
		||||
				continue;
 | 
			
		||||
			fprintf(f, first ? "(" : ", ");
 | 
			
		||||
| 
						 | 
				
			
			@ -542,7 +557,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
			first = false;
 | 
			
		||||
		}
 | 
			
		||||
		fprintf(f, first ? "*\n" : ")\n");
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
 | 
			
		||||
				child->dumpVlog(f, indent + "  ");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -550,7 +565,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
 | 
			
		||||
	case AST_INITIAL:
 | 
			
		||||
		fprintf(f, "%s" "initial\n", indent.c_str());
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
 | 
			
		||||
				child->dumpVlog(f, indent + "  ");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -563,7 +578,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
			fprintf(f, "posedge ");
 | 
			
		||||
		if (type == AST_NEGEDGE)
 | 
			
		||||
			fprintf(f, "negedge ");
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (const auto& child : children)
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +590,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
			else
 | 
			
		||||
				fprintf(f, "%s", id2vl(str).c_str());
 | 
			
		||||
		}
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (const auto& child : children)
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -603,7 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
			children[0]->dumpVlog(f, indent);
 | 
			
		||||
		} else {
 | 
			
		||||
			fprintf(f, "%s" "begin\n", indent.c_str());
 | 
			
		||||
			for (auto child : children)
 | 
			
		||||
			for (const auto& child : children)
 | 
			
		||||
				child->dumpVlog(f, indent + "  ");
 | 
			
		||||
			fprintf(f, "%s" "end\n", indent.c_str());
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -619,7 +634,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
		children[0]->dumpVlog(f, "");
 | 
			
		||||
		fprintf(f, ")\n");
 | 
			
		||||
		for (size_t i = 1; i < children.size(); i++) {
 | 
			
		||||
			AstNode *child = children[i];
 | 
			
		||||
			const auto& child = children[i];
 | 
			
		||||
			child->dumpVlog(f, indent + "  ");
 | 
			
		||||
		}
 | 
			
		||||
		fprintf(f, "%s" "endcase\n", indent.c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -628,7 +643,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
	case AST_COND:
 | 
			
		||||
	case AST_CONDX:
 | 
			
		||||
	case AST_CONDZ:
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (const auto& child : children) {
 | 
			
		||||
			if (child->type == AST_BLOCK) {
 | 
			
		||||
				fprintf(f, ":\n");
 | 
			
		||||
				child->dumpVlog(f, indent + "  ");
 | 
			
		||||
| 
						 | 
				
			
			@ -664,7 +679,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
 | 
			
		|||
	case AST_CONCAT:
 | 
			
		||||
		fprintf(f, "{");
 | 
			
		||||
		for (int i = GetSize(children)-1; i >= 0; i--) {
 | 
			
		||||
			auto child = children[i];
 | 
			
		||||
			const auto& child = children[i];
 | 
			
		||||
			if (!first)
 | 
			
		||||
				fprintf(f, ", ");
 | 
			
		||||
			child->dumpVlog(f, "");
 | 
			
		||||
| 
						 | 
				
			
			@ -819,16 +834,16 @@ bool AstNode::contains(const AstNode *other) const
 | 
			
		|||
{
 | 
			
		||||
	if (this == other)
 | 
			
		||||
		return true;
 | 
			
		||||
	for (auto child : children)
 | 
			
		||||
	for (const auto& child : children)
 | 
			
		||||
		if (child->contains(other))
 | 
			
		||||
			return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create an AST node for a constant (using a 32 bit int as value)
 | 
			
		||||
AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *node = new AstNode(AST_CONSTANT);
 | 
			
		||||
	auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
 | 
			
		||||
	node->integer = v;
 | 
			
		||||
	node->is_signed = is_signed;
 | 
			
		||||
	for (int i = 0; i < width; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -842,9 +857,9 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// create an AST node for a constant (using a bit vector as value)
 | 
			
		||||
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *node = new AstNode(AST_CONSTANT);
 | 
			
		||||
	auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
 | 
			
		||||
	node->is_signed = is_signed;
 | 
			
		||||
	node->bits = v;
 | 
			
		||||
	for (size_t i = 0; i < 32; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -860,15 +875,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
 | 
			
		|||
	return node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed)
 | 
			
		||||
{
 | 
			
		||||
	return mkconst_bits(v, is_signed, false);
 | 
			
		||||
	return mkconst_bits(loc, v, is_signed, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create an AST node for a constant (using a string in bit vector form as value)
 | 
			
		||||
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
 | 
			
		||||
	auto node = mkconst_str(loc, RTLIL::Const(v).decode_string());
 | 
			
		||||
	while (GetSize(node->bits) < GetSize(v))
 | 
			
		||||
		node->bits.push_back(RTLIL::State::S0);
 | 
			
		||||
	log_assert(node->bits == v);
 | 
			
		||||
| 
						 | 
				
			
			@ -876,14 +891,14 @@ AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// create an AST node for a constant (using a string as value)
 | 
			
		||||
AstNode *AstNode::mkconst_str(const std::string &str)
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::string &str)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *node;
 | 
			
		||||
	std::unique_ptr<AstNode> node;
 | 
			
		||||
 | 
			
		||||
	// LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered
 | 
			
		||||
	// equivalent to the ASCII NUL ("\0")
 | 
			
		||||
	if (str.empty()) {
 | 
			
		||||
		node = AstNode::mkconst_int(0, false, 8);
 | 
			
		||||
		node = AstNode::mkconst_int(loc, 0, false, 8);
 | 
			
		||||
	} else {
 | 
			
		||||
		std::vector<RTLIL::State> data;
 | 
			
		||||
		data.reserve(str.size() * 8);
 | 
			
		||||
| 
						 | 
				
			
			@ -894,7 +909,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
 | 
			
		|||
				ch = ch >> 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		node = AstNode::mkconst_bits(data, false);
 | 
			
		||||
		node = AstNode::mkconst_bits(loc, data, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	node->is_string = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -903,18 +918,19 @@ AstNode *AstNode::mkconst_str(const std::string &str)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// create a temporary register
 | 
			
		||||
AstNode *AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
 | 
			
		||||
std::unique_ptr<AstNode> AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true)));
 | 
			
		||||
	wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
 | 
			
		||||
	auto wire_owned = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true)));
 | 
			
		||||
	auto* wire = wire_owned.get();
 | 
			
		||||
	wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
 | 
			
		||||
	if (nosync)
 | 
			
		||||
		wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
 | 
			
		||||
		wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false));
 | 
			
		||||
	wire->is_signed = is_signed;
 | 
			
		||||
	wire->is_logic = true;
 | 
			
		||||
	mod->children.push_back(wire);
 | 
			
		||||
	mod->children.push_back(std::move(wire_owned));
 | 
			
		||||
	while (wire->simplify(true, 1, -1, false)) { }
 | 
			
		||||
 | 
			
		||||
	AstNode *ident = new AstNode(AST_IDENTIFIER);
 | 
			
		||||
	auto ident = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
 | 
			
		||||
	ident->str = wire->str;
 | 
			
		||||
	ident->id2ast = wire;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -968,10 +984,9 @@ RTLIL::Const AstNode::asParaConst() const
 | 
			
		|||
{
 | 
			
		||||
	if (type == AST_REALVALUE)
 | 
			
		||||
	{
 | 
			
		||||
		AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue));
 | 
			
		||||
		auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue));
 | 
			
		||||
		RTLIL::Const val = strnode->asAttrConst();
 | 
			
		||||
		val.flags |= RTLIL::CONST_FLAG_REAL;
 | 
			
		||||
		delete strnode;
 | 
			
		||||
		return val;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1071,7 +1086,7 @@ RTLIL::Const AstNode::realAsConst(int width)
 | 
			
		|||
 | 
			
		||||
std::string AstNode::loc_string() const
 | 
			
		||||
{
 | 
			
		||||
	return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);
 | 
			
		||||
	return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
 | 
			
		||||
| 
						 | 
				
			
			@ -1079,7 +1094,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
 | 
			
		|||
	obj->attributes[ID::src] = ast->loc_string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool param_has_no_default(const AstNode *param) {
 | 
			
		||||
static bool param_has_no_default(const AstNode* param) {
 | 
			
		||||
	const auto &children = param->children;
 | 
			
		||||
	log_assert(param->type == AST_PARAMETER);
 | 
			
		||||
	log_assert(children.size() <= 2);
 | 
			
		||||
| 
						 | 
				
			
			@ -1087,7 +1102,7 @@ static bool param_has_no_default(const AstNode *param) {
 | 
			
		|||
		(children.size() == 1 && children[0]->type == AST_RANGE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false)
 | 
			
		||||
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, std::unique_ptr<AstNode> original_ast = NULL, bool quiet = false)
 | 
			
		||||
{
 | 
			
		||||
	log_assert(current_scope.empty());
 | 
			
		||||
	log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1101,15 +1116,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
	AstModule *module = new AstModule;
 | 
			
		||||
	current_module = module;
 | 
			
		||||
 | 
			
		||||
	module->ast = NULL;
 | 
			
		||||
	module->ast = nullptr;
 | 
			
		||||
	module->name = ast->str;
 | 
			
		||||
	set_src_attr(module, ast);
 | 
			
		||||
	module->set_bool_attribute(ID::cells_not_processed);
 | 
			
		||||
 | 
			
		||||
	current_ast_mod = ast;
 | 
			
		||||
	AstNode *ast_before_simplify;
 | 
			
		||||
	std::unique_ptr<AstNode> ast_before_simplify;
 | 
			
		||||
	if (original_ast != NULL)
 | 
			
		||||
		ast_before_simplify = original_ast;
 | 
			
		||||
		ast_before_simplify = std::move(original_ast);
 | 
			
		||||
	else
 | 
			
		||||
		ast_before_simplify = ast->clone();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1126,15 +1141,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
 | 
			
		||||
	if (!defer)
 | 
			
		||||
	{
 | 
			
		||||
		for (const AstNode *node : ast->children)
 | 
			
		||||
			if (node->type == AST_PARAMETER && param_has_no_default(node))
 | 
			
		||||
		for (auto& node : ast->children)
 | 
			
		||||
			if (node->type == AST_PARAMETER && param_has_no_default(node.get()))
 | 
			
		||||
				node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str());
 | 
			
		||||
 | 
			
		||||
		bool blackbox_module = flag_lib;
 | 
			
		||||
 | 
			
		||||
		if (!blackbox_module && !flag_noblackbox) {
 | 
			
		||||
			blackbox_module = true;
 | 
			
		||||
			for (auto child : ast->children) {
 | 
			
		||||
			for (const auto& child : ast->children) {
 | 
			
		||||
				if (child->type == AST_WIRE && (child->is_input || child->is_output))
 | 
			
		||||
					continue;
 | 
			
		||||
				if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
 | 
			
		||||
| 
						 | 
				
			
			@ -1164,36 +1179,33 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
			ast->dumpVlog(NULL, "    ");
 | 
			
		||||
			log("--- END OF AST DUMP ---\n");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto &attr: ast->attributes)
 | 
			
		||||
			log_assert((bool)attr.second.get());
 | 
			
		||||
		if (flag_nowb && ast->attributes.count(ID::whitebox)) {
 | 
			
		||||
			delete ast->attributes.at(ID::whitebox);
 | 
			
		||||
			ast->attributes.erase(ID::whitebox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto &attr: ast->attributes)
 | 
			
		||||
			log_assert((bool)attr.second.get());
 | 
			
		||||
		if (ast->attributes.count(ID::lib_whitebox)) {
 | 
			
		||||
			if (!flag_lib || flag_nowb) {
 | 
			
		||||
				delete ast->attributes.at(ID::lib_whitebox);
 | 
			
		||||
				ast->attributes.erase(ID::lib_whitebox);
 | 
			
		||||
			} else {
 | 
			
		||||
				if (ast->attributes.count(ID::whitebox)) {
 | 
			
		||||
					delete ast->attributes.at(ID::whitebox);
 | 
			
		||||
					ast->attributes.erase(ID::whitebox);
 | 
			
		||||
				}
 | 
			
		||||
				AstNode *n = ast->attributes.at(ID::lib_whitebox);
 | 
			
		||||
				ast->set_attribute(ID::whitebox, n);
 | 
			
		||||
				ast->attributes.erase(ID::lib_whitebox);
 | 
			
		||||
			if (flag_lib && !flag_nowb) {
 | 
			
		||||
				ast->attributes[ID::whitebox] = std::move(
 | 
			
		||||
					ast->attributes[ID::lib_whitebox]
 | 
			
		||||
				);
 | 
			
		||||
			}
 | 
			
		||||
			ast->attributes.erase(ID::lib_whitebox);
 | 
			
		||||
		}
 | 
			
		||||
		for (auto &attr: ast->attributes)
 | 
			
		||||
			log_assert((bool)attr.second.get());
 | 
			
		||||
 | 
			
		||||
		if (!blackbox_module && ast->attributes.count(ID::blackbox)) {
 | 
			
		||||
			AstNode *n = ast->attributes.at(ID::blackbox);
 | 
			
		||||
			auto& n = ast->attributes.at(ID::blackbox);
 | 
			
		||||
			if (n->type != AST_CONSTANT)
 | 
			
		||||
				ast->input_error("Got blackbox attribute with non-constant value!\n");
 | 
			
		||||
			blackbox_module = n->asBool();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (blackbox_module && ast->attributes.count(ID::whitebox)) {
 | 
			
		||||
			AstNode *n = ast->attributes.at(ID::whitebox);
 | 
			
		||||
			auto& n = ast->attributes.at(ID::whitebox);
 | 
			
		||||
			if (n->type != AST_CONSTANT)
 | 
			
		||||
				ast->input_error("Got whitebox attribute with non-constant value!\n");
 | 
			
		||||
			blackbox_module = !n->asBool();
 | 
			
		||||
| 
						 | 
				
			
			@ -1201,62 +1213,59 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
 | 
			
		||||
		if (ast->attributes.count(ID::noblackbox)) {
 | 
			
		||||
			if (blackbox_module) {
 | 
			
		||||
				AstNode *n = ast->attributes.at(ID::noblackbox);
 | 
			
		||||
				auto& n = ast->attributes.at(ID::noblackbox);
 | 
			
		||||
				if (n->type != AST_CONSTANT)
 | 
			
		||||
					ast->input_error("Got noblackbox attribute with non-constant value!\n");
 | 
			
		||||
				blackbox_module = !n->asBool();
 | 
			
		||||
			}
 | 
			
		||||
			delete ast->attributes.at(ID::noblackbox);
 | 
			
		||||
			ast->attributes.erase(ID::noblackbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto &attr: ast->attributes)
 | 
			
		||||
			log_assert((bool)attr.second.get());
 | 
			
		||||
		if (blackbox_module)
 | 
			
		||||
		{
 | 
			
		||||
			if (ast->attributes.count(ID::whitebox)) {
 | 
			
		||||
				delete ast->attributes.at(ID::whitebox);
 | 
			
		||||
				ast->attributes.erase(ID::whitebox);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ast->attributes.count(ID::lib_whitebox)) {
 | 
			
		||||
				delete ast->attributes.at(ID::lib_whitebox);
 | 
			
		||||
				ast->attributes.erase(ID::lib_whitebox);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			std::vector<AstNode*> new_children;
 | 
			
		||||
			for (auto child : ast->children) {
 | 
			
		||||
			std::vector<std::unique_ptr<AstNode>> new_children;
 | 
			
		||||
			for (auto& child : ast->children) {
 | 
			
		||||
				if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
 | 
			
		||||
					new_children.push_back(child);
 | 
			
		||||
					new_children.push_back(std::move(child));
 | 
			
		||||
				} else if (child->type == AST_PARAMETER) {
 | 
			
		||||
					new_children.push_back(child);
 | 
			
		||||
					new_children.push_back(std::move(child));
 | 
			
		||||
				} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
 | 
			
		||||
						(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
 | 
			
		||||
					new_children.push_back(child);
 | 
			
		||||
				} else {
 | 
			
		||||
					delete child;
 | 
			
		||||
					new_children.push_back(std::move(child));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ast->children.swap(new_children);
 | 
			
		||||
 | 
			
		||||
			if (ast->attributes.count(ID::blackbox) == 0) {
 | 
			
		||||
				ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false));
 | 
			
		||||
				ast->set_attribute(ID::blackbox, AstNode::mkconst_int(ast->location, 1, false));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ignoreThisSignalsInInitial = RTLIL::SigSpec();
 | 
			
		||||
 | 
			
		||||
		for (auto &attr : ast->attributes) {
 | 
			
		||||
			log_assert((bool)attr.second.get());
 | 
			
		||||
			if (attr.second->type != AST_CONSTANT)
 | 
			
		||||
				ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
 | 
			
		||||
			module->attributes[attr.first] = attr.second->asAttrConst();
 | 
			
		||||
		}
 | 
			
		||||
		for (size_t i = 0; i < ast->children.size(); i++) {
 | 
			
		||||
			AstNode *node = ast->children[i];
 | 
			
		||||
			const auto& node = ast->children[i];
 | 
			
		||||
			if (node->type == AST_WIRE || node->type == AST_MEMORY)
 | 
			
		||||
				node->genRTLIL();
 | 
			
		||||
		}
 | 
			
		||||
		for (size_t i = 0; i < ast->children.size(); i++) {
 | 
			
		||||
			AstNode *node = ast->children[i];
 | 
			
		||||
			const auto& node = ast->children[i];
 | 
			
		||||
			if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
 | 
			
		||||
				node->genRTLIL();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1264,7 +1273,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
		ignoreThisSignalsInInitial.sort_and_unify();
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < ast->children.size(); i++) {
 | 
			
		||||
			AstNode *node = ast->children[i];
 | 
			
		||||
			const auto& node = ast->children[i];
 | 
			
		||||
			if (node->type == AST_INITIAL)
 | 
			
		||||
				node->genRTLIL();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1278,14 +1287,14 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
				continue;
 | 
			
		||||
			module->attributes[attr.first] = attr.second->asAttrConst();
 | 
			
		||||
		}
 | 
			
		||||
		for (const AstNode *node : ast->children)
 | 
			
		||||
		for (const auto& node : ast->children)
 | 
			
		||||
			if (node->type == AST_PARAMETER)
 | 
			
		||||
				current_module->avail_parameters(node->str);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ast->type == AST_INTERFACE)
 | 
			
		||||
		module->set_bool_attribute(ID::is_interface);
 | 
			
		||||
	module->ast = ast_before_simplify;
 | 
			
		||||
	module->ast = std::move(ast_before_simplify);
 | 
			
		||||
	module->nolatches = flag_nolatches;
 | 
			
		||||
	module->nomeminit = flag_nomeminit;
 | 
			
		||||
	module->nomem2reg = flag_nomem2reg;
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,8 +1321,8 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
RTLIL::Module *
 | 
			
		||||
AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
 | 
			
		||||
                                         RTLIL::Module *old_module,
 | 
			
		||||
                                         AstNode *new_ast,
 | 
			
		||||
                                         AstNode *original_ast)
 | 
			
		||||
                                         AST::AstNode *new_ast,
 | 
			
		||||
                                         std::unique_ptr<AstNode> original_ast)
 | 
			
		||||
{
 | 
			
		||||
	// The old module will be deleted. Rename and mark for deletion, using
 | 
			
		||||
	// a static counter to make sure we get a unique name.
 | 
			
		||||
| 
						 | 
				
			
			@ -1336,7 +1345,7 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Generate RTLIL from AST for the new module and add to the design:
 | 
			
		||||
	RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast);
 | 
			
		||||
	RTLIL::Module* new_module = process_module(design, new_ast, false, std::move(original_ast));
 | 
			
		||||
 | 
			
		||||
	if (is_top)
 | 
			
		||||
		new_module->set_bool_attribute(ID::top);
 | 
			
		||||
| 
						 | 
				
			
			@ -1348,17 +1357,17 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
 | 
			
		|||
static void rename_in_package_stmts(AstNode *pkg)
 | 
			
		||||
{
 | 
			
		||||
	std::unordered_set<std::string> idents;
 | 
			
		||||
	for (AstNode *item : pkg->children)
 | 
			
		||||
	for (auto& item : pkg->children)
 | 
			
		||||
		idents.insert(item->str);
 | 
			
		||||
	std::function<void(AstNode*)> rename =
 | 
			
		||||
		[&rename, &idents, pkg](AstNode *node) {
 | 
			
		||||
			for (AstNode *child : node->children) {
 | 
			
		||||
	std::function<void(std::unique_ptr<AstNode>&)> rename =
 | 
			
		||||
		[&rename, &idents, pkg](std::unique_ptr<AstNode>& node) {
 | 
			
		||||
			for (auto& child : node->children) {
 | 
			
		||||
				if (idents.count(child->str))
 | 
			
		||||
					child->str = pkg->str + "::" + child->str.substr(1);
 | 
			
		||||
				rename(child);
 | 
			
		||||
			}
 | 
			
		||||
	};
 | 
			
		||||
	for (AstNode *item : pkg->children)
 | 
			
		||||
	for (auto& item : pkg->children)
 | 
			
		||||
		if (item->type == AST_FUNCTION || item->type == AST_TASK)
 | 
			
		||||
			rename(item);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1391,17 +1400,17 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
 | 
			
		|||
	ast->fixup_hierarchy_flags(true);
 | 
			
		||||
 | 
			
		||||
	log_assert(current_ast->type == AST_DESIGN);
 | 
			
		||||
	for (AstNode *child : current_ast->children)
 | 
			
		||||
	for (const auto& child : current_ast->children)
 | 
			
		||||
	{
 | 
			
		||||
		if (child->type == AST_MODULE || child->type == AST_INTERFACE)
 | 
			
		||||
		{
 | 
			
		||||
			for (auto n : design->verilog_globals)
 | 
			
		||||
			for (auto& n : design->verilog_globals)
 | 
			
		||||
				child->children.push_back(n->clone());
 | 
			
		||||
 | 
			
		||||
			// append nodes from previous packages using package-qualified names
 | 
			
		||||
			for (auto &n : design->verilog_packages) {
 | 
			
		||||
			for (auto& n : design->verilog_packages) {
 | 
			
		||||
				for (auto &o : n->children) {
 | 
			
		||||
					AstNode *cloned_node = o->clone();
 | 
			
		||||
					auto cloned_node = o->clone();
 | 
			
		||||
					// log("cloned node %s\n", type2str(cloned_node->type).c_str());
 | 
			
		||||
					if (cloned_node->type == AST_ENUM) {
 | 
			
		||||
						for (auto &e : cloned_node->children) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1411,7 +1420,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
 | 
			
		|||
					} else {
 | 
			
		||||
						cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
 | 
			
		||||
					}
 | 
			
		||||
					child->children.push_back(cloned_node);
 | 
			
		||||
					child->children.push_back(std::move(cloned_node));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1420,8 +1429,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
 | 
			
		|||
 | 
			
		||||
			bool defer_local = defer;
 | 
			
		||||
			if (!defer_local)
 | 
			
		||||
				for (const AstNode *node : child->children)
 | 
			
		||||
					if (node->type == AST_PARAMETER && param_has_no_default(node))
 | 
			
		||||
				for (const auto& node : child->children)
 | 
			
		||||
					if (node->type == AST_PARAMETER && param_has_no_default(node.get()))
 | 
			
		||||
					{
 | 
			
		||||
						log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str());
 | 
			
		||||
						defer_local = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -1435,7 +1444,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
 | 
			
		|||
			if (design->has(child->str)) {
 | 
			
		||||
				RTLIL::Module *existing_mod = design->module(child->str);
 | 
			
		||||
				if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
 | 
			
		||||
					log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str());
 | 
			
		||||
					log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str.c_str());
 | 
			
		||||
				} else if (nooverwrite) {
 | 
			
		||||
					log("Ignoring re-definition of module `%s' at %s.\n",
 | 
			
		||||
							child->str.c_str(), child->loc_string().c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,13 +1457,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			process_module(design, child, defer_local);
 | 
			
		||||
			process_module(design, child.get(), defer_local);
 | 
			
		||||
			current_ast_mod = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
		else if (child->type == AST_PACKAGE) {
 | 
			
		||||
			// process enum/other declarations
 | 
			
		||||
			child->simplify(true, 1, -1, false);
 | 
			
		||||
			rename_in_package_stmts(child);
 | 
			
		||||
			rename_in_package_stmts(child.get());
 | 
			
		||||
			design->verilog_packages.push_back(child->clone());
 | 
			
		||||
			current_scope.clear();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1471,16 +1480,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
 | 
			
		|||
			current_scope.clear();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AstModule destructor
 | 
			
		||||
AstModule::~AstModule()
 | 
			
		||||
{
 | 
			
		||||
	if (ast != NULL)
 | 
			
		||||
		delete ast;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// An interface port with modport is specified like this:
 | 
			
		||||
//    <interface_name>.<modport_name>
 | 
			
		||||
// This function splits the interface_name from the modport_name, and fails if it is not a valid combination
 | 
			
		||||
| 
						 | 
				
			
			@ -1517,7 +1519,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
 | 
			
		|||
	for (auto &ch : intf->children)
 | 
			
		||||
		if (ch->type == AST_MODPORT)
 | 
			
		||||
			if (ch->str == name) // Modport found
 | 
			
		||||
				return ch;
 | 
			
		||||
				return ch.get();
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1525,7 +1527,8 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
 | 
			
		|||
void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
 | 
			
		||||
{
 | 
			
		||||
	for (auto w : intfmodule->wires()){
 | 
			
		||||
		AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true)));
 | 
			
		||||
		auto loc = module_ast->location;
 | 
			
		||||
		auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
 | 
			
		||||
		std::string origname = log_id(w->name);
 | 
			
		||||
		std::string newname = intfname + "." + origname;
 | 
			
		||||
		wire->str = newname;
 | 
			
		||||
| 
						 | 
				
			
			@ -1544,16 +1547,13 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (found_in_modport) {
 | 
			
		||||
				module_ast->children.push_back(wire);
 | 
			
		||||
			}
 | 
			
		||||
			else { // If not found in modport, do not create port
 | 
			
		||||
				delete wire;
 | 
			
		||||
				module_ast->children.push_back(std::move(wire));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else { // If no modport, set inout
 | 
			
		||||
			wire->is_input = true;
 | 
			
		||||
			wire->is_output = true;
 | 
			
		||||
			module_ast->children.push_back(wire);
 | 
			
		||||
			module_ast->children.push_back(std::move(wire));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1571,7 +1571,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design)
 | 
			
		|||
			log("Reprocessing module %s because instantiated module %s has become available.\n",
 | 
			
		||||
					log_id(name), log_id(modname));
 | 
			
		||||
			loadconfig();
 | 
			
		||||
			process_and_replace_module(design, this, ast, NULL);
 | 
			
		||||
			process_and_replace_module(design, this, ast.get(), NULL);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1584,32 +1584,33 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
{
 | 
			
		||||
	loadconfig();
 | 
			
		||||
 | 
			
		||||
	AstNode *new_ast = ast->clone();
 | 
			
		||||
	auto new_ast = ast->clone();
 | 
			
		||||
	auto loc = ast->location;
 | 
			
		||||
	for (auto &intf : local_interfaces) {
 | 
			
		||||
		std::string intfname = intf.first.str();
 | 
			
		||||
		RTLIL::Module *intfmodule = intf.second;
 | 
			
		||||
		for (auto w : intfmodule->wires()){
 | 
			
		||||
			AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true)));
 | 
			
		||||
			auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
 | 
			
		||||
			std::string newname = log_id(w->name);
 | 
			
		||||
			newname = intfname + "." + newname;
 | 
			
		||||
			wire->str = newname;
 | 
			
		||||
			new_ast->children.push_back(wire);
 | 
			
		||||
			new_ast->children.push_back(std::move(wire));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AstNode *ast_before_replacing_interface_ports = new_ast->clone();
 | 
			
		||||
	auto ast_before_replacing_interface_ports = new_ast->clone();
 | 
			
		||||
 | 
			
		||||
	// Explode all interface ports. Note this will only have an effect on 'top
 | 
			
		||||
	// level' modules. Other sub-modules will have their interface ports
 | 
			
		||||
	// exploded via the derive(..) function
 | 
			
		||||
	for (size_t i =0; i<new_ast->children.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		AstNode *ch2 = new_ast->children[i];
 | 
			
		||||
		const auto& ch2 = new_ast->children[i];
 | 
			
		||||
		if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
 | 
			
		||||
			std::string name_port = ch2->str; // Name of the interface port
 | 
			
		||||
			if (ch2->children.size() > 0) {
 | 
			
		||||
				for(size_t j=0; j<ch2->children.size();j++) {
 | 
			
		||||
					AstNode *ch = ch2->children[j];
 | 
			
		||||
					const auto& ch = ch2->children[j];
 | 
			
		||||
					if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
 | 
			
		||||
						std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
 | 
			
		||||
						std::string interface_type = res.first;
 | 
			
		||||
| 
						 | 
				
			
			@ -1617,11 +1618,11 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
						if (design->module(interface_type) != nullptr) {
 | 
			
		||||
							// Add a cell to the module corresponding to the interface port such that
 | 
			
		||||
							// it can further propagated down if needed:
 | 
			
		||||
							AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
 | 
			
		||||
							auto celltype_for_intf = std::make_unique<AstNode>(loc, AST_CELLTYPE);
 | 
			
		||||
							celltype_for_intf->str = interface_type;
 | 
			
		||||
							AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
 | 
			
		||||
							auto cell_for_intf = std::make_unique<AstNode>(loc, AST_CELL, std::move(celltype_for_intf));
 | 
			
		||||
							cell_for_intf->str = name_port + "_inst_from_top_dummy";
 | 
			
		||||
							new_ast->children.push_back(cell_for_intf);
 | 
			
		||||
							new_ast->children.push_back(std::move(cell_for_intf));
 | 
			
		||||
 | 
			
		||||
							// Get all members of this non-overridden dummy interface instance:
 | 
			
		||||
							RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming
 | 
			
		||||
| 
						 | 
				
			
			@ -1629,9 +1630,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
							                                                              // present in design->modules_
 | 
			
		||||
							AstModule *ast_module_of_interface = (AstModule*)intfmodule;
 | 
			
		||||
							std::string interface_modport_compare_str = "\\" + interface_modport;
 | 
			
		||||
							AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport
 | 
			
		||||
							AstNode *modport = find_modport(ast_module_of_interface->ast.get(), interface_modport_compare_str); // modport == NULL if no modport
 | 
			
		||||
							// Iterate over all wires in the interface and add them to the module:
 | 
			
		||||
							explode_interface_port(new_ast, intfmodule, name_port, modport);
 | 
			
		||||
							explode_interface_port(new_ast.get(), intfmodule, name_port, modport);
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			@ -1643,9 +1644,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
	// Generate RTLIL from AST for the new module and add to the design,
 | 
			
		||||
	// renaming this module to move it out of the way.
 | 
			
		||||
	RTLIL::Module* new_module =
 | 
			
		||||
		process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports);
 | 
			
		||||
 | 
			
		||||
	delete new_ast;
 | 
			
		||||
		process_and_replace_module(design, this, new_ast.get(), std::move(ast_before_replacing_interface_ports));
 | 
			
		||||
 | 
			
		||||
	// Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
 | 
			
		||||
	new_module->set_bool_attribute(ID::interfaces_replaced_in_module);
 | 
			
		||||
| 
						 | 
				
			
			@ -1655,7 +1654,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
// This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
 | 
			
		||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool /*mayfail*/)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *new_ast = NULL;
 | 
			
		||||
	std::unique_ptr<AstNode> new_ast = NULL;
 | 
			
		||||
	std::string modname = derive_common(design, parameters, &new_ast);
 | 
			
		||||
 | 
			
		||||
	// Since interfaces themselves may be instantiated with different parameters,
 | 
			
		||||
| 
						 | 
				
			
			@ -1691,14 +1690,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
			if (modports.count(intfname) > 0) {
 | 
			
		||||
				std::string interface_modport = modports.at(intfname).str();
 | 
			
		||||
				AstModule *ast_module_of_interface = (AstModule*)intfmodule;
 | 
			
		||||
				AstNode *ast_node_of_interface = ast_module_of_interface->ast;
 | 
			
		||||
				AstNode *ast_node_of_interface = ast_module_of_interface->ast.get();
 | 
			
		||||
				modport = find_modport(ast_node_of_interface, interface_modport);
 | 
			
		||||
			}
 | 
			
		||||
			// Iterate over all wires in the interface and add them to the module:
 | 
			
		||||
			explode_interface_port(new_ast, intfmodule, intfname, modport);
 | 
			
		||||
			explode_interface_port(new_ast.get(), intfmodule, intfname, modport);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		process_module(design, new_ast, false);
 | 
			
		||||
		process_module(design, new_ast.get(), false);
 | 
			
		||||
		design->module(modname)->check();
 | 
			
		||||
 | 
			
		||||
		RTLIL::Module* mod = design->module(modname);
 | 
			
		||||
| 
						 | 
				
			
			@ -1735,7 +1734,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
		log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete new_ast;
 | 
			
		||||
	return modname;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1744,18 +1742,17 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
 | 
			
		|||
{
 | 
			
		||||
	bool quiet = lib || attributes.count(ID::blackbox) || attributes.count(ID::whitebox);
 | 
			
		||||
 | 
			
		||||
	AstNode *new_ast = NULL;
 | 
			
		||||
	std::unique_ptr<AstNode> new_ast = NULL;
 | 
			
		||||
	std::string modname = derive_common(design, parameters, &new_ast, quiet);
 | 
			
		||||
 | 
			
		||||
	if (!design->has(modname) && new_ast) {
 | 
			
		||||
		new_ast->str = modname;
 | 
			
		||||
		process_module(design, new_ast, false, NULL, quiet);
 | 
			
		||||
		process_module(design, new_ast.get(), false, NULL, quiet);
 | 
			
		||||
		design->module(modname)->check();
 | 
			
		||||
	} else if (!quiet) {
 | 
			
		||||
		log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete new_ast;
 | 
			
		||||
	return modname;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1785,7 +1782,7 @@ std::string AST::derived_module_name(std::string stripped_name, const std::vecto
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// create a new parametric module (when needed) and return the name of the generated module
 | 
			
		||||
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet)
 | 
			
		||||
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, std::unique_ptr<AstNode>* new_ast_out, bool quiet)
 | 
			
		||||
{
 | 
			
		||||
	std::string stripped_name = name.str();
 | 
			
		||||
	(*new_ast_out) = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -1795,7 +1792,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
 | 
			
		|||
 | 
			
		||||
	int para_counter = 0;
 | 
			
		||||
	std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
 | 
			
		||||
	for (const auto child : ast->children) {
 | 
			
		||||
	for (const auto& child : ast->children) {
 | 
			
		||||
		if (child->type != AST_PARAMETER)
 | 
			
		||||
			continue;
 | 
			
		||||
		para_counter++;
 | 
			
		||||
| 
						 | 
				
			
			@ -1829,12 +1826,13 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
 | 
			
		|||
	pool<IdString> rewritten;
 | 
			
		||||
	rewritten.reserve(GetSize(parameters));
 | 
			
		||||
 | 
			
		||||
	AstNode *new_ast = ast->clone();
 | 
			
		||||
	auto new_ast = ast->clone();
 | 
			
		||||
	auto loc = ast->location;
 | 
			
		||||
	if (!new_ast->attributes.count(ID::hdlname))
 | 
			
		||||
		new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1)));
 | 
			
		||||
		new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(loc, stripped_name.substr(1)));
 | 
			
		||||
 | 
			
		||||
	para_counter = 0;
 | 
			
		||||
	for (auto child : new_ast->children) {
 | 
			
		||||
	for (auto& child : new_ast->children) {
 | 
			
		||||
		if (child->type != AST_PARAMETER)
 | 
			
		||||
			continue;
 | 
			
		||||
		para_counter++;
 | 
			
		||||
| 
						 | 
				
			
			@ -1852,16 +1850,15 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
 | 
			
		|||
		}
 | 
			
		||||
		continue;
 | 
			
		||||
	rewrite_parameter:
 | 
			
		||||
		if (param_has_no_default(child))
 | 
			
		||||
		if (param_has_no_default(child.get()))
 | 
			
		||||
			child->children.insert(child->children.begin(), nullptr);
 | 
			
		||||
		delete child->children.at(0);
 | 
			
		||||
		if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) {
 | 
			
		||||
			child->children[0] = new AstNode(AST_REALVALUE);
 | 
			
		||||
			child->children[0] = std::make_unique<AstNode>(loc, AST_REALVALUE);
 | 
			
		||||
			child->children[0]->realvalue = std::stod(it->second.decode_string());
 | 
			
		||||
		} else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0)
 | 
			
		||||
			child->children[0] = AstNode::mkconst_str(it->second.decode_string());
 | 
			
		||||
			child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string());
 | 
			
		||||
		else
 | 
			
		||||
			child->children[0] = AstNode::mkconst_bits(it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
 | 
			
		||||
			child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
 | 
			
		||||
		rewritten.insert(it->first);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1869,17 +1866,17 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
 | 
			
		|||
		for (const auto ¶m : parameters) {
 | 
			
		||||
			if (rewritten.count(param.first))
 | 
			
		||||
				continue;
 | 
			
		||||
			AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER));
 | 
			
		||||
			auto defparam = std::make_unique<AstNode>(loc, AST_DEFPARAM, std::make_unique<AstNode>(loc, AST_IDENTIFIER));
 | 
			
		||||
			defparam->children[0]->str = param.first.str();
 | 
			
		||||
			if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
 | 
			
		||||
				defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string()));
 | 
			
		||||
				defparam->children.push_back(AstNode::mkconst_str(loc, param.second.decode_string()));
 | 
			
		||||
			else
 | 
			
		||||
				defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
 | 
			
		||||
			new_ast->children.push_back(defparam);
 | 
			
		||||
				defparam->children.push_back(AstNode::mkconst_bits(loc, param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
 | 
			
		||||
			new_ast->children.push_back(std::move(defparam));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	new_ast->fixup_hierarchy_flags(true);
 | 
			
		||||
	(*new_ast_out) = new_ast;
 | 
			
		||||
	new_ast_out->reset(new_ast.release());
 | 
			
		||||
	return modname;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1929,7 +1926,7 @@ void AstNode::input_error(const char *format, ...) const
 | 
			
		|||
{
 | 
			
		||||
	va_list ap;
 | 
			
		||||
	va_start(ap, format);
 | 
			
		||||
	logv_file_error(filename, location.first_line, format, ap);
 | 
			
		||||
	logv_file_error(*location.begin.filename, location.begin.line, format, ap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
 | 
			
		||||
#include "kernel/rtlil.h"
 | 
			
		||||
#include "kernel/fmt.h"
 | 
			
		||||
#include "frontends/verilog/verilog_location.h"
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -163,12 +164,7 @@ namespace AST
 | 
			
		|||
		AST_BIND
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct AstSrcLocType {
 | 
			
		||||
		unsigned int first_line, last_line;
 | 
			
		||||
		unsigned int first_column, last_column;
 | 
			
		||||
		AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {}
 | 
			
		||||
		AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}
 | 
			
		||||
	};
 | 
			
		||||
	using AstSrcLocType = Location;
 | 
			
		||||
 | 
			
		||||
	// convert an node type to a string (e.g. for debug output)
 | 
			
		||||
	std::string type2str(AstNodeType type);
 | 
			
		||||
| 
						 | 
				
			
			@ -184,10 +180,10 @@ namespace AST
 | 
			
		|||
		AstNodeType type;
 | 
			
		||||
 | 
			
		||||
		// the list of child nodes for this node
 | 
			
		||||
		std::vector<AstNode*> children;
 | 
			
		||||
		std::vector<std::unique_ptr<AstNode>> children;
 | 
			
		||||
 | 
			
		||||
		// the list of attributes assigned to this node
 | 
			
		||||
		std::map<RTLIL::IdString, AstNode*> attributes;
 | 
			
		||||
		std::map<RTLIL::IdString, std::unique_ptr<AstNode>> attributes;
 | 
			
		||||
		bool get_bool_attribute(RTLIL::IdString id);
 | 
			
		||||
 | 
			
		||||
		// node content - most of it is unused in most node types
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +209,7 @@ namespace AST
 | 
			
		|||
		int unpacked_dimensions;
 | 
			
		||||
 | 
			
		||||
		// this is set by simplify and used during RTLIL generation
 | 
			
		||||
		AstNode *id2ast;
 | 
			
		||||
		AstNode* id2ast;
 | 
			
		||||
 | 
			
		||||
		// this is used by simplify to detect if basic analysis has been performed already on the node
 | 
			
		||||
		bool basic_prep;
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +220,6 @@ namespace AST
 | 
			
		|||
		// this is the original sourcecode location that resulted in this AST node
 | 
			
		||||
		// it is automatically set by the constructor using AST::current_filename and
 | 
			
		||||
		// the AST::get_line_num() callback function.
 | 
			
		||||
		std::string filename;
 | 
			
		||||
		AstSrcLocType location;
 | 
			
		||||
 | 
			
		||||
		// are we embedded in an lvalue, param?
 | 
			
		||||
| 
						 | 
				
			
			@ -235,9 +230,9 @@ namespace AST
 | 
			
		|||
		bool in_param_from_above;
 | 
			
		||||
 | 
			
		||||
		// creating and deleting nodes
 | 
			
		||||
		AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);
 | 
			
		||||
		AstNode *clone() const;
 | 
			
		||||
		void cloneInto(AstNode *other) const;
 | 
			
		||||
		AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);
 | 
			
		||||
		std::unique_ptr<AstNode> clone() const;
 | 
			
		||||
		void cloneInto(AstNode &other) const;
 | 
			
		||||
		void delete_children();
 | 
			
		||||
		~AstNode();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -266,14 +261,14 @@ namespace AST
 | 
			
		|||
		// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
 | 
			
		||||
		bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);
 | 
			
		||||
		void replace_result_wire_name_in_function(const std::string &from, const std::string &to);
 | 
			
		||||
		AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
 | 
			
		||||
		std::unique_ptr<AstNode> readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
 | 
			
		||||
		void expand_genblock(const std::string &prefix);
 | 
			
		||||
		void label_genblks(std::set<std::string>& existing, int &counter);
 | 
			
		||||
		void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
 | 
			
		||||
				dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
 | 
			
		||||
		bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);
 | 
			
		||||
		bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block);
 | 
			
		||||
		bool mem2reg_check(pool<AstNode*> &mem2reg_set);
 | 
			
		||||
		void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
 | 
			
		||||
		void mem2reg_remove(pool<AstNode*> &mem2reg_set);
 | 
			
		||||
		void meminfo(int &mem_width, int &mem_size, int &addr_bits);
 | 
			
		||||
		bool detect_latch(const std::string &var);
 | 
			
		||||
		const RTLIL::Module* lookup_cell_module();
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +284,7 @@ namespace AST
 | 
			
		|||
		};
 | 
			
		||||
		bool has_const_only_constructs();
 | 
			
		||||
		bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
 | 
			
		||||
		AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
 | 
			
		||||
		std::unique_ptr<AstNode> eval_const_function(AstNode *fcall, bool must_succeed);
 | 
			
		||||
		bool is_simple_const_expr();
 | 
			
		||||
 | 
			
		||||
		// helper for parsing format strings
 | 
			
		||||
| 
						 | 
				
			
			@ -306,29 +301,30 @@ namespace AST
 | 
			
		|||
		std::vector<RTLIL::Binding *> genBindings() const;
 | 
			
		||||
 | 
			
		||||
		// used by genRTLIL() for detecting expression width and sign
 | 
			
		||||
		void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
 | 
			
		||||
		void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
 | 
			
		||||
		void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
 | 
			
		||||
		void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
 | 
			
		||||
 | 
			
		||||
		// create RTLIL code for this AST node
 | 
			
		||||
		// for expressions the resulting signal vector is returned
 | 
			
		||||
		// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
 | 
			
		||||
		RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
 | 
			
		||||
		RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
 | 
			
		||||
		RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = nullptr);
 | 
			
		||||
 | 
			
		||||
		// compare AST nodes
 | 
			
		||||
		bool operator==(const AstNode &other) const;
 | 
			
		||||
		bool operator!=(const AstNode &other) const;
 | 
			
		||||
		bool contains(const AstNode *other) const;
 | 
			
		||||
		AstNode operator=(AstNode) = delete;
 | 
			
		||||
 | 
			
		||||
		// helper functions for creating AST nodes for constants
 | 
			
		||||
		static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
 | 
			
		||||
		static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
 | 
			
		||||
		static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
 | 
			
		||||
		static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
 | 
			
		||||
		static AstNode *mkconst_str(const std::string &str);
 | 
			
		||||
		static std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);
 | 
			
		||||
		static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
 | 
			
		||||
		static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);
 | 
			
		||||
		static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);
 | 
			
		||||
		static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);
 | 
			
		||||
 | 
			
		||||
		// helper function to create an AST node for a temporary register
 | 
			
		||||
		AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
 | 
			
		||||
		std::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
 | 
			
		||||
 | 
			
		||||
		// helper function for creating sign-extended const objects
 | 
			
		||||
		RTLIL::Const bitsAsConst(int width, bool is_signed);
 | 
			
		||||
| 
						 | 
				
			
			@ -357,12 +353,12 @@ namespace AST
 | 
			
		|||
 | 
			
		||||
		// helper to clone the node with some of its subexpressions replaced with zero (this is used
 | 
			
		||||
		// to evaluate widths of dynamic ranges)
 | 
			
		||||
		AstNode *clone_at_zero();
 | 
			
		||||
		std::unique_ptr<AstNode> clone_at_zero();
 | 
			
		||||
 | 
			
		||||
		void set_attribute(RTLIL::IdString key, AstNode *node)
 | 
			
		||||
		void set_attribute(RTLIL::IdString key, std::unique_ptr<AstNode> node)
 | 
			
		||||
		{
 | 
			
		||||
			attributes[key] = node;
 | 
			
		||||
			node->set_in_param_flag(true);
 | 
			
		||||
			attributes[key] = std::move(node);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +374,7 @@ namespace AST
 | 
			
		|||
		void fixup_hierarchy_flags(bool force_descend = false);
 | 
			
		||||
 | 
			
		||||
		// helpers for indexing
 | 
			
		||||
		AstNode *make_index_range(AstNode *node, bool unpacked_range = false);
 | 
			
		||||
		std::unique_ptr<AstNode> make_index_range(AstNode *node, bool unpacked_range = false);
 | 
			
		||||
		AstNode *get_struct_member() const;
 | 
			
		||||
 | 
			
		||||
		// helper to print errors from simplify/genrtlil code
 | 
			
		||||
| 
						 | 
				
			
			@ -392,12 +388,11 @@ namespace AST
 | 
			
		|||
	// parametric modules are supported directly by the AST library
 | 
			
		||||
	// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
 | 
			
		||||
	struct AstModule : RTLIL::Module {
 | 
			
		||||
		AstNode *ast;
 | 
			
		||||
		std::unique_ptr<AstNode> ast;
 | 
			
		||||
		bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
 | 
			
		||||
		~AstModule() override;
 | 
			
		||||
		RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail) override;
 | 
			
		||||
		RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
 | 
			
		||||
		std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet = false);
 | 
			
		||||
		std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, std::unique_ptr<AstNode>* new_ast_out, bool quiet = false);
 | 
			
		||||
		void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
 | 
			
		||||
		bool reprocess_if_necessary(RTLIL::Design *design) override;
 | 
			
		||||
		RTLIL::Module *clone() const override;
 | 
			
		||||
| 
						 | 
				
			
			@ -407,9 +402,9 @@ namespace AST
 | 
			
		|||
	// this must be set by the language frontend before parsing the sources
 | 
			
		||||
	// the AstNode constructor then uses current_filename and get_line_num()
 | 
			
		||||
	// to initialize the filename and linenum properties of new nodes
 | 
			
		||||
	extern std::string current_filename;
 | 
			
		||||
	extern void (*set_line_num)(int);
 | 
			
		||||
	extern int (*get_line_num)();
 | 
			
		||||
	// extern std::string current_filename;
 | 
			
		||||
	// also set by the language frontend to control some AST processing
 | 
			
		||||
	extern bool sv_mode_but_global_and_used_for_literally_one_condition;
 | 
			
		||||
 | 
			
		||||
	// for stats
 | 
			
		||||
	unsigned long long astnode_count();
 | 
			
		||||
| 
						 | 
				
			
			@ -419,7 +414,7 @@ namespace AST
 | 
			
		|||
	void use_internal_line_num();
 | 
			
		||||
 | 
			
		||||
	// call a DPI function
 | 
			
		||||
	AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
 | 
			
		||||
	std::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);
 | 
			
		||||
 | 
			
		||||
	// Helper functions related to handling SystemVerilog interfaces
 | 
			
		||||
	std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
 | 
			
		||||
| 
						 | 
				
			
			@ -465,7 +460,7 @@ namespace AST_INTERNAL
 | 
			
		|||
	process_and_replace_module(RTLIL::Design *design,
 | 
			
		||||
	                           RTLIL::Module *old_module,
 | 
			
		||||
	                           AST::AstNode *new_ast,
 | 
			
		||||
	                           AST::AstNode *original_ast = nullptr);
 | 
			
		||||
	                           std::unique_ptr<AST::AstNode> original_ast = nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,9 +64,9 @@ static ffi_fptr resolve_fn (std::string symbol_name)
 | 
			
		|||
	log_error("unable to resolve '%s'.\n", symbol_name.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
 | 
			
		||||
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args)
 | 
			
		||||
{
 | 
			
		||||
	AST::AstNode *newNode = nullptr;
 | 
			
		||||
	std::unique_ptr<AST::AstNode> newNode = nullptr;
 | 
			
		||||
	union value { double f64; float f32; int32_t i32; void *ptr; };
 | 
			
		||||
	std::vector<value> value_store(args.size() + 1);
 | 
			
		||||
	std::vector<ffi_type *> types(args.size() + 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -125,11 +125,11 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
 | 
			
		|||
        ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data());
 | 
			
		||||
 | 
			
		||||
	if (rtype == "real") {
 | 
			
		||||
		newNode = new AstNode(AST_REALVALUE);
 | 
			
		||||
		newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
 | 
			
		||||
		newNode->realvalue = value_store[args.size()].f64;
 | 
			
		||||
		log("  return realvalue: %g\n", newNode->asReal(true));
 | 
			
		||||
	} else if (rtype == "shortreal") {
 | 
			
		||||
		newNode = new AstNode(AST_REALVALUE);
 | 
			
		||||
		newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
 | 
			
		||||
		newNode->realvalue = value_store[args.size()].f32;
 | 
			
		||||
		log("  return realvalue: %g\n", newNode->asReal(true));
 | 
			
		||||
	} else if (rtype == "chandle") {
 | 
			
		||||
| 
						 | 
				
			
			@ -137,10 +137,10 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
 | 
			
		|||
		std::vector<RTLIL::State> bits(64);
 | 
			
		||||
		for (int i = 0; i < 64; i++)
 | 
			
		||||
			bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0;
 | 
			
		||||
		newNode = AstNode::mkconst_bits(bits, false);
 | 
			
		||||
		newNode = AstNode::mkconst_bits(loc, bits, false);
 | 
			
		||||
		log("  return chandle: %llx\n", (unsigned long long)newNode->asInt(false));
 | 
			
		||||
	} else {
 | 
			
		||||
		newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
 | 
			
		||||
		newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false);
 | 
			
		||||
		log("  return integer: %lld\n", (long long)newNode->asInt(true));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END
 | 
			
		|||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
 | 
			
		||||
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<std::unique_ptr<AST::AstNode>>&)
 | 
			
		||||
{
 | 
			
		||||
	log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ using namespace AST_INTERNAL;
 | 
			
		|||
// helper function for creating RTLIL code for unary operations
 | 
			
		||||
static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
 | 
			
		||||
{
 | 
			
		||||
	IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
 | 
			
		||||
	IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
 | 
			
		||||
	RTLIL::Cell *cell = current_module->addCell(name, type);
 | 
			
		||||
	set_src_attr(cell, that);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
 | 
			
		||||
	IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
 | 
			
		||||
	RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
 | 
			
		||||
	set_src_attr(cell, that);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
 | 
			
		|||
	set_src_attr(wire, that);
 | 
			
		||||
	wire->is_signed = that->is_signed;
 | 
			
		||||
 | 
			
		||||
	if (that != NULL)
 | 
			
		||||
	if (that != nullptr)
 | 
			
		||||
		for (auto &attr : that->attributes) {
 | 
			
		||||
			if (attr.second->type != AST_CONSTANT)
 | 
			
		||||
				that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
 | 
			
		|||
// helper function for creating RTLIL code for binary operations
 | 
			
		||||
static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
 | 
			
		||||
{
 | 
			
		||||
	IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
 | 
			
		||||
	IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
 | 
			
		||||
	RTLIL::Cell *cell = current_module->addCell(name, type);
 | 
			
		||||
	set_src_attr(cell, that);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
 | 
			
		|||
	log_assert(cond.size() == 1);
 | 
			
		||||
 | 
			
		||||
	std::stringstream sstr;
 | 
			
		||||
	sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++);
 | 
			
		||||
	sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++);
 | 
			
		||||
 | 
			
		||||
	RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
 | 
			
		||||
	set_src_attr(cell, that);
 | 
			
		||||
| 
						 | 
				
			
			@ -195,22 +195,22 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
		if (node->lookahead) {
 | 
			
		||||
			log_assert(node->type == AST_IDENTIFIER);
 | 
			
		||||
			if (!lookaheadids.count(node->str)) {
 | 
			
		||||
				AstNode *wire = new AstNode(AST_WIRE);
 | 
			
		||||
				for (auto c : node->id2ast->children)
 | 
			
		||||
				auto wire = std::make_unique<AstNode>(node->location, AST_WIRE);
 | 
			
		||||
				for (auto& c : node->id2ast->children)
 | 
			
		||||
					wire->children.push_back(c->clone());
 | 
			
		||||
				wire->fixup_hierarchy_flags();
 | 
			
		||||
				wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++);
 | 
			
		||||
				wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
 | 
			
		||||
				wire->set_attribute(ID::nosync, AstNode::mkconst_int(node->location, 1, false));
 | 
			
		||||
				wire->is_logic = true;
 | 
			
		||||
				while (wire->simplify(true, 1, -1, false)) { }
 | 
			
		||||
				current_ast_mod->children.push_back(wire);
 | 
			
		||||
				lookaheadids[node->str] = make_pair(node->id2ast, wire);
 | 
			
		||||
				lookaheadids[node->str] = make_pair(node->id2ast, wire.get());
 | 
			
		||||
				wire->genRTLIL();
 | 
			
		||||
				current_ast_mod->children.push_back(std::move(wire));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto child : node->children)
 | 
			
		||||
			collect_lookaheadids(child);
 | 
			
		||||
		for (auto& child : node->children)
 | 
			
		||||
			collect_lookaheadids(child.get());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool has_lookaheadids(AstNode *node)
 | 
			
		||||
| 
						 | 
				
			
			@ -218,8 +218,8 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
		if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0)
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		for (auto child : node->children)
 | 
			
		||||
			if (has_lookaheadids(child))
 | 
			
		||||
		for (auto& child : node->children)
 | 
			
		||||
			if (has_lookaheadids(child.get()))
 | 
			
		||||
				return true;
 | 
			
		||||
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -230,8 +230,8 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
		if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0)
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		for (auto child : node->children)
 | 
			
		||||
			if (has_nonlookaheadids(child))
 | 
			
		||||
		for (auto& child : node->children)
 | 
			
		||||
			if (has_nonlookaheadids(child.get()))
 | 
			
		||||
				return true;
 | 
			
		||||
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -241,16 +241,16 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
	{
 | 
			
		||||
		if (node->type == AST_ASSIGN_LE)
 | 
			
		||||
		{
 | 
			
		||||
			if (has_lookaheadids(node->children[0]))
 | 
			
		||||
			if (has_lookaheadids(node->children[0].get()))
 | 
			
		||||
			{
 | 
			
		||||
				if (has_nonlookaheadids(node->children[0]))
 | 
			
		||||
				if (has_nonlookaheadids(node->children[0].get()))
 | 
			
		||||
					log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n");
 | 
			
		||||
 | 
			
		||||
				rewrite_lookaheadids(node->children[0], true);
 | 
			
		||||
				rewrite_lookaheadids(node->children[0].get(), true);
 | 
			
		||||
				node->type = AST_ASSIGN_EQ;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			rewrite_lookaheadids(node->children[1], lhs);
 | 
			
		||||
			rewrite_lookaheadids(node->children[1].get(), lhs);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -261,21 +261,22 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
			lhs = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto child : node->children)
 | 
			
		||||
			rewrite_lookaheadids(child, lhs);
 | 
			
		||||
		for (auto& child : node->children)
 | 
			
		||||
			rewrite_lookaheadids(child.get(), lhs);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LookaheadRewriter(AstNode *top)
 | 
			
		||||
	{
 | 
			
		||||
		// top->dumpAst(NULL, "REWRITE-BEFORE> ");
 | 
			
		||||
		// top->dumpVlog(NULL, "REWRITE-BEFORE> ");
 | 
			
		||||
		// top->dumpAst(nullptr, "REWRITE-BEFORE> ");
 | 
			
		||||
		// top->dumpVlog(nullptr, "REWRITE-BEFORE> ");
 | 
			
		||||
 | 
			
		||||
		AstNode *block = nullptr;
 | 
			
		||||
		auto loc = top->location;
 | 
			
		||||
 | 
			
		||||
		for (auto c : top->children)
 | 
			
		||||
		for (auto& c : top->children)
 | 
			
		||||
			if (c->type == AST_BLOCK) {
 | 
			
		||||
				log_assert(block == nullptr);
 | 
			
		||||
				block = c;
 | 
			
		||||
				block = c.get();
 | 
			
		||||
			}
 | 
			
		||||
		log_assert(block != nullptr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -284,25 +285,25 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
 | 
			
		||||
		for (auto it : lookaheadids)
 | 
			
		||||
		{
 | 
			
		||||
			AstNode *ref_orig = new AstNode(AST_IDENTIFIER);
 | 
			
		||||
			auto ref_orig = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
 | 
			
		||||
			ref_orig->str = it.second.first->str;
 | 
			
		||||
			ref_orig->id2ast = it.second.first;
 | 
			
		||||
			ref_orig->was_checked = true;
 | 
			
		||||
 | 
			
		||||
			AstNode *ref_temp = new AstNode(AST_IDENTIFIER);
 | 
			
		||||
			auto ref_temp = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
 | 
			
		||||
			ref_temp->str = it.second.second->str;
 | 
			
		||||
			ref_temp->id2ast = it.second.second;
 | 
			
		||||
			ref_temp->was_checked = true;
 | 
			
		||||
 | 
			
		||||
			AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
 | 
			
		||||
			AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp);
 | 
			
		||||
			auto init_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
 | 
			
		||||
			auto final_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp));
 | 
			
		||||
 | 
			
		||||
			block->children.insert(block->children.begin(), init_assign);
 | 
			
		||||
			block->children.push_back(final_assign);
 | 
			
		||||
			block->children.insert(block->children.begin(), std::move(init_assign));
 | 
			
		||||
			block->children.push_back(std::move(final_assign));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// top->dumpAst(NULL, "REWRITE-AFTER> ");
 | 
			
		||||
		// top->dumpVlog(NULL, "REWRITE-AFTER> ");
 | 
			
		||||
		// top->dumpAst(nullptr, "REWRITE-AFTER> ");
 | 
			
		||||
		// top->dumpVlog(nullptr, "REWRITE-AFTER> ");
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -310,7 +311,7 @@ struct AST_INTERNAL::LookaheadRewriter
 | 
			
		|||
struct AST_INTERNAL::ProcessGenerator
 | 
			
		||||
{
 | 
			
		||||
	// input and output structures
 | 
			
		||||
	AstNode *always;
 | 
			
		||||
	std::unique_ptr<AstNode> always;
 | 
			
		||||
	RTLIL::SigSpec initSyncSignals;
 | 
			
		||||
	RTLIL::Process *proc;
 | 
			
		||||
	RTLIL::SigSpec outputSignals;
 | 
			
		||||
| 
						 | 
				
			
			@ -341,14 +342,14 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
	// The most recently assigned $print or $check cell \PRIORITY.
 | 
			
		||||
	int last_effect_priority;
 | 
			
		||||
 | 
			
		||||
	ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
 | 
			
		||||
	ProcessGenerator(std::unique_ptr<AstNode> a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
 | 
			
		||||
	{
 | 
			
		||||
		// rewrite lookahead references
 | 
			
		||||
		LookaheadRewriter la_rewriter(always);
 | 
			
		||||
		LookaheadRewriter la_rewriter(always.get());
 | 
			
		||||
 | 
			
		||||
		// generate process and simple root case
 | 
			
		||||
		proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++));
 | 
			
		||||
		set_src_attr(proc, always);
 | 
			
		||||
		proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename).c_str(), always->location.begin.line, autoidx++));
 | 
			
		||||
		set_src_attr(proc, always.get());
 | 
			
		||||
		for (auto &attr : always->attributes) {
 | 
			
		||||
			if (attr.second->type != AST_CONSTANT)
 | 
			
		||||
				always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
 | 
			
		||||
| 
						 | 
				
			
			@ -358,13 +359,13 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
		// create initial temporary signal for all output registers
 | 
			
		||||
		RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to;
 | 
			
		||||
		collect_lvalues(subst_lvalue_from, always, true, true);
 | 
			
		||||
		collect_lvalues(subst_lvalue_from, always.get(), true, true);
 | 
			
		||||
		subst_lvalue_to = new_temp_signal(subst_lvalue_from);
 | 
			
		||||
		subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to);
 | 
			
		||||
 | 
			
		||||
		bool found_global_syncs = false;
 | 
			
		||||
		bool found_anyedge_syncs = false;
 | 
			
		||||
		for (auto child : always->children)
 | 
			
		||||
		for (auto& child : always->children)
 | 
			
		||||
		{
 | 
			
		||||
			if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER &&
 | 
			
		||||
					child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -388,7 +389,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
		// create syncs for the process
 | 
			
		||||
		bool found_clocked_sync = false;
 | 
			
		||||
		for (auto child : always->children)
 | 
			
		||||
		for (auto& child : always->children)
 | 
			
		||||
			if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
 | 
			
		||||
				if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast &&
 | 
			
		||||
						child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk))
 | 
			
		||||
| 
						 | 
				
			
			@ -420,9 +421,9 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		// process the AST
 | 
			
		||||
		for (auto child : always->children)
 | 
			
		||||
		for (auto& child : always->children)
 | 
			
		||||
			if (child->type == AST_BLOCK)
 | 
			
		||||
				processAst(child);
 | 
			
		||||
				processAst(child.get());
 | 
			
		||||
 | 
			
		||||
		for (auto sync: proc->syncs)
 | 
			
		||||
			processMemWrites(sync);
 | 
			
		||||
| 
						 | 
				
			
			@ -472,7 +473,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		for (int i = 0; i < GetSize(chunks); i++)
 | 
			
		||||
		{
 | 
			
		||||
			RTLIL::SigChunk &chunk = chunks[i];
 | 
			
		||||
			if (chunk.wire == NULL)
 | 
			
		||||
			if (chunk.wire == nullptr)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			std::string wire_name;
 | 
			
		||||
| 
						 | 
				
			
			@ -484,7 +485,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
			} while (current_module->wires_.count(wire_name) > 0);
 | 
			
		||||
 | 
			
		||||
			RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width);
 | 
			
		||||
			set_src_attr(wire, always);
 | 
			
		||||
			set_src_attr(wire, always.get());
 | 
			
		||||
 | 
			
		||||
			chunk.wire = wire;
 | 
			
		||||
			chunk.offset = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -499,10 +500,10 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		switch (ast->type)
 | 
			
		||||
		{
 | 
			
		||||
		case AST_CASE:
 | 
			
		||||
			for (auto child : ast->children)
 | 
			
		||||
			for (auto& child : ast->children)
 | 
			
		||||
				if (child != ast->children[0]) {
 | 
			
		||||
					log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
 | 
			
		||||
					collect_lvalues(reg, child, type_eq, type_le, false);
 | 
			
		||||
					collect_lvalues(reg, child.get(), type_eq, type_le, false);
 | 
			
		||||
				}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -511,19 +512,19 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		case AST_CONDZ:
 | 
			
		||||
		case AST_ALWAYS:
 | 
			
		||||
		case AST_INITIAL:
 | 
			
		||||
			for (auto child : ast->children)
 | 
			
		||||
			for (auto& child : ast->children)
 | 
			
		||||
				if (child->type == AST_BLOCK)
 | 
			
		||||
					collect_lvalues(reg, child, type_eq, type_le, false);
 | 
			
		||||
					collect_lvalues(reg, child.get(), type_eq, type_le, false);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case AST_BLOCK:
 | 
			
		||||
			for (auto child : ast->children) {
 | 
			
		||||
			for (auto& child : ast->children) {
 | 
			
		||||
				if (child->type == AST_ASSIGN_EQ && type_eq)
 | 
			
		||||
					reg.append(child->children[0]->genRTLIL());
 | 
			
		||||
				if (child->type == AST_ASSIGN_LE && type_le)
 | 
			
		||||
					reg.append(child->children[0]->genRTLIL());
 | 
			
		||||
				if (child->type == AST_CASE || child->type == AST_BLOCK)
 | 
			
		||||
					collect_lvalues(reg, child, type_eq, type_le, false);
 | 
			
		||||
					collect_lvalues(reg, child.get(), type_eq, type_le, false);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -583,8 +584,8 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
		switch (ast->type)
 | 
			
		||||
		{
 | 
			
		||||
		case AST_BLOCK:
 | 
			
		||||
			for (auto child : ast->children)
 | 
			
		||||
				processAst(child);
 | 
			
		||||
			for (auto& child : ast->children)
 | 
			
		||||
				processAst(child.get());
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case AST_ASSIGN_EQ:
 | 
			
		||||
| 
						 | 
				
			
			@ -641,9 +642,9 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
				RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue;
 | 
			
		||||
				this_case_eq_rvalue.replace(subst_rvalue_map.stdmap());
 | 
			
		||||
 | 
			
		||||
				RTLIL::CaseRule *default_case = NULL;
 | 
			
		||||
				RTLIL::CaseRule *last_generated_case = NULL;
 | 
			
		||||
				for (auto child : ast->children)
 | 
			
		||||
				RTLIL::CaseRule *default_case = nullptr;
 | 
			
		||||
				RTLIL::CaseRule *last_generated_case = nullptr;
 | 
			
		||||
				for (auto& child : ast->children)
 | 
			
		||||
				{
 | 
			
		||||
					if (child == ast->children[0])
 | 
			
		||||
						continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -657,14 +658,14 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
					RTLIL::CaseRule *backup_case = current_case;
 | 
			
		||||
					current_case = new RTLIL::CaseRule;
 | 
			
		||||
					set_src_attr(current_case, child);
 | 
			
		||||
					set_src_attr(current_case, child.get());
 | 
			
		||||
					last_generated_case = current_case;
 | 
			
		||||
					addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
 | 
			
		||||
					for (auto node : child->children) {
 | 
			
		||||
					for (auto& node : child->children) {
 | 
			
		||||
						if (node->type == AST_DEFAULT)
 | 
			
		||||
							default_case = current_case;
 | 
			
		||||
						else if (node->type == AST_BLOCK)
 | 
			
		||||
							processAst(node);
 | 
			
		||||
							processAst(node.get());
 | 
			
		||||
						else
 | 
			
		||||
							current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap()));
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			@ -678,7 +679,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
					subst_rvalue_map.restore();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (last_generated_case != NULL && ast->get_bool_attribute(ID::full_case) && default_case == NULL) {
 | 
			
		||||
				if (last_generated_case != nullptr && ast->get_bool_attribute(ID::full_case) && default_case == nullptr) {
 | 
			
		||||
			#if 0
 | 
			
		||||
					// this is a valid transformation, but as optimization it is premature.
 | 
			
		||||
					// better: add a default case that assigns 'x' to everything, and let later
 | 
			
		||||
| 
						 | 
				
			
			@ -690,7 +691,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
					sw->cases.push_back(default_case);
 | 
			
		||||
			#endif
 | 
			
		||||
				} else {
 | 
			
		||||
					if (default_case == NULL) {
 | 
			
		||||
					if (default_case == nullptr) {
 | 
			
		||||
						default_case = new RTLIL::CaseRule;
 | 
			
		||||
						addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			@ -723,7 +724,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
			if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
 | 
			
		||||
		  ast->str == "$write"   || ast->str == "$writeb"   || ast->str == "$writeh"   || ast->str == "$writeo") {
 | 
			
		||||
				std::stringstream sstr;
 | 
			
		||||
				sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++);
 | 
			
		||||
				sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++);
 | 
			
		||||
 | 
			
		||||
				Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
 | 
			
		||||
				set_src_attr(en, ast);
 | 
			
		||||
| 
						 | 
				
			
			@ -760,14 +761,14 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
					default_base = 16;
 | 
			
		||||
 | 
			
		||||
				std::vector<VerilogFmtArg> args;
 | 
			
		||||
				for (auto node : ast->children) {
 | 
			
		||||
				for (auto& node : ast->children) {
 | 
			
		||||
					int width;
 | 
			
		||||
					bool is_signed;
 | 
			
		||||
					node->detectSignWidth(width, is_signed, nullptr);
 | 
			
		||||
 | 
			
		||||
					VerilogFmtArg arg = {};
 | 
			
		||||
					arg.filename = node->filename;
 | 
			
		||||
					arg.first_line = node->location.first_line;
 | 
			
		||||
					arg.filename = *node->location.begin.filename;
 | 
			
		||||
					arg.first_line = node->location.begin.line;
 | 
			
		||||
					if (node->type == AST_CONSTANT && node->is_string) {
 | 
			
		||||
						arg.type = VerilogFmtArg::STRING;
 | 
			
		||||
						arg.str = node->bitsAsConst().decode_string();
 | 
			
		||||
| 
						 | 
				
			
			@ -793,7 +794,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
					fmt.append_literal("\n");
 | 
			
		||||
				fmt.emit_rtlil(cell);
 | 
			
		||||
			} else if (!ast->str.empty()) {
 | 
			
		||||
				log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
 | 
			
		||||
				log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -813,7 +814,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
 | 
			
		||||
				IdString cellname;
 | 
			
		||||
				if (ast->str.empty())
 | 
			
		||||
					cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++);
 | 
			
		||||
					cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*ast->location.begin.filename).c_str(), ast->location.begin.line, autoidx++);
 | 
			
		||||
				else
 | 
			
		||||
					cellname = ast->str;
 | 
			
		||||
				check_unique_id(current_module, cellname, ast, "procedural assertion");
 | 
			
		||||
| 
						 | 
				
			
			@ -843,7 +844,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
				set_src_attr(cell, ast);
 | 
			
		||||
				for (auto &attr : ast->attributes) {
 | 
			
		||||
					if (attr.second->type != AST_CONSTANT)
 | 
			
		||||
						log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
 | 
			
		||||
						log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
 | 
			
		||||
					cell->attributes[attr.first] = attr.second->asAttrConst();
 | 
			
		||||
				}
 | 
			
		||||
				cell->setParam(ID::FLAVOR, flavor);
 | 
			
		||||
| 
						 | 
				
			
			@ -866,8 +867,8 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			// ast->dumpAst(NULL, "ast> ");
 | 
			
		||||
			// current_ast_mod->dumpAst(NULL, "mod> ");
 | 
			
		||||
			// ast->dumpAst(nullptr, "ast> ");
 | 
			
		||||
			// current_ast_mod->dumpAst(nullptr, "mod> ");
 | 
			
		||||
			log_abort();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -876,14 +877,14 @@ struct AST_INTERNAL::ProcessGenerator
 | 
			
		|||
	{
 | 
			
		||||
		// Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array.
 | 
			
		||||
		dict<std::pair<std::string, int>, int> port_map;
 | 
			
		||||
		for (auto child : always->children)
 | 
			
		||||
		for (auto& child : always->children)
 | 
			
		||||
			if (child->type == AST_MEMWR)
 | 
			
		||||
			{
 | 
			
		||||
				std::string memid = child->str;
 | 
			
		||||
				int portid = child->children[3]->asInt(false);
 | 
			
		||||
				int cur_idx = GetSize(sync->mem_write_actions);
 | 
			
		||||
				RTLIL::MemWriteAction action;
 | 
			
		||||
				set_src_attr(&action, child);
 | 
			
		||||
				set_src_attr(&action, child.get());
 | 
			
		||||
				action.memid = memid;
 | 
			
		||||
				action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap());
 | 
			
		||||
				action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap());
 | 
			
		||||
| 
						 | 
				
			
			@ -971,11 +972,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
	bool sub_sign_hint = true;
 | 
			
		||||
	int sub_width_hint = -1;
 | 
			
		||||
	int this_width = 0;
 | 
			
		||||
	AstNode *range = NULL;
 | 
			
		||||
	AstNode *id_ast = NULL;
 | 
			
		||||
	AstNode *range = nullptr;
 | 
			
		||||
	AstNode *id_ast = nullptr;
 | 
			
		||||
 | 
			
		||||
	bool local_found_real = false;
 | 
			
		||||
	if (found_real == NULL)
 | 
			
		||||
	if (found_real == nullptr)
 | 
			
		||||
		found_real = &local_found_real;
 | 
			
		||||
 | 
			
		||||
	switch (type)
 | 
			
		||||
| 
						 | 
				
			
			@ -1019,22 +1020,22 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
					input_error("Failed to detect width for parameter %s!\n", str.c_str());
 | 
			
		||||
			}
 | 
			
		||||
			if (children.size() != 0)
 | 
			
		||||
				range = children[0];
 | 
			
		||||
				range = children[0].get();
 | 
			
		||||
		} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
 | 
			
		||||
			if (!id_ast->range_valid) {
 | 
			
		||||
				if (id_ast->type == AST_AUTOWIRE)
 | 
			
		||||
					this_width = 1;
 | 
			
		||||
				else {
 | 
			
		||||
					// current_ast_mod->dumpAst(NULL, "mod> ");
 | 
			
		||||
					// current_ast_mod->dumpAst(nullptr, "mod> ");
 | 
			
		||||
					// log("---\n");
 | 
			
		||||
					// id_ast->dumpAst(NULL, "decl> ");
 | 
			
		||||
					// dumpAst(NULL, "ref> ");
 | 
			
		||||
					// id_ast->dumpAst(nullptr, "decl> ");
 | 
			
		||||
					// dumpAst(nullptr, "ref> ");
 | 
			
		||||
					input_error("Failed to detect width of signal access `%s'!\n", str.c_str());
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				this_width = id_ast->range_left - id_ast->range_right + 1;
 | 
			
		||||
				if (children.size() != 0)
 | 
			
		||||
					range = children[0];
 | 
			
		||||
					range = children[0].get();
 | 
			
		||||
			}
 | 
			
		||||
		} else if (id_ast->type == AST_GENVAR) {
 | 
			
		||||
			this_width = 32;
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,26 +1044,23 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
				input_error("Failed to detect width of memory access `%s'!\n", str.c_str());
 | 
			
		||||
			this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
 | 
			
		||||
			if (children.size() > 1)
 | 
			
		||||
				range = children[1];
 | 
			
		||||
				range = children[1].get();
 | 
			
		||||
		} else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) {
 | 
			
		||||
			AstNode *tmp_range = make_index_range(id_ast);
 | 
			
		||||
			auto tmp_range = make_index_range(id_ast);
 | 
			
		||||
			this_width = tmp_range->range_left - tmp_range->range_right + 1;
 | 
			
		||||
			delete tmp_range;
 | 
			
		||||
		} else
 | 
			
		||||
			input_error("Failed to detect width for identifier %s!\n", str.c_str());
 | 
			
		||||
		if (range) {
 | 
			
		||||
			if (range->children.size() == 1)
 | 
			
		||||
				this_width = 1;
 | 
			
		||||
			else if (!range->range_valid) {
 | 
			
		||||
				AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
 | 
			
		||||
				AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
 | 
			
		||||
				auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
 | 
			
		||||
				auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
 | 
			
		||||
				while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
 | 
			
		||||
				while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
 | 
			
		||||
				if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
			
		||||
					input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
			
		||||
				this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
 | 
			
		||||
				delete left_at_zero_ast;
 | 
			
		||||
				delete right_at_zero_ast;
 | 
			
		||||
			} else
 | 
			
		||||
				this_width = range->range_left - range->range_right + 1;
 | 
			
		||||
			sign_hint = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1106,7 +1104,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
		break;
 | 
			
		||||
 | 
			
		||||
	case AST_CONCAT:
 | 
			
		||||
		for (auto child : children) {
 | 
			
		||||
		for (auto& child : children) {
 | 
			
		||||
			sub_width_hint = 0;
 | 
			
		||||
			sub_sign_hint = true;
 | 
			
		||||
			child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
 | 
			
		||||
| 
						 | 
				
			
			@ -1135,7 +1133,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
	case AST_BIT_OR:
 | 
			
		||||
	case AST_BIT_XOR:
 | 
			
		||||
	case AST_BIT_XNOR:
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (auto& child : children)
 | 
			
		||||
			child->detectSignWidthWorker(width_hint, sign_hint, found_real);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1175,7 +1173,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
	case AST_MUL:
 | 
			
		||||
	case AST_DIV:
 | 
			
		||||
	case AST_MOD:
 | 
			
		||||
		for (auto child : children)
 | 
			
		||||
		for (auto& child : children)
 | 
			
		||||
			child->detectSignWidthWorker(width_hint, sign_hint, found_real);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1216,12 +1214,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
			width_hint = max(width_hint, sub_width_hint);
 | 
			
		||||
			sign_hint &= sub_sign_hint;
 | 
			
		||||
		};
 | 
			
		||||
		visit_case_expr(children[0]);
 | 
			
		||||
		visit_case_expr(children[0].get());
 | 
			
		||||
		for (size_t i = 1; i < children.size(); i++) {
 | 
			
		||||
			AstNode *child = children[i];
 | 
			
		||||
			for (AstNode *v : child->children)
 | 
			
		||||
			AstNode *child = children[i].get();
 | 
			
		||||
			for (auto& v : child->children) {
 | 
			
		||||
				if (v->type != AST_DEFAULT && v->type != AST_BLOCK)
 | 
			
		||||
					visit_case_expr(v);
 | 
			
		||||
					visit_case_expr(v.get());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1269,9 +1268,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
			if (func->type != AST_FUNCTION)
 | 
			
		||||
				input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str());
 | 
			
		||||
			const AstNode *wire = nullptr;
 | 
			
		||||
			for (const AstNode *child : func->children)
 | 
			
		||||
			for (const auto& child : func->children)
 | 
			
		||||
				if (child->str == func->str) {
 | 
			
		||||
					wire = child;
 | 
			
		||||
					wire = child.get();
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			log_assert(wire && wire->type == AST_WIRE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1280,10 +1279,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
			if (!wire->children.empty())
 | 
			
		||||
			{
 | 
			
		||||
				log_assert(wire->children.size() == 1);
 | 
			
		||||
				const AstNode *range = wire->children.at(0);
 | 
			
		||||
				const AstNode *range = wire->children.at(0).get();
 | 
			
		||||
				log_assert(range->type == AST_RANGE && range->children.size() == 2);
 | 
			
		||||
				AstNode *left = range->children.at(0)->clone();
 | 
			
		||||
				AstNode *right = range->children.at(1)->clone();
 | 
			
		||||
				auto left = range->children.at(0)->clone();
 | 
			
		||||
				auto right = range->children.at(1)->clone();
 | 
			
		||||
				left->set_in_param_flag(true);
 | 
			
		||||
				right->set_in_param_flag(true);
 | 
			
		||||
				while (left->simplify(true, 1, -1, false)) { }
 | 
			
		||||
| 
						 | 
				
			
			@ -1292,8 +1291,6 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
					input_error("Function %s has non-constant width!",
 | 
			
		||||
							RTLIL::unescape_id(str).c_str());
 | 
			
		||||
				result_width = abs(int(left->asInt(true) - right->asInt(true)));
 | 
			
		||||
				delete left;
 | 
			
		||||
				delete right;
 | 
			
		||||
			}
 | 
			
		||||
			width_hint = max(width_hint, result_width);
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1306,6 +1303,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
			
		|||
		for (auto f : log_files)
 | 
			
		||||
			current_scope_ast->dumpAst(f, "verilog-ast> ");
 | 
			
		||||
		input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (*found_real)
 | 
			
		||||
| 
						 | 
				
			
			@ -1342,8 +1340,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
	// be instantiated for this type of AST node.
 | 
			
		||||
	IdString type_name;
 | 
			
		||||
 | 
			
		||||
	current_filename = filename;
 | 
			
		||||
 | 
			
		||||
	switch (type)
 | 
			
		||||
	{
 | 
			
		||||
	// simply ignore this nodes.
 | 
			
		||||
| 
						 | 
				
			
			@ -1509,7 +1505,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			RTLIL::SigSpec sig = realAsConst(width_hint);
 | 
			
		||||
			log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
 | 
			
		||||
			log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
 | 
			
		||||
			return sig;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1518,11 +1514,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
	// shifter cell is created and the output signal of this cell is returned
 | 
			
		||||
	case AST_IDENTIFIER:
 | 
			
		||||
		{
 | 
			
		||||
			RTLIL::Wire *wire = NULL;
 | 
			
		||||
			RTLIL::Wire *wire = nullptr;
 | 
			
		||||
			RTLIL::SigChunk chunk;
 | 
			
		||||
			bool is_interface = false;
 | 
			
		||||
 | 
			
		||||
			AST::AstNode *member_node = NULL;
 | 
			
		||||
			AST::AstNode *member_node = nullptr;
 | 
			
		||||
			int add_undef_bits_msb = 0;
 | 
			
		||||
			int add_undef_bits_lsb = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1541,7 +1537,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
				if (dynamic_cast<RTLIL::Binding*>(current_module)) {
 | 
			
		||||
					/* nothing to do here */
 | 
			
		||||
				} else if (flag_autowire)
 | 
			
		||||
					log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str());
 | 
			
		||||
					log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str.c_str());
 | 
			
		||||
				else
 | 
			
		||||
					input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1609,14 +1605,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
				}
 | 
			
		||||
 | 
			
		||||
				if (!children[0]->range_valid) {
 | 
			
		||||
					AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
 | 
			
		||||
					AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
 | 
			
		||||
					auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
 | 
			
		||||
					auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
 | 
			
		||||
					while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
 | 
			
		||||
					while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
 | 
			
		||||
					if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
			
		||||
						input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
			
		||||
					int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
 | 
			
		||||
					AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
 | 
			
		||||
					auto fake_ast = std::make_unique<AstNode>(children[0]->location, AST_NONE, clone(), children[0]->children.size() >= 2 ?
 | 
			
		||||
							children[0]->children[1]->clone() : children[0]->children[0]->clone());
 | 
			
		||||
					fake_ast->children[0]->delete_children();
 | 
			
		||||
					if (member_node)
 | 
			
		||||
| 
						 | 
				
			
			@ -1637,10 +1633,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
					}
 | 
			
		||||
					if (GetSize(shift_val) >= 32)
 | 
			
		||||
						fake_ast->children[1]->is_signed = true;
 | 
			
		||||
					RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
 | 
			
		||||
					delete left_at_zero_ast;
 | 
			
		||||
					delete right_at_zero_ast;
 | 
			
		||||
					delete fake_ast;
 | 
			
		||||
					RTLIL::SigSpec sig = binop2rtlil(fake_ast.get(), ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
 | 
			
		||||
					return sig;
 | 
			
		||||
				} else {
 | 
			
		||||
					chunk.width = children[0]->range_left - children[0]->range_right + 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -1649,10 +1642,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
						chunk.offset = source_width - (chunk.offset + chunk.width);
 | 
			
		||||
					if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
 | 
			
		||||
						if (chunk.width == 1)
 | 
			
		||||
							log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
 | 
			
		||||
							log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
 | 
			
		||||
									str.c_str());
 | 
			
		||||
						else
 | 
			
		||||
							log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
 | 
			
		||||
							log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
 | 
			
		||||
									children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
 | 
			
		||||
						chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
 | 
			
		||||
					} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1666,10 +1659,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
							chunk.offset += add_undef_bits_lsb;
 | 
			
		||||
						}
 | 
			
		||||
						if (add_undef_bits_lsb)
 | 
			
		||||
							log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
 | 
			
		||||
							log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
 | 
			
		||||
									children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
 | 
			
		||||
						if (add_undef_bits_msb)
 | 
			
		||||
							log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
 | 
			
		||||
							log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
 | 
			
		||||
									children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -1943,7 +1936,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
	case AST_MEMRD:
 | 
			
		||||
		{
 | 
			
		||||
			std::stringstream sstr;
 | 
			
		||||
			sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
 | 
			
		||||
			sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
 | 
			
		||||
 | 
			
		||||
			RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
 | 
			
		||||
			set_src_attr(cell, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -1981,7 +1974,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
	case AST_MEMINIT:
 | 
			
		||||
		{
 | 
			
		||||
			std::stringstream sstr;
 | 
			
		||||
			sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
 | 
			
		||||
			sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
 | 
			
		||||
 | 
			
		||||
			SigSpec en_sig = children[2]->genRTLIL();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2026,7 +2019,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
 | 
			
		||||
			IdString cellname;
 | 
			
		||||
			if (str.empty())
 | 
			
		||||
				cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
 | 
			
		||||
				cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
 | 
			
		||||
			else
 | 
			
		||||
				cellname = str;
 | 
			
		||||
			check_unique_id(current_module, cellname, this, "procedural assertion");
 | 
			
		||||
| 
						 | 
				
			
			@ -2069,7 +2062,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
						new_left.append(left[i]);
 | 
			
		||||
						new_right.append(right[i]);
 | 
			
		||||
					}
 | 
			
		||||
				log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n"
 | 
			
		||||
				log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n"
 | 
			
		||||
						"    old assignment: %s = %s\n    new assignment: %s = %s.\n",
 | 
			
		||||
						log_signal(left), log_signal(right),
 | 
			
		||||
						log_signal(new_left), log_signal(new_right));
 | 
			
		||||
| 
						 | 
				
			
			@ -2093,7 +2086,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
			cell->set_bool_attribute(ID::module_not_derived);
 | 
			
		||||
 | 
			
		||||
			for (auto it = children.begin(); it != children.end(); it++) {
 | 
			
		||||
				AstNode *child = *it;
 | 
			
		||||
				auto* child = it->get();
 | 
			
		||||
				if (child->type == AST_CELLTYPE) {
 | 
			
		||||
					cell->type = child->str;
 | 
			
		||||
					if (flag_icells && cell->type.begins_with("\\$"))
 | 
			
		||||
| 
						 | 
				
			
			@ -2102,9 +2095,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
				}
 | 
			
		||||
				if (child->type == AST_PARASET) {
 | 
			
		||||
					IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
 | 
			
		||||
					const AstNode *value = child->children[0];
 | 
			
		||||
					const auto* value = child->children[0].get();
 | 
			
		||||
					if (value->type == AST_REALVALUE)
 | 
			
		||||
						log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n",
 | 
			
		||||
						log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n",
 | 
			
		||||
								log_id(cell), log_id(paraname), value->realvalue);
 | 
			
		||||
					else if (value->type != AST_CONSTANT)
 | 
			
		||||
						input_error("Parameter %s.%s with non-constant value!\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -2115,7 +2108,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
				if (child->type == AST_ARGUMENT) {
 | 
			
		||||
					RTLIL::SigSpec sig;
 | 
			
		||||
					if (child->children.size() > 0) {
 | 
			
		||||
						AstNode *arg = child->children[0];
 | 
			
		||||
						auto* arg = child->children[0].get();
 | 
			
		||||
						int local_width_hint = -1;
 | 
			
		||||
						bool local_sign_hint = false;
 | 
			
		||||
						// don't inadvertently attempt to detect the width of interfaces
 | 
			
		||||
| 
						 | 
				
			
			@ -2187,30 +2180,27 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
 | 
			
		||||
	// use ProcessGenerator for always blocks
 | 
			
		||||
	case AST_ALWAYS: {
 | 
			
		||||
			AstNode *always = this->clone();
 | 
			
		||||
			ProcessGenerator generator(always);
 | 
			
		||||
			ProcessGenerator generator(this->clone());
 | 
			
		||||
			ignoreThisSignalsInInitial.append(generator.outputSignals);
 | 
			
		||||
			delete always;
 | 
			
		||||
		} break;
 | 
			
		||||
 | 
			
		||||
	case AST_INITIAL: {
 | 
			
		||||
			AstNode *always = this->clone();
 | 
			
		||||
			ProcessGenerator generator(always, ignoreThisSignalsInInitial);
 | 
			
		||||
			delete always;
 | 
			
		||||
			auto always = this->clone();
 | 
			
		||||
			ProcessGenerator generator(this->clone(), ignoreThisSignalsInInitial);
 | 
			
		||||
		} break;
 | 
			
		||||
 | 
			
		||||
	case AST_TECALL: {
 | 
			
		||||
			int sz = children.size();
 | 
			
		||||
			if (str == "$info") {
 | 
			
		||||
				if (sz > 0)
 | 
			
		||||
					log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str());
 | 
			
		||||
					log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
 | 
			
		||||
				else
 | 
			
		||||
					log_file_info(filename, location.first_line, "\n");
 | 
			
		||||
					log_file_info(*location.begin.filename, location.begin.line, "\n");
 | 
			
		||||
			} else if (str == "$warning") {
 | 
			
		||||
				if (sz > 0)
 | 
			
		||||
					log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str());
 | 
			
		||||
					log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
 | 
			
		||||
				else
 | 
			
		||||
					log_file_warning(filename, location.first_line, "\n");
 | 
			
		||||
					log_file_warning(*location.begin.filename, location.begin.line, "\n");
 | 
			
		||||
			} else if (str == "$error") {
 | 
			
		||||
				if (sz > 0)
 | 
			
		||||
					input_error("%s.\n", children[0]->str.c_str());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -10,6 +10,10 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
 | 
			
		|||
 | 
			
		||||
frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
 | 
			
		||||
 | 
			
		||||
frontends/verilog/verilog_frontend.o: frontends/verilog/verilog_parser.tab.hh
 | 
			
		||||
frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh
 | 
			
		||||
 | 
			
		||||
frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh
 | 
			
		||||
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc
 | 
			
		||||
	$(Q) mkdir -p $(dir $@)
 | 
			
		||||
	$(P) flex -o frontends/verilog/verilog_lexer.cc $<
 | 
			
		||||
| 
						 | 
				
			
			@ -20,5 +24,6 @@ OBJS += frontends/verilog/verilog_parser.tab.o
 | 
			
		|||
OBJS += frontends/verilog/verilog_lexer.o
 | 
			
		||||
OBJS += frontends/verilog/preproc.o
 | 
			
		||||
OBJS += frontends/verilog/verilog_frontend.o
 | 
			
		||||
OBJS += frontends/verilog/verilog_error.o
 | 
			
		||||
OBJS += frontends/verilog/const2ast.o
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,14 +42,23 @@
 | 
			
		|||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
using namespace AST;
 | 
			
		||||
using namespace VERILOG_FRONTEND;
 | 
			
		||||
 | 
			
		||||
void ConstParser::log_maybe_loc_error(std::string msg) {
 | 
			
		||||
	log_file_error(*loc.begin.filename, loc.begin.line, "%s", msg.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConstParser::log_maybe_loc_warn(std::string msg) {
 | 
			
		||||
	log_file_warning(*loc.begin.filename, loc.begin.line, "%s", msg.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// divide an arbitrary length decimal number by two and return the rest
 | 
			
		||||
static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
 | 
			
		||||
int ConstParser::my_decimal_div_by_two(std::vector<uint8_t> &digits)
 | 
			
		||||
{
 | 
			
		||||
	int carry = 0;
 | 
			
		||||
	for (size_t i = 0; i < digits.size(); i++) {
 | 
			
		||||
		if (digits[i] >= 10)
 | 
			
		||||
			log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
 | 
			
		||||
			log_maybe_loc_error("Invalid use of [a-fxz?] in decimal constant.\n");
 | 
			
		||||
		digits[i] += carry * 10;
 | 
			
		||||
		carry = digits[i] % 2;
 | 
			
		||||
		digits[i] /= 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +69,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// find the number of significant bits in a binary number (not including the sign bit)
 | 
			
		||||
static int my_ilog2(int x)
 | 
			
		||||
int ConstParser::my_ilog2(int x)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	while (x != 0 && x != -1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +80,7 @@ static int my_ilog2(int x)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
 | 
			
		||||
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
 | 
			
		||||
void ConstParser::my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
 | 
			
		||||
{
 | 
			
		||||
	// all digits in string (MSB at index 0)
 | 
			
		||||
	std::vector<uint8_t> digits;
 | 
			
		||||
| 
						 | 
				
			
			@ -102,8 +111,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
 | 
			
		|||
		int bits_per_digit = my_ilog2(base-1);
 | 
			
		||||
		for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
 | 
			
		||||
			if (*it > (base-1) && *it < 0xf0)
 | 
			
		||||
				log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
 | 
			
		||||
					       base-1, base);
 | 
			
		||||
				log_maybe_loc_error(stringf("Digit larger than %d used in in base-%d constant.\n",
 | 
			
		||||
							base-1, base));
 | 
			
		||||
			for (int i = 0; i < bits_per_digit; i++) {
 | 
			
		||||
				int bitmask = 1 << i;
 | 
			
		||||
				if (*it == 0xf0)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +135,7 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (is_unsized && (len > len_in_bits))
 | 
			
		||||
		log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
 | 
			
		||||
		log_maybe_loc_error(stringf("Unsized constant must have width of 1 bit, but have %d bits!\n", len));
 | 
			
		||||
 | 
			
		||||
	for (len = len - 1; len >= 0; len--)
 | 
			
		||||
		if (data[len] == State::S1)
 | 
			
		||||
| 
						 | 
				
			
			@ -140,21 +149,19 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (len_in_bits == 0)
 | 
			
		||||
		log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
 | 
			
		||||
		log_maybe_loc_error("Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
 | 
			
		||||
 | 
			
		||||
	if (len > len_in_bits)
 | 
			
		||||
		log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
 | 
			
		||||
			len_in_bits, len, current_filename.c_str(), get_line_num());
 | 
			
		||||
		log_maybe_loc_warn(stringf("Literal has a width of %d bit, but value requires %d bit.\n",
 | 
			
		||||
			len_in_bits, len));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convert the Verilog code for a constant to an AST node
 | 
			
		||||
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
 | 
			
		||||
std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type, bool warn_z)
 | 
			
		||||
{
 | 
			
		||||
	if (warn_z) {
 | 
			
		||||
		AstNode *ret = const2ast(code, case_type);
 | 
			
		||||
		auto ret = const2ast(code, case_type);
 | 
			
		||||
		if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
 | 
			
		||||
			log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
 | 
			
		||||
				current_filename.c_str(), get_line_num());
 | 
			
		||||
			log_maybe_loc_warn("Yosys has only limited support for tri-state logic at the moment.\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +179,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
 | 
			
		|||
				ch = ch >> 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		AstNode *ast = AstNode::mkconst_bits(data, false);
 | 
			
		||||
		auto ast = AstNode::mkconst_bits(loc, data, false);
 | 
			
		||||
		ast->str = code;
 | 
			
		||||
		return ast;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +198,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
 | 
			
		|||
		my_strtobin(data, str, -1, 10, case_type, false);
 | 
			
		||||
		if (data.back() == State::S1)
 | 
			
		||||
			data.push_back(State::S0);
 | 
			
		||||
		return AstNode::mkconst_bits(data, true);
 | 
			
		||||
		return AstNode::mkconst_bits(loc, data, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// unsized constant
 | 
			
		||||
| 
						 | 
				
			
			@ -239,10 +246,11 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
 | 
			
		|||
			if (is_signed && data.back() == State::S1)
 | 
			
		||||
				data.push_back(State::S0);
 | 
			
		||||
		}
 | 
			
		||||
		return AstNode::mkconst_bits(data, is_signed, is_unsized);
 | 
			
		||||
		return AstNode::mkconst_bits(loc, data, is_signed, is_unsized);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@
 | 
			
		|||
 | 
			
		||||
#include "preproc.h"
 | 
			
		||||
#include "verilog_frontend.h"
 | 
			
		||||
#include "frontends/verilog/verilog_parser.tab.hh"
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stack>
 | 
			
		||||
| 
						 | 
				
			
			@ -749,7 +750,9 @@ frontend_verilog_preproc(std::istream                 &f,
 | 
			
		|||
                         std::string                   filename,
 | 
			
		||||
                         const define_map_t           &pre_defines,
 | 
			
		||||
                         define_map_t                 &global_defines_cache,
 | 
			
		||||
                         const std::list<std::string> &include_dirs)
 | 
			
		||||
                         const std::list<std::string> &include_dirs,
 | 
			
		||||
                         ParseState                   &parse_state,
 | 
			
		||||
                         ParseMode                    &parse_mode)
 | 
			
		||||
{
 | 
			
		||||
	define_map_t defines;
 | 
			
		||||
	defines.merge(pre_defines);
 | 
			
		||||
| 
						 | 
				
			
			@ -961,11 +964,11 @@ frontend_verilog_preproc(std::istream                 &f,
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if (tok == "`resetall") {
 | 
			
		||||
			default_nettype_wire = true;
 | 
			
		||||
			parse_state.default_nettype_wire = true;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tok == "`undefineall" && sv_mode) {
 | 
			
		||||
		if (tok == "`undefineall" && parse_mode.sv) {
 | 
			
		||||
			defines.clear();
 | 
			
		||||
			global_defines_cache.clear();
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,11 @@ YOSYS_NAMESPACE_BEGIN
 | 
			
		|||
struct define_body_t;
 | 
			
		||||
struct arg_map_t;
 | 
			
		||||
 | 
			
		||||
namespace VERILOG_FRONTEND {
 | 
			
		||||
	struct ParseState;
 | 
			
		||||
	struct ParseMode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct define_map_t
 | 
			
		||||
{
 | 
			
		||||
	define_map_t();
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +76,9 @@ frontend_verilog_preproc(std::istream                 &f,
 | 
			
		|||
                         std::string                   filename,
 | 
			
		||||
                         const define_map_t           &pre_defines,
 | 
			
		||||
                         define_map_t                 &global_defines_cache,
 | 
			
		||||
                         const std::list<std::string> &include_dirs);
 | 
			
		||||
                         const std::list<std::string> &include_dirs,
 | 
			
		||||
                         VERILOG_FRONTEND::ParseState &parse_state,
 | 
			
		||||
                         VERILOG_FRONTEND::ParseMode  &parse_mode);
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										52
									
								
								frontends/verilog/verilog_error.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								frontends/verilog/verilog_error.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 | 
			
		||||
 *
 | 
			
		||||
 *  Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
 *  purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
 *  copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 *
 | 
			
		||||
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 *
 | 
			
		||||
 *  ---
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys_common.h"
 | 
			
		||||
#include "frontends/verilog/verilog_error.h"
 | 
			
		||||
#include "frontends/verilog/verilog_location.h"
 | 
			
		||||
 | 
			
		||||
USING_YOSYS_NAMESPACE
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Legacy behavior is to only track lines. Now we have columns too, but we don't
 | 
			
		||||
 * report them in errors.
 | 
			
		||||
 * TODO: report columns, too
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[[noreturn]]
 | 
			
		||||
static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
    char buffer[1024];
 | 
			
		||||
    char *p = buffer;
 | 
			
		||||
    p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
 | 
			
		||||
    p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
 | 
			
		||||
    YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer);
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[noreturn]]
 | 
			
		||||
void VERILOG_FRONTEND::err_at_loc(Location loc, char const *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list args;
 | 
			
		||||
    va_start(args, fmt);
 | 
			
		||||
    verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								frontends/verilog/verilog_error.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								frontends/verilog/verilog_error.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
#ifndef VERILOG_ERROR_H
 | 
			
		||||
#define VERILOG_ERROR_H
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys_common.h"
 | 
			
		||||
#include "frontends/ast/ast.h"
 | 
			
		||||
#include "frontends/verilog/verilog_location.h"
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
namespace VERILOG_FRONTEND
 | 
			
		||||
{
 | 
			
		||||
    [[noreturn]]
 | 
			
		||||
    void err_at_loc(Location loc, char const *fmt, ...);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -31,10 +31,14 @@
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#include "verilog_frontend.h"
 | 
			
		||||
#include "verilog_lexer.h"
 | 
			
		||||
#include "verilog_error.h"
 | 
			
		||||
#include "verilog_location.h"
 | 
			
		||||
#include "preproc.h"
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "libs/sha1/sha1.h"
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <list>
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
using namespace VERILOG_FRONTEND;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,13 +50,13 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
 | 
			
		|||
 | 
			
		||||
static void error_on_dpi_function(AST::AstNode *node)
 | 
			
		||||
{
 | 
			
		||||
	if (node->type == AST::AST_DPI_FUNCTION)
 | 
			
		||||
		log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str());
 | 
			
		||||
	for (auto child : node->children)
 | 
			
		||||
		error_on_dpi_function(child);
 | 
			
		||||
    if (node->type == AST::AST_DPI_FUNCTION)
 | 
			
		||||
        err_at_loc(node->location, "Found DPI function %s.\n", node->str.c_str());
 | 
			
		||||
    for (auto& child : node->children)
 | 
			
		||||
        error_on_dpi_function(child.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list)
 | 
			
		||||
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<AST::AstNode>> &package_list)
 | 
			
		||||
{
 | 
			
		||||
	// prime the parser's user type lookup table with the package qualified names
 | 
			
		||||
	// of typedefed names in the packages seen so far.
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +65,7 @@ static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std
 | 
			
		|||
		for (const auto &node: pkg->children) {
 | 
			
		||||
			if (node->type == AST::AST_TYPEDEF) {
 | 
			
		||||
				std::string s = pkg->str + "::" + node->str.substr(1);
 | 
			
		||||
				user_types[s] = node;
 | 
			
		||||
				user_types[s] = node.get();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -250,6 +254,8 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
		bool flag_dump_vlog1 = false;
 | 
			
		||||
		bool flag_dump_vlog2 = false;
 | 
			
		||||
		bool flag_dump_rtlil = false;
 | 
			
		||||
		bool flag_debug_lexer = false;
 | 
			
		||||
		bool flag_debug_parser = false;
 | 
			
		||||
		bool flag_nolatches = false;
 | 
			
		||||
		bool flag_nomeminit = false;
 | 
			
		||||
		bool flag_nomem2reg = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -266,22 +272,24 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
		bool flag_noblackbox = false;
 | 
			
		||||
		bool flag_nowb = false;
 | 
			
		||||
		bool flag_nosynthesis = false;
 | 
			
		||||
		bool flag_yydebug = false;
 | 
			
		||||
		define_map_t defines_map;
 | 
			
		||||
 | 
			
		||||
		std::list<std::string> include_dirs;
 | 
			
		||||
		std::list<std::string> attributes;
 | 
			
		||||
 | 
			
		||||
		frontend_verilog_yydebug = false;
 | 
			
		||||
		sv_mode = false;
 | 
			
		||||
		formal_mode = false;
 | 
			
		||||
		noassert_mode = false;
 | 
			
		||||
		noassume_mode = false;
 | 
			
		||||
		norestrict_mode = false;
 | 
			
		||||
		assume_asserts_mode = false;
 | 
			
		||||
		assert_assumes_mode = false;
 | 
			
		||||
		lib_mode = false;
 | 
			
		||||
		specify_mode = false;
 | 
			
		||||
		default_nettype_wire = true;
 | 
			
		||||
		ParseMode parse_mode = {};
 | 
			
		||||
		ParseState parse_state = {};
 | 
			
		||||
		parse_mode.sv = false;
 | 
			
		||||
		parse_mode.formal = false;
 | 
			
		||||
		parse_mode.noassert = false;
 | 
			
		||||
		parse_mode.noassume = false;
 | 
			
		||||
		parse_mode.norestrict = false;
 | 
			
		||||
		parse_mode.assume_asserts = false;
 | 
			
		||||
		parse_mode.assert_assumes = false;
 | 
			
		||||
		parse_mode.lib = false;
 | 
			
		||||
		parse_mode.specify = false;
 | 
			
		||||
		parse_state.default_nettype_wire = true;
 | 
			
		||||
 | 
			
		||||
		args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -289,11 +297,11 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
		for (argidx = 1; argidx < args.size(); argidx++) {
 | 
			
		||||
			std::string arg = args[argidx];
 | 
			
		||||
			if (arg == "-sv") {
 | 
			
		||||
				sv_mode = true;
 | 
			
		||||
				parse_mode.sv = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-formal") {
 | 
			
		||||
				formal_mode = true;
 | 
			
		||||
				parse_mode.formal = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-nosynthesis") {
 | 
			
		||||
| 
						 | 
				
			
			@ -301,23 +309,23 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-noassert") {
 | 
			
		||||
				noassert_mode = true;
 | 
			
		||||
				parse_mode.noassert = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-noassume") {
 | 
			
		||||
				noassume_mode = true;
 | 
			
		||||
				parse_mode.noassume = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-norestrict") {
 | 
			
		||||
				norestrict_mode = true;
 | 
			
		||||
				parse_mode.norestrict = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-assume-asserts") {
 | 
			
		||||
				assume_asserts_mode = true;
 | 
			
		||||
				parse_mode.assume_asserts = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-assert-assumes") {
 | 
			
		||||
				assert_assumes_mode = true;
 | 
			
		||||
				parse_mode.assert_assumes = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-nodisplay") {
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +337,8 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
				flag_dump_ast2 = true;
 | 
			
		||||
				flag_dump_vlog1 = true;
 | 
			
		||||
				flag_dump_vlog2 = true;
 | 
			
		||||
				frontend_verilog_yydebug = true;
 | 
			
		||||
				flag_debug_lexer = true;
 | 
			
		||||
				flag_debug_parser = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-dump_ast1") {
 | 
			
		||||
| 
						 | 
				
			
			@ -357,7 +366,9 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-yydebug") {
 | 
			
		||||
				frontend_verilog_yydebug = true;
 | 
			
		||||
				flag_yydebug = true;
 | 
			
		||||
				flag_debug_lexer = true;
 | 
			
		||||
				flag_debug_parser = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-nolatches") {
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +404,7 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-lib") {
 | 
			
		||||
				lib_mode = true;
 | 
			
		||||
				parse_mode.lib = true;
 | 
			
		||||
				defines_map.add("BLACKBOX", "");
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -402,7 +413,7 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-specify") {
 | 
			
		||||
				specify_mode = true;
 | 
			
		||||
				parse_mode.specify = true;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-noopt") {
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +443,7 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-noautowire") {
 | 
			
		||||
				default_nettype_wire = false;
 | 
			
		||||
				parse_state.default_nettype_wire = false;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (arg == "-setattr" && argidx+1 < args.size()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -469,76 +480,82 @@ struct VerilogFrontend : public Frontend {
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (formal_mode || !flag_nosynthesis)
 | 
			
		||||
			defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1");
 | 
			
		||||
		if (parse_mode.formal || !flag_nosynthesis)
 | 
			
		||||
			defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1");
 | 
			
		||||
 | 
			
		||||
		extra_args(f, filename, args, argidx);
 | 
			
		||||
 | 
			
		||||
		log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
 | 
			
		||||
 | 
			
		||||
		log("Parsing %s%s input from `%s' to AST representation.\n",
 | 
			
		||||
				formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
 | 
			
		||||
				parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
 | 
			
		||||
 | 
			
		||||
		AST::current_filename = filename;
 | 
			
		||||
		AST::set_line_num = &frontend_verilog_yyset_lineno;
 | 
			
		||||
		AST::get_line_num = &frontend_verilog_yyget_lineno;
 | 
			
		||||
 | 
			
		||||
		current_ast = new AST::AstNode(AST::AST_DESIGN);
 | 
			
		||||
 | 
			
		||||
		lexin = f;
 | 
			
		||||
		AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
 | 
			
		||||
		std::string code_after_preproc;
 | 
			
		||||
 | 
			
		||||
		parse_state.lexin = f;
 | 
			
		||||
		if (!flag_nopp) {
 | 
			
		||||
			code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs);
 | 
			
		||||
			code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode);
 | 
			
		||||
			if (flag_ppdump)
 | 
			
		||||
				log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
 | 
			
		||||
			lexin = new std::istringstream(code_after_preproc);
 | 
			
		||||
			parse_state.lexin = new std::istringstream(code_after_preproc);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto filename_shared = std::make_shared<std::string>(filename);
 | 
			
		||||
		auto top_loc = Location();
 | 
			
		||||
		top_loc.begin.filename = filename_shared;
 | 
			
		||||
		parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN);
 | 
			
		||||
		VerilogLexer lexer(&parse_state, &parse_mode, filename_shared);
 | 
			
		||||
		frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode);
 | 
			
		||||
		lexer.set_debug(flag_debug_lexer);
 | 
			
		||||
		parser.set_debug_level(flag_debug_parser ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
		// make package typedefs available to parser
 | 
			
		||||
		add_package_types(pkg_user_types, design->verilog_packages);
 | 
			
		||||
		add_package_types(parse_state.pkg_user_types, design->verilog_packages);
 | 
			
		||||
 | 
			
		||||
		UserTypeMap global_types_map;
 | 
			
		||||
		for (auto def : design->verilog_globals) {
 | 
			
		||||
		for (auto& def : design->verilog_globals) {
 | 
			
		||||
			if (def->type == AST::AST_TYPEDEF) {
 | 
			
		||||
				global_types_map[def->str] = def;
 | 
			
		||||
				global_types_map[def->str] = def.get();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_assert(user_type_stack.empty());
 | 
			
		||||
		log_assert(parse_state.user_type_stack.empty());
 | 
			
		||||
		// use previous global typedefs as bottom level of user type stack
 | 
			
		||||
		user_type_stack.push_back(std::move(global_types_map));
 | 
			
		||||
		parse_state.user_type_stack.push_back(std::move(global_types_map));
 | 
			
		||||
		// add a new empty type map to allow overriding existing global definitions
 | 
			
		||||
		user_type_stack.push_back(UserTypeMap());
 | 
			
		||||
		parse_state.user_type_stack.push_back(UserTypeMap());
 | 
			
		||||
 | 
			
		||||
		frontend_verilog_yyset_lineno(1);
 | 
			
		||||
		frontend_verilog_yyrestart(NULL);
 | 
			
		||||
		frontend_verilog_yyparse();
 | 
			
		||||
		frontend_verilog_yylex_destroy();
 | 
			
		||||
		if (flag_yydebug) {
 | 
			
		||||
			lexer.set_debug(true);
 | 
			
		||||
			parser.set_debug_level(1);
 | 
			
		||||
		}
 | 
			
		||||
		parser.parse();
 | 
			
		||||
		// frontend_verilog_yyset_lineno(1);
 | 
			
		||||
 | 
			
		||||
		for (auto &child : current_ast->children) {
 | 
			
		||||
		for (auto &child : parse_state.current_ast->children) {
 | 
			
		||||
			if (child->type == AST::AST_MODULE)
 | 
			
		||||
				for (auto &attr : attributes)
 | 
			
		||||
					if (child->attributes.count(attr) == 0)
 | 
			
		||||
						child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
 | 
			
		||||
						child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (flag_nodpi)
 | 
			
		||||
			error_on_dpi_function(current_ast);
 | 
			
		||||
			error_on_dpi_function(parse_state.current_ast);
 | 
			
		||||
 | 
			
		||||
		AST::process(design, current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
 | 
			
		||||
				flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
 | 
			
		||||
		AST::process(design, parse_state.current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
 | 
			
		||||
				flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		if (!flag_nopp)
 | 
			
		||||
			delete lexin;
 | 
			
		||||
			delete parse_state.lexin;
 | 
			
		||||
 | 
			
		||||
		// only the previous and new global type maps remain
 | 
			
		||||
		log_assert(user_type_stack.size() == 2);
 | 
			
		||||
		user_type_stack.clear();
 | 
			
		||||
		log_assert(parse_state.user_type_stack.size() == 2);
 | 
			
		||||
		parse_state.user_type_stack.clear();
 | 
			
		||||
 | 
			
		||||
		delete current_ast;
 | 
			
		||||
		current_ast = NULL;
 | 
			
		||||
		delete parse_state.current_ast;
 | 
			
		||||
		parse_state.current_ast = NULL;
 | 
			
		||||
 | 
			
		||||
		log("Successfully finished Verilog frontend.\n");
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -760,18 +777,3 @@ struct VerilogFileList : public Pass {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
// the yyerror function used by bison to report parser errors
 | 
			
		||||
void frontend_verilog_yyerror(char const *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list ap;
 | 
			
		||||
	char buffer[1024];
 | 
			
		||||
	char *p = buffer;
 | 
			
		||||
	va_start(ap, fmt);
 | 
			
		||||
	p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
	p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
 | 
			
		||||
	YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
 | 
			
		||||
					      "%s", buffer);
 | 
			
		||||
	exit(1);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,70 +31,33 @@
 | 
			
		|||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "frontends/ast/ast.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <list>
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
namespace VERILOG_FRONTEND
 | 
			
		||||
{
 | 
			
		||||
	// this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser
 | 
			
		||||
	extern struct AST::AstNode *current_ast;
 | 
			
		||||
	/* Ephemeral context class */
 | 
			
		||||
	struct ConstParser {
 | 
			
		||||
		AST::AstSrcLocType loc;
 | 
			
		||||
	private:
 | 
			
		||||
		void log_maybe_loc_error(std::string msg);
 | 
			
		||||
		void log_maybe_loc_warn(std::string msg);
 | 
			
		||||
		// divide an arbitrary length decimal number by two and return the rest
 | 
			
		||||
		int my_decimal_div_by_two(std::vector<uint8_t> &digits);
 | 
			
		||||
		// find the number of significant bits in a binary number (not including the sign bit)
 | 
			
		||||
		int my_ilog2(int x);
 | 
			
		||||
		// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
 | 
			
		||||
		void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized);
 | 
			
		||||
	public:
 | 
			
		||||
		// convert the Verilog code for a constant to an AST node
 | 
			
		||||
		std::unique_ptr<AST::AstNode> const2ast(std::string code, char case_type = 0, bool warn_z = false);
 | 
			
		||||
 | 
			
		||||
	// this function converts a Verilog constant to an AST_CONSTANT node
 | 
			
		||||
	AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
 | 
			
		||||
 | 
			
		||||
	// names of locally typedef'ed types in a stack
 | 
			
		||||
	typedef std::map<std::string, AST::AstNode*> UserTypeMap;
 | 
			
		||||
	extern std::vector<UserTypeMap> user_type_stack;
 | 
			
		||||
 | 
			
		||||
	// names of package typedef'ed types
 | 
			
		||||
	extern dict<std::string, AST::AstNode*> pkg_user_types;
 | 
			
		||||
 | 
			
		||||
	// state of `default_nettype
 | 
			
		||||
	extern bool default_nettype_wire;
 | 
			
		||||
 | 
			
		||||
	// running in SystemVerilog mode
 | 
			
		||||
	extern bool sv_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -formal mode
 | 
			
		||||
	extern bool formal_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -noassert mode
 | 
			
		||||
	extern bool noassert_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -noassume mode
 | 
			
		||||
	extern bool noassume_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -norestrict mode
 | 
			
		||||
	extern bool norestrict_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -assume-asserts mode
 | 
			
		||||
	extern bool assume_asserts_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -assert-assumes mode
 | 
			
		||||
	extern bool assert_assumes_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -lib mode
 | 
			
		||||
	extern bool lib_mode;
 | 
			
		||||
 | 
			
		||||
	// running in -specify mode
 | 
			
		||||
	extern bool specify_mode;
 | 
			
		||||
 | 
			
		||||
	// lexer input stream
 | 
			
		||||
	extern std::istream *lexin;
 | 
			
		||||
}
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
// the usual bison/flex stuff
 | 
			
		||||
extern int frontend_verilog_yydebug;
 | 
			
		||||
void frontend_verilog_yyerror(char const *fmt, ...);
 | 
			
		||||
void frontend_verilog_yyrestart(FILE *f);
 | 
			
		||||
int frontend_verilog_yyparse(void);
 | 
			
		||||
int frontend_verilog_yylex_destroy(void);
 | 
			
		||||
int frontend_verilog_yyget_lineno(void);
 | 
			
		||||
void frontend_verilog_yyset_lineno (int);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								frontends/verilog/verilog_lexer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								frontends/verilog/verilog_lexer.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
#ifndef VERILOG_LEXER_H
 | 
			
		||||
#define VERILOG_LEXER_H
 | 
			
		||||
 | 
			
		||||
#include "kernel/yosys.h"
 | 
			
		||||
#include "frontends/ast/ast.h"
 | 
			
		||||
#include "frontends/verilog/verilog_parser.tab.hh"
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#if ! defined(yyFlexLexerOnce)
 | 
			
		||||
#define yyFlexLexer frontend_verilog_yyFlexLexer
 | 
			
		||||
#include <FlexLexer.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
namespace VERILOG_FRONTEND {
 | 
			
		||||
	using parser = frontend_verilog_yy::parser;
 | 
			
		||||
	class VerilogLexer : public frontend_verilog_yyFlexLexer {
 | 
			
		||||
		ParseState* extra;
 | 
			
		||||
		ParseMode* mode;
 | 
			
		||||
		parser::location_type out_loc;
 | 
			
		||||
	public:
 | 
			
		||||
		VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr<string> filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {
 | 
			
		||||
			out_loc.begin.filename = filename;
 | 
			
		||||
		}
 | 
			
		||||
		~VerilogLexer() override {}
 | 
			
		||||
		// autogenerated body due to YY_DECL
 | 
			
		||||
		parser::symbol_type nextToken();
 | 
			
		||||
		// get rid of override virtual function warning
 | 
			
		||||
		using FlexLexer::yylex;
 | 
			
		||||
		parser::symbol_type terminate() {
 | 
			
		||||
			return parser::make_FRONTEND_VERILOG_YYEOF(out_loc);
 | 
			
		||||
		}
 | 
			
		||||
	private:
 | 
			
		||||
		std::shared_ptr<std::string> current_filename;
 | 
			
		||||
		std::vector<std::shared_ptr<std::string>> fn_stack;
 | 
			
		||||
		std::vector<int> ln_stack;
 | 
			
		||||
		int LexerInput(char* buf, int max_size) override {
 | 
			
		||||
			return readsome(*extra->lexin, buf, max_size);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +32,13 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
%option c++
 | 
			
		||||
%option yyclass="VerilogLexer"
 | 
			
		||||
%option noyywrap
 | 
			
		||||
%option nounput
 | 
			
		||||
%option yylineno
 | 
			
		||||
%option prefix="frontend_verilog_yy"
 | 
			
		||||
 | 
			
		||||
%{
 | 
			
		||||
 | 
			
		||||
#ifdef __clang__
 | 
			
		||||
| 
						 | 
				
			
			@ -41,78 +48,109 @@
 | 
			
		|||
#pragma clang diagnostic ignored "-Wmisleading-indentation"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include "frontends/verilog/verilog_frontend.h"
 | 
			
		||||
#include "frontends/verilog/verilog_lexer.h"
 | 
			
		||||
#include "frontends/ast/ast.h"
 | 
			
		||||
#include "verilog_parser.tab.hh"
 | 
			
		||||
#include "frontends/verilog/verilog_location.h"
 | 
			
		||||
#include "kernel/log.h"
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
USING_YOSYS_NAMESPACE
 | 
			
		||||
using namespace AST;
 | 
			
		||||
using namespace VERILOG_FRONTEND;
 | 
			
		||||
 | 
			
		||||
#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
 | 
			
		||||
#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
 | 
			
		||||
using parser = frontend_verilog_yy::parser;
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_BEGIN
 | 
			
		||||
namespace VERILOG_FRONTEND {
 | 
			
		||||
	std::vector<std::string> fn_stack;
 | 
			
		||||
	std::vector<int> ln_stack;
 | 
			
		||||
	YYLTYPE real_location;
 | 
			
		||||
	YYLTYPE old_location;
 | 
			
		||||
}
 | 
			
		||||
#undef YY_DECL
 | 
			
		||||
#define YY_DECL parser::symbol_type VerilogLexer::nextToken()
 | 
			
		||||
 | 
			
		||||
#undef yyterminate
 | 
			
		||||
#define yyterminate() return terminate()
 | 
			
		||||
 | 
			
		||||
YOSYS_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
#define SV_KEYWORD(_tok) \
 | 
			
		||||
	if (sv_mode) return _tok; \
 | 
			
		||||
	if (mode->sv) return _tok; \
 | 
			
		||||
	log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
 | 
			
		||||
			"recognized unless read_verilog is called with -sv!\n", yytext, \
 | 
			
		||||
			AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \
 | 
			
		||||
	yylval->string = new std::string(std::string("\\") + yytext); \
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
			"recognized unless read_verilog is called with -sv!\n", YYText(), \
 | 
			
		||||
			current_filename->c_str(), yylineno); \
 | 
			
		||||
	string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
 | 
			
		||||
#define NON_KEYWORD() \
 | 
			
		||||
	yylval->string = new std::string(std::string("\\") + yytext); \
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
 | 
			
		||||
#define YY_INPUT(buf,result,max_size) \
 | 
			
		||||
	result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
 | 
			
		||||
 | 
			
		||||
#define YY_USER_ACTION \
 | 
			
		||||
       old_location = real_location; \
 | 
			
		||||
       real_location.first_line = real_location.last_line; \
 | 
			
		||||
       real_location.first_column = real_location.last_column; \
 | 
			
		||||
       for(int i = 0; yytext[i] != '\0'; ++i){ \
 | 
			
		||||
               if(yytext[i] == '\n') { \
 | 
			
		||||
                       real_location.last_line++; \
 | 
			
		||||
                       real_location.last_column = 1; \
 | 
			
		||||
               } \
 | 
			
		||||
               else { \
 | 
			
		||||
                       real_location.last_column++; \
 | 
			
		||||
               } \
 | 
			
		||||
       } \
 | 
			
		||||
    (*yylloc) = real_location;
 | 
			
		||||
	out_loc.step(); \
 | 
			
		||||
	for(int i = 0; YYText()[i] != '\0'; ++i){ \
 | 
			
		||||
		if(YYText()[i] == '\n') { \
 | 
			
		||||
			out_loc.lines(); \
 | 
			
		||||
		} \
 | 
			
		||||
		else { \
 | 
			
		||||
			out_loc.columns(); \
 | 
			
		||||
		} \
 | 
			
		||||
	} \
 | 
			
		||||
	out_loc.begin.filename = current_filename; \
 | 
			
		||||
	out_loc.end.filename = current_filename;
 | 
			
		||||
 | 
			
		||||
#define YY_BREAK \
 | 
			
		||||
    (*yylloc) = old_location; \
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
#undef YY_BUF_SIZE
 | 
			
		||||
#define YY_BUF_SIZE 65536
 | 
			
		||||
 | 
			
		||||
extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
 | 
			
		||||
 | 
			
		||||
static bool isUserType(std::string &s)
 | 
			
		||||
static bool isUserType(ParseState* extra, std::string &s)
 | 
			
		||||
{
 | 
			
		||||
	// check current scope then outer scopes for a name
 | 
			
		||||
	for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) {
 | 
			
		||||
	for (auto it = extra->user_type_stack.rbegin(); it != extra->user_type_stack.rend(); ++it) {
 | 
			
		||||
		if (it->count(s) > 0) {
 | 
			
		||||
			return true;
 | 
			
		||||
				return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool is_hex_dig(char c, int *val)
 | 
			
		||||
parser::symbol_type char_tok(char c, parser::location_type loc) {
 | 
			
		||||
	switch (c) {
 | 
			
		||||
		case '!': return parser::make_TOK_EXCL(loc);
 | 
			
		||||
		case '#': return parser::make_TOK_HASH(loc);
 | 
			
		||||
		case '%': return parser::make_TOK_PERC(loc);
 | 
			
		||||
		case '&': return parser::make_TOK_AMP(loc);
 | 
			
		||||
		case '(': return parser::make_TOK_LPAREN(loc);
 | 
			
		||||
		case ')': return parser::make_TOK_RPAREN(loc);
 | 
			
		||||
		case '*': return parser::make_TOK_ASTER(loc);
 | 
			
		||||
		case '+': return parser::make_TOK_PLUS(loc);
 | 
			
		||||
		case ',': return parser::make_TOK_COMMA(loc);
 | 
			
		||||
		case '-': return parser::make_TOK_MINUS(loc);
 | 
			
		||||
		case '.': return parser::make_TOK_DOT(loc);
 | 
			
		||||
		case '/': return parser::make_TOK_SLASH(loc);
 | 
			
		||||
		case ':': return parser::make_TOK_COL(loc);
 | 
			
		||||
		case ';': return parser::make_TOK_SEMICOL(loc);
 | 
			
		||||
		case '<': return parser::make_TOK_LT(loc);
 | 
			
		||||
		case '=': return parser::make_TOK_EQ(loc);
 | 
			
		||||
		case '>': return parser::make_TOK_GT(loc);
 | 
			
		||||
		case '?': return parser::make_TOK_QUE(loc);
 | 
			
		||||
		case '@': return parser::make_TOK_AT(loc);
 | 
			
		||||
		case '[': return parser::make_TOK_LBRA(loc);
 | 
			
		||||
		case ']': return parser::make_TOK_RBRA(loc);
 | 
			
		||||
		case '^': return parser::make_TOK_CARET(loc);
 | 
			
		||||
		case '_': return parser::make_TOK_UNDER(loc);
 | 
			
		||||
		case '{': return parser::make_TOK_LCURL(loc);
 | 
			
		||||
		case '|': return parser::make_TOK_PIPE(loc);
 | 
			
		||||
		case '}': return parser::make_TOK_RCURL(loc);
 | 
			
		||||
		case '~': return parser::make_TOK_TILDE(loc);
 | 
			
		||||
		case 'n': return parser::make_TOK_n(loc);
 | 
			
		||||
		case 'p': return parser::make_TOK_p(loc);
 | 
			
		||||
		case 'x': return parser::make_TOK_x(loc);
 | 
			
		||||
		case 'z': return parser::make_TOK_z(loc);
 | 
			
		||||
		case 0: return parser::make_FRONTEND_VERILOG_YYEOF(loc);
 | 
			
		||||
		default:
 | 
			
		||||
			return parser::make_ch_t(c, loc);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
static bool is_hex_dig(char c, int *val, parser::location_type loc)
 | 
			
		||||
{
 | 
			
		||||
	if ('0' <= c && c <= '9') {
 | 
			
		||||
		*val = c - '0';
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +162,7 @@ static bool is_hex_dig(char c, int *val)
 | 
			
		|||
		*val = c - 'A' + 0xA;
 | 
			
		||||
		return true;
 | 
			
		||||
	} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
 | 
			
		||||
		log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c);
 | 
			
		||||
		log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c);
 | 
			
		||||
		*val = 0; // not semantically valid in hex escape...
 | 
			
		||||
		return true; // ...but still processed as part of hex token
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -132,13 +170,13 @@ static bool is_hex_dig(char c, int *val)
 | 
			
		|||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool is_oct_dig(char c, int *val)
 | 
			
		||||
static bool is_oct_dig(char c, int *val, parser::location_type loc)
 | 
			
		||||
{
 | 
			
		||||
	if ('0' <= c && c <= '7') {
 | 
			
		||||
		*val = c - '0';
 | 
			
		||||
		return true;
 | 
			
		||||
	} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
 | 
			
		||||
		log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c);
 | 
			
		||||
		log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c);
 | 
			
		||||
		*val = 0; // not semantically valid in octal escape...
 | 
			
		||||
		return true; // ...but still processed as part of octal token
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +184,7 @@ static bool is_oct_dig(char c, int *val)
 | 
			
		|||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::string *process_str(char *str, int len, bool triple)
 | 
			
		||||
static parser::symbol_type process_str(char *str, int len, bool triple, parser::location_type loc)
 | 
			
		||||
{
 | 
			
		||||
	char *in, *out; // Overwrite input buffer: flex manual states "Actions
 | 
			
		||||
		// are free to modify 'yytext' except for lengthening it".
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +196,7 @@ static std::string *process_str(char *str, int len, bool triple)
 | 
			
		|||
			if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r'))
 | 
			
		||||
				in++;
 | 
			
		||||
			if (!triple)
 | 
			
		||||
				log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n");
 | 
			
		||||
				log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n");
 | 
			
		||||
			*out++ = '\n';
 | 
			
		||||
			break;
 | 
			
		||||
		case '\\':
 | 
			
		||||
| 
						 | 
				
			
			@ -186,16 +224,16 @@ static std::string *process_str(char *str, int len, bool triple)
 | 
			
		|||
				break;
 | 
			
		||||
			case 'x':
 | 
			
		||||
				int val;
 | 
			
		||||
				if (in + 1 < str + len && is_hex_dig(in[1], &val)) {
 | 
			
		||||
				if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
 | 
			
		||||
					*out = val;
 | 
			
		||||
					in++;
 | 
			
		||||
					if (in + 1 < str + len && is_hex_dig(in[1], &val)) {
 | 
			
		||||
					if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
 | 
			
		||||
						*out = *out * 0x10 + val;
 | 
			
		||||
						in++;
 | 
			
		||||
					}
 | 
			
		||||
					out++;
 | 
			
		||||
				} else
 | 
			
		||||
					log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n");
 | 
			
		||||
					log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n");
 | 
			
		||||
				break;
 | 
			
		||||
			case '\\':
 | 
			
		||||
				*out++ = '\\';
 | 
			
		||||
| 
						 | 
				
			
			@ -213,12 +251,12 @@ static std::string *process_str(char *str, int len, bool triple)
 | 
			
		|||
					int val;
 | 
			
		||||
 | 
			
		||||
					*out = *in - '0';
 | 
			
		||||
					if (in + 1 < str + len && is_oct_dig(in[1], &val)) {
 | 
			
		||||
					if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
 | 
			
		||||
						*out = *out * 010 + val;
 | 
			
		||||
						in++;
 | 
			
		||||
						if (in + 1 < str + len && is_oct_dig(in[1], &val)) {
 | 
			
		||||
						if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
 | 
			
		||||
							if (*out >= 040)
 | 
			
		||||
								log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n");
 | 
			
		||||
								log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n");
 | 
			
		||||
							*out = *out * 010 + val;
 | 
			
		||||
							in++;
 | 
			
		||||
						}
 | 
			
		||||
| 
						 | 
				
			
			@ -232,18 +270,11 @@ static std::string *process_str(char *str, int len, bool triple)
 | 
			
		|||
			*out++ = *in;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	return new std::string(str, out - str);
 | 
			
		||||
	return parser::make_TOK_STRING(std::make_unique<std::string>(str, out - str), loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
%}
 | 
			
		||||
 | 
			
		||||
%option yylineno
 | 
			
		||||
%option noyywrap
 | 
			
		||||
%option nounput
 | 
			
		||||
%option bison-locations
 | 
			
		||||
%option bison-bridge
 | 
			
		||||
%option prefix="frontend_verilog_yy"
 | 
			
		||||
 | 
			
		||||
%x COMMENT
 | 
			
		||||
%x SYNOPSYS_TRANSLATE_OFF
 | 
			
		||||
%x SYNOPSYS_FLAGS
 | 
			
		||||
| 
						 | 
				
			
			@ -256,47 +287,46 @@ FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+
 | 
			
		|||
TIME_SCALE_SUFFIX [munpf]?s
 | 
			
		||||
 | 
			
		||||
%%
 | 
			
		||||
 | 
			
		||||
	// Initialise comment_caller to something to avoid a "maybe undefined"
 | 
			
		||||
	// warning from GCC.
 | 
			
		||||
	int comment_caller = INITIAL;
 | 
			
		||||
 | 
			
		||||
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
 | 
			
		||||
	fn_stack.push_back(current_filename);
 | 
			
		||||
	ln_stack.push_back(frontend_verilog_yyget_lineno());
 | 
			
		||||
	current_filename = yytext+11;
 | 
			
		||||
	if (!current_filename.empty() && current_filename.front() == '"')
 | 
			
		||||
		current_filename = current_filename.substr(1);
 | 
			
		||||
	if (!current_filename.empty() && current_filename.back() == '"')
 | 
			
		||||
		current_filename = current_filename.substr(0, current_filename.size()-1);
 | 
			
		||||
	frontend_verilog_yyset_lineno(0);
 | 
			
		||||
	yylloc->first_line = yylloc->last_line = 0;
 | 
			
		||||
	real_location.first_line = real_location.last_line = 0;
 | 
			
		||||
	ln_stack.push_back(yylineno);
 | 
			
		||||
	std::string filename = YYText()+11;
 | 
			
		||||
	if (!filename.empty() && filename.front() == '"')
 | 
			
		||||
		filename = filename.substr(1);
 | 
			
		||||
	if (!filename.empty() && filename.back() == '"')
 | 
			
		||||
		filename = filename.substr(0, filename.size()-1);
 | 
			
		||||
	current_filename = std::make_shared<std::string>(filename);
 | 
			
		||||
	yylineno = (0);
 | 
			
		||||
	out_loc.begin.line = out_loc.end.line = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
 | 
			
		||||
	current_filename = fn_stack.back();
 | 
			
		||||
	fn_stack.pop_back();
 | 
			
		||||
	frontend_verilog_yyset_lineno(ln_stack.back());
 | 
			
		||||
	yylloc->first_line = yylloc->last_line = ln_stack.back();
 | 
			
		||||
	real_location.first_line = real_location.last_line = ln_stack.back();
 | 
			
		||||
	yylineno = (ln_stack.back());
 | 
			
		||||
	out_loc.begin.line = out_loc.end.line = ln_stack.back();
 | 
			
		||||
	ln_stack.pop_back();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
 | 
			
		||||
	char *p = yytext + 5;
 | 
			
		||||
	const char *p = YYText() + 5;
 | 
			
		||||
	while (*p == ' ' || *p == '\t') p++;
 | 
			
		||||
	frontend_verilog_yyset_lineno(atoi(p));
 | 
			
		||||
	yylloc->first_line = yylloc->last_line = atoi(p);
 | 
			
		||||
	real_location.first_line = real_location.last_line = atoi(p);
 | 
			
		||||
	yylineno = (atoi(p));
 | 
			
		||||
	out_loc.begin.line = out_loc.end.line = atoi(p);
 | 
			
		||||
	while (*p && *p != ' ' && *p != '\t') p++;
 | 
			
		||||
	while (*p == ' ' || *p == '\t') p++;
 | 
			
		||||
	char *q = *p ? p + 1 : p;
 | 
			
		||||
	const char *q = *p ? p + 1 : p;
 | 
			
		||||
	while (*q && *q != '"') q++;
 | 
			
		||||
	current_filename = std::string(p).substr(1, q-p-1);
 | 
			
		||||
	current_filename = std::make_shared<std::string>(std::string(p).substr(1, q-p-1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"`file_notfound "[^\n]* {
 | 
			
		||||
	log_error("Can't open include file `%s'!\n", yytext + 15);
 | 
			
		||||
	log_error("Can't open include file `%s'!\n", YYText() + 15);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
 | 
			
		||||
| 
						 | 
				
			
			@ -305,223 +335,223 @@ TIME_SCALE_SUFFIX [munpf]?s
 | 
			
		|||
"`endcelldefine"[^\n]* /* ignore `endcelldefine */
 | 
			
		||||
 | 
			
		||||
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
 | 
			
		||||
	char *p = yytext;
 | 
			
		||||
	const char *p = YYText();
 | 
			
		||||
	while (*p != 0 && *p != ' ' && *p != '\t') p++;
 | 
			
		||||
	while (*p == ' ' || *p == '\t') p++;
 | 
			
		||||
	if (!strcmp(p, "none"))
 | 
			
		||||
		VERILOG_FRONTEND::default_nettype_wire = false;
 | 
			
		||||
		extra->default_nettype_wire = false;
 | 
			
		||||
	else if (!strcmp(p, "wire"))
 | 
			
		||||
		VERILOG_FRONTEND::default_nettype_wire = true;
 | 
			
		||||
		extra->default_nettype_wire = true;
 | 
			
		||||
	else
 | 
			
		||||
		frontend_verilog_yyerror("Unsupported default nettype: %s", p);
 | 
			
		||||
		err_at_loc(out_loc, "Unsupported default nettype: %s", p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"`protect"[^\n]* /* ignore `protect*/
 | 
			
		||||
"`endprotect"[^\n]* /* ignore `endprotect*/
 | 
			
		||||
 | 
			
		||||
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
 | 
			
		||||
	frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
 | 
			
		||||
	err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"module"       { return TOK_MODULE; }
 | 
			
		||||
"endmodule"    { return TOK_ENDMODULE; }
 | 
			
		||||
"function"     { return TOK_FUNCTION; }
 | 
			
		||||
"endfunction"  { return TOK_ENDFUNCTION; }
 | 
			
		||||
"task"         { return TOK_TASK; }
 | 
			
		||||
"endtask"      { return TOK_ENDTASK; }
 | 
			
		||||
"specify"      { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
 | 
			
		||||
"endspecify"   { return TOK_ENDSPECIFY; }
 | 
			
		||||
"specparam"    { return TOK_SPECPARAM; }
 | 
			
		||||
"package"      { SV_KEYWORD(TOK_PACKAGE); }
 | 
			
		||||
"endpackage"   { SV_KEYWORD(TOK_ENDPACKAGE); }
 | 
			
		||||
"import"       { SV_KEYWORD(TOK_IMPORT); }
 | 
			
		||||
"interface"    { SV_KEYWORD(TOK_INTERFACE); }
 | 
			
		||||
"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
 | 
			
		||||
"modport"      { SV_KEYWORD(TOK_MODPORT); }
 | 
			
		||||
"parameter"    { return TOK_PARAMETER; }
 | 
			
		||||
"localparam"   { return TOK_LOCALPARAM; }
 | 
			
		||||
"defparam"     { return TOK_DEFPARAM; }
 | 
			
		||||
"assign"       { return TOK_ASSIGN; }
 | 
			
		||||
"always"       { return TOK_ALWAYS; }
 | 
			
		||||
"initial"      { return TOK_INITIAL; }
 | 
			
		||||
"begin"	       { return TOK_BEGIN; }
 | 
			
		||||
"end"          { return TOK_END; }
 | 
			
		||||
"if"           { return TOK_IF; }
 | 
			
		||||
"else"         { return TOK_ELSE; }
 | 
			
		||||
"for"          { return TOK_FOR; }
 | 
			
		||||
"posedge"      { return TOK_POSEDGE; }
 | 
			
		||||
"negedge"      { return TOK_NEGEDGE; }
 | 
			
		||||
"or"           { return TOK_OR; }
 | 
			
		||||
"case"         { return TOK_CASE; }
 | 
			
		||||
"casex"        { return TOK_CASEX; }
 | 
			
		||||
"casez"        { return TOK_CASEZ; }
 | 
			
		||||
"endcase"      { return TOK_ENDCASE; }
 | 
			
		||||
"default"      { return TOK_DEFAULT; }
 | 
			
		||||
"generate"     { return TOK_GENERATE; }
 | 
			
		||||
"endgenerate"  { return TOK_ENDGENERATE; }
 | 
			
		||||
"while"        { return TOK_WHILE; }
 | 
			
		||||
"repeat"       { return TOK_REPEAT; }
 | 
			
		||||
"automatic"    { return TOK_AUTOMATIC; }
 | 
			
		||||
"module"       { return parser::make_TOK_MODULE(out_loc); }
 | 
			
		||||
"endmodule"    { return parser::make_TOK_ENDMODULE(out_loc); }
 | 
			
		||||
"function"     { return parser::make_TOK_FUNCTION(out_loc); }
 | 
			
		||||
"endfunction"  { return parser::make_TOK_ENDFUNCTION(out_loc); }
 | 
			
		||||
"task"         { return parser::make_TOK_TASK(out_loc); }
 | 
			
		||||
"endtask"      { return parser::make_TOK_ENDTASK(out_loc); }
 | 
			
		||||
"specify"      { return mode->specify ? parser::make_TOK_SPECIFY(out_loc) : parser::make_TOK_IGNORED_SPECIFY(out_loc); }
 | 
			
		||||
"endspecify"   { return parser::make_TOK_ENDSPECIFY(out_loc); }
 | 
			
		||||
"specparam"    { return parser::make_TOK_SPECPARAM(out_loc); }
 | 
			
		||||
"package"      { SV_KEYWORD(parser::make_TOK_PACKAGE(out_loc)); }
 | 
			
		||||
"endpackage"   { SV_KEYWORD(parser::make_TOK_ENDPACKAGE(out_loc)); }
 | 
			
		||||
"import"       { SV_KEYWORD(parser::make_TOK_IMPORT(out_loc)); }
 | 
			
		||||
"interface"    { SV_KEYWORD(parser::make_TOK_INTERFACE(out_loc)); }
 | 
			
		||||
"endinterface" { SV_KEYWORD(parser::make_TOK_ENDINTERFACE(out_loc)); }
 | 
			
		||||
"modport"      { SV_KEYWORD(parser::make_TOK_MODPORT(out_loc)); }
 | 
			
		||||
"parameter"    { return parser::make_TOK_PARAMETER(out_loc); }
 | 
			
		||||
"localparam"   { return parser::make_TOK_LOCALPARAM(out_loc); }
 | 
			
		||||
"defparam"     { return parser::make_TOK_DEFPARAM(out_loc); }
 | 
			
		||||
"assign"       { return parser::make_TOK_ASSIGN(out_loc); }
 | 
			
		||||
"always"       { return parser::make_TOK_ALWAYS(out_loc); }
 | 
			
		||||
"initial"      { return parser::make_TOK_INITIAL(out_loc); }
 | 
			
		||||
"begin"	       { return parser::make_TOK_BEGIN(out_loc); }
 | 
			
		||||
"end"          { return parser::make_TOK_END(out_loc); }
 | 
			
		||||
"if"           { return parser::make_TOK_IF(out_loc); }
 | 
			
		||||
"else"         { return parser::make_TOK_ELSE(out_loc); }
 | 
			
		||||
"for"          { return parser::make_TOK_FOR(out_loc); }
 | 
			
		||||
"posedge"      { return parser::make_TOK_POSEDGE(out_loc); }
 | 
			
		||||
"negedge"      { return parser::make_TOK_NEGEDGE(out_loc); }
 | 
			
		||||
"or"           { return parser::make_TOK_OR(out_loc); }
 | 
			
		||||
"case"         { return parser::make_TOK_CASE(out_loc); }
 | 
			
		||||
"casex"        { return parser::make_TOK_CASEX(out_loc); }
 | 
			
		||||
"casez"        { return parser::make_TOK_CASEZ(out_loc); }
 | 
			
		||||
"endcase"      { return parser::make_TOK_ENDCASE(out_loc); }
 | 
			
		||||
"default"      { return parser::make_TOK_DEFAULT(out_loc); }
 | 
			
		||||
"generate"     { return parser::make_TOK_GENERATE(out_loc); }
 | 
			
		||||
"endgenerate"  { return parser::make_TOK_ENDGENERATE(out_loc); }
 | 
			
		||||
"while"        { return parser::make_TOK_WHILE(out_loc); }
 | 
			
		||||
"repeat"       { return parser::make_TOK_REPEAT(out_loc); }
 | 
			
		||||
"automatic"    { return parser::make_TOK_AUTOMATIC(out_loc); }
 | 
			
		||||
 | 
			
		||||
"unique"       { SV_KEYWORD(TOK_UNIQUE); }
 | 
			
		||||
"unique0"      { SV_KEYWORD(TOK_UNIQUE0); }
 | 
			
		||||
"priority"     { SV_KEYWORD(TOK_PRIORITY); }
 | 
			
		||||
"unique"       { SV_KEYWORD(parser::make_TOK_UNIQUE(out_loc)); }
 | 
			
		||||
"unique0"      { SV_KEYWORD(parser::make_TOK_UNIQUE0(out_loc)); }
 | 
			
		||||
"priority"     { SV_KEYWORD(parser::make_TOK_PRIORITY(out_loc)); }
 | 
			
		||||
 | 
			
		||||
"always_comb"  { SV_KEYWORD(TOK_ALWAYS_COMB); }
 | 
			
		||||
"always_ff"    { SV_KEYWORD(TOK_ALWAYS_FF); }
 | 
			
		||||
"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); }
 | 
			
		||||
"always_comb"  { SV_KEYWORD(parser::make_TOK_ALWAYS_COMB(out_loc)); }
 | 
			
		||||
"always_ff"    { SV_KEYWORD(parser::make_TOK_ALWAYS_FF(out_loc)); }
 | 
			
		||||
"always_latch" { SV_KEYWORD(parser::make_TOK_ALWAYS_LATCH(out_loc)); }
 | 
			
		||||
 | 
			
		||||
 /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
 | 
			
		||||
    to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
 | 
			
		||||
    global state.. its a mess) */
 | 
			
		||||
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
 | 
			
		||||
	if (!strcmp(yytext, "default"))
 | 
			
		||||
		return TOK_DEFAULT;
 | 
			
		||||
	yylval->string = new std::string(std::string("\\") + yytext);
 | 
			
		||||
	return TOK_SVA_LABEL;
 | 
			
		||||
	if (!strcmp(YYText(), "default"))
 | 
			
		||||
		return parser::make_TOK_DEFAULT(out_loc);
 | 
			
		||||
	string_t val = std::make_unique<std::string>(std::string("\\") + YYText());
 | 
			
		||||
	return parser::make_TOK_SVA_LABEL(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"assert"     { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
 | 
			
		||||
"assume"     { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
 | 
			
		||||
"cover"      { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
 | 
			
		||||
"restrict"   { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
 | 
			
		||||
"property"   { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
 | 
			
		||||
"rand"       { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
 | 
			
		||||
"const"      { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
 | 
			
		||||
"checker"    { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
 | 
			
		||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
 | 
			
		||||
"bind"       { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); }
 | 
			
		||||
"final"      { SV_KEYWORD(TOK_FINAL); }
 | 
			
		||||
"logic"      { SV_KEYWORD(TOK_LOGIC); }
 | 
			
		||||
"var"        { SV_KEYWORD(TOK_VAR); }
 | 
			
		||||
"bit"        { SV_KEYWORD(TOK_LOGIC); }
 | 
			
		||||
"int"        { SV_KEYWORD(TOK_INT); }
 | 
			
		||||
"byte"       { SV_KEYWORD(TOK_BYTE); }
 | 
			
		||||
"shortint"   { SV_KEYWORD(TOK_SHORTINT); }
 | 
			
		||||
"longint"    { SV_KEYWORD(TOK_LONGINT); }
 | 
			
		||||
"void"       { SV_KEYWORD(TOK_VOID); }
 | 
			
		||||
"assert"     { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); }
 | 
			
		||||
"assume"     { if (mode->formal) return parser::make_TOK_ASSUME(out_loc); SV_KEYWORD(parser::make_TOK_ASSUME(out_loc)); }
 | 
			
		||||
"cover"      { if (mode->formal) return parser::make_TOK_COVER(out_loc); SV_KEYWORD(parser::make_TOK_COVER(out_loc)); }
 | 
			
		||||
"restrict"   { if (mode->formal) return parser::make_TOK_RESTRICT(out_loc); SV_KEYWORD(parser::make_TOK_RESTRICT(out_loc)); }
 | 
			
		||||
"property"   { if (mode->formal) return parser::make_TOK_PROPERTY(out_loc); SV_KEYWORD(parser::make_TOK_PROPERTY(out_loc)); }
 | 
			
		||||
"rand"       { if (mode->formal) return parser::make_TOK_RAND(out_loc); SV_KEYWORD(parser::make_TOK_RAND(out_loc)); }
 | 
			
		||||
"const"      { if (mode->formal) return parser::make_TOK_CONST(out_loc); SV_KEYWORD(parser::make_TOK_CONST(out_loc)); }
 | 
			
		||||
"checker"    { if (mode->formal) return parser::make_TOK_CHECKER(out_loc); SV_KEYWORD(parser::make_TOK_CHECKER(out_loc)); }
 | 
			
		||||
"endchecker" { if (mode->formal) return parser::make_TOK_ENDCHECKER(out_loc); SV_KEYWORD(parser::make_TOK_ENDCHECKER(out_loc)); }
 | 
			
		||||
"bind"       { if (mode->formal) return parser::make_TOK_BIND(out_loc); SV_KEYWORD(parser::make_TOK_BIND(out_loc)); }
 | 
			
		||||
"final"      { SV_KEYWORD(parser::make_TOK_FINAL(out_loc)); }
 | 
			
		||||
"logic"      { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
 | 
			
		||||
"var"        { SV_KEYWORD(parser::make_TOK_VAR(out_loc)); }
 | 
			
		||||
"bit"        { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
 | 
			
		||||
"int"        { SV_KEYWORD(parser::make_TOK_INT(out_loc)); }
 | 
			
		||||
"byte"       { SV_KEYWORD(parser::make_TOK_BYTE(out_loc)); }
 | 
			
		||||
"shortint"   { SV_KEYWORD(parser::make_TOK_SHORTINT(out_loc)); }
 | 
			
		||||
"longint"    { SV_KEYWORD(parser::make_TOK_LONGINT(out_loc)); }
 | 
			
		||||
"void"       { SV_KEYWORD(parser::make_TOK_VOID(out_loc)); }
 | 
			
		||||
 | 
			
		||||
"eventually"   { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
 | 
			
		||||
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
 | 
			
		||||
"eventually"   { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
 | 
			
		||||
"s_eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
 | 
			
		||||
 | 
			
		||||
"input"   { return TOK_INPUT; }
 | 
			
		||||
"output"  { return TOK_OUTPUT; }
 | 
			
		||||
"inout"   { return TOK_INOUT; }
 | 
			
		||||
"wire"    { return TOK_WIRE; }
 | 
			
		||||
"tri"     { return TOK_WIRE; }
 | 
			
		||||
"wor"     { return TOK_WOR; }
 | 
			
		||||
"trior"   { return TOK_WOR; }
 | 
			
		||||
"wand"    { return TOK_WAND; }
 | 
			
		||||
"triand"  { return TOK_WAND; }
 | 
			
		||||
"reg"     { return TOK_REG; }
 | 
			
		||||
"integer" { return TOK_INTEGER; }
 | 
			
		||||
"signed"  { return TOK_SIGNED; }
 | 
			
		||||
"unsigned" { SV_KEYWORD(TOK_UNSIGNED); }
 | 
			
		||||
"genvar"  { return TOK_GENVAR; }
 | 
			
		||||
"real"    { return TOK_REAL; }
 | 
			
		||||
"input"   { return parser::make_TOK_INPUT(out_loc); }
 | 
			
		||||
"output"  { return parser::make_TOK_OUTPUT(out_loc); }
 | 
			
		||||
"inout"   { return parser::make_TOK_INOUT(out_loc); }
 | 
			
		||||
"wire"    { return parser::make_TOK_WIRE(out_loc); }
 | 
			
		||||
"tri"     { return parser::make_TOK_WIRE(out_loc); }
 | 
			
		||||
"wor"     { return parser::make_TOK_WOR(out_loc); }
 | 
			
		||||
"trior"   { return parser::make_TOK_WOR(out_loc); }
 | 
			
		||||
"wand"    { return parser::make_TOK_WAND(out_loc); }
 | 
			
		||||
"triand"  { return parser::make_TOK_WAND(out_loc); }
 | 
			
		||||
"reg"     { return parser::make_TOK_REG(out_loc); }
 | 
			
		||||
"integer" { return parser::make_TOK_INTEGER(out_loc); }
 | 
			
		||||
"signed"  { return parser::make_TOK_SIGNED(out_loc); }
 | 
			
		||||
"unsigned" { SV_KEYWORD(parser::make_TOK_UNSIGNED(out_loc)); }
 | 
			
		||||
"genvar"  { return parser::make_TOK_GENVAR(out_loc); }
 | 
			
		||||
"real"    { return parser::make_TOK_REAL(out_loc); }
 | 
			
		||||
 | 
			
		||||
"enum"    { SV_KEYWORD(TOK_ENUM); }
 | 
			
		||||
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
 | 
			
		||||
"struct"  { SV_KEYWORD(TOK_STRUCT); }
 | 
			
		||||
"union"   { SV_KEYWORD(TOK_UNION); }
 | 
			
		||||
"packed"  { SV_KEYWORD(TOK_PACKED); }
 | 
			
		||||
"enum"    { SV_KEYWORD(parser::make_TOK_ENUM(out_loc)); }
 | 
			
		||||
"typedef" { SV_KEYWORD(parser::make_TOK_TYPEDEF(out_loc)); }
 | 
			
		||||
"struct"  { SV_KEYWORD(parser::make_TOK_STRUCT(out_loc)); }
 | 
			
		||||
"union"   { SV_KEYWORD(parser::make_TOK_UNION(out_loc)); }
 | 
			
		||||
"packed"  { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); }
 | 
			
		||||
 | 
			
		||||
{UNSIGNED_NUMBER} {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_CONSTVAL;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_CONSTVAL(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
\'[01zxZX] {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_UNBASED_UNSIZED_CONSTVAL;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
\'[sS]?[bodhBODH] {
 | 
			
		||||
	BEGIN(BASED_CONST);
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_BASE;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_BASE(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* {
 | 
			
		||||
	BEGIN(0);
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_BASED_CONSTVAL;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_BASED_CONSTVAL(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
{FIXED_POINT_NUMBER_DEC} {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_REALVAL;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_REALVAL(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
{FIXED_POINT_NUMBER_NO_DEC} {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_REALVAL;
 | 
			
		||||
	string_t val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_REALVAL(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
\"([^\\"]|\\.|\\\n)*\"			{ yylval->string = process_str(yytext + 1, yyleng - 2, false); return TOK_STRING; }
 | 
			
		||||
\"([^\\"]|\\.|\\\n)*\"			{ return process_str(yytext + 1, yyleng - 2, false, out_loc); }
 | 
			
		||||
 | 
			
		||||
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3}	{ yylval->string = process_str(yytext + 3, yyleng - 6, true); return TOK_STRING; }
 | 
			
		||||
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3}	{ return process_str(yytext + 3, yyleng - 6, true, out_loc); }
 | 
			
		||||
 | 
			
		||||
and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_PRIMITIVE;
 | 
			
		||||
	auto val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_PRIMITIVE(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
supply0 { return TOK_SUPPLY0; }
 | 
			
		||||
supply1 { return TOK_SUPPLY1; }
 | 
			
		||||
supply0 { return parser::make_TOK_SUPPLY0(out_loc); }
 | 
			
		||||
supply1 { return parser::make_TOK_SUPPLY1(out_loc); }
 | 
			
		||||
 | 
			
		||||
"$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
	auto val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
 | 
			
		||||
	if (!specify_mode) REJECT;
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
	if (!mode->specify) REJECT;
 | 
			
		||||
	auto val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"$"(info|warning|error|fatal) {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_MSG_TASKS;
 | 
			
		||||
	auto val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_MSG_TASKS(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"$signed"   { return TOK_TO_SIGNED; }
 | 
			
		||||
"$unsigned" { return TOK_TO_UNSIGNED; }
 | 
			
		||||
"$signed"   { return parser::make_TOK_TO_SIGNED(out_loc); }
 | 
			
		||||
"$unsigned" { return parser::make_TOK_TO_UNSIGNED(out_loc); }
 | 
			
		||||
 | 
			
		||||
[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* {
 | 
			
		||||
	// package qualifier
 | 
			
		||||
	auto s = std::string("\\") + yytext;
 | 
			
		||||
	if (pkg_user_types.count(s) > 0) {
 | 
			
		||||
	auto s = std::string("\\") + YYText();
 | 
			
		||||
	if (extra->pkg_user_types.count(s) > 0) {
 | 
			
		||||
		// package qualified typedefed name
 | 
			
		||||
		yylval->string = new std::string(s);
 | 
			
		||||
		return TOK_PKG_USER_TYPE;
 | 
			
		||||
		auto val = std::make_unique<std::string>(s);
 | 
			
		||||
		return parser::make_TOK_PKG_USER_TYPE(std::move(val), out_loc);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		// backup before :: just return first part
 | 
			
		||||
		size_t len = strchr(yytext, ':') - yytext;
 | 
			
		||||
		size_t len = strchr(YYText(), ':') - YYText();
 | 
			
		||||
		yyless(len);
 | 
			
		||||
		yylval->string = new std::string(std::string("\\") + yytext);
 | 
			
		||||
		return TOK_ID;
 | 
			
		||||
		auto val = std::make_unique<std::string>(std::string("\\") + YYText());
 | 
			
		||||
		return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[a-zA-Z_$][a-zA-Z0-9_$]* {
 | 
			
		||||
	auto s = std::string("\\") + yytext;
 | 
			
		||||
	if (isUserType(s)) {
 | 
			
		||||
	auto s = std::string("\\") + YYText();
 | 
			
		||||
	if (isUserType(extra, s)) {
 | 
			
		||||
		// previously typedefed name
 | 
			
		||||
		yylval->string = new std::string(s);
 | 
			
		||||
		return TOK_USER_TYPE;
 | 
			
		||||
		auto val = std::make_unique<std::string>(s);
 | 
			
		||||
		return parser::make_TOK_USER_TYPE(std::move(val), out_loc);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		yylval->string = new std::string(std::string("\\") + yytext);
 | 
			
		||||
		return TOK_ID;
 | 
			
		||||
		auto val = std::make_unique<std::string>(std::string("\\") + YYText());
 | 
			
		||||
		return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
 | 
			
		||||
	yylval->string = new std::string(std::string("\\") + yytext);
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
	auto val = std::make_unique<std::string>(std::string("\\") + YYText());
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
 | 
			
		||||
| 
						 | 
				
			
			@ -557,7 +587,7 @@ supply1 { return TOK_SUPPLY1; }
 | 
			
		|||
		);
 | 
			
		||||
		printed_warning = true;
 | 
			
		||||
	}
 | 
			
		||||
	return TOK_SYNOPSYS_FULL_CASE;
 | 
			
		||||
	return parser::make_TOK_SYNOPSYS_FULL_CASE(out_loc);
 | 
			
		||||
}
 | 
			
		||||
<SYNOPSYS_FLAGS>parallel_case {
 | 
			
		||||
	static bool printed_warning = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -571,119 +601,115 @@ supply1 { return TOK_SUPPLY1; }
 | 
			
		|||
		);
 | 
			
		||||
		printed_warning = true;
 | 
			
		||||
	}
 | 
			
		||||
	return TOK_SYNOPSYS_PARALLEL_CASE;
 | 
			
		||||
	return parser::make_TOK_SYNOPSYS_PARALLEL_CASE(out_loc);
 | 
			
		||||
}
 | 
			
		||||
<SYNOPSYS_FLAGS>. /* ignore everything else */
 | 
			
		||||
<SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
 | 
			
		||||
 | 
			
		||||
import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
 | 
			
		||||
	BEGIN(IMPORT_DPI);
 | 
			
		||||
	return TOK_DPI_FUNCTION;
 | 
			
		||||
	return parser::make_TOK_DPI_FUNCTION(out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
 | 
			
		||||
	yylval->string = new std::string(std::string("\\") + yytext);
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
	auto val = std::make_unique<std::string>(std::string("\\") + YYText());
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
 | 
			
		||||
 | 
			
		||||
<IMPORT_DPI>";" {
 | 
			
		||||
	BEGIN(0);
 | 
			
		||||
	return *yytext;
 | 
			
		||||
	return char_tok(*YYText(), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<IMPORT_DPI>. {
 | 
			
		||||
	return *yytext;
 | 
			
		||||
	return char_tok(*YYText(), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"\\"[^ \t\r\n]+ {
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_ID;
 | 
			
		||||
	auto val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_ID(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"(*" { return ATTR_BEGIN; }
 | 
			
		||||
"*)" { return ATTR_END; }
 | 
			
		||||
"(*" { return parser::make_ATTR_BEGIN(out_loc); }
 | 
			
		||||
"*)" { return parser::make_ATTR_END(out_loc); }
 | 
			
		||||
 | 
			
		||||
"{*"  { return DEFATTR_BEGIN; }
 | 
			
		||||
"*}"  { return DEFATTR_END; }
 | 
			
		||||
"{*"  { return parser::make_DEFATTR_BEGIN(out_loc); }
 | 
			
		||||
"*}"  { return parser::make_DEFATTR_END(out_loc); }
 | 
			
		||||
 | 
			
		||||
"**" { return OP_POW; }
 | 
			
		||||
"||" { return OP_LOR; }
 | 
			
		||||
"&&" { return OP_LAND; }
 | 
			
		||||
"==" { return OP_EQ; }
 | 
			
		||||
"!=" { return OP_NE; }
 | 
			
		||||
"<=" { return OP_LE; }
 | 
			
		||||
">=" { return OP_GE; }
 | 
			
		||||
"**" { return parser::make_OP_POW(out_loc); }
 | 
			
		||||
"||" { return parser::make_OP_LOR(out_loc); }
 | 
			
		||||
"&&" { return parser::make_OP_LAND(out_loc); }
 | 
			
		||||
"==" { return parser::make_OP_EQ(out_loc); }
 | 
			
		||||
"!=" { return parser::make_OP_NE(out_loc); }
 | 
			
		||||
"<=" { return parser::make_OP_LE(out_loc); }
 | 
			
		||||
">=" { return parser::make_OP_GE(out_loc); }
 | 
			
		||||
 | 
			
		||||
"===" { return OP_EQX; }
 | 
			
		||||
"!==" { return OP_NEX; }
 | 
			
		||||
"===" { return parser::make_OP_EQX(out_loc); }
 | 
			
		||||
"!==" { return parser::make_OP_NEX(out_loc); }
 | 
			
		||||
 | 
			
		||||
"~&" { return OP_NAND; }
 | 
			
		||||
"~|" { return OP_NOR;  }
 | 
			
		||||
"~^" { return OP_XNOR; }
 | 
			
		||||
"^~" { return OP_XNOR; }
 | 
			
		||||
"~&" { return parser::make_OP_NAND(out_loc); }
 | 
			
		||||
"~|" { return parser::make_OP_NOR(out_loc);  }
 | 
			
		||||
"~^" { return parser::make_OP_XNOR(out_loc); }
 | 
			
		||||
"^~" { return parser::make_OP_XNOR(out_loc); }
 | 
			
		||||
 | 
			
		||||
"<<"  { return OP_SHL; }
 | 
			
		||||
">>"  { return OP_SHR; }
 | 
			
		||||
"<<<" { return OP_SSHL; }
 | 
			
		||||
">>>" { return OP_SSHR; }
 | 
			
		||||
"<<"  { return parser::make_OP_SHL(out_loc); }
 | 
			
		||||
">>"  { return parser::make_OP_SHR(out_loc); }
 | 
			
		||||
"<<<" { return parser::make_OP_SSHL(out_loc); }
 | 
			
		||||
">>>" { return parser::make_OP_SSHR(out_loc); }
 | 
			
		||||
 | 
			
		||||
"'" { return OP_CAST; }
 | 
			
		||||
"'" { return parser::make_OP_CAST(out_loc); }
 | 
			
		||||
 | 
			
		||||
"::"  { return TOK_PACKAGESEP; }
 | 
			
		||||
"++"  { return TOK_INCREMENT; }
 | 
			
		||||
"--"  { return TOK_DECREMENT; }
 | 
			
		||||
"::"  { return parser::make_TOK_PACKAGESEP(out_loc); }
 | 
			
		||||
"++"  { return parser::make_TOK_INCREMENT(out_loc); }
 | 
			
		||||
"--"  { return parser::make_TOK_DECREMENT(out_loc); }
 | 
			
		||||
 | 
			
		||||
"+:" { return TOK_POS_INDEXED; }
 | 
			
		||||
"-:" { return TOK_NEG_INDEXED; }
 | 
			
		||||
"+:" { return parser::make_TOK_POS_INDEXED(out_loc); }
 | 
			
		||||
"-:" { return parser::make_TOK_NEG_INDEXED(out_loc); }
 | 
			
		||||
 | 
			
		||||
".*" { return TOK_WILDCARD_CONNECT; }
 | 
			
		||||
".*" { return parser::make_TOK_WILDCARD_CONNECT(out_loc); }
 | 
			
		||||
 | 
			
		||||
"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); }
 | 
			
		||||
"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); }
 | 
			
		||||
"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); }
 | 
			
		||||
"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); }
 | 
			
		||||
"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); }
 | 
			
		||||
"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); }
 | 
			
		||||
"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); }
 | 
			
		||||
"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); }
 | 
			
		||||
"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); }
 | 
			
		||||
">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); }
 | 
			
		||||
"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); }
 | 
			
		||||
">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); }
 | 
			
		||||
"|=" { SV_KEYWORD(parser::make_TOK_BIT_OR_ASSIGN(out_loc)); }
 | 
			
		||||
"&=" { SV_KEYWORD(parser::make_TOK_BIT_AND_ASSIGN(out_loc)); }
 | 
			
		||||
"+=" { SV_KEYWORD(parser::make_TOK_ADD_ASSIGN(out_loc)); }
 | 
			
		||||
"-=" { SV_KEYWORD(parser::make_TOK_SUB_ASSIGN(out_loc)); }
 | 
			
		||||
"^=" { SV_KEYWORD(parser::make_TOK_BIT_XOR_ASSIGN(out_loc)); }
 | 
			
		||||
"/=" { SV_KEYWORD(parser::make_TOK_DIV_ASSIGN(out_loc)); }
 | 
			
		||||
"%=" { SV_KEYWORD(parser::make_TOK_MOD_ASSIGN(out_loc)); }
 | 
			
		||||
"*=" { SV_KEYWORD(parser::make_TOK_MUL_ASSIGN(out_loc)); }
 | 
			
		||||
"<<=" { SV_KEYWORD(parser::make_TOK_SHL_ASSIGN(out_loc)); }
 | 
			
		||||
">>=" { SV_KEYWORD(parser::make_TOK_SHR_ASSIGN(out_loc)); }
 | 
			
		||||
"<<<=" { SV_KEYWORD(parser::make_TOK_SSHL_ASSIGN(out_loc)); }
 | 
			
		||||
">>>=" { SV_KEYWORD(parser::make_TOK_SSHR_ASSIGN(out_loc)); }
 | 
			
		||||
 | 
			
		||||
[-+]?[=*]> {
 | 
			
		||||
	if (!specify_mode) REJECT;
 | 
			
		||||
	yylval->string = new std::string(yytext);
 | 
			
		||||
	return TOK_SPECIFY_OPER;
 | 
			
		||||
	if (!mode->specify) REJECT;
 | 
			
		||||
	auto val = std::make_unique<std::string>(YYText());
 | 
			
		||||
	return parser::make_TOK_SPECIFY_OPER(std::move(val), out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
"&&&" {
 | 
			
		||||
	if (!specify_mode) return TOK_IGNORED_SPECIFY_AND;
 | 
			
		||||
	return TOK_SPECIFY_AND;
 | 
			
		||||
	if (!mode->specify) return parser::make_TOK_IGNORED_SPECIFY_AND(out_loc);
 | 
			
		||||
	return parser::make_TOK_SPECIFY_AND(out_loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
 | 
			
		||||
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
 | 
			
		||||
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
 | 
			
		||||
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
 | 
			
		||||
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
 | 
			
		||||
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
 | 
			
		||||
 | 
			
		||||
<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); }
 | 
			
		||||
<COMMENT>.    /* ignore comment body */
 | 
			
		||||
<COMMENT>\n   /* ignore comment body */
 | 
			
		||||
<COMMENT>"*/" { BEGIN(comment_caller); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<INITIAL,BASED_CONST>[ \t\r\n]		/* ignore whitespaces */
 | 
			
		||||
<INITIAL,BASED_CONST>\\[\r\n]		/* ignore continuation sequence */
 | 
			
		||||
<INITIAL,BASED_CONST>"//"[^\r\n]*	/* ignore one-line comments */
 | 
			
		||||
 | 
			
		||||
<INITIAL>. { return *yytext; }
 | 
			
		||||
<*>. { BEGIN(0); return *yytext; }
 | 
			
		||||
<INITIAL>. { return char_tok(*YYText(), out_loc); }
 | 
			
		||||
<*>. { BEGIN(0); return char_tok(*YYText(), out_loc); }
 | 
			
		||||
 | 
			
		||||
%%
 | 
			
		||||
 | 
			
		||||
// this is a hack to avoid the 'yyinput defined but not used' error msgs
 | 
			
		||||
void *frontend_verilog_avoid_input_warnings() {
 | 
			
		||||
	return (void*)&yyinput;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										96
									
								
								frontends/verilog/verilog_location.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								frontends/verilog/verilog_location.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,96 @@
 | 
			
		|||
#ifndef VERILOG_LOCATION_H
 | 
			
		||||
#define VERILOG_LOCATION_H
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <stack>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provide frontend-wide location tracking like what bison generates
 | 
			
		||||
 * but using shared_ptr for filename
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct Position {
 | 
			
		||||
	std::shared_ptr<std::string> filename;
 | 
			
		||||
	int line;
 | 
			
		||||
	int column;
 | 
			
		||||
 | 
			
		||||
	Position(std::shared_ptr<std::string> filename, int line = 1, int column = 1)
 | 
			
		||||
		: filename(filename), line(line), column(column) {}
 | 
			
		||||
	Position() = default;
 | 
			
		||||
	Position(const Position& other) = default;
 | 
			
		||||
	Position& operator=(const Position& other) = default;
 | 
			
		||||
 | 
			
		||||
	void advance() { ++column; }
 | 
			
		||||
	void columns(int count = 1) {
 | 
			
		||||
		column += count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void lines(int count = 1) {
 | 
			
		||||
		line += count;
 | 
			
		||||
		column = 1;
 | 
			
		||||
	}
 | 
			
		||||
	std::string to_string() const  {
 | 
			
		||||
		std::ostringstream oss;
 | 
			
		||||
		if (filename && !filename->empty()) {
 | 
			
		||||
			oss << *filename << ":";
 | 
			
		||||
		}
 | 
			
		||||
		oss << line << ":" << column;
 | 
			
		||||
		return oss.str();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Location {
 | 
			
		||||
	Position begin;
 | 
			
		||||
	Position end;
 | 
			
		||||
 | 
			
		||||
	Location() = default;
 | 
			
		||||
	Location(const Position& b, const Position& e)
 | 
			
		||||
		: begin(b), end(e) {}
 | 
			
		||||
	Location(const Location& other) = default;
 | 
			
		||||
	Location& operator=(const Location& other) = default;
 | 
			
		||||
 | 
			
		||||
	void step() { begin = end; }
 | 
			
		||||
 | 
			
		||||
	void columns(int count = 1) {
 | 
			
		||||
		end.columns(count);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void lines(int count = 1) {
 | 
			
		||||
		end.lines(count);
 | 
			
		||||
	}
 | 
			
		||||
	std::string to_string() const {
 | 
			
		||||
		std::ostringstream oss;
 | 
			
		||||
		bool same_file = (!begin.filename && !end.filename) ||
 | 
			
		||||
						(begin.filename && end.filename &&
 | 
			
		||||
						*begin.filename == *end.filename);
 | 
			
		||||
 | 
			
		||||
		if (same_file) {
 | 
			
		||||
			if (begin.filename && !begin.filename->empty())
 | 
			
		||||
				oss << *begin.filename << ":";
 | 
			
		||||
 | 
			
		||||
			if (begin.line == end.line) {
 | 
			
		||||
				if (begin.column == end.column) {
 | 
			
		||||
					oss << begin.line << ":" << begin.column;
 | 
			
		||||
				} else {
 | 
			
		||||
					oss << begin.line << ":" << begin.column
 | 
			
		||||
						<< "-" << end.column;
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				oss << begin.line << ":" << begin.column
 | 
			
		||||
					<< "-" << end.line << ":" << end.column;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			oss << begin.to_string() << "-" << end.to_string();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return oss.str();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline std::ostream& operator<<(std::ostream& os, const Location& loc) {
 | 
			
		||||
	return os << loc.to_string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -952,10 +952,6 @@ RTLIL::Design::~Design()
 | 
			
		|||
		delete pr.second;
 | 
			
		||||
	for (auto n : bindings_)
 | 
			
		||||
		delete n;
 | 
			
		||||
	for (auto n : verilog_packages)
 | 
			
		||||
		delete n;
 | 
			
		||||
	for (auto n : verilog_globals)
 | 
			
		||||
		delete n;
 | 
			
		||||
#ifdef WITH_PYTHON
 | 
			
		||||
	RTLIL::Design::get_all_designs()->erase(hashidx_);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -5710,16 +5706,10 @@ static void sigspec_parse_split(std::vector<std::string> &tokens, const std::str
 | 
			
		|||
	tokens.push_back(text.substr(start));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sigspec_parse_get_dummy_line_num()
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str)
 | 
			
		||||
{
 | 
			
		||||
	cover("kernel.rtlil.sigspec.parse");
 | 
			
		||||
 | 
			
		||||
	AST::current_filename = "input";
 | 
			
		||||
 | 
			
		||||
	std::vector<std::string> tokens;
 | 
			
		||||
	sigspec_parse_split(tokens, str, ',');
 | 
			
		||||
| 
						 | 
				
			
			@ -5735,12 +5725,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
 | 
			
		|||
 | 
			
		||||
		if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') {
 | 
			
		||||
			cover("kernel.rtlil.sigspec.parse.const");
 | 
			
		||||
			AST::get_line_num = sigspec_parse_get_dummy_line_num;
 | 
			
		||||
			AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname);
 | 
			
		||||
			if (ast == NULL)
 | 
			
		||||
			VERILOG_FRONTEND::ConstParser p{Location()};
 | 
			
		||||
			auto ast = p.const2ast(netname);
 | 
			
		||||
			if (ast == nullptr)
 | 
			
		||||
				return false;
 | 
			
		||||
			sig.append(RTLIL::Const(ast->bits));
 | 
			
		||||
			delete ast;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1334,7 +1334,7 @@ struct RTLIL::Design
 | 
			
		|||
	dict<RTLIL::IdString, RTLIL::Module*> modules_;
 | 
			
		||||
	std::vector<RTLIL::Binding*> bindings_;
 | 
			
		||||
 | 
			
		||||
	std::vector<AST::AstNode*> verilog_packages, verilog_globals;
 | 
			
		||||
	std::vector<std::unique_ptr<AST::AstNode>> verilog_packages, verilog_globals;
 | 
			
		||||
	std::unique_ptr<define_map_t> verilog_defines;
 | 
			
		||||
 | 
			
		||||
	std::vector<RTLIL::Selection> selection_stack;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,13 @@ mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/.
 | 
			
		|||
rm -rf zlib-1.2.11
 | 
			
		||||
pushd "$vcxsrc"/yosys
 | 
			
		||||
ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]'  >> ../../srcfiles.txt
 | 
			
		||||
 | 
			
		||||
if [ -f "/usr/include/FlexLexer.h" ] ; then
 | 
			
		||||
	mkdir -p libs/flex
 | 
			
		||||
	cp /usr/include/FlexLexer.h libs/flex/FlexLexer.h
 | 
			
		||||
	ls libs/flex/*.h >> ../../srcfiles.txt
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
popd
 | 
			
		||||
{
 | 
			
		||||
	n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l)
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +38,9 @@ popd
 | 
			
		|||
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
 | 
			
		||||
 | 
			
		||||
sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
 | 
			
		||||
if [ -f "/usr/include/FlexLexer.h" ] ; then
 | 
			
		||||
	sed -i 's,</AdditionalIncludeDirectories>,;..\\yosys\\libs\\flex</AdditionalIncludeDirectories>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
 | 
			
		||||
fi
 | 
			
		||||
mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj
 | 
			
		||||
 | 
			
		||||
mkdir -p "$vcxsrc"/yosys
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -368,14 +368,8 @@ struct DesignPass : public Pass {
 | 
			
		|||
 | 
			
		||||
		if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
 | 
			
		||||
		{
 | 
			
		||||
			for (auto node : design->verilog_packages)
 | 
			
		||||
				delete node;
 | 
			
		||||
			design->verilog_packages.clear();
 | 
			
		||||
 | 
			
		||||
			for (auto node : design->verilog_globals)
 | 
			
		||||
				delete node;
 | 
			
		||||
			design->verilog_globals.clear();
 | 
			
		||||
 | 
			
		||||
			design->verilog_defines->clear();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ enum class WrTransKind {
 | 
			
		|||
 | 
			
		||||
struct WrTransDef {
 | 
			
		||||
	WrTransTargetKind target_kind;
 | 
			
		||||
	int target_group;
 | 
			
		||||
	int target_group = 0;
 | 
			
		||||
	WrTransKind kind;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue