mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Merge https://github.com/YosysHQ/yosys into read_aiger
This commit is contained in:
		
						commit
						02e8dc7ad2
					
				
					 113 changed files with 6374 additions and 802 deletions
				
			
		
							
								
								
									
										14
									
								
								.github/issue_template.md
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/issue_template.md
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -4,6 +4,17 @@
 | 
				
			||||||
all necessary source files. (You can simply drag&drop a .zip file into
 | 
					all necessary source files. (You can simply drag&drop a .zip file into
 | 
				
			||||||
the issue editor.)*
 | 
					the issue editor.)*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also, make sure that the issue is actually reproducable in current git
 | 
				
			||||||
 | 
					master of Yosys.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See https://stackoverflow.com/help/mcve for some information on how to
 | 
				
			||||||
 | 
					create a Minimal, Complete, and Verifiable example (MCVE).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please do not waste our time with issues that lack sufficient information
 | 
				
			||||||
 | 
					to reproduce the issue easily. We will simply close those issues.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Expected behavior
 | 
					## Expected behavior
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*Please describe the behavior you would have expected from the tool.*
 | 
					*Please describe the behavior you would have expected from the tool.*
 | 
				
			||||||
| 
						 | 
					@ -11,6 +22,3 @@ the issue editor.)*
 | 
				
			||||||
## Actual behavior
 | 
					## Actual behavior
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*Please describe how the behavior you see differs from the expected behavior.*
 | 
					*Please describe how the behavior you see differs from the expected behavior.*
 | 
				
			||||||
 | 
					 | 
				
			||||||
**Important Note:** Nobody will be able to help you and/or fix the issue if you
 | 
					 | 
				
			||||||
do not provide sufficient information for reproducing the problem.
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -24,6 +24,8 @@
 | 
				
			||||||
/yosys-abc.exe
 | 
					/yosys-abc.exe
 | 
				
			||||||
/yosys-config
 | 
					/yosys-config
 | 
				
			||||||
/yosys-smtbmc
 | 
					/yosys-smtbmc
 | 
				
			||||||
 | 
					/yosys-smtbmc.exe
 | 
				
			||||||
 | 
					/yosys-smtbmc-script.py
 | 
				
			||||||
/yosys-filterlib
 | 
					/yosys-filterlib
 | 
				
			||||||
/yosys-filterlib.exe
 | 
					/yosys-filterlib.exe
 | 
				
			||||||
/kernel/version_*.cc
 | 
					/kernel/version_*.cc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								.travis.yml
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								.travis.yml
									
										
									
									
									
								
							| 
						 | 
					@ -132,11 +132,11 @@ matrix:
 | 
				
			||||||
      env:
 | 
					      env:
 | 
				
			||||||
        - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
 | 
					        - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Latest clang on Mac OS X
 | 
					#   # Latest clang on Mac OS X
 | 
				
			||||||
    - os: osx
 | 
					#   - os: osx
 | 
				
			||||||
      osx_image: xcode9.4
 | 
					#     osx_image: xcode9.4
 | 
				
			||||||
      env:
 | 
					#     env:
 | 
				
			||||||
        - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++"
 | 
					#       - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
before_install:
 | 
					before_install:
 | 
				
			||||||
  - ./.travis/setup.sh
 | 
					  - ./.travis/setup.sh
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,8 @@ echo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################################################
 | 
					##########################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					./yosys tests/simple/fiedler-cooley.v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
 | 
					echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,48 +6,15 @@ source .travis/common.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################################################
 | 
					##########################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Fixing Travis's git clone
 | 
					 | 
				
			||||||
echo
 | 
					 | 
				
			||||||
echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r'
 | 
					 | 
				
			||||||
echo
 | 
					 | 
				
			||||||
git fetch --unshallow && git fetch --tags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# For pull requests, we get more info about the git source.
 | 
					 | 
				
			||||||
if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
 | 
					 | 
				
			||||||
	echo "- Fetching from pull request source"
 | 
					 | 
				
			||||||
	git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git
 | 
					 | 
				
			||||||
	git fetch source && git fetch --tags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	echo "- Fetching the actual pull request"
 | 
					 | 
				
			||||||
	git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head
 | 
					 | 
				
			||||||
	git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# For building branches we need to fix the "detached head" state.
 | 
					 | 
				
			||||||
if [ z"$TRAVIS_BRANCH" != z ]; then
 | 
					 | 
				
			||||||
	TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1)
 | 
					 | 
				
			||||||
	echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)"
 | 
					 | 
				
			||||||
	git remote -v
 | 
					 | 
				
			||||||
	git branch -v
 | 
					 | 
				
			||||||
	if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then
 | 
					 | 
				
			||||||
		echo "Checked out at $TRAVIS_COMMIT"
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
 | 
					 | 
				
			||||||
			git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source"
 | 
					 | 
				
			||||||
		fi
 | 
					 | 
				
			||||||
		git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin"
 | 
					 | 
				
			||||||
	fi
 | 
					 | 
				
			||||||
	git branch -D $TRAVIS_BRANCH || true
 | 
					 | 
				
			||||||
	git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH
 | 
					 | 
				
			||||||
	git branch -v
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Output status information.
 | 
					# Output status information.
 | 
				
			||||||
git status
 | 
					(
 | 
				
			||||||
git describe --tags
 | 
						set +e
 | 
				
			||||||
git log -n 5 --graph
 | 
						set -x
 | 
				
			||||||
 | 
						git status
 | 
				
			||||||
 | 
						git branch -v
 | 
				
			||||||
 | 
						git log -n 5 --graph
 | 
				
			||||||
 | 
						git log --format=oneline -n 20 --graph
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
echo -en 'travis_fold:end:before_install.git\\r'
 | 
					echo -en 'travis_fold:end:before_install.git\\r'
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
					@ -10,6 +10,7 @@ CONFIG := clang
 | 
				
			||||||
# features (the more the better)
 | 
					# features (the more the better)
 | 
				
			||||||
ENABLE_TCL := 1
 | 
					ENABLE_TCL := 1
 | 
				
			||||||
ENABLE_ABC := 1
 | 
					ENABLE_ABC := 1
 | 
				
			||||||
 | 
					ENABLE_GLOB := 1
 | 
				
			||||||
ENABLE_PLUGINS := 1
 | 
					ENABLE_PLUGINS := 1
 | 
				
			||||||
ENABLE_READLINE := 1
 | 
					ENABLE_READLINE := 1
 | 
				
			||||||
ENABLE_EDITLINE := 0
 | 
					ENABLE_EDITLINE := 0
 | 
				
			||||||
| 
						 | 
					@ -100,7 +101,7 @@ LDFLAGS += -rdynamic
 | 
				
			||||||
LDLIBS += -lrt
 | 
					LDLIBS += -lrt
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. | wc -l; })
 | 
					YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; })
 | 
				
			||||||
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
 | 
					GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
 | 
				
			||||||
OBJS = kernel/version_$(GIT_REV).o
 | 
					OBJS = kernel/version_$(GIT_REV).o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,6 +299,10 @@ LDLIBS += -ldl
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(ENABLE_GLOB),1)
 | 
				
			||||||
 | 
					CXXFLAGS += -DYOSYS_ENABLE_GLOB
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(ENABLE_TCL),1)
 | 
					ifeq ($(ENABLE_TCL),1)
 | 
				
			||||||
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
 | 
					TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
 | 
				
			||||||
ifeq ($(OS), FreeBSD)
 | 
					ifeq ($(OS), FreeBSD)
 | 
				
			||||||
| 
						 | 
					@ -570,7 +575,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
 | 
				
			||||||
	+cd tests/simple && bash run-test.sh $(SEEDOPT)
 | 
						+cd tests/simple && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/hana && bash run-test.sh $(SEEDOPT)
 | 
						+cd tests/hana && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
 | 
						+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/realmath && bash run-test.sh $(SEEDOPT)
 | 
						# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/share && bash run-test.sh $(SEEDOPT)
 | 
						+cd tests/share && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/fsm && bash run-test.sh $(SEEDOPT)
 | 
						+cd tests/fsm && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/techmap && bash run-test.sh
 | 
						+cd tests/techmap && bash run-test.sh
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license
 | 
				
			||||||
or the 2-clause BSD license).
 | 
					or the 2-clause BSD license).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Web Site
 | 
					Web Site and Other Resources
 | 
				
			||||||
========
 | 
					============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
More information and documentation can be found on the Yosys web site:
 | 
					More information and documentation can be found on the Yosys web site:
 | 
				
			||||||
http://www.clifford.at/yosys/
 | 
					- http://www.clifford.at/yosys/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The "Documentation" page on the web site contains links to more resources,
 | 
				
			||||||
 | 
					including a manual that even describes some of the Yosys internals:
 | 
				
			||||||
 | 
					- http://www.clifford.at/yosys/documentation.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The file `CodingReadme` in this directory contains additional information
 | 
				
			||||||
 | 
					for people interested in using the Yosys C++ APIs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Users interested in formal verification might want to use the formal verification
 | 
				
			||||||
 | 
					front-end for Yosys, SymbiYosys:
 | 
				
			||||||
 | 
					- https://symbiyosys.readthedocs.io/en/latest/
 | 
				
			||||||
 | 
					- https://github.com/YosysHQ/SymbiYosys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Setup
 | 
					Setup
 | 
				
			||||||
======
 | 
					======
 | 
				
			||||||
| 
						 | 
					@ -92,12 +105,15 @@ Makefile.
 | 
				
			||||||
To build Yosys simply type 'make' in this directory.
 | 
					To build Yosys simply type 'make' in this directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	$ make
 | 
						$ make
 | 
				
			||||||
	$ make test
 | 
					 | 
				
			||||||
	$ sudo make install
 | 
						$ sudo make install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note that this also downloads, builds and installs ABC (using yosys-abc
 | 
					Note that this also downloads, builds and installs ABC (using yosys-abc
 | 
				
			||||||
as executable name).
 | 
					as executable name).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$ make test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Getting Started
 | 
					Getting Started
 | 
				
			||||||
===============
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -296,6 +312,9 @@ Verilog Attributes and non-standard features
 | 
				
			||||||
  passes to identify input and output ports of cells. The Verilog backend
 | 
					  passes to identify input and output ports of cells. The Verilog backend
 | 
				
			||||||
  also does not output blackbox modules on default.
 | 
					  also does not output blackbox modules on default.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The ``dynports'' attribute is used by the Verilog front-end to mark modules
 | 
				
			||||||
 | 
					  that have ports with a width that depends on a parameter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- The ``keep`` attribute on cells and wires is used to mark objects that should
 | 
					- The ``keep`` attribute on cells and wires is used to mark objects that should
 | 
				
			||||||
  never be removed by the optimizer. This is used for example for cells that
 | 
					  never be removed by the optimizer. This is used for example for cells that
 | 
				
			||||||
  have hidden connections that are not part of the netlist, such as IO pads.
 | 
					  have hidden connections that are not part of the netlist, such as IO pads.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,7 @@ struct EdifBackend : public Backend {
 | 
				
			||||||
		bool port_rename = false;
 | 
							bool port_rename = false;
 | 
				
			||||||
		bool attr_properties = false;
 | 
							bool attr_properties = false;
 | 
				
			||||||
		std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
 | 
							std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
 | 
				
			||||||
		bool nogndvcc = false, gndvccy = true;
 | 
							bool nogndvcc = false, gndvccy = false;
 | 
				
			||||||
		CellTypes ct(design);
 | 
							CellTypes ct(design);
 | 
				
			||||||
		EdifNames edif_names;
 | 
							EdifNames edif_names;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,11 +165,9 @@ struct FirrtlWorker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::string fid(RTLIL::IdString internal_id)
 | 
						std::string fid(RTLIL::IdString internal_id)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		const char *str = internal_id.c_str();
 | 
							return make_id(internal_id);
 | 
				
			||||||
		return *str == '\\' ? str + 1 : str;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string cellname(RTLIL::Cell *cell)
 | 
						std::string cellname(RTLIL::Cell *cell)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return fid(cell->name).c_str();
 | 
							return fid(cell->name).c_str();
 | 
				
			||||||
| 
						 | 
					@ -219,29 +217,42 @@ struct FirrtlWorker
 | 
				
			||||||
			if (it->second.size() > 0) {
 | 
								if (it->second.size() > 0) {
 | 
				
			||||||
				const SigSpec &secondSig = it->second;
 | 
									const SigSpec &secondSig = it->second;
 | 
				
			||||||
				const std::string firstName = cell_name + "." + make_id(it->first);
 | 
									const std::string firstName = cell_name + "." + make_id(it->first);
 | 
				
			||||||
				const std::string secondName = make_expr(secondSig);
 | 
									const std::string secondExpr = make_expr(secondSig);
 | 
				
			||||||
				// Find the direction for this port.
 | 
									// Find the direction for this port.
 | 
				
			||||||
				FDirection dir = getPortFDirection(it->first, instModule);
 | 
									FDirection dir = getPortFDirection(it->first, instModule);
 | 
				
			||||||
				std::string source, sink;
 | 
									std::string sourceExpr, sinkExpr;
 | 
				
			||||||
 | 
									const SigSpec *sinkSig = nullptr;
 | 
				
			||||||
				switch (dir) {
 | 
									switch (dir) {
 | 
				
			||||||
					case FD_INOUT:
 | 
										case FD_INOUT:
 | 
				
			||||||
						log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
 | 
											log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
 | 
				
			||||||
					case FD_OUT:
 | 
										case FD_OUT:
 | 
				
			||||||
						source = firstName;
 | 
											sourceExpr = firstName;
 | 
				
			||||||
						sink = secondName;
 | 
											sinkExpr = secondExpr;
 | 
				
			||||||
 | 
											sinkSig = &secondSig;
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					case FD_NODIRECTION:
 | 
										case FD_NODIRECTION:
 | 
				
			||||||
						log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
 | 
											log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
 | 
				
			||||||
						/* FALL_THROUGH */
 | 
											/* FALL_THROUGH */
 | 
				
			||||||
					case FD_IN:
 | 
										case FD_IN:
 | 
				
			||||||
						source = secondName;
 | 
											sourceExpr = secondExpr;
 | 
				
			||||||
						sink = firstName;
 | 
											sinkExpr = firstName;
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					default:
 | 
										default:
 | 
				
			||||||
						log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
 | 
											log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str()));
 | 
									// Check for subfield assignment.
 | 
				
			||||||
 | 
									std::string bitsString = "bits(";
 | 
				
			||||||
 | 
									if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
 | 
				
			||||||
 | 
										if (sinkSig == nullptr)
 | 
				
			||||||
 | 
											log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
 | 
				
			||||||
 | 
										// Don't generate the assignment here.
 | 
				
			||||||
 | 
										// Add the source and sink to the "reverse_wire_map" and we'll output the assignment
 | 
				
			||||||
 | 
										//  as part of the coalesced subfield assignments for this wire.
 | 
				
			||||||
 | 
										register_reverse_wire_map(sourceExpr, *sinkSig);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		wire_exprs.push_back(stringf("\n"));
 | 
							wire_exprs.push_back(stringf("\n"));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
 | 
				
			||||||
		f << stringf("%s  case ", indent.c_str());
 | 
							f << stringf("%s  case ", indent.c_str());
 | 
				
			||||||
		for (size_t i = 0; i < (*it)->compare.size(); i++) {
 | 
							for (size_t i = 0; i < (*it)->compare.size(); i++) {
 | 
				
			||||||
			if (i > 0)
 | 
								if (i > 0)
 | 
				
			||||||
				f << stringf(", ");
 | 
									f << stringf(" , ");
 | 
				
			||||||
			dump_sigspec(f, (*it)->compare[i]);
 | 
								dump_sigspec(f, (*it)->compare[i]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		f << stringf("\n");
 | 
							f << stringf("\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ struct ProtobufDesignSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
 | 
						ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
 | 
				
			||||||
			aig_mode_(aig_mode), use_selection_(use_selection) { }
 | 
								aig_mode_(aig_mode), use_selection_(use_selection) { }
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	string get_name(IdString name)
 | 
						string get_name(IdString name)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return RTLIL::unescape_id(name);
 | 
							return RTLIL::unescape_id(name);
 | 
				
			||||||
| 
						 | 
					@ -60,7 +60,7 @@ struct ProtobufDesignSerializer
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (auto ¶m : parameters) {
 | 
							for (auto ¶m : parameters) {
 | 
				
			||||||
			std::string key = get_name(param.first);
 | 
								std::string key = get_name(param.first);
 | 
				
			||||||
			
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			yosys::pb::Parameter pb_param;
 | 
								yosys::pb::Parameter pb_param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,7 +207,7 @@ struct ProtobufDesignSerializer
 | 
				
			||||||
			(*models)[aig.name] = pb_model;
 | 
								(*models)[aig.name] = pb_model;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	void serialize_design(yosys::pb::Design *pb, Design *design)
 | 
						void serialize_design(yosys::pb::Design *pb, Design *design)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		GOOGLE_PROTOBUF_VERIFY_VERSION;
 | 
							GOOGLE_PROTOBUF_VERIFY_VERSION;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ($(CONFIG),mxe)
 | 
					ifneq ($(CONFIG),mxe)
 | 
				
			||||||
ifneq ($(CONFIG),emcc)
 | 
					ifneq ($(CONFIG),emcc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MSYS targets support yosys-smtbmc, but require a launcher script
 | 
				
			||||||
 | 
					ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
 | 
				
			||||||
 | 
					TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
 | 
				
			||||||
 | 
					# Needed to find the Python interpreter for yosys-smtbmc scripts.
 | 
				
			||||||
 | 
					# Override if necessary, it is only used for msys2 targets.
 | 
				
			||||||
 | 
					PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					yosys-smtbmc-script.py: backends/smt2/smtbmc.py
 | 
				
			||||||
 | 
						$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
 | 
				
			||||||
 | 
							-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
 | 
				
			||||||
 | 
						$(P) gcc -DGUI=0 -O -s -o $@ $<
 | 
				
			||||||
 | 
					# Other targets
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
TARGETS += yosys-smtbmc
 | 
					TARGETS += yosys-smtbmc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
yosys-smtbmc: backends/smt2/smtbmc.py
 | 
					yosys-smtbmc: backends/smt2/smtbmc.py
 | 
				
			||||||
	$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
 | 
						$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
 | 
				
			||||||
	$(Q) chmod +x $@.new
 | 
						$(Q) chmod +x $@.new
 | 
				
			||||||
	$(Q) mv $@.new $@
 | 
						$(Q) mv $@.new $@
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
 | 
					$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -416,6 +416,7 @@ struct Smt2Worker
 | 
				
			||||||
		for (char ch : expr) {
 | 
							for (char ch : expr) {
 | 
				
			||||||
			if (ch == 'A') processed_expr += get_bv(sig_a);
 | 
								if (ch == 'A') processed_expr += get_bv(sig_a);
 | 
				
			||||||
			else if (ch == 'B') processed_expr += get_bv(sig_b);
 | 
								else if (ch == 'B') processed_expr += get_bv(sig_b);
 | 
				
			||||||
 | 
								else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
 | 
				
			||||||
			else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
 | 
								else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
 | 
				
			||||||
			else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
 | 
								else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
 | 
				
			||||||
			else processed_expr += ch;
 | 
								else processed_expr += ch;
 | 
				
			||||||
| 
						 | 
					@ -554,7 +555,7 @@ struct Smt2Worker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (cell->type.in("$shift", "$shiftx")) {
 | 
								if (cell->type.in("$shift", "$shiftx")) {
 | 
				
			||||||
				if (cell->getParam("\\B_SIGNED").as_bool()) {
 | 
									if (cell->getParam("\\B_SIGNED").as_bool()) {
 | 
				
			||||||
					return export_bvop(cell, stringf("(ite (bvsge B #b%0*d) "
 | 
										return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
 | 
				
			||||||
							"(bvlshr A B) (bvlshr A (bvneg B)))",
 | 
												"(bvlshr A B) (bvlshr A (bvneg B)))",
 | 
				
			||||||
							GetSize(cell->getPort("\\B")), 0), 's');
 | 
												GetSize(cell->getPort("\\B")), 0), 's');
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
| 
						 | 
					@ -887,8 +888,8 @@ struct Smt2Worker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				string name_a = get_bool(cell->getPort("\\A"));
 | 
									string name_a = get_bool(cell->getPort("\\A"));
 | 
				
			||||||
				string name_en = get_bool(cell->getPort("\\EN"));
 | 
									string name_en = get_bool(cell->getPort("\\EN"));
 | 
				
			||||||
				decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
 | 
									string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
 | 
				
			||||||
						cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
 | 
									decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (cell->type == "$cover")
 | 
									if (cell->type == "$cover")
 | 
				
			||||||
					decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
 | 
										decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
 | 
				
			||||||
| 
						 | 
					@ -1103,20 +1104,27 @@ struct Smt2Worker
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						Const initword = init_data.extract(i*width, width, State::Sx);
 | 
											Const initword = init_data.extract(i*width, width, State::Sx);
 | 
				
			||||||
 | 
											Const initmask = initword;
 | 
				
			||||||
						bool gen_init_constr = false;
 | 
											bool gen_init_constr = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						for (auto bit : initword.bits)
 | 
											for (int k = 0; k < GetSize(initword); k++) {
 | 
				
			||||||
							if (bit == State::S0 || bit == State::S1)
 | 
												if (initword[k] == State::S0 || initword[k] == State::S1) {
 | 
				
			||||||
								gen_init_constr = true;
 | 
													gen_init_constr = true;
 | 
				
			||||||
 | 
													initmask[k] = State::S1;
 | 
				
			||||||
 | 
												} else {
 | 
				
			||||||
 | 
													initmask[k] = State::S0;
 | 
				
			||||||
 | 
													initword[k] = State::S0;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if (gen_init_constr)
 | 
											if (gen_init_constr)
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							if (statebv)
 | 
												if (statebv)
 | 
				
			||||||
								/* FIXME */;
 | 
													/* FIXME */;
 | 
				
			||||||
							else
 | 
												else
 | 
				
			||||||
								init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
 | 
													init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]",
 | 
				
			||||||
										get_id(module), arrayid, Const(i, abits).as_string().c_str(),
 | 
															get_id(module), arrayid, Const(i, abits).as_string().c_str(),
 | 
				
			||||||
										initword.as_string().c_str(), get_id(cell), i));
 | 
															initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i));
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1484,11 +1484,11 @@ else:  # not tempind, covermode
 | 
				
			||||||
                            smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
 | 
					                            smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
 | 
				
			||||||
                            smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
 | 
					                            smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
 | 
				
			||||||
                            smt_assert_consequent(get_constr_expr(constr_assumes, i))
 | 
					                            smt_assert_consequent(get_constr_expr(constr_assumes, i))
 | 
				
			||||||
                    print_msg("Re-solving with appended steps..")
 | 
					                        print_msg("Re-solving with appended steps..")
 | 
				
			||||||
                    if smt_check_sat() == "unsat":
 | 
					                        if smt_check_sat() == "unsat":
 | 
				
			||||||
                        print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
 | 
					                            print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
 | 
				
			||||||
                        retstatus = False
 | 
					                            retstatus = False
 | 
				
			||||||
                        break
 | 
					                            break
 | 
				
			||||||
                    print_anyconsts(step)
 | 
					                    print_anyconsts(step)
 | 
				
			||||||
                    for i in range(step, last_check_step+1):
 | 
					                    for i in range(step, last_check_step+1):
 | 
				
			||||||
                        print_failed_asserts(i)
 | 
					                        print_failed_asserts(i)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@
 | 
				
			||||||
USING_YOSYS_NAMESPACE
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
PRIVATE_NAMESPACE_BEGIN
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
 | 
					bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
 | 
				
			||||||
int auto_name_counter, auto_name_offset, auto_name_digits;
 | 
					int auto_name_counter, auto_name_offset, auto_name_digits;
 | 
				
			||||||
std::map<RTLIL::IdString, int> auto_name_map;
 | 
					std::map<RTLIL::IdString, int> auto_name_map;
 | 
				
			||||||
std::set<RTLIL::IdString> reg_wires, reg_ct;
 | 
					std::set<RTLIL::IdString> reg_wires, reg_ct;
 | 
				
			||||||
| 
						 | 
					@ -1310,7 +1310,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
 | 
						if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
 | 
				
			||||||
		std::stringstream ss;
 | 
							std::stringstream ss;
 | 
				
			||||||
		dump_reg_init(ss, cell->getPort("\\Q"));
 | 
							dump_reg_init(ss, cell->getPort("\\Q"));
 | 
				
			||||||
		if (!ss.str().empty()) {
 | 
							if (!ss.str().empty()) {
 | 
				
			||||||
| 
						 | 
					@ -1607,6 +1607,10 @@ struct VerilogBackend : public Backend {
 | 
				
			||||||
		log("        without this option all internal cells are converted to Verilog\n");
 | 
							log("        without this option all internal cells are converted to Verilog\n");
 | 
				
			||||||
		log("        expressions.\n");
 | 
							log("        expressions.\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -siminit\n");
 | 
				
			||||||
 | 
							log("        add initial statements with hierarchical refs to initialize FFs when\n");
 | 
				
			||||||
 | 
							log("        in -noexpr mode.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
		log("    -nodec\n");
 | 
							log("    -nodec\n");
 | 
				
			||||||
		log("        32-bit constant values are by default dumped as decimal numbers,\n");
 | 
							log("        32-bit constant values are by default dumped as decimal numbers,\n");
 | 
				
			||||||
		log("        not bit pattern. This option deactivates this feature and instead\n");
 | 
							log("        not bit pattern. This option deactivates this feature and instead\n");
 | 
				
			||||||
| 
						 | 
					@ -1663,11 +1667,14 @@ struct VerilogBackend : public Backend {
 | 
				
			||||||
		nostr = false;
 | 
							nostr = false;
 | 
				
			||||||
		defparam = false;
 | 
							defparam = false;
 | 
				
			||||||
		decimal = false;
 | 
							decimal = false;
 | 
				
			||||||
 | 
							siminit = false;
 | 
				
			||||||
		auto_prefix = "";
 | 
							auto_prefix = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool blackboxes = false;
 | 
							bool blackboxes = false;
 | 
				
			||||||
		bool selected = false;
 | 
							bool selected = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto_name_map.clear();
 | 
				
			||||||
 | 
							reg_wires.clear();
 | 
				
			||||||
		reg_ct.clear();
 | 
							reg_ct.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		reg_ct.insert("$dff");
 | 
							reg_ct.insert("$dff");
 | 
				
			||||||
| 
						 | 
					@ -1739,6 +1746,10 @@ struct VerilogBackend : public Backend {
 | 
				
			||||||
				decimal = true;
 | 
									decimal = true;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (arg == "-siminit") {
 | 
				
			||||||
 | 
									siminit = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (arg == "-blackboxes") {
 | 
								if (arg == "-blackboxes") {
 | 
				
			||||||
				blackboxes = true;
 | 
									blackboxes = true;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
| 
						 | 
					@ -1770,6 +1781,8 @@ struct VerilogBackend : public Backend {
 | 
				
			||||||
			dump_module(*f, "", it->second);
 | 
								dump_module(*f, "", it->second);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto_name_map.clear();
 | 
				
			||||||
 | 
							reg_wires.clear();
 | 
				
			||||||
		reg_ct.clear();
 | 
							reg_ct.clear();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
} VerilogBackend;
 | 
					} VerilogBackend;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								examples/anlogic/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								examples/anlogic/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					demo.bit
 | 
				
			||||||
 | 
					demo_phy.area
 | 
				
			||||||
 | 
					full.v
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					*.h
 | 
				
			||||||
 | 
					*.tde
 | 
				
			||||||
 | 
					*.svf
 | 
				
			||||||
							
								
								
									
										12
									
								
								examples/anlogic/README
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								examples/anlogic/README
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					LED Blink project for Anlogic Lichee Tang board.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Follow the install instructions for the Tang Dynasty IDE from given link below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export TD_HOME=<TD Install Directory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					then run "bash build.sh" in this directory.
 | 
				
			||||||
							
								
								
									
										4
									
								
								examples/anlogic/build.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								examples/anlogic/build.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					set -ex
 | 
				
			||||||
 | 
					yosys demo.ys
 | 
				
			||||||
 | 
					$TD_HOME/bin/td build.tcl
 | 
				
			||||||
							
								
								
									
										11
									
								
								examples/anlogic/build.tcl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								examples/anlogic/build.tcl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					import_device eagle_s20.db -package BG256
 | 
				
			||||||
 | 
					read_verilog full.v -top demo
 | 
				
			||||||
 | 
					read_adc demo.adc
 | 
				
			||||||
 | 
					optimize_rtl
 | 
				
			||||||
 | 
					map_macro
 | 
				
			||||||
 | 
					map
 | 
				
			||||||
 | 
					pack
 | 
				
			||||||
 | 
					place
 | 
				
			||||||
 | 
					route
 | 
				
			||||||
 | 
					report_area -io_info -file demo_phy.area
 | 
				
			||||||
 | 
					bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000
 | 
				
			||||||
							
								
								
									
										2
									
								
								examples/anlogic/demo.adc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								examples/anlogic/demo.adc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					set_pin_assignment {CLK_IN} { LOCATION = K14;  } ##24MHZ
 | 
				
			||||||
 | 
					set_pin_assignment {R_LED} { LOCATION = R3;  } ##R_LED
 | 
				
			||||||
							
								
								
									
										18
									
								
								examples/anlogic/demo.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								examples/anlogic/demo.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					module demo (
 | 
				
			||||||
 | 
					    input wire CLK_IN,
 | 
				
			||||||
 | 
					    output wire R_LED
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					    parameter time1 = 30'd12_000_000;
 | 
				
			||||||
 | 
					    reg led_state;
 | 
				
			||||||
 | 
					    reg [29:0] count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    always @(posedge CLK_IN)begin
 | 
				
			||||||
 | 
					        if(count == time1)begin
 | 
				
			||||||
 | 
					            count<= 30'd0;
 | 
				
			||||||
 | 
					            led_state <= ~led_state;
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            count <= count + 1'b1;
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    assign R_LED = led_state;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
							
								
								
									
										3
									
								
								examples/anlogic/demo.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								examples/anlogic/demo.ys
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					read_verilog demo.v
 | 
				
			||||||
 | 
					synth_anlogic -top demo
 | 
				
			||||||
 | 
					write_verilog full.v
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/igloo2/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								examples/igloo2/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
/netlist.edn
 | 
					/netlist.edn
 | 
				
			||||||
/netlist.vm
 | 
					/netlist.vm
 | 
				
			||||||
 | 
					/example.stp
 | 
				
			||||||
/proj
 | 
					/proj
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +1,20 @@
 | 
				
			||||||
# Add placement constraints here
 | 
					# Add placement constraints here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set_io clk  -pinname H16 -fixed yes -DIRECTION INPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set_io SW1  -pinname H12 -fixed yes -DIRECTION INPUT
 | 
				
			||||||
 | 
					set_io SW2  -pinname H13 -fixed yes -DIRECTION INPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set_io AA   -pinname L12 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io AB   -pinname L13 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io AC   -pinname M13 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io AD   -pinname N15 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io AE   -pinname L11 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io AF   -pinname L14 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io AG   -pinname N14 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
 | 
					set_io CA   -pinname M15 -fixed yes -DIRECTION OUTPUT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +1,2 @@
 | 
				
			||||||
# Add timing constraints here
 | 
					# Add timing constraints here
 | 
				
			||||||
 | 
					create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +1,64 @@
 | 
				
			||||||
module example (
 | 
					module example (
 | 
				
			||||||
	input  clk,
 | 
						input  clk,
 | 
				
			||||||
	input  EN,
 | 
						input  SW1,
 | 
				
			||||||
 | 
						input  SW2,
 | 
				
			||||||
	output LED1,
 | 
						output LED1,
 | 
				
			||||||
	output LED2,
 | 
						output LED2,
 | 
				
			||||||
	output LED3,
 | 
						output LED3,
 | 
				
			||||||
	output LED4,
 | 
						output LED4,
 | 
				
			||||||
	output LED5
 | 
					
 | 
				
			||||||
 | 
						output AA, AB, AC, AD,
 | 
				
			||||||
 | 
						output AE, AF, AG, CA
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	localparam BITS = 5;
 | 
						localparam BITS = 8;
 | 
				
			||||||
	localparam LOG2DELAY = 22;
 | 
						localparam LOG2DELAY = 22;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reg [BITS+LOG2DELAY-1:0] counter = 0;
 | 
						reg [BITS+LOG2DELAY-1:0] counter = 0;
 | 
				
			||||||
	reg [BITS-1:0] outcnt;
 | 
						reg [BITS-1:0] outcnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	always @(posedge clk) begin
 | 
						always @(posedge clk) begin
 | 
				
			||||||
		counter <= counter + EN;
 | 
							counter <= counter + SW1 + SW2 + 1;
 | 
				
			||||||
		outcnt <= counter >> LOG2DELAY;
 | 
							outcnt <= counter >> LOG2DELAY;
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1);
 | 
						assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// assign CA = counter[10];
 | 
				
			||||||
 | 
						// seg7enc seg7encinst (
 | 
				
			||||||
 | 
						// 	.seg({AA, AB, AC, AD, AE, AF, AG}),
 | 
				
			||||||
 | 
						// 	.dat(CA ? outcnt[3:0] : outcnt[7:4])
 | 
				
			||||||
 | 
						// );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
 | 
				
			||||||
 | 
						assign CA = outcnt[7];
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module seg7enc (
 | 
				
			||||||
 | 
						input [3:0] dat,
 | 
				
			||||||
 | 
						output [6:0] seg
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						reg [6:0] seg_inv;
 | 
				
			||||||
 | 
						always @* begin
 | 
				
			||||||
 | 
							seg_inv = 0;
 | 
				
			||||||
 | 
							case (dat)
 | 
				
			||||||
 | 
								4'h0: seg_inv = 7'b 0111111;
 | 
				
			||||||
 | 
								4'h1: seg_inv = 7'b 0000110;
 | 
				
			||||||
 | 
								4'h2: seg_inv = 7'b 1011011;
 | 
				
			||||||
 | 
								4'h3: seg_inv = 7'b 1001111;
 | 
				
			||||||
 | 
								4'h4: seg_inv = 7'b 1100110;
 | 
				
			||||||
 | 
								4'h5: seg_inv = 7'b 1101101;
 | 
				
			||||||
 | 
								4'h6: seg_inv = 7'b 1111101;
 | 
				
			||||||
 | 
								4'h7: seg_inv = 7'b 0000111;
 | 
				
			||||||
 | 
								4'h8: seg_inv = 7'b 1111111;
 | 
				
			||||||
 | 
								4'h9: seg_inv = 7'b 1101111;
 | 
				
			||||||
 | 
								4'hA: seg_inv = 7'b 1110111;
 | 
				
			||||||
 | 
								4'hB: seg_inv = 7'b 1111100;
 | 
				
			||||||
 | 
								4'hC: seg_inv = 7'b 0111001;
 | 
				
			||||||
 | 
								4'hD: seg_inv = 7'b 1011110;
 | 
				
			||||||
 | 
								4'hE: seg_inv = 7'b 1111001;
 | 
				
			||||||
 | 
								4'hF: seg_inv = 7'b 1110001;
 | 
				
			||||||
 | 
							endcase
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign seg = ~seg_inv;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,13 +8,14 @@ new_project \
 | 
				
			||||||
    -block_mode 0 \
 | 
					    -block_mode 0 \
 | 
				
			||||||
    -hdl "VERILOG" \
 | 
					    -hdl "VERILOG" \
 | 
				
			||||||
    -family IGLOO2 \
 | 
					    -family IGLOO2 \
 | 
				
			||||||
    -die PA4MGL500 \
 | 
					    -die PA4MGL2500 \
 | 
				
			||||||
    -package tq144 \
 | 
					    -package vf256 \
 | 
				
			||||||
    -speed -1
 | 
					    -speed -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import_files -hdl_source {netlist.vm}
 | 
					import_files -hdl_source {netlist.vm}
 | 
				
			||||||
import_files -sdc {example.sdc}
 | 
					import_files -sdc {example.sdc}
 | 
				
			||||||
import_files -io_pdc {example.pdc}
 | 
					import_files -io_pdc {example.pdc}
 | 
				
			||||||
 | 
					build_design_hierarchy
 | 
				
			||||||
set_option -synth 0
 | 
					set_option -synth 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
organize_tool_files -tool PLACEROUTE \
 | 
					organize_tool_files -tool PLACEROUTE \
 | 
				
			||||||
| 
						 | 
					@ -32,22 +33,25 @@ configure_tool -name PLACEROUTE \
 | 
				
			||||||
    -params EFFORT_LEVEL:false \
 | 
					    -params EFFORT_LEVEL:false \
 | 
				
			||||||
    -params REPAIR_MIN_DELAY:false
 | 
					    -params REPAIR_MIN_DELAY:false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					puts ""
 | 
				
			||||||
puts "**> COMPILE"
 | 
					puts "**> COMPILE"
 | 
				
			||||||
run_tool -name {COMPILE}
 | 
					run_tool -name {COMPILE}
 | 
				
			||||||
puts "<** COMPILE"
 | 
					puts "<** COMPILE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					puts ""
 | 
				
			||||||
puts "**> PLACEROUTE"
 | 
					puts "**> PLACEROUTE"
 | 
				
			||||||
run_tool -name {PLACEROUTE}
 | 
					run_tool -name {PLACEROUTE}
 | 
				
			||||||
puts "<** PLACEROUTE"
 | 
					puts "<** PLACEROUTE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					puts ""
 | 
				
			||||||
puts "**> VERIFYTIMING"
 | 
					puts "**> VERIFYTIMING"
 | 
				
			||||||
run_tool -name {VERIFYTIMING}
 | 
					run_tool -name {VERIFYTIMING}
 | 
				
			||||||
puts "<** VERIFYTIMING"
 | 
					puts "<** VERIFYTIMING"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
save_project
 | 
					puts ""
 | 
				
			||||||
 | 
					puts "**> BITSTREAM"
 | 
				
			||||||
# puts "**> export_bitstream"
 | 
					export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
 | 
				
			||||||
# export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
 | 
					puts "<** BITSTREAM"
 | 
				
			||||||
# puts "<** export_bitstream"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					puts ""
 | 
				
			||||||
exit 0
 | 
					exit 0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,6 @@
 | 
				
			||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
set -ex
 | 
					set -ex
 | 
				
			||||||
yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
 | 
					yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
 | 
				
			||||||
LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v11.9/Libero/bin/libero SCRIPT:libero.tcl
 | 
					export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
 | 
				
			||||||
 | 
					/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl
 | 
				
			||||||
 | 
					cp proj/designer/example/export/example.stp .
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,6 +214,8 @@ namespace AST
 | 
				
			||||||
			MEM2REG_FL_SET_ASYNC = 0x00000800,
 | 
								MEM2REG_FL_SET_ASYNC = 0x00000800,
 | 
				
			||||||
			MEM2REG_FL_EQ2       = 0x00001000,
 | 
								MEM2REG_FL_EQ2       = 0x00001000,
 | 
				
			||||||
			MEM2REG_FL_CMPLX_LHS = 0x00002000,
 | 
								MEM2REG_FL_CMPLX_LHS = 0x00002000,
 | 
				
			||||||
 | 
								MEM2REG_FL_CONST_LHS = 0x00004000,
 | 
				
			||||||
 | 
								MEM2REG_FL_VAR_LHS   = 0x00008000,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* proc flags */
 | 
								/* proc flags */
 | 
				
			||||||
			MEM2REG_FL_EQ1       = 0x01000000,
 | 
								MEM2REG_FL_EQ1       = 0x01000000,
 | 
				
			||||||
| 
						 | 
					@ -237,6 +239,7 @@ namespace AST
 | 
				
			||||||
		bool has_const_only_constructs(bool &recommend_const_eval);
 | 
							bool has_const_only_constructs(bool &recommend_const_eval);
 | 
				
			||||||
		void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
 | 
							void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
 | 
				
			||||||
		AstNode *eval_const_function(AstNode *fcall);
 | 
							AstNode *eval_const_function(AstNode *fcall);
 | 
				
			||||||
 | 
							bool is_simple_const_expr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// create a human-readable text representation of the AST (for debugging)
 | 
							// create a human-readable text representation of the AST (for debugging)
 | 
				
			||||||
		void dumpAst(FILE *f, std::string indent) const;
 | 
							void dumpAst(FILE *f, std::string indent) const;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -525,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
 | 
									if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
 | 
				
			||||||
 | 
								#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
 | 
				
			||||||
 | 
										// optimizations take care of the rest
 | 
				
			||||||
					last_generated_case->compare.clear();
 | 
										last_generated_case->compare.clear();
 | 
				
			||||||
 | 
								#else
 | 
				
			||||||
 | 
										default_case = new RTLIL::CaseRule;
 | 
				
			||||||
 | 
										addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
 | 
				
			||||||
 | 
										sw->cases.push_back(default_case);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					if (default_case == NULL) {
 | 
										if (default_case == NULL) {
 | 
				
			||||||
						default_case = new RTLIL::CaseRule;
 | 
											default_case = new RTLIL::CaseRule;
 | 
				
			||||||
| 
						 | 
					@ -544,7 +553,11 @@ struct AST_INTERNAL::ProcessGenerator
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case AST_WIRE:
 | 
							case AST_WIRE:
 | 
				
			||||||
			log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n");
 | 
								log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case AST_ASSIGN:
 | 
				
			||||||
 | 
								log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n");
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case AST_PARAMETER:
 | 
							case AST_PARAMETER:
 | 
				
			||||||
| 
						 | 
					@ -644,7 +657,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
				
			||||||
				while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
									while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
				
			||||||
				if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
									if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
				
			||||||
					log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
										log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
				
			||||||
				this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
 | 
									this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
 | 
				
			||||||
				delete left_at_zero_ast;
 | 
									delete left_at_zero_ast;
 | 
				
			||||||
				delete right_at_zero_ast;
 | 
									delete right_at_zero_ast;
 | 
				
			||||||
			} else
 | 
								} else
 | 
				
			||||||
| 
						 | 
					@ -792,7 +805,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 | 
				
			||||||
	// everything should have been handled above -> print error if not.
 | 
						// everything should have been handled above -> print error if not.
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		for (auto f : log_files)
 | 
							for (auto f : log_files)
 | 
				
			||||||
			current_ast->dumpAst(f, "verilog-ast> ");
 | 
								current_ast_mod->dumpAst(f, "verilog-ast> ");
 | 
				
			||||||
		log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
 | 
							log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1034,7 +1047,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
				
			||||||
					while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
										while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
				
			||||||
					if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
										if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
				
			||||||
						log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
											log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
				
			||||||
					int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
 | 
										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 ?
 | 
										AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
 | 
				
			||||||
							children[0]->children[1]->clone() : children[0]->children[0]->clone());
 | 
												children[0]->children[1]->clone() : children[0]->children[0]->clone());
 | 
				
			||||||
					fake_ast->children[0]->delete_children();
 | 
										fake_ast->children[0]->delete_children();
 | 
				
			||||||
| 
						 | 
					@ -1409,10 +1422,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
				
			||||||
			if (GetSize(en) != 1)
 | 
								if (GetSize(en) != 1)
 | 
				
			||||||
				en = current_module->ReduceBool(NEW_ID, en);
 | 
									en = current_module->ReduceBool(NEW_ID, en);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::stringstream sstr;
 | 
								IdString cellname;
 | 
				
			||||||
			sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
 | 
								if (str.empty()) {
 | 
				
			||||||
 | 
									std::stringstream sstr;
 | 
				
			||||||
 | 
									sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
 | 
				
			||||||
 | 
									cellname = sstr.str();
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									cellname = str;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
 | 
								RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
 | 
				
			||||||
			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
 | 
								cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (auto &attr : attributes) {
 | 
								for (auto &attr : attributes) {
 | 
				
			||||||
| 
						 | 
					@ -1565,7 +1584,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
				
			||||||
	// everything should have been handled above -> print error if not.
 | 
						// everything should have been handled above -> print error if not.
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		for (auto f : log_files)
 | 
							for (auto f : log_files)
 | 
				
			||||||
			current_ast->dumpAst(f, "verilog-ast> ");
 | 
								current_ast_mod->dumpAst(f, "verilog-ast> ");
 | 
				
			||||||
		type_name = type2str(type);
 | 
							type_name = type2str(type);
 | 
				
			||||||
		log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());
 | 
							log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,7 +50,6 @@ using namespace AST_INTERNAL;
 | 
				
			||||||
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
 | 
					bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static int recursion_counter = 0;
 | 
						static int recursion_counter = 0;
 | 
				
			||||||
	static pair<string, int> last_blocking_assignment_warn;
 | 
					 | 
				
			||||||
	static bool deep_recursion_warning = false;
 | 
						static bool deep_recursion_warning = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (recursion_counter++ == 1000 && deep_recursion_warning) {
 | 
						if (recursion_counter++ == 1000 && deep_recursion_warning) {
 | 
				
			||||||
| 
						 | 
					@ -72,7 +71,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
	if (stage == 0)
 | 
						if (stage == 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		log_assert(type == AST_MODULE || type == AST_INTERFACE);
 | 
							log_assert(type == AST_MODULE || type == AST_INTERFACE);
 | 
				
			||||||
		last_blocking_assignment_warn = pair<string, int>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		deep_recursion_warning = true;
 | 
							deep_recursion_warning = true;
 | 
				
			||||||
		while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
 | 
							while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
 | 
				
			||||||
| 
						 | 
					@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
				if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
 | 
									if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
 | 
				
			||||||
					goto verbose_activate;
 | 
										goto verbose_activate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS))
 | 
				
			||||||
 | 
										goto verbose_activate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
 | 
									// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,6 +326,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
		for (size_t i = 0; i < children.size(); i++) {
 | 
							for (size_t i = 0; i < children.size(); i++) {
 | 
				
			||||||
			AstNode *node = children[i];
 | 
								AstNode *node = children[i];
 | 
				
			||||||
			if (node->type == AST_WIRE) {
 | 
								if (node->type == AST_WIRE) {
 | 
				
			||||||
 | 
									if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
 | 
				
			||||||
 | 
										for (auto c : node->children[0]->children) {
 | 
				
			||||||
 | 
											if (!c->is_simple_const_expr()) {
 | 
				
			||||||
 | 
												if (attributes.count("\\dynports"))
 | 
				
			||||||
 | 
													delete attributes.at("\\dynports");
 | 
				
			||||||
 | 
												attributes["\\dynports"] = AstNode::mkconst_int(1, true);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				if (this_wire_scope.count(node->str) > 0) {
 | 
									if (this_wire_scope.count(node->str) > 0) {
 | 
				
			||||||
					AstNode *first_node = this_wire_scope[node->str];
 | 
										AstNode *first_node = this_wire_scope[node->str];
 | 
				
			||||||
					if (first_node->is_input && node->is_reg)
 | 
										if (first_node->is_input && node->is_reg)
 | 
				
			||||||
| 
						 | 
					@ -642,6 +652,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
	// (iterate by index as e.g. auto wires can add new children in the process)
 | 
						// (iterate by index as e.g. auto wires can add new children in the process)
 | 
				
			||||||
	for (size_t i = 0; i < children.size(); i++) {
 | 
						for (size_t i = 0; i < children.size(); i++) {
 | 
				
			||||||
		bool did_something_here = true;
 | 
							bool did_something_here = true;
 | 
				
			||||||
 | 
							bool backup_flag_autowire = flag_autowire;
 | 
				
			||||||
		if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
 | 
							if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1)
 | 
							if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1)
 | 
				
			||||||
| 
						 | 
					@ -652,6 +663,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (type == AST_PREFIX && i >= 1)
 | 
							if (type == AST_PREFIX && i >= 1)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							if (type == AST_DEFPARAM && i == 0)
 | 
				
			||||||
 | 
								flag_autowire = true;
 | 
				
			||||||
		while (did_something_here && i < children.size()) {
 | 
							while (did_something_here && i < children.size()) {
 | 
				
			||||||
			bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
 | 
								bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
 | 
				
			||||||
			int width_hint_here = width_hint;
 | 
								int width_hint_here = width_hint;
 | 
				
			||||||
| 
						 | 
					@ -686,6 +699,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
			children.erase(children.begin() + (i--));
 | 
								children.erase(children.begin() + (i--));
 | 
				
			||||||
			did_something = true;
 | 
								did_something = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							flag_autowire = backup_flag_autowire;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (auto &attr : attributes) {
 | 
						for (auto &attr : attributes) {
 | 
				
			||||||
		while (attr.second->simplify(true, false, false, stage, -1, false, true))
 | 
							while (attr.second->simplify(true, false, false, stage, -1, false, true))
 | 
				
			||||||
| 
						 | 
					@ -934,12 +948,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (current_scope.count(str) == 0) {
 | 
							if (current_scope.count(str) == 0) {
 | 
				
			||||||
			// log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
 | 
								if (flag_autowire || str == "\\$global_clock") {
 | 
				
			||||||
			AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
 | 
									AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
 | 
				
			||||||
			auto_wire->str = str;
 | 
									auto_wire->str = str;
 | 
				
			||||||
			current_ast_mod->children.push_back(auto_wire);
 | 
									current_ast_mod->children.push_back(auto_wire);
 | 
				
			||||||
			current_scope[str] = auto_wire;
 | 
									current_scope[str] = auto_wire;
 | 
				
			||||||
			did_something = true;
 | 
									did_something = true;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (id2ast != current_scope[str]) {
 | 
							if (id2ast != current_scope[str]) {
 | 
				
			||||||
			id2ast = current_scope[str];
 | 
								id2ast = current_scope[str];
 | 
				
			||||||
| 
						 | 
					@ -1492,6 +1509,7 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
		newNode->children.push_back(assign_en);
 | 
							newNode->children.push_back(assign_en);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AstNode *assertnode = new AstNode(type);
 | 
							AstNode *assertnode = new AstNode(type);
 | 
				
			||||||
 | 
							assertnode->str = str;
 | 
				
			||||||
		assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
 | 
							assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
 | 
				
			||||||
		assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
 | 
							assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
 | 
				
			||||||
		assertnode->children[0]->str = id_check;
 | 
							assertnode->children[0]->str = id_check;
 | 
				
			||||||
| 
						 | 
					@ -1572,14 +1590,6 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
		sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
 | 
							sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
 | 
				
			||||||
		std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
 | 
							std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (type == AST_ASSIGN_EQ) {
 | 
					 | 
				
			||||||
			pair<string, int> this_blocking_assignment_warn(filename, linenum);
 | 
					 | 
				
			||||||
			if (this_blocking_assignment_warn != last_blocking_assignment_warn)
 | 
					 | 
				
			||||||
				log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
 | 
					 | 
				
			||||||
						filename.c_str(), linenum);
 | 
					 | 
				
			||||||
			last_blocking_assignment_warn = this_blocking_assignment_warn;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int mem_width, mem_size, addr_bits;
 | 
							int mem_width, mem_size, addr_bits;
 | 
				
			||||||
		bool mem_signed = children[0]->id2ast->is_signed;
 | 
							bool mem_signed = children[0]->id2ast->is_signed;
 | 
				
			||||||
		children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
 | 
							children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
 | 
				
			||||||
| 
						 | 
					@ -1689,7 +1699,7 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
				while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
									while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
 | 
				
			||||||
				if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
									if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
 | 
				
			||||||
					log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
										log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
 | 
				
			||||||
				int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
 | 
									int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
 | 
									assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
 | 
				
			||||||
						new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
 | 
											new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
 | 
				
			||||||
| 
						 | 
					@ -1778,7 +1788,7 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (str == "\\$past")
 | 
								if (str == "\\$past")
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (width_hint <= 0)
 | 
									if (width_hint < 0)
 | 
				
			||||||
					goto replace_fcall_later;
 | 
										goto replace_fcall_later;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				int num_steps = 1;
 | 
									int num_steps = 1;
 | 
				
			||||||
| 
						 | 
					@ -2162,6 +2172,8 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
 | 
									newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
 | 
				
			||||||
 | 
									delete node_filename;
 | 
				
			||||||
 | 
									delete node_memory;
 | 
				
			||||||
				goto apply_newNode;
 | 
									goto apply_newNode;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2203,6 +2215,8 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
		std::map<std::string, std::string> replace_rules;
 | 
							std::map<std::string, std::string> replace_rules;
 | 
				
			||||||
		vector<AstNode*> added_mod_children;
 | 
							vector<AstNode*> added_mod_children;
 | 
				
			||||||
		dict<std::string, AstNode*> wire_cache;
 | 
							dict<std::string, AstNode*> wire_cache;
 | 
				
			||||||
 | 
							vector<AstNode*> new_stmts;
 | 
				
			||||||
 | 
							vector<AstNode*> output_assignments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (current_block == NULL)
 | 
							if (current_block == NULL)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -2327,8 +2341,8 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
					wire->port_id = 0;
 | 
										wire->port_id = 0;
 | 
				
			||||||
					wire->is_input = false;
 | 
										wire->is_input = false;
 | 
				
			||||||
					wire->is_output = false;
 | 
										wire->is_output = false;
 | 
				
			||||||
					if (!child->is_output)
 | 
										wire->is_reg = true;
 | 
				
			||||||
						wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
 | 
										wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
 | 
				
			||||||
					wire_cache[child->str] = wire;
 | 
										wire_cache[child->str] = wire;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					current_ast_mod->children.push_back(wire);
 | 
										current_ast_mod->children.push_back(wire);
 | 
				
			||||||
| 
						 | 
					@ -2350,13 +2364,10 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
							new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
 | 
												new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
 | 
				
			||||||
							new AstNode(AST_ASSIGN_EQ, arg, wire_id);
 | 
												new AstNode(AST_ASSIGN_EQ, arg, wire_id);
 | 
				
			||||||
					assign->children[0]->was_checked = true;
 | 
										assign->children[0]->was_checked = true;
 | 
				
			||||||
 | 
										if (child->is_input)
 | 
				
			||||||
					for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
 | 
											new_stmts.push_back(assign);
 | 
				
			||||||
						if (*it != current_block_child)
 | 
										else
 | 
				
			||||||
							continue;
 | 
											output_assignments.push_back(assign);
 | 
				
			||||||
						current_block->children.insert(it, assign);
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2370,15 +2381,19 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				AstNode *stmt = child->clone();
 | 
									AstNode *stmt = child->clone();
 | 
				
			||||||
				stmt->replace_ids(prefix, replace_rules);
 | 
									stmt->replace_ids(prefix, replace_rules);
 | 
				
			||||||
 | 
									new_stmts.push_back(stmt);
 | 
				
			||||||
				for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
 | 
					 | 
				
			||||||
					if (*it != current_block_child)
 | 
					 | 
				
			||||||
						continue;
 | 
					 | 
				
			||||||
					current_block->children.insert(it, stmt);
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto it = current_block->children.begin(); ; it++) {
 | 
				
			||||||
 | 
								log_assert(it != current_block->children.end());
 | 
				
			||||||
 | 
								if (*it == current_block_child) {
 | 
				
			||||||
 | 
									current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	replace_fcall_with_id:
 | 
						replace_fcall_with_id:
 | 
				
			||||||
		if (type == AST_FCALL) {
 | 
							if (type == AST_FCALL) {
 | 
				
			||||||
			delete_children();
 | 
								delete_children();
 | 
				
			||||||
| 
						 | 
					@ -2848,7 +2863,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < children.size(); i++) {
 | 
						for (size_t i = 0; i < children.size(); i++) {
 | 
				
			||||||
		AstNode *child = children[i];
 | 
							AstNode *child = children[i];
 | 
				
			||||||
		if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX)
 | 
							// AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
 | 
				
			||||||
 | 
							// still needs to recursed-into
 | 
				
			||||||
 | 
							if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (child->type != AST_FUNCTION && child->type != AST_TASK)
 | 
				
			||||||
			child->expand_genblock(index_var, prefix, name_map);
 | 
								child->expand_genblock(index_var, prefix, name_map);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2903,7 +2922,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
 | 
				
			||||||
		dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
 | 
							dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t children_flags = 0;
 | 
						uint32_t children_flags = 0;
 | 
				
			||||||
	int ignore_children_counter = 0;
 | 
						int lhs_children_counter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
 | 
						if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -2929,6 +2948,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
 | 
				
			||||||
				proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
 | 
									proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// for proper (non-init) writes: remember if this is a constant index or not
 | 
				
			||||||
 | 
								if ((flags & MEM2REG_FL_INIT) == 0) {
 | 
				
			||||||
 | 
									if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
 | 
				
			||||||
 | 
										if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
 | 
				
			||||||
 | 
											mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// remember where this is
 | 
								// remember where this is
 | 
				
			||||||
			if (flags & MEM2REG_FL_INIT) {
 | 
								if (flags & MEM2REG_FL_INIT) {
 | 
				
			||||||
				if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
 | 
									if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
 | 
				
			||||||
| 
						 | 
					@ -2941,7 +2970,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ignore_children_counter = 1;
 | 
							lhs_children_counter = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
 | 
						if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
 | 
				
			||||||
| 
						 | 
					@ -2984,12 +3013,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
 | 
				
			||||||
	log_assert((flags & ~0x000000ff) == 0);
 | 
						log_assert((flags & ~0x000000ff) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto child : children)
 | 
						for (auto child : children)
 | 
				
			||||||
		if (ignore_children_counter > 0)
 | 
						{
 | 
				
			||||||
			ignore_children_counter--;
 | 
							if (lhs_children_counter > 0) {
 | 
				
			||||||
		else if (proc_flags_p)
 | 
								lhs_children_counter--;
 | 
				
			||||||
 | 
								if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) {
 | 
				
			||||||
 | 
									for (auto c : child->children[0]->children) {
 | 
				
			||||||
 | 
										if (proc_flags_p)
 | 
				
			||||||
 | 
											c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
							if (proc_flags_p)
 | 
				
			||||||
			child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
 | 
								child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
 | 
								child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flags &= ~children_flags | backup_flags;
 | 
						flags &= ~children_flags | backup_flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3041,6 +3081,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
 | 
				
			||||||
	if (type == AST_FUNCTION || type == AST_TASK)
 | 
						if (type == AST_FUNCTION || type == AST_TASK)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log_assert(children[0]->type == AST_CONSTANT);
 | 
				
			||||||
 | 
							log_assert(children[1]->type == AST_CONSTANT);
 | 
				
			||||||
 | 
							log_assert(children[2]->type == AST_CONSTANT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int cursor = children[0]->asInt(false);
 | 
				
			||||||
 | 
							Const data = children[1]->bitsAsConst();
 | 
				
			||||||
 | 
							int length = children[2]->asInt(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (length != 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK));
 | 
				
			||||||
 | 
								mod->children.push_back(block);
 | 
				
			||||||
 | 
								block = block->children[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int wordsz = GetSize(data) / length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (int i = 0; i < length; i++) {
 | 
				
			||||||
 | 
									block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false)));
 | 
				
			||||||
 | 
									block->children.back()->children[0]->str = str;
 | 
				
			||||||
 | 
									block->children.back()->children[0]->id2ast = id2ast;
 | 
				
			||||||
 | 
									block->children.back()->children[0]->was_checked = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							AstNode *newNode = new AstNode(AST_NONE);
 | 
				
			||||||
 | 
							newNode->cloneInto(this);
 | 
				
			||||||
 | 
							delete newNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							did_something = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
 | 
						if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (async_block == NULL) {
 | 
							if (async_block == NULL) {
 | 
				
			||||||
| 
						 | 
					@ -3270,6 +3343,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool AstNode::is_simple_const_expr()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (type == AST_IDENTIFIER)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						for (auto child : children)
 | 
				
			||||||
 | 
							if (!child->is_simple_const_expr())
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// helper function for AstNode::eval_const_function()
 | 
					// helper function for AstNode::eval_const_function()
 | 
				
			||||||
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
 | 
					void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ Then run in the following command in this directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sby -f example.sby
 | 
						sby -f example.sby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This will generate approximately one page of text outpout. The last lines
 | 
					This will generate approximately one page of text output. The last lines
 | 
				
			||||||
should be something like this:
 | 
					should be something like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
 | 
						SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1855,6 +1855,13 @@ struct VerificPass : public Pass {
 | 
				
			||||||
		log("  -autocover\n");
 | 
							log("  -autocover\n");
 | 
				
			||||||
		log("    Generate automatic cover statements for all asserts\n");
 | 
							log("    Generate automatic cover statements for all asserts\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("  -chparam name value \n");
 | 
				
			||||||
 | 
							log("    Elaborate the specified top modules (all modules when -all given) using\n");
 | 
				
			||||||
 | 
							log("    this parameter value. Modules on which this parameter does not exist will\n");
 | 
				
			||||||
 | 
							log("    cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n");
 | 
				
			||||||
 | 
							log("    can be specified multiple times to override multiple parameters.\n");
 | 
				
			||||||
 | 
							log("    String values must be passed in double quotes (\").\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
		log("  -v, -vv\n");
 | 
							log("  -v, -vv\n");
 | 
				
			||||||
		log("    Verbose log messages. (-vv is even more verbose than -v.)\n");
 | 
							log("    Verbose log messages. (-vv is even more verbose than -v.)\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
| 
						 | 
					@ -1920,6 +1927,10 @@ struct VerificPass : public Pass {
 | 
				
			||||||
			// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
 | 
								// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
 | 
				
			||||||
			Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
 | 
								Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DB_PRESERVE_INITIAL_VALUE
 | 
				
			||||||
 | 
					#  warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			set_verific_global_flags = false;
 | 
								set_verific_global_flags = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2105,6 +2116,7 @@ struct VerificPass : public Pass {
 | 
				
			||||||
			bool mode_autocover = false;
 | 
								bool mode_autocover = false;
 | 
				
			||||||
			bool flatten = false, extnets = false;
 | 
								bool flatten = false, extnets = false;
 | 
				
			||||||
			string dumpfile;
 | 
								string dumpfile;
 | 
				
			||||||
 | 
								Map parameters(STRING_HASH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (argidx++; argidx < GetSize(args); argidx++) {
 | 
								for (argidx++; argidx < GetSize(args); argidx++) {
 | 
				
			||||||
				if (args[argidx] == "-all") {
 | 
									if (args[argidx] == "-all") {
 | 
				
			||||||
| 
						 | 
					@ -2143,6 +2155,15 @@ struct VerificPass : public Pass {
 | 
				
			||||||
					mode_autocover = true;
 | 
										mode_autocover = true;
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx] == "-chparam"  && argidx+2 < GetSize(args)) {
 | 
				
			||||||
 | 
					                                        const std::string &key = args[++argidx];
 | 
				
			||||||
 | 
					                                        const std::string &value = args[++argidx];
 | 
				
			||||||
 | 
										unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
 | 
				
			||||||
 | 
														           1 /* force_overwrite */);
 | 
				
			||||||
 | 
										if (!new_insertion)
 | 
				
			||||||
 | 
											log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str());
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				if (args[argidx] == "-V") {
 | 
									if (args[argidx] == "-V") {
 | 
				
			||||||
					mode_verific = true;
 | 
										mode_verific = true;
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
| 
						 | 
					@ -2176,7 +2197,7 @@ struct VerificPass : public Pass {
 | 
				
			||||||
				if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
 | 
									if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
 | 
				
			||||||
				if (veri_lib) veri_libs.InsertLast(veri_lib);
 | 
									if (veri_lib) veri_libs.InsertLast(veri_lib);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
 | 
									Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters);
 | 
				
			||||||
				Netlist *nl;
 | 
									Netlist *nl;
 | 
				
			||||||
				int i;
 | 
									int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2213,7 +2234,7 @@ struct VerificPass : public Pass {
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				log("Running hier_tree::Elaborate().\n");
 | 
									log("Running hier_tree::Elaborate().\n");
 | 
				
			||||||
				Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units);
 | 
									Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters);
 | 
				
			||||||
				Netlist *nl;
 | 
									Netlist *nl;
 | 
				
			||||||
				int i;
 | 
									int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2312,7 +2333,7 @@ struct ReadPass : public Pass {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (args.size() < 2)
 | 
							if (args.size() < 2 || args[1][0] != '-')
 | 
				
			||||||
			log_cmd_error("Missing mode parameter.\n");
 | 
								log_cmd_error("Missing mode parameter.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (args.size() < 3)
 | 
							if (args.size() < 3)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1666,7 +1666,20 @@ struct VerificSvaImporter
 | 
				
			||||||
				log("  importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
 | 
									log("  importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
 | 
				
			||||||
						LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
 | 
											LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
 | 
								bool is_user_declared = root->IsUserDeclared();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// FIXME
 | 
				
			||||||
 | 
								if (!is_user_declared) {
 | 
				
			||||||
 | 
									const char *name = root->Name();
 | 
				
			||||||
 | 
									for (int i = 0; name[i]; i++) {
 | 
				
			||||||
 | 
										if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
 | 
				
			||||||
 | 
											is_user_declared = true;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// parse SVA sequence into trigger signal
 | 
								// parse SVA sequence into trigger signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,6 +189,14 @@ YOSYS_NAMESPACE_END
 | 
				
			||||||
"always_ff"    { SV_KEYWORD(TOK_ALWAYS); }
 | 
					"always_ff"    { SV_KEYWORD(TOK_ALWAYS); }
 | 
				
			||||||
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
 | 
					"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 /* 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_$\.] {
 | 
				
			||||||
 | 
						frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
 | 
				
			||||||
 | 
						return TOK_SVA_LABEL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"assert"     { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
 | 
					"assert"     { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
 | 
				
			||||||
"assume"     { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
 | 
					"assume"     { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
 | 
				
			||||||
"cover"      { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
 | 
					"cover"      { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
 | 
				
			||||||
| 
						 | 
					@ -303,7 +311,7 @@ supply1 { return TOK_SUPPLY1; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
 | 
					[a-zA-Z_$][a-zA-Z0-9_$\.]* {
 | 
				
			||||||
	frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
 | 
						frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
 | 
				
			||||||
    return TOK_ID;
 | 
						return TOK_ID;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
 | 
					"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,8 @@ static void free_attr(std::map<std::string, AstNode*> *al)
 | 
				
			||||||
	bool boolean;
 | 
						bool boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
 | 
					%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
 | 
				
			||||||
 | 
					%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
 | 
				
			||||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
 | 
					%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
 | 
				
			||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
 | 
					%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
 | 
				
			||||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
 | 
					%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
 | 
				
			||||||
| 
						 | 
					@ -119,14 +120,13 @@ static void free_attr(std::map<std::string, AstNode*> *al)
 | 
				
			||||||
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
 | 
					%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
 | 
				
			||||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
 | 
					%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
 | 
				
			||||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
 | 
					%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
 | 
				
			||||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
 | 
					%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
 | 
				
			||||||
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
 | 
					 | 
				
			||||||
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
 | 
					%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
 | 
				
			||||||
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
 | 
					%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%type <ast> range range_or_multirange  non_opt_range non_opt_multirange range_or_signed_int
 | 
					%type <ast> range range_or_multirange  non_opt_range non_opt_multirange range_or_signed_int
 | 
				
			||||||
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
 | 
					%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
 | 
				
			||||||
%type <string> opt_label tok_prim_wrapper hierarchical_id
 | 
					%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
 | 
				
			||||||
%type <boolean> opt_signed opt_property unique_case_attr
 | 
					%type <boolean> opt_signed opt_property unique_case_attr
 | 
				
			||||||
%type <al> attr case_attr
 | 
					%type <al> attr case_attr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1329,6 +1329,14 @@ opt_label:
 | 
				
			||||||
		$$ = NULL;
 | 
							$$ = NULL;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					opt_sva_label:
 | 
				
			||||||
 | 
						TOK_SVA_LABEL ':' {
 | 
				
			||||||
 | 
							$$ = $1;
 | 
				
			||||||
 | 
						} |
 | 
				
			||||||
 | 
						/* empty */ {
 | 
				
			||||||
 | 
							$$ = NULL;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
opt_property:
 | 
					opt_property:
 | 
				
			||||||
	TOK_PROPERTY {
 | 
						TOK_PROPERTY {
 | 
				
			||||||
		$$ = true;
 | 
							$$ = true;
 | 
				
			||||||
| 
						 | 
					@ -1337,9 +1345,6 @@ opt_property:
 | 
				
			||||||
		$$ = false;
 | 
							$$ = false;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
opt_stmt_label:
 | 
					 | 
				
			||||||
	TOK_ID ':' | /* empty */;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
modport_stmt:
 | 
					modport_stmt:
 | 
				
			||||||
    TOK_MODPORT TOK_ID {
 | 
					    TOK_MODPORT TOK_ID {
 | 
				
			||||||
        AstNode *modport = new AstNode(AST_MODPORT);
 | 
					        AstNode *modport = new AstNode(AST_MODPORT);
 | 
				
			||||||
| 
						 | 
					@ -1376,83 +1381,164 @@ modport_type_token:
 | 
				
			||||||
    TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
 | 
					    TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
assert:
 | 
					assert:
 | 
				
			||||||
	opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
 | 
						opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
 | 
				
			||||||
		if (noassert_mode)
 | 
							if (noassert_mode) {
 | 
				
			||||||
			delete $5;
 | 
								delete $5;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
 | 
								AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
 | 
				
			||||||
 | 
								if ($1 != nullptr)
 | 
				
			||||||
 | 
									node->str = *$1;
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ($1 != nullptr)
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
 | 
						opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
 | 
				
			||||||
		if (noassume_mode)
 | 
							if (noassume_mode) {
 | 
				
			||||||
			delete $5;
 | 
								delete $5;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5));
 | 
								AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
 | 
				
			||||||
 | 
								if ($1 != nullptr)
 | 
				
			||||||
 | 
									node->str = *$1;
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ($1 != nullptr)
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
						opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
				
			||||||
		if (noassert_mode)
 | 
							if (noassert_mode) {
 | 
				
			||||||
			delete $6;
 | 
								delete $6;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
 | 
								AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
 | 
				
			||||||
 | 
								if ($1 != nullptr)
 | 
				
			||||||
 | 
									node->str = *$1;
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ($1 != nullptr)
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
						opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
				
			||||||
		if (noassume_mode)
 | 
							if (noassume_mode) {
 | 
				
			||||||
			delete $6;
 | 
								delete $6;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6));
 | 
								AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
 | 
				
			||||||
 | 
								if ($1 != nullptr)
 | 
				
			||||||
 | 
									node->str = *$1;
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ($1 != nullptr)
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
 | 
						opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
 | 
							AstNode *node = new AstNode(AST_COVER, $5);
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								node->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ast_stack.back()->children.push_back(node);
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
 | 
						opt_sva_label TOK_COVER opt_property '(' ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
 | 
							AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								node->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ast_stack.back()->children.push_back(node);
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_COVER ';' {
 | 
						opt_sva_label TOK_COVER ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
 | 
							AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								node->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ast_stack.back()->children.push_back(node);
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
 | 
						opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
 | 
				
			||||||
		if (norestrict_mode)
 | 
							if (norestrict_mode) {
 | 
				
			||||||
			delete $5;
 | 
								delete $5;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
 | 
								AstNode *node = new AstNode(AST_ASSUME, $5);
 | 
				
			||||||
 | 
								if ($1 != nullptr)
 | 
				
			||||||
 | 
									node->str = *$1;
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (!$3)
 | 
							if (!$3)
 | 
				
			||||||
			log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
 | 
								log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
 | 
				
			||||||
 | 
							if ($1 != nullptr)
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
						opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
				
			||||||
		if (norestrict_mode)
 | 
							if (norestrict_mode) {
 | 
				
			||||||
			delete $6;
 | 
								delete $6;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
 | 
								AstNode *node = new AstNode(AST_FAIR, $6);
 | 
				
			||||||
 | 
								if ($1 != nullptr)
 | 
				
			||||||
 | 
									node->str = *$1;
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (!$3)
 | 
							if (!$3)
 | 
				
			||||||
			log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
 | 
								log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
 | 
				
			||||||
 | 
							if ($1 != nullptr)
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
assert_property:
 | 
					assert_property:
 | 
				
			||||||
	TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
 | 
						opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
 | 
							ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
 | 
						opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
 | 
							ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
 | 
						opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
 | 
							ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
 | 
						opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
 | 
							ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
 | 
						opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
 | 
							ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
 | 
				
			||||||
 | 
							if ($1 != nullptr) {
 | 
				
			||||||
 | 
								ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
								delete $1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
	TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
 | 
						opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
 | 
				
			||||||
		if (norestrict_mode)
 | 
							if (norestrict_mode) {
 | 
				
			||||||
			delete $4;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
 | 
					 | 
				
			||||||
	} |
 | 
					 | 
				
			||||||
	TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
 | 
					 | 
				
			||||||
		if (norestrict_mode)
 | 
					 | 
				
			||||||
			delete $5;
 | 
								delete $5;
 | 
				
			||||||
		else
 | 
							} else {
 | 
				
			||||||
			ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
 | 
								ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
 | 
				
			||||||
 | 
								if ($1 != nullptr) {
 | 
				
			||||||
 | 
									ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
									delete $1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} |
 | 
				
			||||||
 | 
						opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
 | 
				
			||||||
 | 
							if (norestrict_mode) {
 | 
				
			||||||
 | 
								delete $6;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
 | 
				
			||||||
 | 
								if ($1 != nullptr) {
 | 
				
			||||||
 | 
									ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
									delete $1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
simple_behavioral_stmt:
 | 
					simple_behavioral_stmt:
 | 
				
			||||||
| 
						 | 
					@ -1670,6 +1756,11 @@ case_expr_list:
 | 
				
			||||||
	TOK_DEFAULT {
 | 
						TOK_DEFAULT {
 | 
				
			||||||
		ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
 | 
							ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
 | 
						TOK_SVA_LABEL {
 | 
				
			||||||
 | 
							ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
 | 
				
			||||||
 | 
							ast_stack.back()->children.back()->str = *$1;
 | 
				
			||||||
 | 
							delete $1;
 | 
				
			||||||
 | 
						} |
 | 
				
			||||||
	expr {
 | 
						expr {
 | 
				
			||||||
		ast_stack.back()->children.push_back($1);
 | 
							ast_stack.back()->children.push_back($1);
 | 
				
			||||||
	} |
 | 
						} |
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,6 +81,27 @@ struct CellTypes
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setup_internals()
 | 
						void setup_internals()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							setup_internals_eval();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							setup_type("$tribuf", {A, EN}, {Y}, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
				
			||||||
 | 
							setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
				
			||||||
 | 
							setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
				
			||||||
 | 
							setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
				
			||||||
 | 
							setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
				
			||||||
 | 
							setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
 | 
				
			||||||
 | 
							setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
				
			||||||
 | 
							setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
				
			||||||
 | 
							setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
				
			||||||
 | 
							setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
				
			||||||
 | 
							setup_type("$equiv", {A, B}, {Y}, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setup_internals_eval()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		std::vector<RTLIL::IdString> unary_ops = {
 | 
							std::vector<RTLIL::IdString> unary_ops = {
 | 
				
			||||||
			"$not", "$pos", "$neg",
 | 
								"$not", "$pos", "$neg",
 | 
				
			||||||
| 
						 | 
					@ -111,20 +132,6 @@ struct CellTypes
 | 
				
			||||||
		setup_type("$lcu", {P, G, CI}, {CO}, true);
 | 
							setup_type("$lcu", {P, G, CI}, {CO}, true);
 | 
				
			||||||
		setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
 | 
							setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
 | 
				
			||||||
		setup_type("$fa", {A, B, C}, {X, Y}, true);
 | 
							setup_type("$fa", {A, B, C}, {X, Y}, true);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		setup_type("$tribuf", {A, EN}, {Y}, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
					 | 
				
			||||||
		setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
					 | 
				
			||||||
		setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
					 | 
				
			||||||
		setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
					 | 
				
			||||||
		setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
 | 
					 | 
				
			||||||
		setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
 | 
					 | 
				
			||||||
		setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
					 | 
				
			||||||
		setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
					 | 
				
			||||||
		setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
 | 
					 | 
				
			||||||
		setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
 | 
					 | 
				
			||||||
		setup_type("$equiv", {A, B}, {Y}, true);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setup_internals_mem()
 | 
						void setup_internals_mem()
 | 
				
			||||||
| 
						 | 
					@ -153,6 +160,15 @@ struct CellTypes
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setup_stdcells()
 | 
						void setup_stdcells()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							setup_stdcells_eval();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IdString A = "\\A", E = "\\E", Y = "\\Y";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							setup_type("$_TBUF_", {A, E}, {Y}, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setup_stdcells_eval()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
 | 
							IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
 | 
				
			||||||
		IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
 | 
							IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
 | 
				
			||||||
| 
						 | 
					@ -179,7 +195,6 @@ struct CellTypes
 | 
				
			||||||
		setup_type("$_OAI3_", {A, B, C}, {Y}, true);
 | 
							setup_type("$_OAI3_", {A, B, C}, {Y}, true);
 | 
				
			||||||
		setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
 | 
							setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
 | 
				
			||||||
		setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
 | 
							setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
 | 
				
			||||||
		setup_type("$_TBUF_", {A, E}, {Y}, true);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setup_stdcells_mem()
 | 
						void setup_stdcells_mem()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -179,6 +179,7 @@ int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::string frontend_command = "auto";
 | 
						std::string frontend_command = "auto";
 | 
				
			||||||
	std::string backend_command = "auto";
 | 
						std::string backend_command = "auto";
 | 
				
			||||||
 | 
						std::vector<std::string> vlog_defines;
 | 
				
			||||||
	std::vector<std::string> passes_commands;
 | 
						std::vector<std::string> passes_commands;
 | 
				
			||||||
	std::vector<std::string> plugin_filenames;
 | 
						std::vector<std::string> plugin_filenames;
 | 
				
			||||||
	std::string output_filename = "";
 | 
						std::string output_filename = "";
 | 
				
			||||||
| 
						 | 
					@ -268,7 +269,10 @@ int main(int argc, char **argv)
 | 
				
			||||||
		printf("    -A\n");
 | 
							printf("    -A\n");
 | 
				
			||||||
		printf("        will call abort() at the end of the script. for debugging\n");
 | 
							printf("        will call abort() at the end of the script. for debugging\n");
 | 
				
			||||||
		printf("\n");
 | 
							printf("\n");
 | 
				
			||||||
		printf("    -D <header_id>[:<filename>]\n");
 | 
							printf("    -D <macro>[=<value>]\n");
 | 
				
			||||||
 | 
							printf("        set the specified Verilog define (via \"read -define\")\n");
 | 
				
			||||||
 | 
							printf("\n");
 | 
				
			||||||
 | 
							printf("    -P <header_id>[:<filename>]\n");
 | 
				
			||||||
		printf("        dump the design when printing the specified log header to a file.\n");
 | 
							printf("        dump the design when printing the specified log header to a file.\n");
 | 
				
			||||||
		printf("        yosys_dump_<header_id>.il is used as filename if none is specified.\n");
 | 
							printf("        yosys_dump_<header_id>.il is used as filename if none is specified.\n");
 | 
				
			||||||
		printf("        Use 'ALL' as <header_id> to dump at every header.\n");
 | 
							printf("        Use 'ALL' as <header_id> to dump at every header.\n");
 | 
				
			||||||
| 
						 | 
					@ -307,7 +311,7 @@ int main(int argc, char **argv)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int opt;
 | 
						int opt;
 | 
				
			||||||
	while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
 | 
						while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		switch (opt)
 | 
							switch (opt)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -408,6 +412,9 @@ int main(int argc, char **argv)
 | 
				
			||||||
					std::regex_constants::egrep));
 | 
										std::regex_constants::egrep));
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'D':
 | 
							case 'D':
 | 
				
			||||||
 | 
								vlog_defines.push_back(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'P':
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				auto args = split_tokens(optarg, ":");
 | 
									auto args = split_tokens(optarg, ":");
 | 
				
			||||||
				if (!args.empty() && args[0] == "ALL") {
 | 
									if (!args.empty() && args[0] == "ALL") {
 | 
				
			||||||
| 
						 | 
					@ -473,6 +480,13 @@ int main(int argc, char **argv)
 | 
				
			||||||
		shell(yosys_design);
 | 
							shell(yosys_design);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!vlog_defines.empty()) {
 | 
				
			||||||
 | 
							std::string vdef_cmd = "read -define";
 | 
				
			||||||
 | 
							for (auto vdef : vlog_defines)
 | 
				
			||||||
 | 
								vdef_cmd += " " + vdef;
 | 
				
			||||||
 | 
							run_pass(vdef_cmd);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (optind < argc)
 | 
						while (optind < argc)
 | 
				
			||||||
		run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
 | 
							run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -557,9 +557,11 @@ public:
 | 
				
			||||||
	void clear() { hashtable.clear(); entries.clear(); }
 | 
						void clear() { hashtable.clear(); entries.clear(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterator begin() { return iterator(this, int(entries.size())-1); }
 | 
						iterator begin() { return iterator(this, int(entries.size())-1); }
 | 
				
			||||||
 | 
						iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
 | 
				
			||||||
	iterator end() { return iterator(nullptr, -1); }
 | 
						iterator end() { return iterator(nullptr, -1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
 | 
						const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
 | 
				
			||||||
 | 
						const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
 | 
				
			||||||
	const_iterator end() const { return const_iterator(nullptr, -1); }
 | 
						const_iterator end() const { return const_iterator(nullptr, -1); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -881,9 +883,11 @@ public:
 | 
				
			||||||
	void clear() { hashtable.clear(); entries.clear(); }
 | 
						void clear() { hashtable.clear(); entries.clear(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterator begin() { return iterator(this, int(entries.size())-1); }
 | 
						iterator begin() { return iterator(this, int(entries.size())-1); }
 | 
				
			||||||
 | 
						iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
 | 
				
			||||||
	iterator end() { return iterator(nullptr, -1); }
 | 
						iterator end() { return iterator(nullptr, -1); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
 | 
						const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
 | 
				
			||||||
 | 
						const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
 | 
				
			||||||
	const_iterator end() const { return const_iterator(nullptr, -1); }
 | 
						const_iterator end() const { return const_iterator(nullptr, -1); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -952,6 +956,7 @@ public:
 | 
				
			||||||
	void clear() { database.clear(); }
 | 
						void clear() { database.clear(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const_iterator begin() const { return database.begin(); }
 | 
						const_iterator begin() const { return database.begin(); }
 | 
				
			||||||
 | 
						const_iterator element(int n) const { return database.element(n); }
 | 
				
			||||||
	const_iterator end() const { return database.end(); }
 | 
						const_iterator end() const { return database.end(); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1051,6 +1056,7 @@ public:
 | 
				
			||||||
	void clear() { database.clear(); parents.clear(); }
 | 
						void clear() { database.clear(); parents.clear(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const_iterator begin() const { return database.begin(); }
 | 
						const_iterator begin() const { return database.begin(); }
 | 
				
			||||||
 | 
						const_iterator element(int n) const { return database.element(n); }
 | 
				
			||||||
	const_iterator end() const { return database.end(); }
 | 
						const_iterator end() const { return database.end(); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -196,7 +196,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
 | 
				
			||||||
	if (log_hdump.count(header_id) && design != nullptr)
 | 
						if (log_hdump.count(header_id) && design != nullptr)
 | 
				
			||||||
		for (auto &filename : log_hdump.at(header_id)) {
 | 
							for (auto &filename : log_hdump.at(header_id)) {
 | 
				
			||||||
			log("Dumping current design to '%s'.\n", filename.c_str());
 | 
								log("Dumping current design to '%s'.\n", filename.c_str());
 | 
				
			||||||
 | 
								if (yosys_xtrace)
 | 
				
			||||||
 | 
									IdString::xtrace_db_dump();
 | 
				
			||||||
			Pass::call(design, {"dump", "-o", filename});
 | 
								Pass::call(design, {"dump", "-o", filename});
 | 
				
			||||||
 | 
								if (yosys_xtrace)
 | 
				
			||||||
 | 
									log("#X# -- end of dump --\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pop_errfile)
 | 
						if (pop_errfile)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,8 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Pass::post_execute(Pass::pre_post_exec_state_t state)
 | 
					void Pass::post_execute(Pass::pre_post_exec_state_t state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						IdString::checkpoint();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
 | 
						int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
 | 
				
			||||||
	runtime_ns += time_ns;
 | 
						runtime_ns += time_ns;
 | 
				
			||||||
	current_pass = state.parent_pass;
 | 
						current_pass = state.parent_pass;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_;
 | 
				
			||||||
std::vector<char*> RTLIL::IdString::global_id_storage_;
 | 
					std::vector<char*> RTLIL::IdString::global_id_storage_;
 | 
				
			||||||
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
 | 
					dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
 | 
				
			||||||
std::vector<int> RTLIL::IdString::global_free_idx_list_;
 | 
					std::vector<int> RTLIL::IdString::global_free_idx_list_;
 | 
				
			||||||
 | 
					int RTLIL::IdString::last_created_idx_[8];
 | 
				
			||||||
 | 
					int RTLIL::IdString::last_created_idx_ptr_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RTLIL::Const::Const()
 | 
					RTLIL::Const::Const()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -758,7 +760,7 @@ namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void check()
 | 
							void check()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
 | 
								if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
 | 
				
			||||||
					cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
 | 
										cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2358,7 +2360,7 @@ void RTLIL::Cell::check()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 | 
					void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
 | 
						if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
 | 
				
			||||||
			type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
 | 
								type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2410,6 +2412,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
 | 
				
			||||||
	if (connections_.count("\\Y"))
 | 
						if (connections_.count("\\Y"))
 | 
				
			||||||
		parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
 | 
							parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connections_.count("\\Q"))
 | 
				
			||||||
 | 
							parameters["\\WIDTH"] = GetSize(connections_["\\Q"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	check();
 | 
						check();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,6 +76,9 @@ namespace RTLIL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct IdString
 | 
						struct IdString
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							#undef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
 | 
							#undef YOSYS_SORT_ID_FREE_LIST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// the global id string cache
 | 
							// the global id string cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static struct destruct_guard_t {
 | 
							static struct destruct_guard_t {
 | 
				
			||||||
| 
						 | 
					@ -89,9 +92,43 @@ namespace RTLIL
 | 
				
			||||||
		static dict<char*, int, hash_cstr_ops> global_id_index_;
 | 
							static dict<char*, int, hash_cstr_ops> global_id_index_;
 | 
				
			||||||
		static std::vector<int> global_free_idx_list_;
 | 
							static std::vector<int> global_free_idx_list_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static int last_created_idx_ptr_;
 | 
				
			||||||
 | 
							static int last_created_idx_[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static inline void xtrace_db_dump()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
 | 
								for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (global_id_storage_.at(idx) == nullptr)
 | 
				
			||||||
 | 
										log("#X# DB-DUMP index %d: FREE\n", idx);
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static inline void checkpoint()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								last_created_idx_ptr_ = 0;
 | 
				
			||||||
 | 
								for (int i = 0; i < 8; i++) {
 | 
				
			||||||
 | 
									if (last_created_idx_[i])
 | 
				
			||||||
 | 
										put_reference(last_created_idx_[i]);
 | 
				
			||||||
 | 
									last_created_idx_[i] = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#ifdef YOSYS_SORT_ID_FREE_LIST
 | 
				
			||||||
 | 
								std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static inline int get_reference(int idx)
 | 
							static inline int get_reference(int idx)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			global_refcount_storage_.at(idx)++;
 | 
								global_refcount_storage_.at(idx)++;
 | 
				
			||||||
 | 
							#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
 | 
								if (yosys_xtrace) {
 | 
				
			||||||
 | 
									log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
			return idx;
 | 
								return idx;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,6 +144,11 @@ namespace RTLIL
 | 
				
			||||||
			auto it = global_id_index_.find((char*)p);
 | 
								auto it = global_id_index_.find((char*)p);
 | 
				
			||||||
			if (it != global_id_index_.end()) {
 | 
								if (it != global_id_index_.end()) {
 | 
				
			||||||
				global_refcount_storage_.at(it->second)++;
 | 
									global_refcount_storage_.at(it->second)++;
 | 
				
			||||||
 | 
							#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
 | 
									if (yosys_xtrace) {
 | 
				
			||||||
 | 
										log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
				return it->second;
 | 
									return it->second;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,16 +166,22 @@ namespace RTLIL
 | 
				
			||||||
			global_refcount_storage_.at(idx)++;
 | 
								global_refcount_storage_.at(idx)++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Avoid Create->Delete->Create pattern
 | 
								// Avoid Create->Delete->Create pattern
 | 
				
			||||||
			static IdString last_created_id;
 | 
								if (last_created_idx_[last_created_idx_ptr_])
 | 
				
			||||||
			put_reference(last_created_id.index_);
 | 
									put_reference(last_created_idx_[last_created_idx_ptr_]);
 | 
				
			||||||
			last_created_id.index_ = idx;
 | 
								last_created_idx_[last_created_idx_ptr_] = idx;
 | 
				
			||||||
			get_reference(last_created_id.index_);
 | 
								get_reference(last_created_idx_[last_created_idx_ptr_]);
 | 
				
			||||||
 | 
								last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (yosys_xtrace) {
 | 
								if (yosys_xtrace) {
 | 
				
			||||||
				log("#X# New IdString '%s' with index %d.\n", p, idx);
 | 
									log("#X# New IdString '%s' with index %d.\n", p, idx);
 | 
				
			||||||
				log_backtrace("-X- ", yosys_xtrace-1);
 | 
									log_backtrace("-X- ", yosys_xtrace-1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
 | 
								if (yosys_xtrace) {
 | 
				
			||||||
 | 
									log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
			return idx;
 | 
								return idx;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,6 +192,12 @@ namespace RTLIL
 | 
				
			||||||
			if (!destruct_guard.ok)
 | 
								if (!destruct_guard.ok)
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
 | 
								if (yosys_xtrace) {
 | 
				
			||||||
 | 
									log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			log_assert(global_refcount_storage_.at(idx) > 0);
 | 
								log_assert(global_refcount_storage_.at(idx) > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (--global_refcount_storage_.at(idx) != 0)
 | 
								if (--global_refcount_storage_.at(idx) != 0)
 | 
				
			||||||
| 
						 | 
					@ -1282,7 +1336,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
 | 
				
			||||||
		return wire ? (offset < other.offset) : (data < other.data);
 | 
							return wire ? (offset < other.offset) : (data < other.data);
 | 
				
			||||||
	if (wire != nullptr && other.wire != nullptr)
 | 
						if (wire != nullptr && other.wire != nullptr)
 | 
				
			||||||
		return wire->name < other.wire->name;
 | 
							return wire->name < other.wire->name;
 | 
				
			||||||
	return wire < other.wire;
 | 
						return (wire != nullptr) < (other.wire != nullptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
 | 
					inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@
 | 
				
			||||||
#  include <dlfcn.h>
 | 
					#  include <dlfcn.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#if defined(_WIN32)
 | 
				
			||||||
#  include <windows.h>
 | 
					#  include <windows.h>
 | 
				
			||||||
#  include <io.h>
 | 
					#  include <io.h>
 | 
				
			||||||
#elif defined(__APPLE__)
 | 
					#elif defined(__APPLE__)
 | 
				
			||||||
| 
						 | 
					@ -41,13 +41,15 @@
 | 
				
			||||||
#  include <unistd.h>
 | 
					#  include <unistd.h>
 | 
				
			||||||
#  include <dirent.h>
 | 
					#  include <dirent.h>
 | 
				
			||||||
#  include <sys/stat.h>
 | 
					#  include <sys/stat.h>
 | 
				
			||||||
#  include <glob.h>
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#  include <unistd.h>
 | 
					#  include <unistd.h>
 | 
				
			||||||
#  include <dirent.h>
 | 
					#  include <dirent.h>
 | 
				
			||||||
#  include <sys/types.h>
 | 
					#  include <sys/types.h>
 | 
				
			||||||
#  include <sys/wait.h>
 | 
					#  include <sys/wait.h>
 | 
				
			||||||
#  include <sys/stat.h>
 | 
					#  include <sys/stat.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
 | 
				
			||||||
#  include <glob.h>
 | 
					#  include <glob.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,12 +218,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
 | 
						if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
 | 
				
			||||||
		string sep_string = sep;
 | 
							string sep_string = sep;
 | 
				
			||||||
		for (size_t i = pos_begin+1; i < text.size(); i++)
 | 
							for (size_t i = pos_begin+1; i < text.size(); i++) {
 | 
				
			||||||
			if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
 | 
								if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
 | 
				
			||||||
				std::string token = text.substr(pos_begin, i-pos_begin+1);
 | 
									std::string token = text.substr(pos_begin, i-pos_begin+1);
 | 
				
			||||||
				text = text.substr(i+1);
 | 
									text = text.substr(i+1);
 | 
				
			||||||
				return token;
 | 
									return token;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
 | 
				
			||||||
 | 
									std::string token = text.substr(pos_begin, i-pos_begin+1);
 | 
				
			||||||
 | 
									text = text.substr(i+2);
 | 
				
			||||||
 | 
									return token + ";";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t pos_end = text.find_first_of(sep, pos_begin);
 | 
						size_t pos_end = text.find_first_of(sep, pos_begin);
 | 
				
			||||||
| 
						 | 
					@ -564,7 +572,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::vector<std::string> results;
 | 
						std::vector<std::string> results;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
 | 
				
			||||||
	results.push_back(filename_pattern);
 | 
						results.push_back(filename_pattern);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	glob_t globbuf;
 | 
						glob_t globbuf;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										358
									
								
								misc/launcher.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								misc/launcher.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,358 @@
 | 
				
			||||||
 | 
					/* This file comes from the PyPA Setuptools repository, commit 16e452a:
 | 
				
			||||||
 | 
					https://github.com/pypa/setuptools
 | 
				
			||||||
 | 
					Modifications include this comment and inline inclusion of the LICENSE text. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
				
			||||||
 | 
					this software and associated documentation files (the "Software"), to deal in
 | 
				
			||||||
 | 
					the Software without restriction, including without limitation the rights to
 | 
				
			||||||
 | 
					use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
				
			||||||
 | 
					of the Software, and to permit persons to whom the Software is furnished to do
 | 
				
			||||||
 | 
					so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*  Setuptools Script Launcher for Windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This is a stub executable for Windows that functions somewhat like
 | 
				
			||||||
 | 
					    Effbot's "exemaker", in that it runs a script with the same name but
 | 
				
			||||||
 | 
					    a .py extension, using information from a #! line.  It differs in that
 | 
				
			||||||
 | 
					    it spawns the actual Python executable, rather than attempting to
 | 
				
			||||||
 | 
					    hook into the Python DLL.  This means that the script will run with
 | 
				
			||||||
 | 
					    sys.executable set to the Python executable, where exemaker ends up with
 | 
				
			||||||
 | 
					    sys.executable pointing to itself.  (Which means it won't work if you try
 | 
				
			||||||
 | 
					    to run another Python process using sys.executable.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    To build/rebuild with mingw32, do this in the setuptools project directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       gcc -DGUI=0           -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
 | 
				
			||||||
 | 
					       gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    To build for Windows RT, install both Visual Studio Express for Windows 8
 | 
				
			||||||
 | 
					    and for Windows Desktop (both freeware), create "win32" application using
 | 
				
			||||||
 | 
					    "Windows Desktop" version, create new "ARM" target via
 | 
				
			||||||
 | 
					    "Configuration Manager" menu and modify ".vcxproj" file by adding
 | 
				
			||||||
 | 
					    "<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
 | 
				
			||||||
 | 
					    as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
 | 
				
			||||||
 | 
					    properties.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
 | 
				
			||||||
 | 
					    actually run Python in the same process.  Note that using 'exec' instead
 | 
				
			||||||
 | 
					    of 'spawn' doesn't work, because on Windows this leads to the Python
 | 
				
			||||||
 | 
					    executable running in the *background*, attached to the same console
 | 
				
			||||||
 | 
					    window, meaning you get a command prompt back *before* Python even finishes
 | 
				
			||||||
 | 
					    starting.  So, we have to use spawnv() and wait for Python to exit before
 | 
				
			||||||
 | 
					    continuing.  :(
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <windows.h>
 | 
				
			||||||
 | 
					#include <tchar.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int child_pid=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int fail(char *format, char *data) {
 | 
				
			||||||
 | 
					    /* Print error message to stderr and return 2 */
 | 
				
			||||||
 | 
					    fprintf(stderr, format, data);
 | 
				
			||||||
 | 
					    return 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *quoted(char *data) {
 | 
				
			||||||
 | 
					    int i, ln = strlen(data), nb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* We allocate twice as much space as needed to deal with worse-case
 | 
				
			||||||
 | 
					       of having to escape everything. */
 | 
				
			||||||
 | 
					    char *result = calloc(ln*2+3, sizeof(char));
 | 
				
			||||||
 | 
					    char *presult = result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *presult++ = '"';
 | 
				
			||||||
 | 
					    for (nb=0, i=0; i < ln; i++)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        if (data[i] == '\\')
 | 
				
			||||||
 | 
					          nb += 1;
 | 
				
			||||||
 | 
					        else if (data[i] == '"')
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            for (; nb > 0; nb--)
 | 
				
			||||||
 | 
					              *presult++ = '\\';
 | 
				
			||||||
 | 
					            *presult++ = '\\';
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          nb = 0;
 | 
				
			||||||
 | 
					        *presult++ = data[i];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (; nb > 0; nb--)        /* Deal w trailing slashes */
 | 
				
			||||||
 | 
					      *presult++ = '\\';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *presult++ = '"';
 | 
				
			||||||
 | 
					    *presult++ = 0;
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *loadable_exe(char *exename) {
 | 
				
			||||||
 | 
					    /* HINSTANCE hPython;  DLL handle for python executable */
 | 
				
			||||||
 | 
					    char *result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
 | 
				
			||||||
 | 
					    if (!hPython) return NULL; */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Return the absolute filename for spawnv */
 | 
				
			||||||
 | 
					    result = calloc(MAX_PATH, sizeof(char));
 | 
				
			||||||
 | 
					    strncpy(result, exename, MAX_PATH);
 | 
				
			||||||
 | 
					    /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreeLibrary(hPython); */
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *find_exe(char *exename, char *script) {
 | 
				
			||||||
 | 
					    char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
 | 
				
			||||||
 | 
					    char path[_MAX_PATH], c, *result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* convert slashes to backslashes for uniform search below */
 | 
				
			||||||
 | 
					    result = exename;
 | 
				
			||||||
 | 
					    while (c = *result++) if (c=='/') result[-1] = '\\';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _splitpath(exename, drive, dir, fname, ext);
 | 
				
			||||||
 | 
					    if (drive[0] || dir[0]=='\\') {
 | 
				
			||||||
 | 
					        return loadable_exe(exename);   /* absolute path, use directly */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* Use the script's parent directory, which should be the Python home
 | 
				
			||||||
 | 
					       (This should only be used for bdist_wininst-installed scripts, because
 | 
				
			||||||
 | 
					        easy_install-ed scripts use the absolute path to python[w].exe
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    _splitpath(script, drive, dir, fname, ext);
 | 
				
			||||||
 | 
					    result = dir + strlen(dir) -1;
 | 
				
			||||||
 | 
					    if (*result == '\\') result--;
 | 
				
			||||||
 | 
					    while (*result != '\\' && result>=dir) *result-- = 0;
 | 
				
			||||||
 | 
					    _makepath(path, drive, dir, exename, NULL);
 | 
				
			||||||
 | 
					    return loadable_exe(path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char **parse_argv(char *cmdline, int *argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* Parse a command line in-place using MS C rules */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char **result = calloc(strlen(cmdline), sizeof(char *));
 | 
				
			||||||
 | 
					    char *output = cmdline;
 | 
				
			||||||
 | 
					    char c;
 | 
				
			||||||
 | 
					    int nb = 0;
 | 
				
			||||||
 | 
					    int iq = 0;
 | 
				
			||||||
 | 
					    *argc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    result[0] = output;
 | 
				
			||||||
 | 
					    while (isspace(*cmdline)) cmdline++;   /* skip leading spaces */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        c = *cmdline++;
 | 
				
			||||||
 | 
					        if (!c || (isspace(c) && !iq)) {
 | 
				
			||||||
 | 
					            while (nb) {*output++ = '\\'; nb--; }
 | 
				
			||||||
 | 
					            *output++ = 0;
 | 
				
			||||||
 | 
					            result[++*argc] = output;
 | 
				
			||||||
 | 
					            if (!c) return result;
 | 
				
			||||||
 | 
					            while (isspace(*cmdline)) cmdline++;  /* skip leading spaces */
 | 
				
			||||||
 | 
					            if (!*cmdline) return result;  /* avoid empty arg if trailing ws */
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (c == '\\')
 | 
				
			||||||
 | 
					            ++nb;   /* count \'s */
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            if (c == '"') {
 | 
				
			||||||
 | 
					                if (!(nb & 1)) { iq = !iq; c = 0; }  /* skip " unless odd # of \ */
 | 
				
			||||||
 | 
					                nb = nb >> 1;   /* cut \'s in half */
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            while (nb) {*output++ = '\\'; nb--; }
 | 
				
			||||||
 | 
					            if (c) *output++ = c;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } while (1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pass_control_to_child(DWORD control_type) {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * distribute-issue207
 | 
				
			||||||
 | 
					     * passes the control event to child process (Python)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (!child_pid) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    GenerateConsoleCtrlEvent(child_pid,0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOL control_handler(DWORD control_type) {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * distribute-issue207
 | 
				
			||||||
 | 
					     * control event handler callback function
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    switch (control_type) {
 | 
				
			||||||
 | 
					        case CTRL_C_EVENT:
 | 
				
			||||||
 | 
					            pass_control_to_child(0);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int create_and_wait_for_subprocess(char* command) {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * distribute-issue207
 | 
				
			||||||
 | 
					     * launches child process (Python)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    DWORD return_value = 0;
 | 
				
			||||||
 | 
					    LPSTR commandline = command;
 | 
				
			||||||
 | 
					    STARTUPINFOA s_info;
 | 
				
			||||||
 | 
					    PROCESS_INFORMATION p_info;
 | 
				
			||||||
 | 
					    ZeroMemory(&p_info, sizeof(p_info));
 | 
				
			||||||
 | 
					    ZeroMemory(&s_info, sizeof(s_info));
 | 
				
			||||||
 | 
					    s_info.cb = sizeof(STARTUPINFO);
 | 
				
			||||||
 | 
					    // set-up control handler callback funciotn
 | 
				
			||||||
 | 
					    SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
 | 
				
			||||||
 | 
					    if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "failed to create process.\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    child_pid = p_info.dwProcessId;
 | 
				
			||||||
 | 
					    // wait for Python to exit
 | 
				
			||||||
 | 
					    WaitForSingleObject(p_info.hProcess, INFINITE);
 | 
				
			||||||
 | 
					    if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "failed to get exit code from process.\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return return_value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char* join_executable_and_args(char *executable, char **args, int argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * distribute-issue207
 | 
				
			||||||
 | 
					     * CreateProcess needs a long string of the executable and command-line arguments,
 | 
				
			||||||
 | 
					     * so we need to convert it from the args that was built
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    int len,counter;
 | 
				
			||||||
 | 
					    char* cmdline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    len=strlen(executable)+2;
 | 
				
			||||||
 | 
					    for (counter=1; counter<argc; counter++) {
 | 
				
			||||||
 | 
					        len+=strlen(args[counter])+1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmdline = (char*)calloc(len, sizeof(char));
 | 
				
			||||||
 | 
					    sprintf(cmdline, "%s", executable);
 | 
				
			||||||
 | 
					    len=strlen(executable);
 | 
				
			||||||
 | 
					    for (counter=1; counter<argc; counter++) {
 | 
				
			||||||
 | 
					        sprintf(cmdline+len, " %s", args[counter]);
 | 
				
			||||||
 | 
					        len+=strlen(args[counter])+1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return cmdline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int run(int argc, char **argv, int is_gui) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char python[256];   /* python executable's filename*/
 | 
				
			||||||
 | 
					    char *pyopt;        /* Python option */
 | 
				
			||||||
 | 
					    char script[256];   /* the script's filename */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int scriptf;        /* file descriptor for script file */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char **newargs, **newargsp, **parsedargs; /* argument array for exec */
 | 
				
			||||||
 | 
					    char *ptr, *end;    /* working pointers for string manipulation */
 | 
				
			||||||
 | 
					    char *cmdline;
 | 
				
			||||||
 | 
					    int i, parsedargc;              /* loop counter */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* compute script name from our .exe name*/
 | 
				
			||||||
 | 
					    GetModuleFileNameA(NULL, script, sizeof(script));
 | 
				
			||||||
 | 
					    end = script + strlen(script);
 | 
				
			||||||
 | 
					    while( end>script && *end != '.')
 | 
				
			||||||
 | 
					        *end-- = '\0';
 | 
				
			||||||
 | 
					    *end-- = '\0';
 | 
				
			||||||
 | 
					    strcat(script, (GUI ? "-script.pyw" : "-script.py"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* figure out the target python executable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    scriptf = open(script, O_RDONLY);
 | 
				
			||||||
 | 
					    if (scriptf == -1) {
 | 
				
			||||||
 | 
					        return fail("Cannot open %s\n", script);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    end = python + read(scriptf, python, sizeof(python));
 | 
				
			||||||
 | 
					    close(scriptf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr = python-1;
 | 
				
			||||||
 | 
					    while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *ptr-- = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strncmp(python, "#!", 2)) {
 | 
				
			||||||
 | 
					        /* default to python.exe if no #! header */
 | 
				
			||||||
 | 
					        strcpy(python, "#!python.exe");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parsedargs = parse_argv(python+2, &parsedargc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Using spawnv() can fail strangely if you e.g. find the Cygwin
 | 
				
			||||||
 | 
					       Python, so we'll make sure Windows can find and load it */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr = find_exe(parsedargs[0], script);
 | 
				
			||||||
 | 
					    if (!ptr) {
 | 
				
			||||||
 | 
					        return fail("Cannot find Python executable %s\n", parsedargs[0]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* printf("Python executable: %s\n", ptr); */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Argument array needs to be
 | 
				
			||||||
 | 
					       parsedargc + argc, plus 1 for null sentinel */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
 | 
				
			||||||
 | 
					    newargsp = newargs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *newargsp++ = quoted(ptr);
 | 
				
			||||||
 | 
					    for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *newargsp++ = quoted(script);
 | 
				
			||||||
 | 
					    for (i = 1; i < argc; i++)     *newargsp++ = quoted(argv[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *newargsp++ = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (is_gui) {
 | 
				
			||||||
 | 
					        /* Use exec, we don't need to wait for the GUI to finish */
 | 
				
			||||||
 | 
					        execv(ptr, (const char * const *)(newargs));
 | 
				
			||||||
 | 
					        return fail("Could not exec %s", ptr);   /* shouldn't get here! */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * distribute-issue207: using CreateProcessA instead of spawnv
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
 | 
				
			||||||
 | 
					    return create_and_wait_for_subprocess(cmdline);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
 | 
				
			||||||
 | 
					    return run(__argc, __argv, GUI);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char** argv) {
 | 
				
			||||||
 | 
					    return run(argc, argv, GUI);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,12 @@
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// yosys -- Yosys Open SYnthesis Suite
 | 
					// yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
// 
 | 
					//
 | 
				
			||||||
// Copyright (C) 2018  Serge Bazanski <q3k@symbioticeda.com>
 | 
					// Copyright (C) 2018  Serge Bazanski <q3k@symbioticeda.com>
 | 
				
			||||||
// 
 | 
					//
 | 
				
			||||||
// Permission to use, copy, modify, and/or distribute this software for any
 | 
					// Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
// purpose with or without fee is hereby granted, provided that the above
 | 
					// purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
// copyright notice and this permission notice appear in all copies.
 | 
					// copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
// 
 | 
					//
 | 
				
			||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
					// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
					// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
					// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
| 
						 | 
					@ -73,7 +73,7 @@ message Module {
 | 
				
			||||||
        BitVector bits = 2;
 | 
					        BitVector bits = 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    map<string, Port> port = 2;
 | 
					    map<string, Port> port = 2;
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    // Named cells in this module.
 | 
					    // Named cells in this module.
 | 
				
			||||||
    message Cell {
 | 
					    message Cell {
 | 
				
			||||||
        // Set to true when the name of this cell is automatically created and
 | 
					        // Set to true when the name of this cell is automatically created and
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,7 @@ message Model {
 | 
				
			||||||
            TYPE_FALSE = 6;
 | 
					            TYPE_FALSE = 6;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        Type type = 1;
 | 
					        Type type = 1;
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
        message Port {
 | 
					        message Port {
 | 
				
			||||||
            // Name of port.
 | 
					            // Name of port.
 | 
				
			||||||
            string portname = 1;
 | 
					            string portname = 1;
 | 
				
			||||||
| 
						 | 
					@ -148,7 +148,7 @@ message Model {
 | 
				
			||||||
            // Set for AND, NAND.
 | 
					            // Set for AND, NAND.
 | 
				
			||||||
            Gate gate = 3;
 | 
					            Gate gate = 3;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
        // Set when the node drives given output port(s).
 | 
					        // Set when the node drives given output port(s).
 | 
				
			||||||
        message OutPort {
 | 
					        message OutPort {
 | 
				
			||||||
            // Name of port.
 | 
					            // Name of port.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,6 +143,9 @@ struct SetundefPass : public Pass {
 | 
				
			||||||
		log("    -init\n");
 | 
							log("    -init\n");
 | 
				
			||||||
		log("        also create/update init values for flip-flops\n");
 | 
							log("        also create/update init values for flip-flops\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -params\n");
 | 
				
			||||||
 | 
							log("        replace undef in cell parameters\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -150,6 +153,7 @@ struct SetundefPass : public Pass {
 | 
				
			||||||
		bool undriven_mode = false;
 | 
							bool undriven_mode = false;
 | 
				
			||||||
		bool expose_mode = false;
 | 
							bool expose_mode = false;
 | 
				
			||||||
		bool init_mode = false;
 | 
							bool init_mode = false;
 | 
				
			||||||
 | 
							bool params_mode = false;
 | 
				
			||||||
		SetundefWorker worker;
 | 
							SetundefWorker worker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
 | 
							log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
 | 
				
			||||||
| 
						 | 
					@ -199,6 +203,10 @@ struct SetundefPass : public Pass {
 | 
				
			||||||
				init_mode = true;
 | 
									init_mode = true;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-params") {
 | 
				
			||||||
 | 
									params_mode = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
 | 
								if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
 | 
				
			||||||
				got_value = true;
 | 
									got_value = true;
 | 
				
			||||||
				worker.next_bit_mode = MODE_RANDOM;
 | 
									worker.next_bit_mode = MODE_RANDOM;
 | 
				
			||||||
| 
						 | 
					@ -228,6 +236,18 @@ struct SetundefPass : public Pass {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto module : design->selected_modules())
 | 
							for (auto module : design->selected_modules())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
								if (params_mode)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									for (auto *cell : module->selected_cells()) {
 | 
				
			||||||
 | 
										for (auto ¶meter : cell->parameters) {
 | 
				
			||||||
 | 
											for (auto &bit : parameter.second.bits) {
 | 
				
			||||||
 | 
												if (bit > RTLIL::State::S1)
 | 
				
			||||||
 | 
													bit = worker.next_bit();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (undriven_mode)
 | 
								if (undriven_mode)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (!module->processes.empty())
 | 
									if (!module->processes.empty())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,6 +140,23 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Return the "basic" type for an array item.
 | 
				
			||||||
 | 
					std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) {
 | 
				
			||||||
 | 
						std::string basicType = celltype;
 | 
				
			||||||
 | 
						if (celltype.substr(0, 7) == "$array:") {
 | 
				
			||||||
 | 
							int pos_idx = celltype.find_first_of(':');
 | 
				
			||||||
 | 
							int pos_num = celltype.find_first_of(':', pos_idx + 1);
 | 
				
			||||||
 | 
							int pos_type = celltype.find_first_of(':', pos_num + 1);
 | 
				
			||||||
 | 
							basicType = celltype.substr(pos_type + 1);
 | 
				
			||||||
 | 
							if (pos != nullptr) {
 | 
				
			||||||
 | 
								pos[0] = pos_idx;
 | 
				
			||||||
 | 
								pos[1] = pos_num;
 | 
				
			||||||
 | 
								pos[2] = pos_type;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return basicType;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
 | 
					bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool did_something = false;
 | 
						bool did_something = false;
 | 
				
			||||||
| 
						 | 
					@ -178,9 +195,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
 | 
				
			||||||
		std::vector<RTLIL::SigSpec> connections_to_add_signal;
 | 
							std::vector<RTLIL::SigSpec> connections_to_add_signal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (cell->type.substr(0, 7) == "$array:") {
 | 
							if (cell->type.substr(0, 7) == "$array:") {
 | 
				
			||||||
			int pos_idx = cell->type.str().find_first_of(':');
 | 
								int pos[3];
 | 
				
			||||||
			int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
 | 
								basic_cell_type(cell->type.str(), pos);
 | 
				
			||||||
			int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
 | 
								int pos_idx = pos[0];
 | 
				
			||||||
 | 
								int pos_num = pos[1];
 | 
				
			||||||
 | 
								int pos_type = pos[2];
 | 
				
			||||||
			int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
 | 
								int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
 | 
				
			||||||
			int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
 | 
								int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
 | 
				
			||||||
			array_cells[cell] = std::pair<int, int>(idx, num);
 | 
								array_cells[cell] = std::pair<int, int>(idx, num);
 | 
				
			||||||
| 
						 | 
					@ -439,10 +458,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
 | 
				
			||||||
	for (auto cell : mod->cells()) {
 | 
						for (auto cell : mod->cells()) {
 | 
				
			||||||
		std::string celltype = cell->type.str();
 | 
							std::string celltype = cell->type.str();
 | 
				
			||||||
		if (celltype.substr(0, 7) == "$array:") {
 | 
							if (celltype.substr(0, 7) == "$array:") {
 | 
				
			||||||
			int pos_idx = celltype.find_first_of(':');
 | 
								celltype = basic_cell_type(celltype);
 | 
				
			||||||
			int pos_num = celltype.find_first_of(':', pos_idx + 1);
 | 
					 | 
				
			||||||
			int pos_type = celltype.find_first_of(':', pos_num + 1);
 | 
					 | 
				
			||||||
			celltype = celltype.substr(pos_type + 1);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (design->module(celltype))
 | 
							if (design->module(celltype))
 | 
				
			||||||
			hierarchy_worker(design, used, design->module(celltype), indent+4);
 | 
								hierarchy_worker(design, used, design->module(celltype), indent+4);
 | 
				
			||||||
| 
						 | 
					@ -502,9 +518,19 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
 | 
				
			||||||
	if (db.count(module) == 0) {
 | 
						if (db.count(module) == 0) {
 | 
				
			||||||
		int score = 0;
 | 
							int score = 0;
 | 
				
			||||||
		db[module] = 0;
 | 
							db[module] = 0;
 | 
				
			||||||
		for (auto cell : module->cells())
 | 
							for (auto cell : module->cells()) {
 | 
				
			||||||
			if (design->module(cell->type))
 | 
								std::string celltype = cell->type.str();
 | 
				
			||||||
				score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
 | 
								// Is this an array instance
 | 
				
			||||||
 | 
								if (celltype.substr(0, 7) == "$array:") {
 | 
				
			||||||
 | 
									celltype = basic_cell_type(celltype);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Is this cell a module instance?
 | 
				
			||||||
 | 
								auto instModule = design->module(celltype);
 | 
				
			||||||
 | 
								// If there is no instance for this, issue a warning.
 | 
				
			||||||
 | 
								if (instModule != nullptr) {
 | 
				
			||||||
 | 
									score = max(score, find_top_mod_score(design, instModule, db) + 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		db[module] = score;
 | 
							db[module] = score;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return db.at(module);
 | 
						return db.at(module);
 | 
				
			||||||
| 
						 | 
					@ -884,7 +910,7 @@ struct HierarchyPass : public Pass {
 | 
				
			||||||
			if (m == nullptr)
 | 
								if (m == nullptr)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) {
 | 
								if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
 | 
				
			||||||
				IdString new_m_name = m->derive(design, cell->parameters, true);
 | 
									IdString new_m_name = m->derive(design, cell->parameters, true);
 | 
				
			||||||
				if (new_m_name.empty())
 | 
									if (new_m_name.empty())
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,6 +155,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
 | 
				
			||||||
			new_b.append_bit(it.first.second);
 | 
								new_b.append_bit(it.first.second);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
 | 
				
			||||||
 | 
								log("  Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
 | 
				
			||||||
 | 
								module->connect(new_y, new_b);
 | 
				
			||||||
 | 
								module->connect(new_conn);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
 | 
							RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		c->setPort("\\A", new_a);
 | 
							c->setPort("\\A", new_a);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,8 +174,6 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
 | 
				
			||||||
			cell->unsetParam("\\CLR_POLARITY");
 | 
								cell->unsetParam("\\CLR_POLARITY");
 | 
				
			||||||
			cell->unsetPort("\\SET");
 | 
								cell->unsetPort("\\SET");
 | 
				
			||||||
			cell->unsetPort("\\CLR");
 | 
								cell->unsetPort("\\CLR");
 | 
				
			||||||
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -186,11 +184,12 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
 | 
				
			||||||
			cell->unsetParam("\\CLR_POLARITY");
 | 
								cell->unsetParam("\\CLR_POLARITY");
 | 
				
			||||||
			cell->unsetPort("\\SET");
 | 
								cell->unsetPort("\\SET");
 | 
				
			||||||
			cell->unsetPort("\\CLR");
 | 
								cell->unsetPort("\\CLR");
 | 
				
			||||||
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
					
 | 
				
			||||||
 | 
						if (!hasreset)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		IdString new_type;
 | 
							IdString new_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,8 +206,10 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
 | 
				
			||||||
		cell->unsetPort("\\S");
 | 
							cell->unsetPort("\\S");
 | 
				
			||||||
		cell->unsetPort("\\R");
 | 
							cell->unsetPort("\\R");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return did_something;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return did_something;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
 | 
					bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,8 @@ struct WreduceConfig
 | 
				
			||||||
			"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
 | 
								"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
 | 
				
			||||||
			"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
 | 
								"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
 | 
				
			||||||
			"$add", "$sub", "$mul", // "$div", "$mod", "$pow",
 | 
								"$add", "$sub", "$mul", // "$div", "$mod", "$pow",
 | 
				
			||||||
			"$mux", "$pmux"
 | 
								"$mux", "$pmux",
 | 
				
			||||||
 | 
								"$dff", "$adff"
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -52,6 +53,7 @@ struct WreduceWorker
 | 
				
			||||||
	std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
 | 
						std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
 | 
				
			||||||
	std::set<SigBit> work_queue_bits;
 | 
						std::set<SigBit> work_queue_bits;
 | 
				
			||||||
	pool<SigBit> keep_bits;
 | 
						pool<SigBit> keep_bits;
 | 
				
			||||||
 | 
						dict<SigBit, State> init_bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WreduceWorker(WreduceConfig *config, Module *module) :
 | 
						WreduceWorker(WreduceConfig *config, Module *module) :
 | 
				
			||||||
			config(config), module(module), mi(module) { }
 | 
								config(config), module(module), mi(module) { }
 | 
				
			||||||
| 
						 | 
					@ -134,6 +136,88 @@ struct WreduceWorker
 | 
				
			||||||
		module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
 | 
							module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void run_cell_dff(Cell *cell)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Reduce size of FF if inputs are just sign/zero extended or output bit is not used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SigSpec sig_d = mi.sigmap(cell->getPort("\\D"));
 | 
				
			||||||
 | 
							SigSpec sig_q = mi.sigmap(cell->getPort("\\Q"));
 | 
				
			||||||
 | 
							Const initval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int width_before = GetSize(sig_q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (width_before == 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
 | 
				
			||||||
 | 
							bool sign_ext = !zero_ext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < GetSize(sig_q); i++) {
 | 
				
			||||||
 | 
								SigBit bit = sig_q[i];
 | 
				
			||||||
 | 
								if (init_bits.count(bit))
 | 
				
			||||||
 | 
									initval.bits.push_back(init_bits.at(bit));
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									initval.bits.push_back(State::Sx);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = GetSize(sig_q)-1; i >= 0; i--)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
 | 
				
			||||||
 | 
									module->connect(sig_q[i], State::S0);
 | 
				
			||||||
 | 
									sig_d.remove(i);
 | 
				
			||||||
 | 
									sig_q.remove(i);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
 | 
				
			||||||
 | 
									module->connect(sig_q[i], sig_q[i-1]);
 | 
				
			||||||
 | 
									sig_d.remove(i);
 | 
				
			||||||
 | 
									sig_q.remove(i);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto info = mi.query(sig_q[i]);
 | 
				
			||||||
 | 
								if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
 | 
				
			||||||
 | 
									sig_d.remove(i);
 | 
				
			||||||
 | 
									sig_q.remove(i);
 | 
				
			||||||
 | 
									zero_ext = false;
 | 
				
			||||||
 | 
									sign_ext = false;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (width_before == GetSize(sig_q))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (GetSize(sig_q) == 0) {
 | 
				
			||||||
 | 
								log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
 | 
				
			||||||
 | 
								module->remove(cell);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before,
 | 
				
			||||||
 | 
									log_id(module), log_id(cell), log_id(cell->type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto bit : sig_d)
 | 
				
			||||||
 | 
								work_queue_bits.insert(bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto bit : sig_q)
 | 
				
			||||||
 | 
								work_queue_bits.insert(bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Narrow ARST_VALUE parameter to new size.
 | 
				
			||||||
 | 
							if (cell->parameters.count("\\ARST_VALUE")) {
 | 
				
			||||||
 | 
								Const arst_value = cell->getParam("\\ARST_VALUE");
 | 
				
			||||||
 | 
								arst_value.bits.resize(GetSize(sig_q));
 | 
				
			||||||
 | 
								cell->setParam("\\ARST_VALUE", arst_value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cell->setPort("\\D", sig_d);
 | 
				
			||||||
 | 
							cell->setPort("\\Q", sig_q);
 | 
				
			||||||
 | 
							cell->fixup_parameters();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
 | 
						void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
 | 
							port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
 | 
				
			||||||
| 
						 | 
					@ -176,6 +260,9 @@ struct WreduceWorker
 | 
				
			||||||
		if (cell->type.in("$mux", "$pmux"))
 | 
							if (cell->type.in("$mux", "$pmux"))
 | 
				
			||||||
			return run_cell_mux(cell);
 | 
								return run_cell_mux(cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (cell->type.in("$dff", "$adff"))
 | 
				
			||||||
 | 
								return run_cell_dff(cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
 | 
							SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sig.has_const())
 | 
							if (sig.has_const())
 | 
				
			||||||
| 
						 | 
					@ -300,10 +387,18 @@ struct WreduceWorker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void run()
 | 
						void run()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (auto w : module->wires())
 | 
							for (auto w : module->wires()) {
 | 
				
			||||||
			if (w->get_bool_attribute("\\keep"))
 | 
								if (w->get_bool_attribute("\\keep"))
 | 
				
			||||||
				for (auto bit : mi.sigmap(w))
 | 
									for (auto bit : mi.sigmap(w))
 | 
				
			||||||
					keep_bits.insert(bit);
 | 
										keep_bits.insert(bit);
 | 
				
			||||||
 | 
								if (w->attributes.count("\\init")) {
 | 
				
			||||||
 | 
									Const initval = w->attributes.at("\\init");
 | 
				
			||||||
 | 
									SigSpec initsig = mi.sigmap(w);
 | 
				
			||||||
 | 
									int width = std::min(GetSize(initval), GetSize(initsig));
 | 
				
			||||||
 | 
									for (int i = 0; i < width; i++)
 | 
				
			||||||
 | 
										init_bits[initsig[i]] = initval[i];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto c : module->selected_cells())
 | 
							for (auto c : module->selected_cells())
 | 
				
			||||||
			work_queue_cells.insert(c);
 | 
								work_queue_cells.insert(c);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								passes/pmgen/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								passes/pmgen/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					/ice40_dsp_pm.h
 | 
				
			||||||
							
								
								
									
										8
									
								
								passes/pmgen/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								passes/pmgen/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					OBJS += passes/pmgen/ice40_dsp.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
 | 
				
			||||||
 | 
					EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
 | 
				
			||||||
 | 
					.SECONDARY: passes/pmgen/ice40_dsp_pm.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
 | 
				
			||||||
 | 
						$(P) mkdir -p passes/pmgen && python3 $^ $@
 | 
				
			||||||
							
								
								
									
										224
									
								
								passes/pmgen/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								passes/pmgen/README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,224 @@
 | 
				
			||||||
 | 
					Pattern Matcher Generator
 | 
				
			||||||
 | 
					=========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The program `pmgen.py` reads a `.pmg` (Pattern Matcher Generator) file and
 | 
				
			||||||
 | 
					writes a header-only C++ library that implements that pattern matcher.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The "patterns" in this context are subgraphs in a Yosys RTLIL netlist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The algorithm used in the generated pattern matcher is a simple recursive
 | 
				
			||||||
 | 
					search with backtracking. It is left to the author of the `.pmg` file to
 | 
				
			||||||
 | 
					determine an efficient cell order for the search that allows for maximum
 | 
				
			||||||
 | 
					use of indices and early backtracking.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					API of Generated Matcher
 | 
				
			||||||
 | 
					========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing
 | 
				
			||||||
 | 
					a class `foobar_pm`. That class is instantiated with an RTLIL module and a
 | 
				
			||||||
 | 
					list of cells from that module:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    foobar_pm pm(module, module->selected_cells());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The caller must make sure that none of the cells in the 2nd argument are
 | 
				
			||||||
 | 
					deleted for as long as the patter matcher instance is used.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					At any time it is possible to disable cells, preventing them from showing
 | 
				
			||||||
 | 
					up in any future matches:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pm.blacklist(some_cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `.run(callback_function)` method searches for all matches and calls the
 | 
				
			||||||
 | 
					callback function for each found match:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pm.run([&](){
 | 
				
			||||||
 | 
					        log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
 | 
				
			||||||
 | 
					        log("          with 'bar' cell: %s\n", log_id(pm.st.bar));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `.pmg` file declares matcher state variables that are accessible via the
 | 
				
			||||||
 | 
					`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Similarly the `.pmg` file declares user data variables that become members of
 | 
				
			||||||
 | 
					`.ud`, a struct of type `foobar_pm::udata_t`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The .pmg File Format
 | 
				
			||||||
 | 
					====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `.pmg` file format is a simple line-based file format. For the most part
 | 
				
			||||||
 | 
					lines consist of whitespace-separated tokens.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Lines in `.pmg` files starting with `//` are comments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Declaring state variables
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					One or more state variables can be declared using the `state` statement,
 | 
				
			||||||
 | 
					followed by a C++ type in angle brackets, followed by a whitespace separated
 | 
				
			||||||
 | 
					list of variable names. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state <bool> flag1 flag2 happy big
 | 
				
			||||||
 | 
					    state <SigSpec> sigA sigB sigY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					State variables are automatically managed by the generated backtracking algorithm
 | 
				
			||||||
 | 
					and saved and restored as needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					They are automatically initialized to the default constructed value of their type
 | 
				
			||||||
 | 
					when `.run(callback_function)` is called.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Declaring udata variables
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Udata (user-data) variables can be used for example to configure the matcher or
 | 
				
			||||||
 | 
					the callback function used to perform actions on found matches.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There is no automatic management of udata variables. For this reason it is
 | 
				
			||||||
 | 
					recommended that the user-supplied matcher code treats them as read-only
 | 
				
			||||||
 | 
					variables.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					They are declared like state variables, just using the `udata` statement:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    udata <int> min_data_width max_data_width
 | 
				
			||||||
 | 
					    udata <IdString> data_port_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					They are atomatically initialzed to the default constructed value of their type
 | 
				
			||||||
 | 
					when ther pattern matcher object is constructed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Embedded C++ code
 | 
				
			||||||
 | 
					-----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Many statements in a `.pmg` file contain C++ code. However, there are some
 | 
				
			||||||
 | 
					slight additions to regular C++/Yosys/RTLIL code that make it a bit easier to
 | 
				
			||||||
 | 
					write matchers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Identifiers starting with a dollar sign or backslash are automatically
 | 
				
			||||||
 | 
					  converted to special IdString variables that are initialized when the
 | 
				
			||||||
 | 
					  matcher object is constructed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The `port(<cell>, <portname>)` function is a handy alias for
 | 
				
			||||||
 | 
					  `sigmap(<cell>->getPort(<portname>))`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Similarly `param(<cell>, <paramname>)` looks up a parameter on a cell.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The function `nusers(<sigspec>)` returns the number of different cells
 | 
				
			||||||
 | 
					  connected to any of the given signal bits, plus one if any of the signal
 | 
				
			||||||
 | 
					  bits is also a primary input or primary output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- In `code..endcode` blocks there exist `accept`, `reject`, and `branch`
 | 
				
			||||||
 | 
					  statements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- In `index` statements there is a special `===` operator for the index
 | 
				
			||||||
 | 
					  lookup.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Matching cells
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cells are matched using `match..endmatch` blocks. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match mul
 | 
				
			||||||
 | 
					        if ff
 | 
				
			||||||
 | 
					        select mul->type == $mul
 | 
				
			||||||
 | 
					        select nusers(port(mul, \Y) == 2
 | 
				
			||||||
 | 
					        index <SigSpec> port(mul, \Y) === port(ff, \D)
 | 
				
			||||||
 | 
					        filter some_weird_function(mul) < other_weird_function(ff)
 | 
				
			||||||
 | 
					        optional
 | 
				
			||||||
 | 
					    endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A `match` block starts with `match <statevar>` and implicitly generates
 | 
				
			||||||
 | 
					a state variable `<statevar>` of type `RTLIL::Cell*`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All statements in the match block are optional. (An empty match block
 | 
				
			||||||
 | 
					would simply match each and every cell in the module.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `if <expression>` statement makes the match block conditional. If
 | 
				
			||||||
 | 
					`<expression>` evaluates to `false` then the match block will be ignored
 | 
				
			||||||
 | 
					and the corresponding state variable is set to `nullptr`. In our example
 | 
				
			||||||
 | 
					we only try to match the `mul` cell if the `ff` state variable points
 | 
				
			||||||
 | 
					to a cell. (Presumably `ff` is provided by a prior `match` block.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `select` lines are evaluated once for each cell when the matcher is
 | 
				
			||||||
 | 
					initialized. A `match` block will only consider cells for which all `select`
 | 
				
			||||||
 | 
					expressions evaluated to `true`. Note that the state variable corresponding to
 | 
				
			||||||
 | 
					the match (in the example `mul`) is the only state variable that may be used
 | 
				
			||||||
 | 
					in `select` lines.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Index lines are using the `index <type> expr1 === expr2` syntax.  `expr1` is
 | 
				
			||||||
 | 
					evaluated during matcher initialization and the same restrictions apply as for
 | 
				
			||||||
 | 
					`select` expressions. `expr2` is evaluated when the match is calulated. It is a
 | 
				
			||||||
 | 
					function of any state variables assigned to by previous blocks. Both expression
 | 
				
			||||||
 | 
					are converted to the given type and compared for equality. Only cells for which
 | 
				
			||||||
 | 
					all `index` statements in the block pass are considered by the match.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that `select` and `index` are fast operations. Thus `select` and `index`
 | 
				
			||||||
 | 
					should be used whenever possible to create efficient matchers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Finally, `filter <expression>` narrows down the remaining list of cells. For
 | 
				
			||||||
 | 
					performance reasons `filter` statements should only be used for things that
 | 
				
			||||||
 | 
					can't be done using `select` and `index`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `optional` statement marks optional matches. I.e. the matcher will also
 | 
				
			||||||
 | 
					explore the case where `mul` is set to `nullptr`. Without the `optional`
 | 
				
			||||||
 | 
					statement a match may only be assigned nullptr when one of the `if` expressions
 | 
				
			||||||
 | 
					evaluates to `false`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Additional code
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Interleaved with `match..endmatch` blocks there may be `code..endcode` blocks.
 | 
				
			||||||
 | 
					Such a block starts with the keyword `code` followed by a list of state variables
 | 
				
			||||||
 | 
					that the block may modify. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    code addAB sigS
 | 
				
			||||||
 | 
					        if (addA) {
 | 
				
			||||||
 | 
					            addAB = addA;
 | 
				
			||||||
 | 
					            sigS = port(addA, \B);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (addB) {
 | 
				
			||||||
 | 
					            addAB = addB;
 | 
				
			||||||
 | 
					            sigS = port(addB, \A);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The special keyword `reject` can be used to reject the current state and
 | 
				
			||||||
 | 
					backtrack. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    code
 | 
				
			||||||
 | 
					        if (ffA && ffB) {
 | 
				
			||||||
 | 
					            if (port(ffA, \CLK) != port(ffB, \CLK))
 | 
				
			||||||
 | 
					                reject;
 | 
				
			||||||
 | 
					            if (param(ffA, \CLK_POLARITY) != param(ffB, \CLK_POLARITY))
 | 
				
			||||||
 | 
					                reject;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Similarly, the special keyword `accept` can be used to accept the current
 | 
				
			||||||
 | 
					state. (`accept` will not backtrack. This means it continues with the current
 | 
				
			||||||
 | 
					branch and may accept a larger match later.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The special keyword `branch` can be used to explore different cases. Note that
 | 
				
			||||||
 | 
					each code block has an implicit `branch` at the end. So most use-cases of the
 | 
				
			||||||
 | 
					`branch` keyword need to end the block with `reject` to avoid the implicit
 | 
				
			||||||
 | 
					branch at the end. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state <int> mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    code mode
 | 
				
			||||||
 | 
					        for (mode = 0; mode < 8; mode++)
 | 
				
			||||||
 | 
					            branch;
 | 
				
			||||||
 | 
					        reject;
 | 
				
			||||||
 | 
					    endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					But in some cases it is more natural to utilize the implicit branch statement:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state <IdString> portAB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    code portAB
 | 
				
			||||||
 | 
					        portAB = \A;
 | 
				
			||||||
 | 
					        branch;
 | 
				
			||||||
 | 
					        portAB = \B;
 | 
				
			||||||
 | 
					    endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There is an implicit `code..endcode` block at the end of each `.pgm` file
 | 
				
			||||||
 | 
					that just accepts everything that gets all the way there.
 | 
				
			||||||
							
								
								
									
										237
									
								
								passes/pmgen/ice40_dsp.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								passes/pmgen/ice40_dsp.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,237 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.h"
 | 
				
			||||||
 | 
					#include "kernel/sigtools.h"
 | 
				
			||||||
 | 
					#include "passes/pmgen/ice40_dsp_pm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void create_ice40_dsp(ice40_dsp_pm &pm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						log("\n");
 | 
				
			||||||
 | 
						log("ffA:   %s\n", log_id(pm.st.ffA, "--"));
 | 
				
			||||||
 | 
						log("ffB:   %s\n", log_id(pm.st.ffB, "--"));
 | 
				
			||||||
 | 
						log("mul:   %s\n", log_id(pm.st.mul, "--"));
 | 
				
			||||||
 | 
						log("ffY:   %s\n", log_id(pm.st.ffY, "--"));
 | 
				
			||||||
 | 
						log("addAB: %s\n", log_id(pm.st.addAB, "--"));
 | 
				
			||||||
 | 
						log("muxAB: %s\n", log_id(pm.st.muxAB, "--"));
 | 
				
			||||||
 | 
						log("ffS:   %s\n", log_id(pm.st.ffS, "--"));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (GetSize(pm.st.sigA) > 16) {
 | 
				
			||||||
 | 
							log("  input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (GetSize(pm.st.sigB) > 16) {
 | 
				
			||||||
 | 
							log("  input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (GetSize(pm.st.sigS) > 32) {
 | 
				
			||||||
 | 
							log("  accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (GetSize(pm.st.sigY) > 32) {
 | 
				
			||||||
 | 
							log("  output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mul_signed) {
 | 
				
			||||||
 | 
							log("  inference of signed iCE40 DSP arithmetic is currently not supported.\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log("  replacing $mul with SB_MAC16 cell.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
 | 
				
			||||||
 | 
						pm.module->swap_names(cell, pm.st.mul);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SB_MAC16 Input Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec A = pm.st.sigA;
 | 
				
			||||||
 | 
						A.extend_u0(16, mul_signed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec B = pm.st.sigB;
 | 
				
			||||||
 | 
						B.extend_u0(16, mul_signed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec CD;
 | 
				
			||||||
 | 
						if (pm.st.muxA)
 | 
				
			||||||
 | 
							CD = pm.st.muxA->getPort("\\B");
 | 
				
			||||||
 | 
						if (pm.st.muxB)
 | 
				
			||||||
 | 
							CD = pm.st.muxB->getPort("\\A");
 | 
				
			||||||
 | 
						CD.extend_u0(32, mul_signed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\A", A);
 | 
				
			||||||
 | 
						cell->setPort("\\B", B);
 | 
				
			||||||
 | 
						cell->setPort("\\C", CD.extract(0, 16));
 | 
				
			||||||
 | 
						cell->setPort("\\D", CD.extract(16, 16));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\AHOLD", State::S0);
 | 
				
			||||||
 | 
						cell->setPort("\\BHOLD", State::S0);
 | 
				
			||||||
 | 
						cell->setPort("\\CHOLD", State::S0);
 | 
				
			||||||
 | 
						cell->setPort("\\DHOLD", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\IRSTTOP", State::S0);
 | 
				
			||||||
 | 
						cell->setPort("\\IRSTBOT", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pm.st.clock_vld)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							cell->setPort("\\CLK", pm.st.clock);
 | 
				
			||||||
 | 
							cell->setPort("\\CE", State::S1);
 | 
				
			||||||
 | 
							cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log("  clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (pm.st.ffA)
 | 
				
			||||||
 | 
								log(" ffA:%s", log_id(pm.st.ffA));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (pm.st.ffB)
 | 
				
			||||||
 | 
								log(" ffB:%s", log_id(pm.st.ffB));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (pm.st.ffY)
 | 
				
			||||||
 | 
								log(" ffY:%s", log_id(pm.st.ffY));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (pm.st.ffS)
 | 
				
			||||||
 | 
								log(" ffS:%s", log_id(pm.st.ffS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							cell->setPort("\\CLK", State::S0);
 | 
				
			||||||
 | 
							cell->setPort("\\CE", State::S0);
 | 
				
			||||||
 | 
							cell->setParam("\\NEG_TRIGGER", State::S0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SB_MAC16 Cascade Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\SIGNEXTIN", State::Sx);
 | 
				
			||||||
 | 
						cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\CI", State::Sx);
 | 
				
			||||||
 | 
						cell->setPort("\\CO", pm.module->addWire(NEW_ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\ACCUMCI", State::Sx);
 | 
				
			||||||
 | 
						cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SB_MAC16 Output Interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY;
 | 
				
			||||||
 | 
						if (GetSize(O) < 32)
 | 
				
			||||||
 | 
							O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\O", O);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pm.st.addAB) {
 | 
				
			||||||
 | 
							log("  accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type));
 | 
				
			||||||
 | 
							cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
 | 
				
			||||||
 | 
							cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cell->setPort("\\ADDSUBTOP", State::S0);
 | 
				
			||||||
 | 
							cell->setPort("\\ADDSUBBOT", State::S0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\ORSTTOP", State::S0);
 | 
				
			||||||
 | 
						cell->setPort("\\ORSTBOT", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\OHOLDTOP", State::S0);
 | 
				
			||||||
 | 
						cell->setPort("\\OHOLDBOT", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec acc_reset = State::S0;
 | 
				
			||||||
 | 
						if (pm.st.muxA)
 | 
				
			||||||
 | 
							acc_reset = pm.st.muxA->getPort("\\S");
 | 
				
			||||||
 | 
						if (pm.st.muxB)
 | 
				
			||||||
 | 
							acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setPort("\\OLOADTOP", acc_reset);
 | 
				
			||||||
 | 
						cell->setPort("\\OLOADBOT", acc_reset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SB_MAC16 Remaining Parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setParam("\\C_REG", State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\D_REG", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2));
 | 
				
			||||||
 | 
						cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
 | 
				
			||||||
 | 
						cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2));
 | 
				
			||||||
 | 
						cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
 | 
				
			||||||
 | 
						cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cell->setParam("\\MODE_8x8", State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
 | 
				
			||||||
 | 
						cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pm.autoremove(pm.st.mul);
 | 
				
			||||||
 | 
						pm.autoremove(pm.st.ffY);
 | 
				
			||||||
 | 
						pm.autoremove(pm.st.ffS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Ice40DspPass : public Pass {
 | 
				
			||||||
 | 
						Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { }
 | 
				
			||||||
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    ice40_dsp [options] [selection]\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log_header(design, "Executing ICE40_DSP pass (map multipliers).\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t argidx;
 | 
				
			||||||
 | 
							for (argidx = 1; argidx < args.size(); argidx++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// if (args[argidx] == "-singleton") {
 | 
				
			||||||
 | 
								// 	singleton_mode = true;
 | 
				
			||||||
 | 
								// 	continue;
 | 
				
			||||||
 | 
								// }
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto module : design->selected_modules())
 | 
				
			||||||
 | 
								ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} Ice40DspPass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
							
								
								
									
										160
									
								
								passes/pmgen/ice40_dsp.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								passes/pmgen/ice40_dsp.pmg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,160 @@
 | 
				
			||||||
 | 
					state <SigBit> clock
 | 
				
			||||||
 | 
					state <bool> clock_pol clock_vld
 | 
				
			||||||
 | 
					state <SigSpec> sigA sigB sigY sigS
 | 
				
			||||||
 | 
					state <Cell*> addAB muxAB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match mul
 | 
				
			||||||
 | 
						select mul->type.in($mul)
 | 
				
			||||||
 | 
						select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
 | 
				
			||||||
 | 
						select GetSize(mul->getPort(\Y)) > 10
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ffA
 | 
				
			||||||
 | 
						select ffA->type.in($dff)
 | 
				
			||||||
 | 
						// select nusers(port(ffA, \Q)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(ffA, \Q) === port(mul, \A)
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code sigA clock clock_pol clock_vld
 | 
				
			||||||
 | 
						sigA = port(mul, \A);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ffA) {
 | 
				
			||||||
 | 
							sigA = port(ffA, \D);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							clock = port(ffA, \CLK).as_bit();
 | 
				
			||||||
 | 
							clock_pol = param(ffA, \CLK_POLARITY).as_bool();
 | 
				
			||||||
 | 
							clock_vld = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ffB
 | 
				
			||||||
 | 
						select ffB->type.in($dff)
 | 
				
			||||||
 | 
						// select nusers(port(ffB, \Q)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(ffB, \Q) === port(mul, \B)
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code sigB clock clock_pol clock_vld
 | 
				
			||||||
 | 
						sigB = port(mul, \B);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ffB) {
 | 
				
			||||||
 | 
							sigB = port(ffB, \D);
 | 
				
			||||||
 | 
							SigBit c = port(ffB, \CLK).as_bit();
 | 
				
			||||||
 | 
							bool cp = param(ffB, \CLK_POLARITY).as_bool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (clock_vld && (c != clock || cp != clock_pol))
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							clock = c;
 | 
				
			||||||
 | 
							clock_pol = cp;
 | 
				
			||||||
 | 
							clock_vld = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ffY
 | 
				
			||||||
 | 
						select ffY->type.in($dff)
 | 
				
			||||||
 | 
						select nusers(port(ffY, \D)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(ffY, \D) === port(mul, \Y)
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code sigY clock clock_pol clock_vld
 | 
				
			||||||
 | 
						sigY = port(mul, \Y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ffY) {
 | 
				
			||||||
 | 
							sigY = port(ffY, \Q);
 | 
				
			||||||
 | 
							SigBit c = port(ffY, \CLK).as_bit();
 | 
				
			||||||
 | 
							bool cp = param(ffY, \CLK_POLARITY).as_bool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (clock_vld && (c != clock || cp != clock_pol))
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							clock = c;
 | 
				
			||||||
 | 
							clock_pol = cp;
 | 
				
			||||||
 | 
							clock_vld = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match addA
 | 
				
			||||||
 | 
						select addA->type.in($add)
 | 
				
			||||||
 | 
						select nusers(port(addA, \A)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(addA, \A) === sigY
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match addB
 | 
				
			||||||
 | 
						if !addA
 | 
				
			||||||
 | 
						select addB->type.in($add, $sub)
 | 
				
			||||||
 | 
						select nusers(port(addB, \B)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(addB, \B) === sigY
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code addAB sigS
 | 
				
			||||||
 | 
						if (addA) {
 | 
				
			||||||
 | 
							addAB = addA;
 | 
				
			||||||
 | 
							sigS = port(addA, \B);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (addB) {
 | 
				
			||||||
 | 
							addAB = addB;
 | 
				
			||||||
 | 
							sigS = port(addB, \A);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (addAB) {
 | 
				
			||||||
 | 
							int natural_mul_width = GetSize(sigA) + GetSize(sigB);
 | 
				
			||||||
 | 
							int actual_mul_width = GetSize(sigY);
 | 
				
			||||||
 | 
							int actual_acc_width = GetSize(sigS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
							if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool()))
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match muxA
 | 
				
			||||||
 | 
						if addAB
 | 
				
			||||||
 | 
						select muxA->type.in($mux)
 | 
				
			||||||
 | 
						select nusers(port(muxA, \A)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(muxA, \A) === port(addAB, \Y)
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match muxB
 | 
				
			||||||
 | 
						if addAB
 | 
				
			||||||
 | 
						if !muxA
 | 
				
			||||||
 | 
						select muxB->type.in($mux)
 | 
				
			||||||
 | 
						select nusers(port(muxB, \B)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(muxB, \B) === port(addAB, \Y)
 | 
				
			||||||
 | 
						optional
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code muxAB
 | 
				
			||||||
 | 
						muxAB = addAB;
 | 
				
			||||||
 | 
						if (muxA)
 | 
				
			||||||
 | 
							muxAB = muxA;
 | 
				
			||||||
 | 
						if (muxB)
 | 
				
			||||||
 | 
							muxAB = muxB;
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match ffS
 | 
				
			||||||
 | 
						if muxAB
 | 
				
			||||||
 | 
						select ffS->type.in($dff)
 | 
				
			||||||
 | 
						select nusers(port(ffS, \D)) == 2
 | 
				
			||||||
 | 
						index <SigSpec> port(ffS, \D) === port(muxAB, \Y)
 | 
				
			||||||
 | 
						index <SigSpec> port(ffS, \Q) === sigS
 | 
				
			||||||
 | 
					endmatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					code clock clock_pol clock_vld
 | 
				
			||||||
 | 
						if (ffS) {
 | 
				
			||||||
 | 
							SigBit c = port(ffS, \CLK).as_bit();
 | 
				
			||||||
 | 
							bool cp = param(ffS, \CLK_POLARITY).as_bool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (clock_vld && (c != clock || cp != clock_pol))
 | 
				
			||||||
 | 
								reject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							clock = c;
 | 
				
			||||||
 | 
							clock_pol = cp;
 | 
				
			||||||
 | 
							clock_vld = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					endcode
 | 
				
			||||||
							
								
								
									
										486
									
								
								passes/pmgen/pmgen.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										486
									
								
								passes/pmgen/pmgen.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,486 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import pprint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pp = pprint.PrettyPrinter(indent=4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pmgfile = sys.argv[1]
 | 
				
			||||||
 | 
					assert pmgfile.endswith(".pmg")
 | 
				
			||||||
 | 
					prefix = pmgfile[0:-4]
 | 
				
			||||||
 | 
					prefix = prefix.split('/')[-1]
 | 
				
			||||||
 | 
					outfile = sys.argv[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					state_types = dict()
 | 
				
			||||||
 | 
					udata_types = dict()
 | 
				
			||||||
 | 
					blocks = list()
 | 
				
			||||||
 | 
					ids = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def rewrite_cpp(s):
 | 
				
			||||||
 | 
					    t = list()
 | 
				
			||||||
 | 
					    i = 0
 | 
				
			||||||
 | 
					    while i < len(s):
 | 
				
			||||||
 | 
					        if s[i] in ("'", '"') and i + 1 < len(s):
 | 
				
			||||||
 | 
					            j = i + 1
 | 
				
			||||||
 | 
					            while j + 1 < len(s) and s[j] != s[i]:
 | 
				
			||||||
 | 
					                if s[j] == '\\' and j + 1 < len(s):
 | 
				
			||||||
 | 
					                    j += 1
 | 
				
			||||||
 | 
					                j += 1
 | 
				
			||||||
 | 
					            t.append(s[i:j+1])
 | 
				
			||||||
 | 
					            i = j + 1
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if s[i] in ('$', '\\') and i + 1 < len(s):
 | 
				
			||||||
 | 
					            j = i + 1
 | 
				
			||||||
 | 
					            while True:
 | 
				
			||||||
 | 
					                if j == len(s):
 | 
				
			||||||
 | 
					                    j -= 1
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                if ord('a') <= ord(s[j]) <= ord('z'):
 | 
				
			||||||
 | 
					                    j += 1
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                if ord('A') <= ord(s[j]) <= ord('Z'):
 | 
				
			||||||
 | 
					                    j += 1
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                if ord('0') <= ord(s[j]) <= ord('9'):
 | 
				
			||||||
 | 
					                    j += 1
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                if s[j] == '_':
 | 
				
			||||||
 | 
					                    j += 1
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                j -= 1
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            n = s[i:j+1]
 | 
				
			||||||
 | 
					            i = j + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if n[0] == '$':
 | 
				
			||||||
 | 
					                v = "id_d_" + n[1:]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                v = "id_b_" + n[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if v not in ids:
 | 
				
			||||||
 | 
					                ids[v] = n
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                assert ids[v] == n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.append(v)
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if s[i] == "\t":
 | 
				
			||||||
 | 
					            t.append("  ")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            t.append(s[i])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        i += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return "".join(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					with open(pmgfile, "r") as f:
 | 
				
			||||||
 | 
					    while True:
 | 
				
			||||||
 | 
					        line = f.readline()
 | 
				
			||||||
 | 
					        if line == "": break
 | 
				
			||||||
 | 
					        line = line.strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cmd = line.split()
 | 
				
			||||||
 | 
					        if len(cmd) == 0 or cmd[0].startswith("//"): continue
 | 
				
			||||||
 | 
					        cmd = cmd[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if cmd == "state":
 | 
				
			||||||
 | 
					            m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
 | 
				
			||||||
 | 
					            assert m
 | 
				
			||||||
 | 
					            type_str = m.group(1)
 | 
				
			||||||
 | 
					            states_str = m.group(2)
 | 
				
			||||||
 | 
					            for s in re.split(r"\s+", states_str):
 | 
				
			||||||
 | 
					                assert s not in state_types
 | 
				
			||||||
 | 
					                state_types[s] = type_str
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if cmd == "udata":
 | 
				
			||||||
 | 
					            m = re.match(r"^udata\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
 | 
				
			||||||
 | 
					            assert m
 | 
				
			||||||
 | 
					            type_str = m.group(1)
 | 
				
			||||||
 | 
					            udatas_str = m.group(2)
 | 
				
			||||||
 | 
					            for s in re.split(r"\s+", udatas_str):
 | 
				
			||||||
 | 
					                assert s not in udata_types
 | 
				
			||||||
 | 
					                udata_types[s] = type_str
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if cmd == "match":
 | 
				
			||||||
 | 
					            block = dict()
 | 
				
			||||||
 | 
					            block["type"] = "match"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            line = line.split()
 | 
				
			||||||
 | 
					            assert len(line) == 2
 | 
				
			||||||
 | 
					            assert line[1] not in state_types
 | 
				
			||||||
 | 
					            block["cell"] = line[1]
 | 
				
			||||||
 | 
					            state_types[line[1]] = "Cell*";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            block["if"] = list()
 | 
				
			||||||
 | 
					            block["select"] = list()
 | 
				
			||||||
 | 
					            block["index"] = list()
 | 
				
			||||||
 | 
					            block["filter"] = list()
 | 
				
			||||||
 | 
					            block["optional"] = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while True:
 | 
				
			||||||
 | 
					                l = f.readline()
 | 
				
			||||||
 | 
					                assert l != ""
 | 
				
			||||||
 | 
					                a = l.split()
 | 
				
			||||||
 | 
					                if len(a) == 0 or a[0].startswith("//"): continue
 | 
				
			||||||
 | 
					                if a[0] == "endmatch": break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if a[0] == "if":
 | 
				
			||||||
 | 
					                    b = l.lstrip()[2:]
 | 
				
			||||||
 | 
					                    block["if"].append(rewrite_cpp(b.strip()))
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if a[0] == "select":
 | 
				
			||||||
 | 
					                    b = l.lstrip()[6:]
 | 
				
			||||||
 | 
					                    block["select"].append(rewrite_cpp(b.strip()))
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if a[0] == "index":
 | 
				
			||||||
 | 
					                    m = re.match(r"^\s*index\s+<(.*?)>\s+(.*?)\s*===\s*(.*?)\s*$", l)
 | 
				
			||||||
 | 
					                    assert m
 | 
				
			||||||
 | 
					                    block["index"].append((m.group(1), rewrite_cpp(m.group(2)), rewrite_cpp(m.group(3))))
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if a[0] == "filter":
 | 
				
			||||||
 | 
					                    b = l.lstrip()[6:]
 | 
				
			||||||
 | 
					                    block["filter"].append(rewrite_cpp(b.strip()))
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if a[0] == "optional":
 | 
				
			||||||
 | 
					                    block["optional"] = True
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                assert False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            blocks.append(block)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if cmd == "code":
 | 
				
			||||||
 | 
					            block = dict()
 | 
				
			||||||
 | 
					            block["type"] = "code"
 | 
				
			||||||
 | 
					            block["code"] = list()
 | 
				
			||||||
 | 
					            block["states"] = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for s in line.split()[1:]:
 | 
				
			||||||
 | 
					                assert s in state_types
 | 
				
			||||||
 | 
					                block["states"].add(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while True:
 | 
				
			||||||
 | 
					                l = f.readline()
 | 
				
			||||||
 | 
					                assert l != ""
 | 
				
			||||||
 | 
					                a = l.split()
 | 
				
			||||||
 | 
					                if len(a) == 0: continue
 | 
				
			||||||
 | 
					                if a[0] == "endcode": break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                block["code"].append(rewrite_cpp(l.rstrip()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            blocks.append(block)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					with open(outfile, "w") as f:
 | 
				
			||||||
 | 
					    print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("#include \"kernel/yosys.h\"", file=f)
 | 
				
			||||||
 | 
					    print("#include \"kernel/sigtools.h\"", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("YOSYS_NAMESPACE_BEGIN", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("struct {}_pm {{".format(prefix), file=f)
 | 
				
			||||||
 | 
					    print("  Module *module;", file=f)
 | 
				
			||||||
 | 
					    print("  SigMap sigmap;", file=f)
 | 
				
			||||||
 | 
					    print("  std::function<void()> on_accept;".format(prefix), file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for index in range(len(blocks)):
 | 
				
			||||||
 | 
					        block = blocks[index]
 | 
				
			||||||
 | 
					        if block["type"] == "match":
 | 
				
			||||||
 | 
					            index_types = list()
 | 
				
			||||||
 | 
					            for entry in block["index"]:
 | 
				
			||||||
 | 
					                index_types.append(entry[0])
 | 
				
			||||||
 | 
					            print("  typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f)
 | 
				
			||||||
 | 
					            print("  dict<index_{}_key_type, vector<Cell*>> index_{};".format(index, index), file=f)
 | 
				
			||||||
 | 
					    print("  dict<SigBit, pool<Cell*>> sigusers;", file=f)
 | 
				
			||||||
 | 
					    print("  pool<Cell*> blacklist_cells;", file=f)
 | 
				
			||||||
 | 
					    print("  pool<Cell*> autoremove_cells;", file=f)
 | 
				
			||||||
 | 
					    print("  bool blacklist_dirty;", file=f)
 | 
				
			||||||
 | 
					    print("  int rollback;", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  struct state_t {", file=f)
 | 
				
			||||||
 | 
					    for s, t in sorted(state_types.items()):
 | 
				
			||||||
 | 
					        print("    {} {};".format(t, s), file=f)
 | 
				
			||||||
 | 
					    print("  } st;", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  struct udata_t {", file=f)
 | 
				
			||||||
 | 
					    for s, t in sorted(udata_types.items()):
 | 
				
			||||||
 | 
					        print("    {} {};".format(t, s), file=f)
 | 
				
			||||||
 | 
					    print("  } ud;", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for v, n in sorted(ids.items()):
 | 
				
			||||||
 | 
					        if n[0] == "\\":
 | 
				
			||||||
 | 
					            print("  IdString {}{{\"\\{}\"}};".format(v, n), file=f)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print("  IdString {}{{\"{}\"}};".format(v, n), file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void add_siguser(const SigSpec &sig, Cell *cell) {", file=f)
 | 
				
			||||||
 | 
					    print("    for (auto bit : sigmap(sig)) {", file=f)
 | 
				
			||||||
 | 
					    print("      if (bit.wire == nullptr) continue;", file=f)
 | 
				
			||||||
 | 
					    print("      if (sigusers.count(bit) == 0 && bit.wire->port_id)", file=f)
 | 
				
			||||||
 | 
					    print("        sigusers[bit].insert(nullptr);", file=f)
 | 
				
			||||||
 | 
					    print("      sigusers[bit].insert(cell);", file=f)
 | 
				
			||||||
 | 
					    print("    }", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void blacklist(Cell *cell) {", file=f)
 | 
				
			||||||
 | 
					    print("    if (cell != nullptr) {", file=f)
 | 
				
			||||||
 | 
					    print("      if (blacklist_cells.insert(cell).second)", file=f)
 | 
				
			||||||
 | 
					    print("        blacklist_dirty = true;", file=f)
 | 
				
			||||||
 | 
					    print("    }", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void autoremove(Cell *cell) {", file=f)
 | 
				
			||||||
 | 
					    print("    if (cell != nullptr) {", file=f)
 | 
				
			||||||
 | 
					    print("      if (blacklist_cells.insert(cell).second)", file=f)
 | 
				
			||||||
 | 
					    print("        blacklist_dirty = true;", file=f)
 | 
				
			||||||
 | 
					    print("      autoremove_cells.insert(cell);", file=f)
 | 
				
			||||||
 | 
					    print("    }", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void check_blacklist() {", file=f)
 | 
				
			||||||
 | 
					    print("    if (!blacklist_dirty)", file=f)
 | 
				
			||||||
 | 
					    print("      return;", file=f)
 | 
				
			||||||
 | 
					    print("    blacklist_dirty = false;", file=f)
 | 
				
			||||||
 | 
					    for index in range(len(blocks)):
 | 
				
			||||||
 | 
					        block = blocks[index]
 | 
				
			||||||
 | 
					        if block["type"] == "match":
 | 
				
			||||||
 | 
					            print("    if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f)
 | 
				
			||||||
 | 
					            print("      rollback = {};".format(index+1), file=f)
 | 
				
			||||||
 | 
					            print("      return;", file=f)
 | 
				
			||||||
 | 
					            print("    }", file=f)
 | 
				
			||||||
 | 
					    print("    rollback = 0;", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  SigSpec port(Cell *cell, IdString portname) {", file=f)
 | 
				
			||||||
 | 
					    print("    return sigmap(cell->getPort(portname));", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  Const param(Cell *cell, IdString paramname) {", file=f)
 | 
				
			||||||
 | 
					    print("    return cell->getParam(paramname);", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  int nusers(const SigSpec &sig) {", file=f)
 | 
				
			||||||
 | 
					    print("    pool<Cell*> users;", file=f)
 | 
				
			||||||
 | 
					    print("    for (auto bit : sigmap(sig))", file=f)
 | 
				
			||||||
 | 
					    print("      for (auto user : sigusers[bit])", file=f)
 | 
				
			||||||
 | 
					    print("        users.insert(user);", file=f)
 | 
				
			||||||
 | 
					    print("    return GetSize(users);", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
 | 
				
			||||||
 | 
					    print("      module(module), sigmap(module) {", file=f)
 | 
				
			||||||
 | 
					    for s, t in sorted(udata_types.items()):
 | 
				
			||||||
 | 
					        if t.endswith("*"):
 | 
				
			||||||
 | 
					            print("    ud.{} = nullptr;".format(s), file=f)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print("    ud.{} = {}();".format(s, t), file=f)
 | 
				
			||||||
 | 
					    print("    for (auto cell : module->cells()) {", file=f)
 | 
				
			||||||
 | 
					    print("      for (auto &conn : cell->connections())", file=f)
 | 
				
			||||||
 | 
					    print("        add_siguser(conn.second, cell);", file=f)
 | 
				
			||||||
 | 
					    print("    }", file=f)
 | 
				
			||||||
 | 
					    print("    for (auto cell : cells) {", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for index in range(len(blocks)):
 | 
				
			||||||
 | 
					        block = blocks[index]
 | 
				
			||||||
 | 
					        if block["type"] == "match":
 | 
				
			||||||
 | 
					            print("      do {", file=f)
 | 
				
			||||||
 | 
					            print("        Cell *{} = cell;".format(block["cell"]), file=f)
 | 
				
			||||||
 | 
					            for expr in block["select"]:
 | 
				
			||||||
 | 
					                print("        if (!({})) break;".format(expr), file=f)
 | 
				
			||||||
 | 
					            print("        index_{}_key_type key;".format(index), file=f)
 | 
				
			||||||
 | 
					            for field, entry in enumerate(block["index"]):
 | 
				
			||||||
 | 
					                print("        std::get<{}>(key) = {};".format(field, entry[1]), file=f)
 | 
				
			||||||
 | 
					            print("        index_{}[key].push_back(cell);".format(index), file=f)
 | 
				
			||||||
 | 
					            print("      } while (0);", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("    }", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  ~{}_pm() {{".format(prefix), file=f)
 | 
				
			||||||
 | 
					    print("    for (auto cell : autoremove_cells)", file=f)
 | 
				
			||||||
 | 
					    print("      module->remove(cell);", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void run(std::function<void()> on_accept_f) {", file=f)
 | 
				
			||||||
 | 
					    print("    on_accept = on_accept_f;", file=f)
 | 
				
			||||||
 | 
					    print("    rollback = 0;", file=f)
 | 
				
			||||||
 | 
					    print("    blacklist_dirty = false;", file=f)
 | 
				
			||||||
 | 
					    for s, t in sorted(state_types.items()):
 | 
				
			||||||
 | 
					        if t.endswith("*"):
 | 
				
			||||||
 | 
					            print("    st.{} = nullptr;".format(s), file=f)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print("    st.{} = {}();".format(s, t), file=f)
 | 
				
			||||||
 | 
					    print("    block_0();", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f)
 | 
				
			||||||
 | 
					    print("    run([&](){on_accept_f(*this);});", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for index in range(len(blocks)):
 | 
				
			||||||
 | 
					        block = blocks[index]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print("  void block_{}() {{".format(index), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const_st = set()
 | 
				
			||||||
 | 
					        nonconst_st = set()
 | 
				
			||||||
 | 
					        restore_st = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in range(index):
 | 
				
			||||||
 | 
					            if blocks[i]["type"] == "code":
 | 
				
			||||||
 | 
					                for s in blocks[i]["states"]:
 | 
				
			||||||
 | 
					                    const_st.add(s)
 | 
				
			||||||
 | 
					            elif blocks[i]["type"] == "match":
 | 
				
			||||||
 | 
					                const_st.add(blocks[i]["cell"])
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                assert False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if block["type"] == "code":
 | 
				
			||||||
 | 
					            for s in block["states"]:
 | 
				
			||||||
 | 
					                if s in const_st:
 | 
				
			||||||
 | 
					                    const_st.remove(s)
 | 
				
			||||||
 | 
					                    restore_st.add(s)
 | 
				
			||||||
 | 
					                nonconst_st.add(s)
 | 
				
			||||||
 | 
					        elif block["type"] == "match":
 | 
				
			||||||
 | 
					            s = block["cell"]
 | 
				
			||||||
 | 
					            assert s not in const_st
 | 
				
			||||||
 | 
					            nonconst_st.add(s)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            assert False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for s in sorted(const_st):
 | 
				
			||||||
 | 
					            t = state_types[s]
 | 
				
			||||||
 | 
					            if t.endswith("*"):
 | 
				
			||||||
 | 
					                print("    {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                print("    const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for s in sorted(nonconst_st):
 | 
				
			||||||
 | 
					            t = state_types[s]
 | 
				
			||||||
 | 
					            print("    {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(restore_st):
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            for s in sorted(restore_st):
 | 
				
			||||||
 | 
					                t = state_types[s]
 | 
				
			||||||
 | 
					                print("    {} backup_{} = {};".format(t, s, s), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if block["type"] == "code":
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            print("    do {", file=f)
 | 
				
			||||||
 | 
					            print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
 | 
				
			||||||
 | 
					            print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f)
 | 
				
			||||||
 | 
					            print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for line in block["code"]:
 | 
				
			||||||
 | 
					                print("    " + line, file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            print("      block_{}();".format(index+1), file=f)
 | 
				
			||||||
 | 
					            print("#undef reject", file=f)
 | 
				
			||||||
 | 
					            print("#undef accept", file=f)
 | 
				
			||||||
 | 
					            print("#undef branch", file=f)
 | 
				
			||||||
 | 
					            print("    } while (0);", file=f)
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            print("rollback_label:", file=f)
 | 
				
			||||||
 | 
					            print("    YS_ATTRIBUTE(unused);", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if len(restore_st) or len(nonconst_st):
 | 
				
			||||||
 | 
					                print("", file=f)
 | 
				
			||||||
 | 
					                for s in sorted(restore_st):
 | 
				
			||||||
 | 
					                    t = state_types[s]
 | 
				
			||||||
 | 
					                    print("    {} = backup_{};".format(s, s), file=f)
 | 
				
			||||||
 | 
					                for s in sorted(nonconst_st):
 | 
				
			||||||
 | 
					                    if s not in restore_st:
 | 
				
			||||||
 | 
					                        t = state_types[s]
 | 
				
			||||||
 | 
					                        if t.endswith("*"):
 | 
				
			||||||
 | 
					                            print("    {} = nullptr;".format(s), file=f)
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
 | 
					                            print("    {} = {}();".format(s, t), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elif block["type"] == "match":
 | 
				
			||||||
 | 
					            assert len(restore_st) == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if len(block["if"]):
 | 
				
			||||||
 | 
					                for expr in block["if"]:
 | 
				
			||||||
 | 
					                    print("", file=f)
 | 
				
			||||||
 | 
					                    print("    if (!({})) {{".format(expr), file=f)
 | 
				
			||||||
 | 
					                    print("      {} = nullptr;".format(block["cell"]), file=f)
 | 
				
			||||||
 | 
					                    print("      block_{}();".format(index+1), file=f)
 | 
				
			||||||
 | 
					                    print("      return;", file=f)
 | 
				
			||||||
 | 
					                    print("    }", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            print("    index_{}_key_type key;".format(index), file=f)
 | 
				
			||||||
 | 
					            for field, entry in enumerate(block["index"]):
 | 
				
			||||||
 | 
					                print("    std::get<{}>(key) = {};".format(field, entry[2]), file=f)
 | 
				
			||||||
 | 
					            print("    const vector<Cell*> &cells = index_{}[key];".format(index), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            print("    for (int idx = 0; idx < GetSize(cells); idx++) {", file=f)
 | 
				
			||||||
 | 
					            print("      {} = cells[idx];".format(block["cell"]), file=f)
 | 
				
			||||||
 | 
					            print("      if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
 | 
				
			||||||
 | 
					            for expr in block["filter"]:
 | 
				
			||||||
 | 
					                print("      if (!({})) continue;".format(expr), file=f)
 | 
				
			||||||
 | 
					            print("      block_{}();".format(index+1), file=f)
 | 
				
			||||||
 | 
					            print("      if (rollback) {", file=f)
 | 
				
			||||||
 | 
					            print("        if (rollback != {}) {{".format(index+1), file=f)
 | 
				
			||||||
 | 
					            print("          {} = nullptr;".format(block["cell"]), file=f)
 | 
				
			||||||
 | 
					            print("          return;", file=f)
 | 
				
			||||||
 | 
					            print("        }", file=f)
 | 
				
			||||||
 | 
					            print("        rollback = 0;", file=f)
 | 
				
			||||||
 | 
					            print("      }", file=f)
 | 
				
			||||||
 | 
					            print("    }", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print("", file=f)
 | 
				
			||||||
 | 
					            print("    {} = nullptr;".format(block["cell"]), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if block["optional"]:
 | 
				
			||||||
 | 
					                print("    block_{}();".format(index+1), file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            assert False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print("  }", file=f)
 | 
				
			||||||
 | 
					        print("", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("  void block_{}() {{".format(len(blocks)), file=f)
 | 
				
			||||||
 | 
					    print("    on_accept();", file=f)
 | 
				
			||||||
 | 
					    print("    check_blacklist();", file=f)
 | 
				
			||||||
 | 
					    print("  }", file=f)
 | 
				
			||||||
 | 
					    print("};", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("", file=f)
 | 
				
			||||||
 | 
					    print("YOSYS_NAMESPACE_END", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pp.pprint(blocks)
 | 
				
			||||||
| 
						 | 
					@ -8,4 +8,7 @@ OBJS += passes/sat/expose.o
 | 
				
			||||||
OBJS += passes/sat/assertpmux.o
 | 
					OBJS += passes/sat/assertpmux.o
 | 
				
			||||||
OBJS += passes/sat/clk2fflogic.o
 | 
					OBJS += passes/sat/clk2fflogic.o
 | 
				
			||||||
OBJS += passes/sat/async2sync.o
 | 
					OBJS += passes/sat/async2sync.o
 | 
				
			||||||
 | 
					OBJS += passes/sat/supercover.o
 | 
				
			||||||
 | 
					OBJS += passes/sat/fmcombine.o
 | 
				
			||||||
 | 
					OBJS += passes/sat/mutate.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ struct Async2syncPass : public Pass {
 | 
				
			||||||
		log("reset value in the next cycle regardless of the data-in value at the time of\n");
 | 
							log("reset value in the next cycle regardless of the data-in value at the time of\n");
 | 
				
			||||||
		log("the clock edge.\n");
 | 
							log("the clock edge.\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
		log("Currently only $adff cells are supported by this pass.\n");
 | 
							log("Currently only $adff and $dffsr cells are supported by this pass.\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,7 @@ struct Async2syncPass : public Pass {
 | 
				
			||||||
					bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
 | 
										bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
 | 
				
			||||||
					Const arst_val = cell->parameters["\\ARST_VALUE"];
 | 
										Const arst_val = cell->parameters["\\ARST_VALUE"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					SigSpec sig_clk = cell->getPort("\\CLK");
 | 
										// SigSpec sig_clk = cell->getPort("\\CLK");
 | 
				
			||||||
					SigSpec sig_arst = cell->getPort("\\ARST");
 | 
										SigSpec sig_arst = cell->getPort("\\ARST");
 | 
				
			||||||
					SigSpec sig_d = cell->getPort("\\D");
 | 
										SigSpec sig_d = cell->getPort("\\D");
 | 
				
			||||||
					SigSpec sig_q = cell->getPort("\\Q");
 | 
										SigSpec sig_q = cell->getPort("\\Q");
 | 
				
			||||||
| 
						 | 
					@ -120,6 +120,55 @@ struct Async2syncPass : public Pass {
 | 
				
			||||||
					cell->type = "$dff";
 | 
										cell->type = "$dff";
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (cell->type.in("$dffsr"))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
 | 
				
			||||||
 | 
										bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool();
 | 
				
			||||||
 | 
										bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// SigSpec sig_clk = cell->getPort("\\CLK");
 | 
				
			||||||
 | 
										SigSpec sig_set = cell->getPort("\\SET");
 | 
				
			||||||
 | 
										SigSpec sig_clr = cell->getPort("\\CLR");
 | 
				
			||||||
 | 
										SigSpec sig_d = cell->getPort("\\D");
 | 
				
			||||||
 | 
										SigSpec sig_q = cell->getPort("\\Q");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
 | 
				
			||||||
 | 
												log_id(module), log_id(cell), log_id(cell->type),
 | 
				
			||||||
 | 
												log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Const init_val;
 | 
				
			||||||
 | 
										for (int i = 0; i < GetSize(sig_q); i++) {
 | 
				
			||||||
 | 
											SigBit bit = sigmap(sig_q[i]);
 | 
				
			||||||
 | 
											init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
 | 
				
			||||||
 | 
											del_initbits.insert(bit);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
 | 
				
			||||||
 | 
										Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
 | 
				
			||||||
 | 
										new_q->attributes["\\init"] = init_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (!set_pol)
 | 
				
			||||||
 | 
											sig_set = module->Not(NEW_ID, sig_set);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (clr_pol)
 | 
				
			||||||
 | 
											sig_clr = module->Not(NEW_ID, sig_clr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set);
 | 
				
			||||||
 | 
										module->addAnd(NEW_ID, tmp, sig_clr, new_d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										tmp = module->Or(NEW_ID, new_q, sig_set);
 | 
				
			||||||
 | 
										module->addAnd(NEW_ID, tmp, sig_clr, sig_q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										cell->setPort("\\D", new_d);
 | 
				
			||||||
 | 
										cell->setPort("\\Q", new_q);
 | 
				
			||||||
 | 
										cell->unsetPort("\\SET");
 | 
				
			||||||
 | 
										cell->unsetPort("\\CLR");
 | 
				
			||||||
 | 
										cell->unsetParam("\\SET_POLARITY");
 | 
				
			||||||
 | 
										cell->unsetParam("\\CLR_POLARITY");
 | 
				
			||||||
 | 
										cell->type = "$dff";
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (auto wire : module->wires())
 | 
								for (auto wire : module->wires())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										341
									
								
								passes/sat/fmcombine.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								passes/sat/fmcombine.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,341 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.h"
 | 
				
			||||||
 | 
					#include "kernel/sigtools.h"
 | 
				
			||||||
 | 
					#include "kernel/celltypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct opts_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool fwd = false;
 | 
				
			||||||
 | 
						bool bwd = false;
 | 
				
			||||||
 | 
						bool nop = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct FmcombineWorker
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const opts_t &opts;
 | 
				
			||||||
 | 
						Design *design;
 | 
				
			||||||
 | 
						Module *original = nullptr;
 | 
				
			||||||
 | 
						Module *module = nullptr;
 | 
				
			||||||
 | 
						IdString orig_type, combined_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) :
 | 
				
			||||||
 | 
								opts(opts), design(design), original(design->module(orig_type)),
 | 
				
			||||||
 | 
								orig_type(orig_type), combined_type("$fmcombine" + orig_type.str())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec import_sig(SigSpec sig, const string &suffix)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SigSpec newsig;
 | 
				
			||||||
 | 
							for (auto chunk : sig.chunks()) {
 | 
				
			||||||
 | 
								if (chunk.wire != nullptr)
 | 
				
			||||||
 | 
									chunk.wire = module->wire(chunk.wire->name.str() + suffix);
 | 
				
			||||||
 | 
								newsig.append(chunk);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return newsig;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void import_prim_cell(Cell *cell, const string &suffix)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
 | 
				
			||||||
 | 
							c->parameters = cell->parameters;
 | 
				
			||||||
 | 
							c->attributes = cell->attributes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &conn : cell->connections())
 | 
				
			||||||
 | 
								c->setPort(conn.first, import_sig(conn.second, suffix));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void import_hier_cell(Cell *cell)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!cell->parameters.empty())
 | 
				
			||||||
 | 
								log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FmcombineWorker sub_worker(design, cell->type, opts);
 | 
				
			||||||
 | 
							sub_worker.generate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type);
 | 
				
			||||||
 | 
							// c->parameters = cell->parameters;
 | 
				
			||||||
 | 
							c->attributes = cell->attributes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &conn : cell->connections()) {
 | 
				
			||||||
 | 
								c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold"));
 | 
				
			||||||
 | 
								c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate"));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void generate()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (design->module(combined_type)) {
 | 
				
			||||||
 | 
								// log("Combined module %s already exists.\n", log_id(combined_type));
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type));
 | 
				
			||||||
 | 
							module = design->addModule(combined_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto wire : original->wires()) {
 | 
				
			||||||
 | 
								module->addWire(wire->name.str() + "_gold", wire);
 | 
				
			||||||
 | 
								module->addWire(wire->name.str() + "_gate", wire);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							module->fixup_ports();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto cell : original->cells()) {
 | 
				
			||||||
 | 
								if (design->module(cell->type) == nullptr) {
 | 
				
			||||||
 | 
									import_prim_cell(cell, "_gold");
 | 
				
			||||||
 | 
									import_prim_cell(cell, "_gate");
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									import_hier_cell(cell);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &conn : original->connections()) {
 | 
				
			||||||
 | 
								module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold"));
 | 
				
			||||||
 | 
								module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate"));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (opts.nop)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CellTypes ct;
 | 
				
			||||||
 | 
							ct.setup_internals_eval();
 | 
				
			||||||
 | 
							ct.setup_stdcells_eval();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SigMap sigmap(module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dict<SigBit, SigBit> data_bit_to_eq_net;
 | 
				
			||||||
 | 
							dict<Cell*, SigSpec> cell_to_eq_nets;
 | 
				
			||||||
 | 
							dict<SigSpec, SigSpec> reduce_db;
 | 
				
			||||||
 | 
							dict<SigSpec, SigSpec> invert_db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto cell : original->cells())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!ct.cell_known(cell->type))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto &conn : cell->connections())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (!cell->output(conn.first))
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SigSpec A = import_sig(conn.second, "_gold");
 | 
				
			||||||
 | 
									SigSpec B = import_sig(conn.second, "_gate");
 | 
				
			||||||
 | 
									SigBit EQ = module->Eq(NEW_ID, A, B);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (auto bit : sigmap({A, B}))
 | 
				
			||||||
 | 
										data_bit_to_eq_net[bit] = EQ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									cell_to_eq_nets[cell].append(EQ);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto cell : original->cells())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!ct.cell_known(cell->type))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bool skip_cell = !cell_to_eq_nets.count(cell);
 | 
				
			||||||
 | 
								pool<SigBit> src_eq_bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto &conn : cell->connections())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (skip_cell)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (cell->output(conn.first))
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SigSpec A = import_sig(conn.second, "_gold");
 | 
				
			||||||
 | 
									SigSpec B = import_sig(conn.second, "_gate");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (auto bit : sigmap({A, B})) {
 | 
				
			||||||
 | 
										if (data_bit_to_eq_net.count(bit))
 | 
				
			||||||
 | 
											src_eq_bits.insert(data_bit_to_eq_net.at(bit));
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											skip_cell = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!skip_cell) {
 | 
				
			||||||
 | 
									SigSpec antecedent = SigSpec(src_eq_bits);
 | 
				
			||||||
 | 
									antecedent.sort_and_unify();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (GetSize(antecedent) > 1) {
 | 
				
			||||||
 | 
										if (reduce_db.count(antecedent) == 0)
 | 
				
			||||||
 | 
											reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent);
 | 
				
			||||||
 | 
										antecedent = reduce_db.at(antecedent);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SigSpec consequent = cell_to_eq_nets.at(cell);
 | 
				
			||||||
 | 
									consequent.sort_and_unify();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (GetSize(consequent) > 1) {
 | 
				
			||||||
 | 
										if (reduce_db.count(consequent) == 0)
 | 
				
			||||||
 | 
											reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent);
 | 
				
			||||||
 | 
										consequent = reduce_db.at(consequent);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (opts.fwd)
 | 
				
			||||||
 | 
										module->addAssume(NEW_ID, consequent, antecedent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (opts.bwd)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (invert_db.count(antecedent) == 0)
 | 
				
			||||||
 | 
											invert_db[antecedent] = module->Not(NEW_ID, antecedent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (invert_db.count(consequent) == 0)
 | 
				
			||||||
 | 
											invert_db[consequent] = module->Not(NEW_ID, consequent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct FmcombinePass : public Pass {
 | 
				
			||||||
 | 
						FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { }
 | 
				
			||||||
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    fmcombine [options] module_name gold_cell gate_cell\n");
 | 
				
			||||||
 | 
							// log("    fmcombine [options] @gold_cell @gate_cell\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("This pass takes two cells, which are instances of the same module, and replaces\n");
 | 
				
			||||||
 | 
							log("them with one instance of a special 'combined' module, that effectively\n");
 | 
				
			||||||
 | 
							log("contains two copies of the original module, plus some formal properties.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("This is useful for formal test benches that check what differences in behavior\n");
 | 
				
			||||||
 | 
							log("a slight difference in input causes in a module.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -fwd\n");
 | 
				
			||||||
 | 
							log("        Insert forward hint assumptions into the combined module.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -bwd\n");
 | 
				
			||||||
 | 
							log("        Insert backward hint assumptions into the combined module.\n");
 | 
				
			||||||
 | 
							log("        (Backward hints are logically equivalend to fordward hits, but\n");
 | 
				
			||||||
 | 
							log("        some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -nop\n");
 | 
				
			||||||
 | 
							log("        Don't insert hint assumptions into the combined module.\n");
 | 
				
			||||||
 | 
							log("        (This should not provide any speedup over the original design, but\n");
 | 
				
			||||||
 | 
							log("        strangely sometimes it does.)\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							opts_t opts;
 | 
				
			||||||
 | 
							Module *module = nullptr;
 | 
				
			||||||
 | 
							Cell *gold_cell = nullptr;
 | 
				
			||||||
 | 
							Cell *gate_cell = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log_header(design, "Executing FMCOMBINE pass.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t argidx;
 | 
				
			||||||
 | 
							for (argidx = 1; argidx < args.size(); argidx++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// if (args[argidx] == "-o" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
								// 	filename = args[++argidx];
 | 
				
			||||||
 | 
								// 	continue;
 | 
				
			||||||
 | 
								// }
 | 
				
			||||||
 | 
								if (args[argidx] == "-fwd") {
 | 
				
			||||||
 | 
									opts.fwd = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-bwd") {
 | 
				
			||||||
 | 
									opts.bwd = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-nop") {
 | 
				
			||||||
 | 
									opts.nop = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (argidx+2 == args.size())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								string gold_name = args[argidx++];
 | 
				
			||||||
 | 
								string gate_name = args[argidx++];
 | 
				
			||||||
 | 
								log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (argidx+3 == args.size())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								IdString module_name = RTLIL::escape_id(args[argidx++]);
 | 
				
			||||||
 | 
								IdString gold_name = RTLIL::escape_id(args[argidx++]);
 | 
				
			||||||
 | 
								IdString gate_name = RTLIL::escape_id(args[argidx++]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								module = design->module(module_name);
 | 
				
			||||||
 | 
								if (module == nullptr)
 | 
				
			||||||
 | 
									log_cmd_error("Module %s not found.\n", log_id(module_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gold_cell = module->cell(gold_name);
 | 
				
			||||||
 | 
								if (gold_cell == nullptr)
 | 
				
			||||||
 | 
									log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gate_cell = module->cell(gate_name);
 | 
				
			||||||
 | 
								if (gate_cell == nullptr)
 | 
				
			||||||
 | 
									log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								log_cmd_error("Invalid number of arguments.\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (opts.nop && (opts.fwd || opts.bwd))
 | 
				
			||||||
 | 
								log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!opts.nop && !opts.fwd && !opts.bwd)
 | 
				
			||||||
 | 
								opts.fwd = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (gold_cell->type != gate_cell->type)
 | 
				
			||||||
 | 
								log_cmd_error("Types of gold and gate cells do not match.\n");
 | 
				
			||||||
 | 
							if (!gold_cell->parameters.empty())
 | 
				
			||||||
 | 
								log_cmd_error("Gold cell has unresolved instance parameters.\n");
 | 
				
			||||||
 | 
							if (!gate_cell->parameters.empty())
 | 
				
			||||||
 | 
								log_cmd_error("Gold cell has unresolved instance parameters.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FmcombineWorker worker(design, gold_cell->type, opts);
 | 
				
			||||||
 | 
							worker.generate();
 | 
				
			||||||
 | 
							IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Cell *cell = module->addCell(combined_cell_name, worker.combined_type);
 | 
				
			||||||
 | 
							cell->attributes = gold_cell->attributes;
 | 
				
			||||||
 | 
							cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &conn : gold_cell->connections())
 | 
				
			||||||
 | 
								cell->setPort(conn.first.str() + "_gold", conn.second);
 | 
				
			||||||
 | 
							module->remove(gold_cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &conn : gate_cell->connections())
 | 
				
			||||||
 | 
								cell->setPort(conn.first.str() + "_gate", conn.second);
 | 
				
			||||||
 | 
							module->remove(gate_cell);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} FmcombinePass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
							
								
								
									
										905
									
								
								passes/sat/mutate.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										905
									
								
								passes/sat/mutate.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,905 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.h"
 | 
				
			||||||
 | 
					#include "kernel/sigtools.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mutate_t {
 | 
				
			||||||
 | 
						string mode;
 | 
				
			||||||
 | 
						pool<string> src;
 | 
				
			||||||
 | 
						IdString module, cell;
 | 
				
			||||||
 | 
						IdString port, wire;
 | 
				
			||||||
 | 
						int portbit = -1;
 | 
				
			||||||
 | 
						int ctrlbit = -1;
 | 
				
			||||||
 | 
						int wirebit = -1;
 | 
				
			||||||
 | 
						bool used = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mutate_opts_t {
 | 
				
			||||||
 | 
						int seed = 0;
 | 
				
			||||||
 | 
						std::string mode;
 | 
				
			||||||
 | 
						pool<string> src;
 | 
				
			||||||
 | 
						IdString module, cell, port, wire;
 | 
				
			||||||
 | 
						int portbit = -1;
 | 
				
			||||||
 | 
						int ctrlbit = -1;
 | 
				
			||||||
 | 
						int wirebit = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						IdString ctrl_name;
 | 
				
			||||||
 | 
						int ctrl_width = -1, ctrl_value = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int pick_cover_prcnt = 80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int weight_cover = 500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int weight_pq_w = 100;
 | 
				
			||||||
 | 
						int weight_pq_b = 100;
 | 
				
			||||||
 | 
						int weight_pq_c = 100;
 | 
				
			||||||
 | 
						int weight_pq_s = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int weight_pq_mw = 100;
 | 
				
			||||||
 | 
						int weight_pq_mb = 100;
 | 
				
			||||||
 | 
						int weight_pq_mc = 100;
 | 
				
			||||||
 | 
						int weight_pq_ms = 100;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void database_add(std::vector<mutate_t> &database, const mutate_opts_t &opts, const mutate_t &entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!opts.mode.empty() && opts.mode != entry.mode)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!opts.src.empty()) {
 | 
				
			||||||
 | 
							bool found_match = false;
 | 
				
			||||||
 | 
							for (auto &s : opts.src) {
 | 
				
			||||||
 | 
								if (entry.src.count(s))
 | 
				
			||||||
 | 
									found_match = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!found_match)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!opts.module.empty() && opts.module != entry.module)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!opts.cell.empty() && opts.cell != entry.cell)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!opts.port.empty() && opts.port != entry.port)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opts.portbit >= 0 && opts.portbit != entry.portbit)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!opts.wire.empty() && opts.wire != entry.wire)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						database.push_back(entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct xs128_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t x = 123456789;
 | 
				
			||||||
 | 
						uint32_t y = 0, z = 0, w = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xs128_t(int seed = 0) : w(seed) {
 | 
				
			||||||
 | 
							next();
 | 
				
			||||||
 | 
							next();
 | 
				
			||||||
 | 
							next();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void next() {
 | 
				
			||||||
 | 
							uint32_t t = x ^ (x << 11);
 | 
				
			||||||
 | 
							x = y, y = z, z = w;
 | 
				
			||||||
 | 
							w ^= (w >> 19) ^ t ^ (t >> 8);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int operator()() {
 | 
				
			||||||
 | 
							next();
 | 
				
			||||||
 | 
							return w & 0x3fffffff;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int operator()(int n) {
 | 
				
			||||||
 | 
							if (n < 2)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							while (1) {
 | 
				
			||||||
 | 
								int k = (*this)(), p = k % n;
 | 
				
			||||||
 | 
								if ((k - p + n) <= 0x40000000)
 | 
				
			||||||
 | 
									return p;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct coverdb_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dict<string, int> src_db;
 | 
				
			||||||
 | 
						dict<tuple<IdString, IdString>, int> wire_db;
 | 
				
			||||||
 | 
						dict<tuple<IdString, IdString, int>, int> wirebit_db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void insert(const mutate_t &m) {
 | 
				
			||||||
 | 
							if (!m.wire.empty()) {
 | 
				
			||||||
 | 
								wire_db[tuple<IdString, IdString>(m.module, m.wire)] = 0;
 | 
				
			||||||
 | 
								wirebit_db[tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)] = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto &s : m.src) {
 | 
				
			||||||
 | 
								src_db[s] = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void update(const mutate_t &m) {
 | 
				
			||||||
 | 
							if (!m.wire.empty()) {
 | 
				
			||||||
 | 
								wire_db.at(tuple<IdString, IdString>(m.module, m.wire))++;
 | 
				
			||||||
 | 
								wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit))++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto &s : m.src) {
 | 
				
			||||||
 | 
								src_db.at(s)++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int score(const mutate_t &m) {
 | 
				
			||||||
 | 
							int this_score = m.src.empty() ? 0 : 1;
 | 
				
			||||||
 | 
							if (!m.wire.empty()) {
 | 
				
			||||||
 | 
								this_score += wire_db.at(tuple<IdString, IdString>(m.module, m.wire)) ? 0 : 5;
 | 
				
			||||||
 | 
								this_score += wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)) ? 0 : 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto &s : m.src) {
 | 
				
			||||||
 | 
								this_score += src_db.at(s) ? 0 : 5;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return this_score;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mutate_queue_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pool<mutate_t*, hash_ptr_ops> db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
				
			||||||
 | 
							mutate_t *m = nullptr;
 | 
				
			||||||
 | 
							if (rng(100) < opts.pick_cover_prcnt) {
 | 
				
			||||||
 | 
								vector<mutate_t*> candidates, rmqueue;
 | 
				
			||||||
 | 
								int best_score = -1;
 | 
				
			||||||
 | 
								for (auto p : db) {
 | 
				
			||||||
 | 
									if (p->used) {
 | 
				
			||||||
 | 
										rmqueue.push_back(p);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									int this_score = coverdb.score(*p);
 | 
				
			||||||
 | 
									if (this_score > best_score) {
 | 
				
			||||||
 | 
										best_score = this_score;
 | 
				
			||||||
 | 
										candidates.clear();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (best_score == this_score)
 | 
				
			||||||
 | 
										candidates.push_back(p);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (auto p : rmqueue)
 | 
				
			||||||
 | 
									db.erase(p);
 | 
				
			||||||
 | 
								if (!candidates.empty())
 | 
				
			||||||
 | 
									m = candidates[rng(GetSize(candidates))];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (m == nullptr) {
 | 
				
			||||||
 | 
								while (!db.empty()) {
 | 
				
			||||||
 | 
									int i = rng(GetSize(db));
 | 
				
			||||||
 | 
									auto it = db.element(i);
 | 
				
			||||||
 | 
									mutate_t *p = *it;
 | 
				
			||||||
 | 
									db.erase(it);
 | 
				
			||||||
 | 
									if (p->used == false) {
 | 
				
			||||||
 | 
										m = p;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return m;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void add(mutate_t *m) {
 | 
				
			||||||
 | 
							db.insert(m);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename K, typename T>
 | 
				
			||||||
 | 
					struct mutate_chain_queue_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dict<K, T> db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
				
			||||||
 | 
							while (!db.empty()) {
 | 
				
			||||||
 | 
								int i = rng(GetSize(db));
 | 
				
			||||||
 | 
								auto it = db.element(i);
 | 
				
			||||||
 | 
								mutate_t *m = it->second.pick(rng, coverdb, opts);
 | 
				
			||||||
 | 
								if (m != nullptr)
 | 
				
			||||||
 | 
									return m;
 | 
				
			||||||
 | 
								db.erase(it);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename... Args>
 | 
				
			||||||
 | 
						void add(mutate_t *m, K key, Args... args) {
 | 
				
			||||||
 | 
							db[key].add(m, args...);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename K, typename T>
 | 
				
			||||||
 | 
					struct mutate_once_queue_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dict<K, T> db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
				
			||||||
 | 
							while (!db.empty()) {
 | 
				
			||||||
 | 
								int i = rng(GetSize(db));
 | 
				
			||||||
 | 
								auto it = db.element(i);
 | 
				
			||||||
 | 
								mutate_t *m = it->second.pick(rng, coverdb, opts);
 | 
				
			||||||
 | 
								db.erase(it);
 | 
				
			||||||
 | 
								if (m != nullptr)
 | 
				
			||||||
 | 
									return m;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename... Args>
 | 
				
			||||||
 | 
						void add(mutate_t *m, K key, Args... args) {
 | 
				
			||||||
 | 
							db[key].add(m, args...);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts, int N, xs128_t &rng)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::vector<mutate_t> new_database;
 | 
				
			||||||
 | 
						coverdb_t coverdb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s;
 | 
				
			||||||
 | 
						total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (N >= GetSize(database))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_wire;
 | 
				
			||||||
 | 
						mutate_once_queue_t<tuple<IdString, IdString, int>, mutate_queue_t> primary_queue_bit;
 | 
				
			||||||
 | 
						mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_cell;
 | 
				
			||||||
 | 
						mutate_once_queue_t<string, mutate_queue_t> primary_queue_src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_wire;
 | 
				
			||||||
 | 
						mutate_chain_queue_t<IdString, mutate_once_queue_t<pair<IdString, int>, mutate_queue_t>> primary_queue_module_bit;
 | 
				
			||||||
 | 
						mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_cell;
 | 
				
			||||||
 | 
						mutate_chain_queue_t<IdString, mutate_once_queue_t<string, mutate_queue_t>> primary_queue_module_src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &m : database)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							coverdb.insert(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!m.wire.empty()) {
 | 
				
			||||||
 | 
								primary_queue_wire.add(&m, tuple<IdString, IdString>(m.module, m.wire));
 | 
				
			||||||
 | 
								primary_queue_bit.add(&m, tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit));
 | 
				
			||||||
 | 
								primary_queue_module_wire.add(&m, m.module, m.wire);
 | 
				
			||||||
 | 
								primary_queue_module_bit.add(&m, m.module, pair<IdString, int>(m.wire, m.wirebit));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							primary_queue_cell.add(&m, tuple<IdString, IdString>(m.module, m.cell));
 | 
				
			||||||
 | 
							primary_queue_module_cell.add(&m, m.module, m.cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &s : m.src) {
 | 
				
			||||||
 | 
								primary_queue_src.add(&m, s);
 | 
				
			||||||
 | 
								primary_queue_module_src.add(&m, m.module, s);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vector<mutate_t*> cover_candidates;
 | 
				
			||||||
 | 
						int best_cover_score = -1;
 | 
				
			||||||
 | 
						bool skip_cover = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (GetSize(new_database) < N)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int k = rng(total_weight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							k -= opts.weight_cover;
 | 
				
			||||||
 | 
							if (k < 0) {
 | 
				
			||||||
 | 
								while (!skip_cover) {
 | 
				
			||||||
 | 
									if (cover_candidates.empty()) {
 | 
				
			||||||
 | 
										best_cover_score = -1;
 | 
				
			||||||
 | 
										for (auto &m : database) {
 | 
				
			||||||
 | 
											if (m.used || m.src.empty())
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											int this_score = -1;
 | 
				
			||||||
 | 
											for (auto &s : m.src) {
 | 
				
			||||||
 | 
												if (this_score == -1 || this_score > coverdb.src_db.at(s))
 | 
				
			||||||
 | 
													this_score = coverdb.src_db.at(s);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											log_assert(this_score != -1);
 | 
				
			||||||
 | 
											if (best_cover_score == -1 || this_score < best_cover_score) {
 | 
				
			||||||
 | 
												cover_candidates.clear();
 | 
				
			||||||
 | 
												best_cover_score = this_score;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if (best_cover_score == this_score)
 | 
				
			||||||
 | 
												cover_candidates.push_back(&m);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if (best_cover_score == -1) {
 | 
				
			||||||
 | 
											skip_cover = true;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									mutate_t *m = nullptr;
 | 
				
			||||||
 | 
									while (!cover_candidates.empty())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										int idx = rng(GetSize(cover_candidates));
 | 
				
			||||||
 | 
										mutate_t *p = cover_candidates[idx];
 | 
				
			||||||
 | 
										cover_candidates[idx] = cover_candidates.back();
 | 
				
			||||||
 | 
										cover_candidates.pop_back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (p->used)
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										int this_score = -1;
 | 
				
			||||||
 | 
										for (auto &s : p->src) {
 | 
				
			||||||
 | 
											if (this_score == -1 || this_score > coverdb.src_db.at(s))
 | 
				
			||||||
 | 
												this_score = coverdb.src_db.at(s);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (this_score != best_cover_score)
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										m = p;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (m != nullptr) {
 | 
				
			||||||
 | 
										m->used = true;
 | 
				
			||||||
 | 
										coverdb.update(*m);
 | 
				
			||||||
 | 
										new_database.push_back(*m);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define X(__wght, __queue)                               \
 | 
				
			||||||
 | 
					    k -= __wght;                                         \
 | 
				
			||||||
 | 
					    if (k < 0) {                                         \
 | 
				
			||||||
 | 
					      mutate_t *m = __queue.pick(rng, coverdb, opts);    \
 | 
				
			||||||
 | 
					      if (m != nullptr) {                                \
 | 
				
			||||||
 | 
					        m->used = true;                                  \
 | 
				
			||||||
 | 
					        coverdb.update(*m);                              \
 | 
				
			||||||
 | 
					        new_database.push_back(*m);                      \
 | 
				
			||||||
 | 
					      };                                                 \
 | 
				
			||||||
 | 
					      continue;                                          \
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							X(opts.weight_pq_w, primary_queue_wire)
 | 
				
			||||||
 | 
							X(opts.weight_pq_b, primary_queue_bit)
 | 
				
			||||||
 | 
							X(opts.weight_pq_c, primary_queue_cell)
 | 
				
			||||||
 | 
							X(opts.weight_pq_s, primary_queue_src)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							X(opts.weight_pq_mw, primary_queue_module_wire)
 | 
				
			||||||
 | 
							X(opts.weight_pq_mb, primary_queue_module_bit)
 | 
				
			||||||
 | 
							X(opts.weight_pq_mc, primary_queue_module_cell)
 | 
				
			||||||
 | 
							X(opts.weight_pq_ms, primary_queue_module_src)
 | 
				
			||||||
 | 
					#undef X
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::swap(new_database, database);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int covered_src_cnt = 0;
 | 
				
			||||||
 | 
						int covered_wire_cnt = 0;
 | 
				
			||||||
 | 
						int covered_wirebit_cnt = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &it : coverdb.src_db)
 | 
				
			||||||
 | 
							if (it.second)
 | 
				
			||||||
 | 
								covered_src_cnt++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &it : coverdb.wire_db)
 | 
				
			||||||
 | 
							if (it.second)
 | 
				
			||||||
 | 
								covered_wire_cnt++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &it : coverdb.wirebit_db)
 | 
				
			||||||
 | 
							if (it.second)
 | 
				
			||||||
 | 
								covered_wirebit_cnt++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db));
 | 
				
			||||||
 | 
						log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db));
 | 
				
			||||||
 | 
						log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::vector<mutate_t> database;
 | 
				
			||||||
 | 
						xs128_t rng(opts.seed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto module : design->selected_modules())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!opts.module.empty() && module->name != opts.module)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SigMap sigmap(module);
 | 
				
			||||||
 | 
							dict<SigBit, int> bit_user_cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto wire : module->wires()) {
 | 
				
			||||||
 | 
								if (wire->name[0] == '\\' && wire->attributes.count("\\src"))
 | 
				
			||||||
 | 
									sigmap.add(wire);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto cell : module->cells()) {
 | 
				
			||||||
 | 
								for (auto &conn : cell->connections()) {
 | 
				
			||||||
 | 
									if (cell->output(conn.first))
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									for (auto bit : sigmap(conn.second))
 | 
				
			||||||
 | 
										bit_user_cnt[bit]++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto wire : module->selected_wires())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								for (SigBit bit : SigSpec(wire))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									SigBit sigbit = sigmap(bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (bit.wire == nullptr || sigbit.wire == nullptr)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!bit.wire->port_id != !sigbit.wire->port_id) {
 | 
				
			||||||
 | 
										if (bit.wire->port_id)
 | 
				
			||||||
 | 
											sigmap.add(bit);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!bit.wire->name[0] != !sigbit.wire->name[0]) {
 | 
				
			||||||
 | 
										if (bit.wire->name[0] == '\\')
 | 
				
			||||||
 | 
											sigmap.add(bit);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto cell : module->selected_cells())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!opts.cell.empty() && cell->name != opts.cell)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto &conn : cell->connections())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									for (int i = 0; i < GetSize(conn.second); i++) {
 | 
				
			||||||
 | 
										mutate_t entry;
 | 
				
			||||||
 | 
										entry.module = module->name;
 | 
				
			||||||
 | 
										entry.cell = cell->name;
 | 
				
			||||||
 | 
										entry.port = conn.first;
 | 
				
			||||||
 | 
										entry.portbit = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for (auto &s : cell->get_strpool_attribute("\\src"))
 | 
				
			||||||
 | 
											entry.src.insert(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										SigBit bit = sigmap(conn.second[i]);
 | 
				
			||||||
 | 
										if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
 | 
				
			||||||
 | 
											for (auto &s : bit.wire->get_strpool_attribute("\\src"))
 | 
				
			||||||
 | 
												entry.src.insert(s);
 | 
				
			||||||
 | 
											entry.wire = bit.wire->name;
 | 
				
			||||||
 | 
											entry.wirebit = bit.offset;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										entry.mode = "inv";
 | 
				
			||||||
 | 
										database_add(database, opts, entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										entry.mode = "const0";
 | 
				
			||||||
 | 
										database_add(database, opts, entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										entry.mode = "const1";
 | 
				
			||||||
 | 
										database_add(database, opts, entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										entry.mode = "cnot0";
 | 
				
			||||||
 | 
										entry.ctrlbit = rng(GetSize(conn.second));
 | 
				
			||||||
 | 
										if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
 | 
				
			||||||
 | 
											database_add(database, opts, entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										entry.mode = "cnot1";
 | 
				
			||||||
 | 
										entry.ctrlbit = rng(GetSize(conn.second));
 | 
				
			||||||
 | 
										if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
 | 
				
			||||||
 | 
											database_add(database, opts, entry);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log("Raw database size: %d\n", GetSize(database));
 | 
				
			||||||
 | 
						if (N != 0) {
 | 
				
			||||||
 | 
							database_reduce(database, opts, N, rng);
 | 
				
			||||||
 | 
							log("Reduced database size: %d\n", GetSize(database));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::ofstream fout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!filename.empty()) {
 | 
				
			||||||
 | 
							fout.open(filename, std::ios::out | std::ios::trunc);
 | 
				
			||||||
 | 
							if (!fout.is_open())
 | 
				
			||||||
 | 
								log_error("Could not open file \"%s\" with write access.\n", filename.c_str());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int ctrl_value = opts.ctrl_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &entry : database) {
 | 
				
			||||||
 | 
							string str = "mutate";
 | 
				
			||||||
 | 
							if (!opts.ctrl_name.empty())
 | 
				
			||||||
 | 
								str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
 | 
				
			||||||
 | 
							str += stringf(" -mode %s", entry.mode.c_str());
 | 
				
			||||||
 | 
							if (!entry.module.empty())
 | 
				
			||||||
 | 
								str += stringf(" -module %s", log_id(entry.module));
 | 
				
			||||||
 | 
							if (!entry.cell.empty())
 | 
				
			||||||
 | 
								str += stringf(" -cell %s", log_id(entry.cell));
 | 
				
			||||||
 | 
							if (!entry.port.empty())
 | 
				
			||||||
 | 
								str += stringf(" -port %s", log_id(entry.port));
 | 
				
			||||||
 | 
							if (entry.portbit >= 0)
 | 
				
			||||||
 | 
								str += stringf(" -portbit %d", entry.portbit);
 | 
				
			||||||
 | 
							if (entry.ctrlbit >= 0)
 | 
				
			||||||
 | 
								str += stringf(" -ctrlbit %d", entry.ctrlbit);
 | 
				
			||||||
 | 
							if (!entry.wire.empty())
 | 
				
			||||||
 | 
								str += stringf(" -wire %s", log_id(entry.wire));
 | 
				
			||||||
 | 
							if (entry.wirebit >= 0)
 | 
				
			||||||
 | 
								str += stringf(" -wirebit %d", entry.wirebit);
 | 
				
			||||||
 | 
							for (auto &s : entry.src)
 | 
				
			||||||
 | 
								str += stringf(" -src %s", s.c_str());
 | 
				
			||||||
 | 
							if (filename.empty())
 | 
				
			||||||
 | 
								log("%s\n", str.c_str());
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								fout << str << std::endl;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SigSpec mutate_ctrl_sig(Module *module, IdString name, int width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Wire *ctrl_wire = module->wire(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ctrl_wire == nullptr)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctrl_wire = module->addWire(name, width);
 | 
				
			||||||
 | 
							ctrl_wire->port_input = true;
 | 
				
			||||||
 | 
							module->fixup_ports();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto mod : module->design->modules())
 | 
				
			||||||
 | 
							for (auto cell : mod->cells())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (cell->type != module->name)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SigSpec ctrl = mutate_ctrl_sig(mod, name, width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod));
 | 
				
			||||||
 | 
								cell->setPort(name, ctrl);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log_assert(GetSize(ctrl_wire) == width);
 | 
				
			||||||
 | 
						return ctrl_wire;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (opts.ctrl_name.empty())
 | 
				
			||||||
 | 
							return State::S1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width);
 | 
				
			||||||
 | 
						return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SigBit ctrl_bit = mutate_ctrl(module, opts);
 | 
				
			||||||
 | 
						if (ctrl_bit == State::S0)
 | 
				
			||||||
 | 
							return unchanged_sig;
 | 
				
			||||||
 | 
						if (ctrl_bit == State::S1)
 | 
				
			||||||
 | 
							return changed_sig;
 | 
				
			||||||
 | 
						return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mutate_inv(Design *design, const mutate_opts_t &opts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Module *module = design->module(opts.module);
 | 
				
			||||||
 | 
						Cell *cell = module->cell(opts.cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigBit bit = cell->getPort(opts.port)[opts.portbit];
 | 
				
			||||||
 | 
						SigBit inbit, outbit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cell->input(opts.port))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
				
			||||||
 | 
							SigBit outbit = module->Not(NEW_ID, bit);
 | 
				
			||||||
 | 
							bit = mutate_ctrl_mux(module, opts, bit, outbit);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
				
			||||||
 | 
							SigBit inbit = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
							SigBit outbit = module->Not(NEW_ID, inbit);
 | 
				
			||||||
 | 
							module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
 | 
				
			||||||
 | 
							bit = inbit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec s = cell->getPort(opts.port);
 | 
				
			||||||
 | 
						s[opts.portbit] = bit;
 | 
				
			||||||
 | 
						cell->setPort(opts.port, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mutate_const(Design *design, const mutate_opts_t &opts, bool one)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Module *module = design->module(opts.module);
 | 
				
			||||||
 | 
						Cell *cell = module->cell(opts.cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigBit bit = cell->getPort(opts.port)[opts.portbit];
 | 
				
			||||||
 | 
						SigBit inbit, outbit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cell->input(opts.port))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
				
			||||||
 | 
							SigBit outbit = one ? State::S1 : State::S0;
 | 
				
			||||||
 | 
							bit = mutate_ctrl_mux(module, opts, bit, outbit);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
 | 
				
			||||||
 | 
							SigBit inbit = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
							SigBit outbit = one ? State::S1 : State::S0;
 | 
				
			||||||
 | 
							module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
 | 
				
			||||||
 | 
							bit = inbit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec s = cell->getPort(opts.port);
 | 
				
			||||||
 | 
						s[opts.portbit] = bit;
 | 
				
			||||||
 | 
						cell->setPort(opts.port, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Module *module = design->module(opts.module);
 | 
				
			||||||
 | 
						Cell *cell = module->cell(opts.cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigBit bit = cell->getPort(opts.port)[opts.portbit];
 | 
				
			||||||
 | 
						SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit];
 | 
				
			||||||
 | 
						SigBit inbit, outbit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cell->input(opts.port))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
 | 
				
			||||||
 | 
							SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl);
 | 
				
			||||||
 | 
							bit = mutate_ctrl_mux(module, opts, bit, outbit);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
 | 
				
			||||||
 | 
							SigBit inbit = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
							SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl);
 | 
				
			||||||
 | 
							module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
 | 
				
			||||||
 | 
							bit = inbit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SigSpec s = cell->getPort(opts.port);
 | 
				
			||||||
 | 
						s[opts.portbit] = bit;
 | 
				
			||||||
 | 
						cell->setPort(opts.port, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct MutatePass : public Pass {
 | 
				
			||||||
 | 
						MutatePass() : Pass("mutate", "generate or apply design mutations") { }
 | 
				
			||||||
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    mutate -list N [options] [selection]\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("Create a list of N mutations using an even sampling.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -o filename\n");
 | 
				
			||||||
 | 
							log("        Write list to this file instead of console output\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -seed N\n");
 | 
				
			||||||
 | 
							log("        RNG seed for selecting mutations\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -ctrl name width value\n");
 | 
				
			||||||
 | 
							log("        Add -ctrl options to the output. Use 'value' for first mutation, then\n");
 | 
				
			||||||
 | 
							log("        simply count up from there.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -mode name\n");
 | 
				
			||||||
 | 
							log("    -module name\n");
 | 
				
			||||||
 | 
							log("    -cell name\n");
 | 
				
			||||||
 | 
							log("    -port name\n");
 | 
				
			||||||
 | 
							log("    -portbit int\n");
 | 
				
			||||||
 | 
							log("    -ctrlbit int\n");
 | 
				
			||||||
 | 
							log("    -wire name\n");
 | 
				
			||||||
 | 
							log("    -wirebit int\n");
 | 
				
			||||||
 | 
							log("    -src string\n");
 | 
				
			||||||
 | 
							log("        Filter list of mutation candidates to those matching\n");
 | 
				
			||||||
 | 
							log("        the given parameters.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -cfg option int\n");
 | 
				
			||||||
 | 
							log("        Set a configuration option. Options available:\n");
 | 
				
			||||||
 | 
							log("          weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n");
 | 
				
			||||||
 | 
							log("          weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n");
 | 
				
			||||||
 | 
							log("          weight_cover pick_cover_prcnt\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    mutate -mode MODE [options]\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("Apply the given mutation.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -ctrl name width value\n");
 | 
				
			||||||
 | 
							log("        Add a control signal with the given name and width. The mutation is\n");
 | 
				
			||||||
 | 
							log("        activated if the control signal equals the given value.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -module name\n");
 | 
				
			||||||
 | 
							log("    -cell name\n");
 | 
				
			||||||
 | 
							log("    -port name\n");
 | 
				
			||||||
 | 
							log("    -portbit int\n");
 | 
				
			||||||
 | 
							log("    -ctrlbit int\n");
 | 
				
			||||||
 | 
							log("        Mutation parameters, as generated by 'mutate -list N'.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -wire name\n");
 | 
				
			||||||
 | 
							log("    -wirebit int\n");
 | 
				
			||||||
 | 
							log("    -src string\n");
 | 
				
			||||||
 | 
							log("        Ignored. (They are generated by -list for documentation purposes.)\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							mutate_opts_t opts;
 | 
				
			||||||
 | 
							string filename;
 | 
				
			||||||
 | 
							int N = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log_header(design, "Executing MUTATE pass.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t argidx;
 | 
				
			||||||
 | 
							for (argidx = 1; argidx < args.size(); argidx++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (args[argidx] == "-list" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									N = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-o" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									filename = args[++argidx];
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-seed" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.seed = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-mode" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.mode = args[++argidx];
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-ctrl" && argidx+3 < args.size()) {
 | 
				
			||||||
 | 
									opts.ctrl_name = RTLIL::escape_id(args[++argidx]);
 | 
				
			||||||
 | 
									opts.ctrl_width = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									opts.ctrl_value = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-module" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.module = RTLIL::escape_id(args[++argidx]);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-cell" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.cell = RTLIL::escape_id(args[++argidx]);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-port" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.port = RTLIL::escape_id(args[++argidx]);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-portbit" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.portbit = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.ctrlbit = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-wire" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.wire = RTLIL::escape_id(args[++argidx]);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-wirebit" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.wirebit = atoi(args[++argidx].c_str());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-src" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									opts.src.insert(args[++argidx]);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-cfg" && argidx+2 < args.size()) {
 | 
				
			||||||
 | 
									if (args[argidx+1] == "pick_cover_prcnt") {
 | 
				
			||||||
 | 
										opts.pick_cover_prcnt = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_cover") {
 | 
				
			||||||
 | 
										opts.weight_cover = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_w") {
 | 
				
			||||||
 | 
										opts.weight_pq_w = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_b") {
 | 
				
			||||||
 | 
										opts.weight_pq_b = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_c") {
 | 
				
			||||||
 | 
										opts.weight_pq_c = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_s") {
 | 
				
			||||||
 | 
										opts.weight_pq_s = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_mw") {
 | 
				
			||||||
 | 
										opts.weight_pq_mw = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_mb") {
 | 
				
			||||||
 | 
										opts.weight_pq_mb = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_mc") {
 | 
				
			||||||
 | 
										opts.weight_pq_mc = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (args[argidx+1] == "weight_pq_ms") {
 | 
				
			||||||
 | 
										opts.weight_pq_ms = atoi(args[argidx+2].c_str());
 | 
				
			||||||
 | 
										argidx += 2;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (N >= 0) {
 | 
				
			||||||
 | 
								mutate_list(design, opts, filename, N);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (opts.mode == "inv") {
 | 
				
			||||||
 | 
								mutate_inv(design, opts);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (opts.mode == "const0" || opts.mode == "const1") {
 | 
				
			||||||
 | 
								mutate_const(design, opts, opts.mode == "const1");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (opts.mode == "cnot0" || opts.mode == "cnot1") {
 | 
				
			||||||
 | 
								mutate_cnot(design, opts, opts.mode == "cnot1");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log_cmd_error("Invalid mode: %s\n", opts.mode.c_str());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} MutatePass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
							
								
								
									
										92
									
								
								passes/sat/supercover.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								passes/sat/supercover.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.h"
 | 
				
			||||||
 | 
					#include "kernel/sigtools.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SupercoverPass : public Pass {
 | 
				
			||||||
 | 
						SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { }
 | 
				
			||||||
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    supercover [options] [selection]\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("This command adds two cover cells for each bit of each selected wire, one\n");
 | 
				
			||||||
 | 
							log("checking for a hi signal level and one checking for lo level.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// bool flag_noinit = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log_header(design, "Executing SUPERCOVER pass.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t argidx;
 | 
				
			||||||
 | 
							for (argidx = 1; argidx < args.size(); argidx++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// if (args[argidx] == "-noinit") {
 | 
				
			||||||
 | 
								// 	flag_noinit = true;
 | 
				
			||||||
 | 
								// 	continue;
 | 
				
			||||||
 | 
								// }
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto module : design->selected_modules())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								SigMap sigmap(module);
 | 
				
			||||||
 | 
								pool<SigBit> handled_bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int cnt_wire = 0, cnt_bits = 0;
 | 
				
			||||||
 | 
								log("Adding cover cells to module %s.\n", log_id(module));
 | 
				
			||||||
 | 
								for (auto wire : module->selected_wires())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									bool counted_wire = false;
 | 
				
			||||||
 | 
									std::string src = wire->get_src_attribute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (auto bit : sigmap(SigSpec(wire)))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (bit.wire == nullptr)
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (handled_bits.count(bit))
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										SigSpec inv = module->Not(NEW_ID, bit);
 | 
				
			||||||
 | 
										module->addCover(NEW_ID, bit, State::S1, src);
 | 
				
			||||||
 | 
										module->addCover(NEW_ID, inv, State::S1, src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										handled_bits.insert(bit);
 | 
				
			||||||
 | 
										if (!counted_wire) {
 | 
				
			||||||
 | 
											counted_wire = false;
 | 
				
			||||||
 | 
											cnt_wire++;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										cnt_bits++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								log("  added cover cells to %d wires, %d bits.\n", cnt_wire, cnt_bits);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} SupercoverPass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
| 
						 | 
					@ -327,8 +327,26 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string remap_name(RTLIL::IdString abc_name)
 | 
					std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						std::string abc_sname = abc_name.substr(1);
 | 
				
			||||||
 | 
						if (abc_sname.substr(0, 5) == "ys__n") {
 | 
				
			||||||
 | 
							int sid = std::stoi(abc_sname.substr(5));
 | 
				
			||||||
 | 
							bool inv = abc_sname.back() == 'v';
 | 
				
			||||||
 | 
							for (auto sig : signal_list) {
 | 
				
			||||||
 | 
								if (sig.id == sid && sig.bit.wire != nullptr) {
 | 
				
			||||||
 | 
									std::stringstream sstr;
 | 
				
			||||||
 | 
									sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
 | 
				
			||||||
 | 
									if (sig.bit.wire->width != 1)
 | 
				
			||||||
 | 
										sstr << "[" << sig.bit.offset << "]";
 | 
				
			||||||
 | 
									if (inv)
 | 
				
			||||||
 | 
										sstr << "_inv";
 | 
				
			||||||
 | 
									if (orig_wire != nullptr)
 | 
				
			||||||
 | 
										*orig_wire = sig.bit.wire;
 | 
				
			||||||
 | 
									return sstr.str();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	std::stringstream sstr;
 | 
						std::stringstream sstr;
 | 
				
			||||||
	sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
 | 
						sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
 | 
				
			||||||
	return sstr.str();
 | 
						return sstr.str();
 | 
				
			||||||
| 
						 | 
					@ -353,12 +371,12 @@ void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto n : nodes)
 | 
						for (auto n : nodes)
 | 
				
			||||||
		fprintf(f, "  n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
 | 
							fprintf(f, "  ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
 | 
				
			||||||
				n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
 | 
									n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto &e : edges)
 | 
						for (auto &e : edges)
 | 
				
			||||||
	for (auto n : e.second)
 | 
						for (auto n : e.second)
 | 
				
			||||||
		fprintf(f, "  n%d -> n%d;\n", e.first, n);
 | 
							fprintf(f, "  ys__n%d -> ys__n%d;\n", e.first, n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fprintf(f, "}\n");
 | 
						fprintf(f, "}\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -624,7 +642,7 @@ struct abc_output_filter
 | 
				
			||||||
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
 | 
					void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
 | 
				
			||||||
		std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
 | 
							std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
 | 
				
			||||||
		bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
 | 
							bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
 | 
				
			||||||
		const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
 | 
							const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	module = current_module;
 | 
						module = current_module;
 | 
				
			||||||
	map_autoidx = autoidx++;
 | 
						map_autoidx = autoidx++;
 | 
				
			||||||
| 
						 | 
					@ -728,7 +746,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
 | 
						for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
 | 
				
			||||||
		abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
 | 
							abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
 | 
				
			||||||
 | 
						if (abc_dress)
 | 
				
			||||||
 | 
							abc_script += "; dress";
 | 
				
			||||||
	abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
 | 
						abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
 | 
				
			||||||
	abc_script = add_echos_to_abc_cmd(abc_script);
 | 
						abc_script = add_echos_to_abc_cmd(abc_script);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -784,7 +803,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
	for (auto &si : signal_list) {
 | 
						for (auto &si : signal_list) {
 | 
				
			||||||
		if (!si.is_port || si.type != G(NONE))
 | 
							if (!si.is_port || si.type != G(NONE))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		fprintf(f, " n%d", si.id);
 | 
							fprintf(f, " ys__n%d", si.id);
 | 
				
			||||||
		pi_map[count_input++] = log_signal(si.bit);
 | 
							pi_map[count_input++] = log_signal(si.bit);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (count_input == 0)
 | 
						if (count_input == 0)
 | 
				
			||||||
| 
						 | 
					@ -796,17 +815,17 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
	for (auto &si : signal_list) {
 | 
						for (auto &si : signal_list) {
 | 
				
			||||||
		if (!si.is_port || si.type == G(NONE))
 | 
							if (!si.is_port || si.type == G(NONE))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		fprintf(f, " n%d", si.id);
 | 
							fprintf(f, " ys__n%d", si.id);
 | 
				
			||||||
		po_map[count_output++] = log_signal(si.bit);
 | 
							po_map[count_output++] = log_signal(si.bit);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fprintf(f, "\n");
 | 
						fprintf(f, "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto &si : signal_list)
 | 
						for (auto &si : signal_list)
 | 
				
			||||||
		fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit));
 | 
							fprintf(f, "# ys__n%-5d %s\n", si.id, log_signal(si.bit));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto &si : signal_list) {
 | 
						for (auto &si : signal_list) {
 | 
				
			||||||
		if (si.bit.wire == NULL) {
 | 
							if (si.bit.wire == NULL) {
 | 
				
			||||||
			fprintf(f, ".names n%d\n", si.id);
 | 
								fprintf(f, ".names ys__n%d\n", si.id);
 | 
				
			||||||
			if (si.bit == RTLIL::State::S1)
 | 
								if (si.bit == RTLIL::State::S1)
 | 
				
			||||||
				fprintf(f, "1\n");
 | 
									fprintf(f, "1\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -815,68 +834,68 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
	int count_gates = 0;
 | 
						int count_gates = 0;
 | 
				
			||||||
	for (auto &si : signal_list) {
 | 
						for (auto &si : signal_list) {
 | 
				
			||||||
		if (si.type == G(BUF)) {
 | 
							if (si.type == G(BUF)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d\n", si.in1, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id);
 | 
				
			||||||
			fprintf(f, "1 1\n");
 | 
								fprintf(f, "1 1\n");
 | 
				
			||||||
		} else if (si.type == G(NOT)) {
 | 
							} else if (si.type == G(NOT)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d\n", si.in1, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id);
 | 
				
			||||||
			fprintf(f, "0 1\n");
 | 
								fprintf(f, "0 1\n");
 | 
				
			||||||
		} else if (si.type == G(AND)) {
 | 
							} else if (si.type == G(AND)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "11 1\n");
 | 
								fprintf(f, "11 1\n");
 | 
				
			||||||
		} else if (si.type == G(NAND)) {
 | 
							} else if (si.type == G(NAND)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "0- 1\n");
 | 
								fprintf(f, "0- 1\n");
 | 
				
			||||||
			fprintf(f, "-0 1\n");
 | 
								fprintf(f, "-0 1\n");
 | 
				
			||||||
		} else if (si.type == G(OR)) {
 | 
							} else if (si.type == G(OR)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "-1 1\n");
 | 
								fprintf(f, "-1 1\n");
 | 
				
			||||||
			fprintf(f, "1- 1\n");
 | 
								fprintf(f, "1- 1\n");
 | 
				
			||||||
		} else if (si.type == G(NOR)) {
 | 
							} else if (si.type == G(NOR)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "00 1\n");
 | 
								fprintf(f, "00 1\n");
 | 
				
			||||||
		} else if (si.type == G(XOR)) {
 | 
							} else if (si.type == G(XOR)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "01 1\n");
 | 
								fprintf(f, "01 1\n");
 | 
				
			||||||
			fprintf(f, "10 1\n");
 | 
								fprintf(f, "10 1\n");
 | 
				
			||||||
		} else if (si.type == G(XNOR)) {
 | 
							} else if (si.type == G(XNOR)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "00 1\n");
 | 
								fprintf(f, "00 1\n");
 | 
				
			||||||
			fprintf(f, "11 1\n");
 | 
								fprintf(f, "11 1\n");
 | 
				
			||||||
		} else if (si.type == G(ANDNOT)) {
 | 
							} else if (si.type == G(ANDNOT)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "10 1\n");
 | 
								fprintf(f, "10 1\n");
 | 
				
			||||||
		} else if (si.type == G(ORNOT)) {
 | 
							} else if (si.type == G(ORNOT)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
 | 
				
			||||||
			fprintf(f, "1- 1\n");
 | 
								fprintf(f, "1- 1\n");
 | 
				
			||||||
			fprintf(f, "-0 1\n");
 | 
								fprintf(f, "-0 1\n");
 | 
				
			||||||
		} else if (si.type == G(MUX)) {
 | 
							} else if (si.type == G(MUX)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
 | 
				
			||||||
			fprintf(f, "1-0 1\n");
 | 
								fprintf(f, "1-0 1\n");
 | 
				
			||||||
			fprintf(f, "-11 1\n");
 | 
								fprintf(f, "-11 1\n");
 | 
				
			||||||
		} else if (si.type == G(AOI3)) {
 | 
							} else if (si.type == G(AOI3)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
 | 
				
			||||||
			fprintf(f, "-00 1\n");
 | 
								fprintf(f, "-00 1\n");
 | 
				
			||||||
			fprintf(f, "0-0 1\n");
 | 
								fprintf(f, "0-0 1\n");
 | 
				
			||||||
		} else if (si.type == G(OAI3)) {
 | 
							} else if (si.type == G(OAI3)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
 | 
				
			||||||
			fprintf(f, "00- 1\n");
 | 
								fprintf(f, "00- 1\n");
 | 
				
			||||||
			fprintf(f, "--0 1\n");
 | 
								fprintf(f, "--0 1\n");
 | 
				
			||||||
		} else if (si.type == G(AOI4)) {
 | 
							} else if (si.type == G(AOI4)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
 | 
				
			||||||
			fprintf(f, "-0-0 1\n");
 | 
								fprintf(f, "-0-0 1\n");
 | 
				
			||||||
			fprintf(f, "-00- 1\n");
 | 
								fprintf(f, "-00- 1\n");
 | 
				
			||||||
			fprintf(f, "0--0 1\n");
 | 
								fprintf(f, "0--0 1\n");
 | 
				
			||||||
			fprintf(f, "0-0- 1\n");
 | 
								fprintf(f, "0-0- 1\n");
 | 
				
			||||||
		} else if (si.type == G(OAI4)) {
 | 
							} else if (si.type == G(OAI4)) {
 | 
				
			||||||
			fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
 | 
								fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
 | 
				
			||||||
			fprintf(f, "00-- 1\n");
 | 
								fprintf(f, "00-- 1\n");
 | 
				
			||||||
			fprintf(f, "--00 1\n");
 | 
								fprintf(f, "--00 1\n");
 | 
				
			||||||
		} else if (si.type == G(FF)) {
 | 
							} else if (si.type == G(FF)) {
 | 
				
			||||||
			if (si.init == State::S0 || si.init == State::S1) {
 | 
								if (si.init == State::S0 || si.init == State::S1) {
 | 
				
			||||||
				fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
 | 
									fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
 | 
				
			||||||
				recover_init = true;
 | 
									recover_init = true;
 | 
				
			||||||
			} else
 | 
								} else
 | 
				
			||||||
				fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id);
 | 
									fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
 | 
				
			||||||
		} else if (si.type != G(NONE))
 | 
							} else if (si.type != G(NONE))
 | 
				
			||||||
			log_abort();
 | 
								log_abort();
 | 
				
			||||||
		if (si.type != G(NONE))
 | 
							if (si.type != G(NONE))
 | 
				
			||||||
| 
						 | 
					@ -889,7 +908,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
	log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
 | 
						log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
 | 
				
			||||||
			count_gates, GetSize(signal_list), count_input, count_output);
 | 
								count_gates, GetSize(signal_list), count_input, count_output);
 | 
				
			||||||
	log_push();
 | 
						log_push();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (count_output > 0)
 | 
						if (count_output > 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		log_header(design, "Executing ABC.\n");
 | 
							log_header(design, "Executing ABC.\n");
 | 
				
			||||||
| 
						 | 
					@ -988,7 +1006,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
			log_error("ABC output file does not contain a module `netlist'.\n");
 | 
								log_error("ABC output file does not contain a module `netlist'.\n");
 | 
				
			||||||
		for (auto &it : mapped_mod->wires_) {
 | 
							for (auto &it : mapped_mod->wires_) {
 | 
				
			||||||
			RTLIL::Wire *w = it.second;
 | 
								RTLIL::Wire *w = it.second;
 | 
				
			||||||
			RTLIL::Wire *wire = module->addWire(remap_name(w->name));
 | 
								RTLIL::Wire *orig_wire = nullptr;
 | 
				
			||||||
 | 
								RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire));
 | 
				
			||||||
 | 
								if (orig_wire != nullptr && orig_wire->attributes.count("\\src"))
 | 
				
			||||||
 | 
									wire->attributes["\\src"] = orig_wire->attributes["\\src"];
 | 
				
			||||||
			if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx;
 | 
								if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx;
 | 
				
			||||||
			design->select(module, wire);
 | 
								design->select(module, wire);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1213,7 +1234,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
		for (auto &si : signal_list)
 | 
							for (auto &si : signal_list)
 | 
				
			||||||
			if (si.is_port) {
 | 
								if (si.is_port) {
 | 
				
			||||||
				char buffer[100];
 | 
									char buffer[100];
 | 
				
			||||||
				snprintf(buffer, 100, "\\n%d", si.id);
 | 
									snprintf(buffer, 100, "\\ys__n%d", si.id);
 | 
				
			||||||
				RTLIL::SigSig conn;
 | 
									RTLIL::SigSig conn;
 | 
				
			||||||
				if (si.type != G(NONE)) {
 | 
									if (si.type != G(NONE)) {
 | 
				
			||||||
					conn.first = si.bit;
 | 
										conn.first = si.bit;
 | 
				
			||||||
| 
						 | 
					@ -1407,6 +1428,11 @@ struct AbcPass : public Pass {
 | 
				
			||||||
		log("        this attribute is a unique integer for each ABC process started. This\n");
 | 
							log("        this attribute is a unique integer for each ABC process started. This\n");
 | 
				
			||||||
		log("        is useful for debugging the partitioning of clock domains.\n");
 | 
							log("        is useful for debugging the partitioning of clock domains.\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -dress\n");
 | 
				
			||||||
 | 
							log("        run the 'dress' command after all other ABC commands. This aims to\n");
 | 
				
			||||||
 | 
							log("        preserve naming by an equivalence check between the original and post-ABC\n");
 | 
				
			||||||
 | 
							log("        netlists (experimental).\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
		log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
 | 
							log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
 | 
				
			||||||
		log("loaded into ABC before the ABC script is executed.\n");
 | 
							log("loaded into ABC before the ABC script is executed.\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
| 
						 | 
					@ -1441,6 +1467,7 @@ struct AbcPass : public Pass {
 | 
				
			||||||
		std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
 | 
							std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
 | 
				
			||||||
		bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
 | 
							bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
 | 
				
			||||||
		bool show_tempdir = false, sop_mode = false;
 | 
							bool show_tempdir = false, sop_mode = false;
 | 
				
			||||||
 | 
							bool abc_dress = false;
 | 
				
			||||||
		vector<int> lut_costs;
 | 
							vector<int> lut_costs;
 | 
				
			||||||
		markgroups = false;
 | 
							markgroups = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1555,6 +1582,10 @@ struct AbcPass : public Pass {
 | 
				
			||||||
				map_mux16 = true;
 | 
									map_mux16 = true;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (arg == "-dress") {
 | 
				
			||||||
 | 
									abc_dress = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (arg == "-g" && argidx+1 < args.size()) {
 | 
								if (arg == "-g" && argidx+1 < args.size()) {
 | 
				
			||||||
				for (auto g : split_tokens(args[++argidx], ",")) {
 | 
									for (auto g : split_tokens(args[++argidx], ",")) {
 | 
				
			||||||
					vector<string> gate_list;
 | 
										vector<string> gate_list;
 | 
				
			||||||
| 
						 | 
					@ -1704,7 +1735,7 @@ struct AbcPass : public Pass {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!dff_mode || !clk_str.empty()) {
 | 
								if (!dff_mode || !clk_str.empty()) {
 | 
				
			||||||
				abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
 | 
									abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
 | 
				
			||||||
						delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
 | 
											delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress);
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1849,7 +1880,7 @@ struct AbcPass : public Pass {
 | 
				
			||||||
				en_polarity = std::get<2>(it.first);
 | 
									en_polarity = std::get<2>(it.first);
 | 
				
			||||||
				en_sig = assign_map(std::get<3>(it.first));
 | 
									en_sig = assign_map(std::get<3>(it.first));
 | 
				
			||||||
				abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
 | 
									abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
 | 
				
			||||||
						keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode);
 | 
											keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
 | 
				
			||||||
				assign_map.set(mod);
 | 
									assign_map.set(mod);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -660,8 +660,8 @@ struct DfflibmapPass : public Pass {
 | 
				
			||||||
		map_adff_to_dff("$_DFF_PP0_", "$_DFF_P_");
 | 
							map_adff_to_dff("$_DFF_PP0_", "$_DFF_P_");
 | 
				
			||||||
		map_adff_to_dff("$_DFF_PP1_", "$_DFF_P_");
 | 
							map_adff_to_dff("$_DFF_PP1_", "$_DFF_P_");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 		log("  final dff cell mappings:\n");
 | 
							log("  final dff cell mappings:\n");
 | 
				
			||||||
 		logmap_all();
 | 
							logmap_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto &it : design->modules_)
 | 
							for (auto &it : design->modules_)
 | 
				
			||||||
			if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
 | 
								if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,9 +132,9 @@ static void dump_dot_graph(string filename,
 | 
				
			||||||
                           pool<RTLIL::SigBit> nodes, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges,
 | 
					                           pool<RTLIL::SigBit> nodes, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges,
 | 
				
			||||||
                           pool<RTLIL::SigBit> inputs, pool<RTLIL::SigBit> outputs,
 | 
					                           pool<RTLIL::SigBit> inputs, pool<RTLIL::SigBit> outputs,
 | 
				
			||||||
                           std::function<GraphStyle(RTLIL::SigBit)> node_style =
 | 
					                           std::function<GraphStyle(RTLIL::SigBit)> node_style =
 | 
				
			||||||
                           		[](RTLIL::SigBit) { return GraphStyle{}; },
 | 
					                                   [](RTLIL::SigBit) { return GraphStyle{}; },
 | 
				
			||||||
                           std::function<GraphStyle(RTLIL::SigBit, RTLIL::SigBit)> edge_style =
 | 
					                           std::function<GraphStyle(RTLIL::SigBit, RTLIL::SigBit)> edge_style =
 | 
				
			||||||
                           		[](RTLIL::SigBit, RTLIL::SigBit) { return GraphStyle{}; },
 | 
					                                   [](RTLIL::SigBit, RTLIL::SigBit) { return GraphStyle{}; },
 | 
				
			||||||
                           string name = "")
 | 
					                           string name = "")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FILE *f = fopen(filename.c_str(), "w");
 | 
						FILE *f = fopen(filename.c_str(), "w");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ endmodule
 | 
				
			||||||
module PADOUT (output padout, input padin, input oe);
 | 
					module PADOUT (output padout, input padin, input oe);
 | 
				
			||||||
   assign padout  = padin;
 | 
					   assign padout  = padin;
 | 
				
			||||||
   assign oe = oe;
 | 
					   assign oe = oe;
 | 
				
			||||||
endmodule 
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module LUT4 (output dout,
 | 
					module LUT4 (output dout,
 | 
				
			||||||
             input  din0, din1, din2, din3);
 | 
					             input  din0, din1, din2, din3);
 | 
				
			||||||
| 
						 | 
					@ -66,14 +66,14 @@ always @(dataa_w or datab_w or datac_w or datad_w) begin
 | 
				
			||||||
                         datac_w, datad_w);
 | 
					                         datac_w, datad_w);
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
assign dout = combout_rt & 1'b1;
 | 
					assign dout = combout_rt & 1'b1;
 | 
				
			||||||
endmodule 
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module DFF (output q,
 | 
					module DFF (output q,
 | 
				
			||||||
            input  d, ck);
 | 
					            input  d, ck);
 | 
				
			||||||
   reg             q;
 | 
					   reg             q;
 | 
				
			||||||
   always @(posedge ck)
 | 
					   always @(posedge ck)
 | 
				
			||||||
     q <= d;
 | 
					     q <= d;
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,13 +52,13 @@ struct AnlogicEqnPass : public Pass {
 | 
				
			||||||
						eqn += names[j];
 | 
											eqn += names[j];
 | 
				
			||||||
					else
 | 
										else
 | 
				
			||||||
						eqn += std::string("~") + names[j];
 | 
											eqn += std::string("~") + names[j];
 | 
				
			||||||
					
 | 
					
 | 
				
			||||||
					if (j!=(inputs-1)) eqn += "*";
 | 
										if (j!=(inputs-1)) eqn += "*";
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				eqn += ")+";
 | 
									eqn += ")+";
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (eqn.empty()) return Const("0");		
 | 
							if (eqn.empty()) return Const("0");
 | 
				
			||||||
		eqn = eqn.substr(0, eqn.length()-1);
 | 
							eqn = eqn.substr(0, eqn.length()-1);
 | 
				
			||||||
		return Const(eqn);
 | 
							return Const(eqn);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS += techlibs/ecp5/synth_ecp5.o
 | 
					OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
 | 
					$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
 | 
				
			||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
 | 
					$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
	input CI, BI;
 | 
						input CI, BI;
 | 
				
			||||||
	output [Y_WIDTH-1:0] CO;
 | 
						output [Y_WIDTH-1:0] CO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
 | 
						wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wire [Y_WIDTH-1:0] A_buf, B_buf;
 | 
						wire [Y_WIDTH-1:0] A_buf, B_buf;
 | 
				
			||||||
	\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
 | 
						\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -156,6 +156,41 @@ module OSCG(
 | 
				
			||||||
parameter DIV = 128;
 | 
					parameter DIV = 128;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *) (* keep *)
 | 
				
			||||||
 | 
					module USRMCLK(
 | 
				
			||||||
 | 
						input USRMCLKI, USRMCLKTS,
 | 
				
			||||||
 | 
						output USRMCLKO
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *) (* keep *)
 | 
				
			||||||
 | 
					module JTAGG(
 | 
				
			||||||
 | 
						input TCK, TMS, TDI, JTDO2, JTDO1,
 | 
				
			||||||
 | 
						output TDO, JTDI, JTCK, JRTI2, JRTI1,
 | 
				
			||||||
 | 
						output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					parameter ER1 = "ENABLED";
 | 
				
			||||||
 | 
					parameter ER2 = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module DELAYF(
 | 
				
			||||||
 | 
						input A, LOADN, MOVE, DIRECTION,
 | 
				
			||||||
 | 
						output Z, CFLAG
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter DEL_MODE = "USER_DEFINED";
 | 
				
			||||||
 | 
						parameter DEL_VALUE = 0;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module DELAYG(
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Z
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter DEL_MODE = "USER_DEFINED";
 | 
				
			||||||
 | 
						parameter DEL_VALUE = 0;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(* blackbox *)
 | 
					(* blackbox *)
 | 
				
			||||||
module IDDRX1F(
 | 
					module IDDRX1F(
 | 
				
			||||||
	input D, SCLK, RST,
 | 
						input D, SCLK, RST,
 | 
				
			||||||
| 
						 | 
					@ -164,6 +199,31 @@ module IDDRX1F(
 | 
				
			||||||
	parameter GSR = "ENABLED";
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module IDDRX2F(
 | 
				
			||||||
 | 
						input D, SCLK, ECLK, RST,
 | 
				
			||||||
 | 
						output Q0, Q1, Q2, Q3
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module IDDR71B(
 | 
				
			||||||
 | 
						input D, SCLK, ECLK, RST, ALIGNWD,
 | 
				
			||||||
 | 
						output Q0, Q1, Q2, Q3, Q4, Q5, Q6
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module IDDRX2DQA(
 | 
				
			||||||
 | 
						input D, DQSR90, ECLK, SCLK, RST,
 | 
				
			||||||
 | 
						input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0,
 | 
				
			||||||
 | 
						output Q0, Q1, Q2, Q3, QWL
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(* blackbox *)
 | 
					(* blackbox *)
 | 
				
			||||||
module ODDRX1F(
 | 
					module ODDRX1F(
 | 
				
			||||||
	input SCLK, RST, D0, D1,
 | 
						input SCLK, RST, D0, D1,
 | 
				
			||||||
| 
						 | 
					@ -172,6 +232,91 @@ module ODDRX1F(
 | 
				
			||||||
	parameter GSR = "ENABLED";
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module ODDRX2F(
 | 
				
			||||||
 | 
						input SCLK, ECLK, RST, D0, D1, D2, D3,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module ODDR71B(
 | 
				
			||||||
 | 
						input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module OSHX2A(
 | 
				
			||||||
 | 
						input D0, D1, RST, ECLK, SCLK,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module ODDRX2DQA(
 | 
				
			||||||
 | 
						input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module ODDRX2DQSB(
 | 
				
			||||||
 | 
						input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module TSHX2DQA(
 | 
				
			||||||
 | 
						input T0, T1, SCLK, ECLK, DQSW270, RST,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
						parameter REGSET = "SET";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module TSHX2DQSA(
 | 
				
			||||||
 | 
						input T0, T1, SCLK, ECLK, DQSW, RST,
 | 
				
			||||||
 | 
						output Q
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
						parameter REGSET = "SET";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module DQSBUFM(
 | 
				
			||||||
 | 
						input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL,
 | 
				
			||||||
 | 
						input ECLK, SCLK,
 | 
				
			||||||
 | 
						input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4,
 | 
				
			||||||
 | 
						input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0, 
 | 
				
			||||||
 | 
						input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE,
 | 
				
			||||||
 | 
						output DQSR90, DQSW, DQSW270,
 | 
				
			||||||
 | 
						output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0,
 | 
				
			||||||
 | 
						output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter DQS_LI_DEL_ADJ = "FACTORYONLY";
 | 
				
			||||||
 | 
						parameter DQS_LI_DEL_VAL = 0;
 | 
				
			||||||
 | 
						parameter DQS_LO_DEL_ADJ = "FACTORYONLY";
 | 
				
			||||||
 | 
						parameter DQS_LO_DEL_VAL = 0;
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module DDRDLLA(
 | 
				
			||||||
 | 
						input CLK, RST, UDDCNTLN, FREEZE,
 | 
				
			||||||
 | 
						output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter FORCE_MAX_DELAY = "NO";
 | 
				
			||||||
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(* blackbox *)
 | 
					(* blackbox *)
 | 
				
			||||||
module CLKDIVF(
 | 
					module CLKDIVF(
 | 
				
			||||||
	input CLKI, RST, ALIGNWD,
 | 
						input CLKI, RST, ALIGNWD,
 | 
				
			||||||
| 
						 | 
					@ -181,6 +326,13 @@ module CLKDIVF(
 | 
				
			||||||
	parameter DIV = "2.0";
 | 
						parameter DIV = "2.0";
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(* blackbox *)
 | 
				
			||||||
 | 
					module ECLKSYNCB(
 | 
				
			||||||
 | 
						input ECLKI, STOP,
 | 
				
			||||||
 | 
						output ECLKO
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(* blackbox *)
 | 
					(* blackbox *)
 | 
				
			||||||
module DCCA(
 | 
					module DCCA(
 | 
				
			||||||
	input CLKI, CE,
 | 
						input CLKI, CE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,9 @@ module  \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"
 | 
				
			||||||
module  \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
 | 
					module  \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
 | 
				
			||||||
module  \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
 | 
					module  \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
 | 
				
			||||||
 | 
					module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`ifndef NO_LUT
 | 
					`ifndef NO_LUT
 | 
				
			||||||
module \$lut (A, Y);
 | 
					module \$lut (A, Y);
 | 
				
			||||||
    parameter WIDTH = 0;
 | 
					    parameter WIDTH = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,7 @@ module TRELLIS_RAM16X2 (
 | 
				
			||||||
	input RAD0, RAD1, RAD2, RAD3,
 | 
						input RAD0, RAD1, RAD2, RAD3,
 | 
				
			||||||
	output DO0, DO1
 | 
						output DO0, DO1
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
  	parameter WCKMUX = "WCK";
 | 
						parameter WCKMUX = "WCK";
 | 
				
			||||||
	parameter WREMUX = "WRE";
 | 
						parameter WREMUX = "WRE";
 | 
				
			||||||
	parameter INITVAL_0 = 16'h0000;
 | 
						parameter INITVAL_0 = 16'h0000;
 | 
				
			||||||
	parameter INITVAL_1 = 16'h0000;
 | 
						parameter INITVAL_1 = 16'h0000;
 | 
				
			||||||
| 
						 | 
					@ -104,7 +104,7 @@ module TRELLIS_DPR16X4 (
 | 
				
			||||||
	input [3:0] RAD,
 | 
						input [3:0] RAD,
 | 
				
			||||||
	output [3:0] DO
 | 
						output [3:0] DO
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
  	parameter WCKMUX = "WCK";
 | 
						parameter WCKMUX = "WCK";
 | 
				
			||||||
	parameter WREMUX = "WRE";
 | 
						parameter WREMUX = "WRE";
 | 
				
			||||||
	parameter [63:0] INITVAL = 64'h0000000000000000;
 | 
						parameter [63:0] INITVAL = 64'h0000000000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,13 +203,14 @@ endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---------------------------------------
 | 
					// ---------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
 | 
					module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
 | 
				
			||||||
	parameter GSR = "ENABLED";
 | 
						parameter GSR = "ENABLED";
 | 
				
			||||||
	parameter [127:0] CEMUX = "1";
 | 
						parameter [127:0] CEMUX = "1";
 | 
				
			||||||
	parameter CLKMUX = "CLK";
 | 
						parameter CLKMUX = "CLK";
 | 
				
			||||||
	parameter LSRMUX = "LSR";
 | 
						parameter LSRMUX = "LSR";
 | 
				
			||||||
	parameter SRMODE = "LSR_OVER_CE";
 | 
						parameter SRMODE = "LSR_OVER_CE";
 | 
				
			||||||
	parameter REGSET = "RESET";
 | 
						parameter REGSET = "RESET";
 | 
				
			||||||
 | 
						parameter [127:0] LSRMODE = "LSR";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reg muxce;
 | 
						reg muxce;
 | 
				
			||||||
	always @(*)
 | 
						always @(*)
 | 
				
			||||||
| 
						 | 
					@ -222,8 +223,13 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
 | 
						wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
 | 
				
			||||||
	wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
 | 
						wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
 | 
				
			||||||
 | 
						wire srval;
 | 
				
			||||||
	localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0;
 | 
						generate
 | 
				
			||||||
 | 
							if (LSRMODE == "PRLD")
 | 
				
			||||||
 | 
								assign srval = M;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								assign srval = (REGSET == "SET") ? 1'b1 : 1'b0;
 | 
				
			||||||
 | 
						endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initial Q = srval;
 | 
						initial Q = srval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,6 +345,8 @@ module TRELLIS_SLICE(
 | 
				
			||||||
	parameter REG1_SD = "0";
 | 
						parameter REG1_SD = "0";
 | 
				
			||||||
	parameter REG0_REGSET = "RESET";
 | 
						parameter REG0_REGSET = "RESET";
 | 
				
			||||||
	parameter REG1_REGSET = "RESET";
 | 
						parameter REG1_REGSET = "RESET";
 | 
				
			||||||
 | 
						parameter REG0_LSRMODE = "LSR";
 | 
				
			||||||
 | 
						parameter REG1_LSRMODE = "LSR";
 | 
				
			||||||
	parameter [127:0] CCU2_INJECT1_0 = "NO";
 | 
						parameter [127:0] CCU2_INJECT1_0 = "NO";
 | 
				
			||||||
	parameter [127:0] CCU2_INJECT1_1 = "NO";
 | 
						parameter [127:0] CCU2_INJECT1_1 = "NO";
 | 
				
			||||||
	parameter WREMUX = "WRE";
 | 
						parameter WREMUX = "WRE";
 | 
				
			||||||
| 
						 | 
					@ -428,10 +436,11 @@ module TRELLIS_SLICE(
 | 
				
			||||||
		.CLKMUX(CLKMUX),
 | 
							.CLKMUX(CLKMUX),
 | 
				
			||||||
		.LSRMUX(LSRMUX),
 | 
							.LSRMUX(LSRMUX),
 | 
				
			||||||
		.SRMODE(SRMODE),
 | 
							.SRMODE(SRMODE),
 | 
				
			||||||
		.REGSET(REG0_REGSET)
 | 
							.REGSET(REG0_REGSET),
 | 
				
			||||||
 | 
							.LSRMODE(REG0_LSRMODE)
 | 
				
			||||||
	) ff_0 (
 | 
						) ff_0 (
 | 
				
			||||||
		.CLK(CLK), .LSR(LSR), .CE(CE),
 | 
							.CLK(CLK), .LSR(LSR), .CE(CE),
 | 
				
			||||||
		.DI(muxdi0),
 | 
							.DI(muxdi0), .M(M0),
 | 
				
			||||||
		.Q(Q0)
 | 
							.Q(Q0)
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
	TRELLIS_FF #(
 | 
						TRELLIS_FF #(
 | 
				
			||||||
| 
						 | 
					@ -440,10 +449,11 @@ module TRELLIS_SLICE(
 | 
				
			||||||
		.CLKMUX(CLKMUX),
 | 
							.CLKMUX(CLKMUX),
 | 
				
			||||||
		.LSRMUX(LSRMUX),
 | 
							.LSRMUX(LSRMUX),
 | 
				
			||||||
		.SRMODE(SRMODE),
 | 
							.SRMODE(SRMODE),
 | 
				
			||||||
		.REGSET(REG1_REGSET)
 | 
							.REGSET(REG1_REGSET),
 | 
				
			||||||
 | 
							.LSRMODE(REG1_LSRMODE)
 | 
				
			||||||
	) ff_1 (
 | 
						) ff_1 (
 | 
				
			||||||
		.CLK(CLK), .LSR(LSR), .CE(CE),
 | 
							.CLK(CLK), .LSR(LSR), .CE(CE),
 | 
				
			||||||
		.DI(muxdi1),
 | 
							.DI(muxdi1), .M(M1),
 | 
				
			||||||
		.Q(Q1)
 | 
							.Q(Q1)
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
| 
						 | 
					@ -547,3 +557,20 @@ module DP16KD(
 | 
				
			||||||
  parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
 | 
					  parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
  parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
 | 
					  parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
 | 
				
			||||||
 | 
					module FD1S3BX(input PD, D, CK, output Q);
 | 
				
			||||||
 | 
						TRELLIS_FF #(
 | 
				
			||||||
 | 
							.GSR("DISABLED"),
 | 
				
			||||||
 | 
							.CEMUX("1"),
 | 
				
			||||||
 | 
							.CLKMUX("CLK"),
 | 
				
			||||||
 | 
							.LSRMUX("LSR"),
 | 
				
			||||||
 | 
							.REGSET("SET"),
 | 
				
			||||||
 | 
							.SRMODE("ASYNC")
 | 
				
			||||||
 | 
						) tff_i (
 | 
				
			||||||
 | 
							.CLK(CK),
 | 
				
			||||||
 | 
							.LSR(PD),
 | 
				
			||||||
 | 
							.DI(D),
 | 
				
			||||||
 | 
							.Q(Q)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										203
									
								
								techlibs/ecp5/ecp5_ffinit.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								techlibs/ecp5/ecp5_ffinit.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,203 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *  Copyright (C) 2018-19  David Shah <david@symbioticeda.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.h"
 | 
				
			||||||
 | 
					#include "kernel/sigtools.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Ecp5FfinitPass : public Pass {
 | 
				
			||||||
 | 
						Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { }
 | 
				
			||||||
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    ecp5_ffinit [options] [selection]\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("Remove init values for FF output signals when equal to reset value.\n");
 | 
				
			||||||
 | 
							log("If reset is not used, set the reset value to the init value, otherwise\n");
 | 
				
			||||||
 | 
							log("unmap out the reset (if not an async reset).\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t argidx;
 | 
				
			||||||
 | 
							for (argidx = 1; argidx < args.size(); argidx++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// if (args[argidx] == "-singleton") {
 | 
				
			||||||
 | 
								// 	singleton_mode = true;
 | 
				
			||||||
 | 
								// 	continue;
 | 
				
			||||||
 | 
								// }
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto module : design->selected_modules())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								log("Handling FF init values in %s.\n", log_id(module));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SigMap sigmap(module);
 | 
				
			||||||
 | 
								pool<Wire*> init_wires;
 | 
				
			||||||
 | 
								dict<SigBit, State> initbits;
 | 
				
			||||||
 | 
								dict<SigBit, SigBit> initbit_to_wire;
 | 
				
			||||||
 | 
								pool<SigBit> handled_initbits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto wire : module->selected_wires())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (wire->attributes.count("\\init") == 0)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SigSpec wirebits = sigmap(wire);
 | 
				
			||||||
 | 
									Const initval = wire->attributes.at("\\init");
 | 
				
			||||||
 | 
									init_wires.insert(wire);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										SigBit bit = wirebits[i];
 | 
				
			||||||
 | 
										State val = initval[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (val != State::S0 && val != State::S1)
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (initbits.count(bit)) {
 | 
				
			||||||
 | 
											if (initbits.at(bit) != val) {
 | 
				
			||||||
 | 
												log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n",
 | 
				
			||||||
 | 
														log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val),
 | 
				
			||||||
 | 
														log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit)));
 | 
				
			||||||
 | 
												initbits.at(bit) = State::Sx;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										initbits[bit] = val;
 | 
				
			||||||
 | 
										initbit_to_wire[bit] = SigBit(wire, i);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (auto cell : module->selected_cells())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (cell->type != "\\TRELLIS_FF")
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									SigSpec sig_d = cell->getPort("\\DI");
 | 
				
			||||||
 | 
									SigSpec sig_q = cell->getPort("\\Q");
 | 
				
			||||||
 | 
									SigSpec sig_lsr = cell->getPort("\\LSR");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SigBit bit_d = sigmap(sig_d[0]);
 | 
				
			||||||
 | 
									SigBit bit_q = sigmap(sig_q[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									std::string regset = "RESET";
 | 
				
			||||||
 | 
									if (cell->hasParam("\\REGSET"))
 | 
				
			||||||
 | 
										regset = cell->getParam("\\REGSET").decode_string();
 | 
				
			||||||
 | 
									State resetState;
 | 
				
			||||||
 | 
									if (regset == "SET")
 | 
				
			||||||
 | 
										resetState = State::S1;
 | 
				
			||||||
 | 
									else if (regset == "RESET")
 | 
				
			||||||
 | 
										resetState = State::S0;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										log_error("FF cell %s has illegal REGSET value %s.\n",
 | 
				
			||||||
 | 
											log_id(cell), regset.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!initbits.count(bit_q))
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									State val = initbits.at(bit_q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (val == State::Sx)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
 | 
				
			||||||
 | 
											log_signal(bit_q), val != State::S0 ? '1' : '0');
 | 
				
			||||||
 | 
									// Initval is the same as the reset state. Matches hardware, nowt more to do
 | 
				
			||||||
 | 
									if (val == resetState) {
 | 
				
			||||||
 | 
										handled_initbits.insert(bit_q);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) {
 | 
				
			||||||
 | 
										std::string srmode = "LSR_OVER_CE";
 | 
				
			||||||
 | 
										if (cell->hasParam("\\SRMODE"))
 | 
				
			||||||
 | 
											srmode = cell->getParam("\\SRMODE").decode_string();
 | 
				
			||||||
 | 
										if (srmode == "ASYNC") {
 | 
				
			||||||
 | 
											log("Async reset value %c for FF cell %s inconsistent with init value %c.\n",
 | 
				
			||||||
 | 
												resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0');
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											SigBit bit_lsr = sigmap(sig_lsr[0]);
 | 
				
			||||||
 | 
											Wire *new_bit_d = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
											if (resetState == State::S0) {
 | 
				
			||||||
 | 
												module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d);
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											cell->setPort("\\DI", new_bit_d);
 | 
				
			||||||
 | 
											cell->setPort("\\LSR", State::S0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if(cell->hasPort("\\CE")) {
 | 
				
			||||||
 | 
												std::string cemux = "CE";
 | 
				
			||||||
 | 
												if (cell->hasParam("\\CEMUX"))
 | 
				
			||||||
 | 
													cemux = cell->getParam("\\CEMUX").decode_string();
 | 
				
			||||||
 | 
												SigSpec sig_ce = cell->getPort("\\CE");
 | 
				
			||||||
 | 
												if (GetSize(sig_ce) >= 1) {
 | 
				
			||||||
 | 
													SigBit bit_ce = sigmap(sig_ce[0]);
 | 
				
			||||||
 | 
													Wire *new_bit_ce = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
													if (cemux == "INV")
 | 
				
			||||||
 | 
														module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce);
 | 
				
			||||||
 | 
													else
 | 
				
			||||||
 | 
														module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce);
 | 
				
			||||||
 | 
													cell->setPort("\\CE", new_bit_ce);
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET"));
 | 
				
			||||||
 | 
											handled_initbits.insert(bit_q);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET"));
 | 
				
			||||||
 | 
										handled_initbits.insert(bit_q);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (auto wire : init_wires)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (wire->attributes.count("\\init") == 0)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SigSpec wirebits = sigmap(wire);
 | 
				
			||||||
 | 
									Const &initval = wire->attributes.at("\\init");
 | 
				
			||||||
 | 
									bool remove_attribute = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) {
 | 
				
			||||||
 | 
										if (handled_initbits.count(wirebits[i]))
 | 
				
			||||||
 | 
											initval[i] = State::Sx;
 | 
				
			||||||
 | 
										else if (initval[i] != State::Sx)
 | 
				
			||||||
 | 
											remove_attribute = false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (remove_attribute)
 | 
				
			||||||
 | 
										wire->attributes.erase("\\init");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} Ecp5FfinitPass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
| 
						 | 
					@ -255,10 +255,7 @@ struct SynthEcp5Pass : public ScriptPass
 | 
				
			||||||
			run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
 | 
								run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
 | 
				
			||||||
			run("opt_expr -mux_undef");
 | 
								run("opt_expr -mux_undef");
 | 
				
			||||||
			run("simplemap");
 | 
								run("simplemap");
 | 
				
			||||||
			// TODO
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
			run("ecp5_ffinit");
 | 
								run("ecp5_ffinit");
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (check_label("map_luts"))
 | 
							if (check_label("map_luts"))
 | 
				
			||||||
| 
						 | 
					@ -268,9 +265,9 @@ struct SynthEcp5Pass : public ScriptPass
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			run("techmap -map +/ecp5/latches_map.v");
 | 
								run("techmap -map +/ecp5/latches_map.v");
 | 
				
			||||||
			if (nomux)
 | 
								if (nomux)
 | 
				
			||||||
				run("abc -lut 4");
 | 
									run("abc -lut 4 -dress");
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				run("abc -lut 4:7");
 | 
									run("abc -lut 4:7 -dress");
 | 
				
			||||||
			run("clean");
 | 
								run("clean");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,24 +25,24 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
   parameter A_WIDTH = 1;
 | 
					   parameter A_WIDTH = 1;
 | 
				
			||||||
   parameter B_WIDTH = 1;
 | 
					   parameter B_WIDTH = 1;
 | 
				
			||||||
   parameter Y_WIDTH = 1;
 | 
					   parameter Y_WIDTH = 1;
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   input [A_WIDTH-1:0] A;
 | 
					   input [A_WIDTH-1:0] A;
 | 
				
			||||||
   input [B_WIDTH-1:0] B;
 | 
					   input [B_WIDTH-1:0] B;
 | 
				
			||||||
   output [Y_WIDTH-1:0] X, Y;
 | 
					   output [Y_WIDTH-1:0] X, Y;
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   input 		CI, BI;
 | 
					   input 		CI, BI;
 | 
				
			||||||
   output [Y_WIDTH-1:0] CO;
 | 
					   output [Y_WIDTH-1:0] CO;
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   wire 		_TECHMAP_FAIL_ = Y_WIDTH <= 2;
 | 
					   wire 		_TECHMAP_FAIL_ = Y_WIDTH <= 2;
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   wire [Y_WIDTH-1:0] 	A_buf, B_buf;
 | 
					   wire [Y_WIDTH-1:0] 	A_buf, B_buf;
 | 
				
			||||||
   \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
 | 
					   \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
 | 
				
			||||||
   \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
 | 
					   \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   wire [Y_WIDTH-1:0] 	AA = A_buf;
 | 
					   wire [Y_WIDTH-1:0] 	AA = A_buf;
 | 
				
			||||||
   wire [Y_WIDTH-1:0] 	BB = BI ? ~B_buf : B_buf;
 | 
					   wire [Y_WIDTH-1:0] 	BB = BI ? ~B_buf : B_buf;
 | 
				
			||||||
   wire [Y_WIDTH-1:0] 	C = {CO, CI};
 | 
					   wire [Y_WIDTH-1:0] 	C = {CO, CI};
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   genvar 		i;
 | 
					   genvar 		i;
 | 
				
			||||||
   generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
 | 
					   generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
 | 
				
			||||||
      ALU #(.ALU_MODE(32'b0))
 | 
					      ALU #(.ALU_MODE(32'b0))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,7 +111,7 @@ struct SynthGowinPass : public ScriptPass
 | 
				
			||||||
			if (args[argidx] == "-noflatten") {
 | 
								if (args[argidx] == "-noflatten") {
 | 
				
			||||||
				flatten = false;
 | 
									flatten = false;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}			
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		extra_args(args, argidx, design);
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,14 +112,14 @@ module GP_OBUFT(input IN, input OE, output OUT);
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module \$lut (A, Y);
 | 
					module \$lut (A, Y);
 | 
				
			||||||
  parameter WIDTH = 0;
 | 
						parameter WIDTH = 0;
 | 
				
			||||||
  parameter LUT = 0;
 | 
						parameter LUT = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  input [WIDTH-1:0] A;
 | 
						input [WIDTH-1:0] A;
 | 
				
			||||||
  output Y;
 | 
						output Y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  generate
 | 
						generate
 | 
				
			||||||
    if (WIDTH == 1) begin
 | 
							if (WIDTH == 1) begin
 | 
				
			||||||
		if(LUT == 2'b01) begin
 | 
							if(LUT == 2'b01) begin
 | 
				
			||||||
			GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) );
 | 
								GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) );
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
| 
						 | 
					@ -127,22 +127,22 @@ module \$lut (A, Y);
 | 
				
			||||||
			GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
								GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
				
			||||||
				.IN0(A[0]), .IN1(1'b0));
 | 
									.IN0(A[0]), .IN1(1'b0));
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
    end else
 | 
							end else
 | 
				
			||||||
    if (WIDTH == 2) begin
 | 
							if (WIDTH == 2) begin
 | 
				
			||||||
      GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
								GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
				
			||||||
      	.IN0(A[0]), .IN1(A[1]));
 | 
									.IN0(A[0]), .IN1(A[1]));
 | 
				
			||||||
    end else
 | 
							end else
 | 
				
			||||||
    if (WIDTH == 3) begin
 | 
							if (WIDTH == 3) begin
 | 
				
			||||||
      GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
								GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
				
			||||||
      	.IN0(A[0]), .IN1(A[1]), .IN2(A[2]));
 | 
									.IN0(A[0]), .IN1(A[1]), .IN2(A[2]));
 | 
				
			||||||
    end else
 | 
							end else
 | 
				
			||||||
    if (WIDTH == 4) begin
 | 
							if (WIDTH == 4) begin
 | 
				
			||||||
      GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
								GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
 | 
				
			||||||
      	.IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3]));
 | 
									.IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3]));
 | 
				
			||||||
    end else begin
 | 
							end else begin
 | 
				
			||||||
      wire _TECHMAP_FAIL_ = 1;
 | 
								wire _TECHMAP_FAIL_ = 1;
 | 
				
			||||||
    end
 | 
							end
 | 
				
			||||||
  endgenerate
 | 
						endgenerate
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
 | 
					module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS += techlibs/ice40/synth_ice40.o
 | 
					OBJS += techlibs/ice40/synth_ice40.o
 | 
				
			||||||
 | 
					OBJS += techlibs/ice40/ice40_braminit.o
 | 
				
			||||||
OBJS += techlibs/ice40/ice40_ffssr.o
 | 
					OBJS += techlibs/ice40/ice40_ffssr.o
 | 
				
			||||||
OBJS += techlibs/ice40/ice40_ffinit.o
 | 
					OBJS += techlibs/ice40/ice40_ffinit.o
 | 
				
			||||||
OBJS += techlibs/ice40/ice40_opt.o
 | 
					OBJS += techlibs/ice40/ice40_opt.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,8 @@ module \$__ICE40_RAM4K (
 | 
				
			||||||
	input  [10:0] WADDR,
 | 
						input  [10:0] WADDR,
 | 
				
			||||||
	input  [15:0] MASK, WDATA
 | 
						input  [15:0] MASK, WDATA
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
	parameter integer READ_MODE = 0;
 | 
						parameter [1:0] READ_MODE = 0;
 | 
				
			||||||
	parameter integer WRITE_MODE = 0;
 | 
						parameter [1:0] WRITE_MODE = 0;
 | 
				
			||||||
	parameter [0:0] NEGCLK_R = 0;
 | 
						parameter [0:0] NEGCLK_R = 0;
 | 
				
			||||||
	parameter [0:0] NEGCLK_W = 0;
 | 
						parameter [0:0] NEGCLK_W = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,6 +326,8 @@ module SB_RAM40_4K (
 | 
				
			||||||
	parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
	parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parameter INIT_FILE = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`ifndef BLACKBOX
 | 
					`ifndef BLACKBOX
 | 
				
			||||||
	wire [15:0] WMASK_I;
 | 
						wire [15:0] WMASK_I;
 | 
				
			||||||
	wire [15:0] RMASK_I;
 | 
						wire [15:0] RMASK_I;
 | 
				
			||||||
| 
						 | 
					@ -408,43 +410,27 @@ module SB_RAM40_4K (
 | 
				
			||||||
	reg [15:0] memory [0:255];
 | 
						reg [15:0] memory [0:255];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initial begin
 | 
						initial begin
 | 
				
			||||||
		for (i=0; i<16; i=i+1) begin
 | 
							if (INIT_FILE != "")
 | 
				
			||||||
`ifdef YOSYS
 | 
								$readmemh(INIT_FILE, memory);
 | 
				
			||||||
			memory[ 0*16 + i] <= INIT_0[16*i +: 16];
 | 
							else
 | 
				
			||||||
			memory[ 1*16 + i] <= INIT_1[16*i +: 16];
 | 
								for (i=0; i<16; i=i+1) begin
 | 
				
			||||||
			memory[ 2*16 + i] <= INIT_2[16*i +: 16];
 | 
									memory[ 0*16 + i] = INIT_0[16*i +: 16];
 | 
				
			||||||
			memory[ 3*16 + i] <= INIT_3[16*i +: 16];
 | 
									memory[ 1*16 + i] = INIT_1[16*i +: 16];
 | 
				
			||||||
			memory[ 4*16 + i] <= INIT_4[16*i +: 16];
 | 
									memory[ 2*16 + i] = INIT_2[16*i +: 16];
 | 
				
			||||||
			memory[ 5*16 + i] <= INIT_5[16*i +: 16];
 | 
									memory[ 3*16 + i] = INIT_3[16*i +: 16];
 | 
				
			||||||
			memory[ 6*16 + i] <= INIT_6[16*i +: 16];
 | 
									memory[ 4*16 + i] = INIT_4[16*i +: 16];
 | 
				
			||||||
			memory[ 7*16 + i] <= INIT_7[16*i +: 16];
 | 
									memory[ 5*16 + i] = INIT_5[16*i +: 16];
 | 
				
			||||||
			memory[ 8*16 + i] <= INIT_8[16*i +: 16];
 | 
									memory[ 6*16 + i] = INIT_6[16*i +: 16];
 | 
				
			||||||
			memory[ 9*16 + i] <= INIT_9[16*i +: 16];
 | 
									memory[ 7*16 + i] = INIT_7[16*i +: 16];
 | 
				
			||||||
			memory[10*16 + i] <= INIT_A[16*i +: 16];
 | 
									memory[ 8*16 + i] = INIT_8[16*i +: 16];
 | 
				
			||||||
			memory[11*16 + i] <= INIT_B[16*i +: 16];
 | 
									memory[ 9*16 + i] = INIT_9[16*i +: 16];
 | 
				
			||||||
			memory[12*16 + i] <= INIT_C[16*i +: 16];
 | 
									memory[10*16 + i] = INIT_A[16*i +: 16];
 | 
				
			||||||
			memory[13*16 + i] <= INIT_D[16*i +: 16];
 | 
									memory[11*16 + i] = INIT_B[16*i +: 16];
 | 
				
			||||||
			memory[14*16 + i] <= INIT_E[16*i +: 16];
 | 
									memory[12*16 + i] = INIT_C[16*i +: 16];
 | 
				
			||||||
			memory[15*16 + i] <= INIT_F[16*i +: 16];
 | 
									memory[13*16 + i] = INIT_D[16*i +: 16];
 | 
				
			||||||
`else
 | 
									memory[14*16 + i] = INIT_E[16*i +: 16];
 | 
				
			||||||
			memory[ 0*16 + i] = INIT_0[16*i +: 16];
 | 
									memory[15*16 + i] = INIT_F[16*i +: 16];
 | 
				
			||||||
			memory[ 1*16 + i] = INIT_1[16*i +: 16];
 | 
								end
 | 
				
			||||||
			memory[ 2*16 + i] = INIT_2[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 3*16 + i] = INIT_3[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 4*16 + i] = INIT_4[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 5*16 + i] = INIT_5[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 6*16 + i] = INIT_6[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 7*16 + i] = INIT_7[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 8*16 + i] = INIT_8[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[ 9*16 + i] = INIT_9[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[10*16 + i] = INIT_A[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[11*16 + i] = INIT_B[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[12*16 + i] = INIT_C[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[13*16 + i] = INIT_D[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[14*16 + i] = INIT_E[16*i +: 16];
 | 
					 | 
				
			||||||
			memory[15*16 + i] = INIT_F[16*i +: 16];
 | 
					 | 
				
			||||||
`endif
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	always @(posedge WCLK) begin
 | 
						always @(posedge WCLK) begin
 | 
				
			||||||
| 
						 | 
					@ -504,6 +490,8 @@ module SB_RAM40_4KNR (
 | 
				
			||||||
	parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
	parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parameter INIT_FILE = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SB_RAM40_4K #(
 | 
						SB_RAM40_4K #(
 | 
				
			||||||
		.WRITE_MODE(WRITE_MODE),
 | 
							.WRITE_MODE(WRITE_MODE),
 | 
				
			||||||
		.READ_MODE (READ_MODE ),
 | 
							.READ_MODE (READ_MODE ),
 | 
				
			||||||
| 
						 | 
					@ -522,7 +510,8 @@ module SB_RAM40_4KNR (
 | 
				
			||||||
		.INIT_C    (INIT_C    ),
 | 
							.INIT_C    (INIT_C    ),
 | 
				
			||||||
		.INIT_D    (INIT_D    ),
 | 
							.INIT_D    (INIT_D    ),
 | 
				
			||||||
		.INIT_E    (INIT_E    ),
 | 
							.INIT_E    (INIT_E    ),
 | 
				
			||||||
		.INIT_F    (INIT_F    )
 | 
							.INIT_F    (INIT_F    ),
 | 
				
			||||||
 | 
							.INIT_FILE (INIT_FILE )
 | 
				
			||||||
	) RAM (
 | 
						) RAM (
 | 
				
			||||||
		.RDATA(RDATA),
 | 
							.RDATA(RDATA),
 | 
				
			||||||
		.RCLK (~RCLKN),
 | 
							.RCLK (~RCLKN),
 | 
				
			||||||
| 
						 | 
					@ -566,6 +555,8 @@ module SB_RAM40_4KNW (
 | 
				
			||||||
	parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
	parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parameter INIT_FILE = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SB_RAM40_4K #(
 | 
						SB_RAM40_4K #(
 | 
				
			||||||
		.WRITE_MODE(WRITE_MODE),
 | 
							.WRITE_MODE(WRITE_MODE),
 | 
				
			||||||
		.READ_MODE (READ_MODE ),
 | 
							.READ_MODE (READ_MODE ),
 | 
				
			||||||
| 
						 | 
					@ -584,7 +575,8 @@ module SB_RAM40_4KNW (
 | 
				
			||||||
		.INIT_C    (INIT_C    ),
 | 
							.INIT_C    (INIT_C    ),
 | 
				
			||||||
		.INIT_D    (INIT_D    ),
 | 
							.INIT_D    (INIT_D    ),
 | 
				
			||||||
		.INIT_E    (INIT_E    ),
 | 
							.INIT_E    (INIT_E    ),
 | 
				
			||||||
		.INIT_F    (INIT_F    )
 | 
							.INIT_F    (INIT_F    ),
 | 
				
			||||||
 | 
							.INIT_FILE (INIT_FILE )
 | 
				
			||||||
	) RAM (
 | 
						) RAM (
 | 
				
			||||||
		.RDATA(RDATA),
 | 
							.RDATA(RDATA),
 | 
				
			||||||
		.RCLK (RCLK ),
 | 
							.RCLK (RCLK ),
 | 
				
			||||||
| 
						 | 
					@ -628,6 +620,8 @@ module SB_RAM40_4KNRNW (
 | 
				
			||||||
	parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
	parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
						parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parameter INIT_FILE = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SB_RAM40_4K #(
 | 
						SB_RAM40_4K #(
 | 
				
			||||||
		.WRITE_MODE(WRITE_MODE),
 | 
							.WRITE_MODE(WRITE_MODE),
 | 
				
			||||||
		.READ_MODE (READ_MODE ),
 | 
							.READ_MODE (READ_MODE ),
 | 
				
			||||||
| 
						 | 
					@ -646,7 +640,8 @@ module SB_RAM40_4KNRNW (
 | 
				
			||||||
		.INIT_C    (INIT_C    ),
 | 
							.INIT_C    (INIT_C    ),
 | 
				
			||||||
		.INIT_D    (INIT_D    ),
 | 
							.INIT_D    (INIT_D    ),
 | 
				
			||||||
		.INIT_E    (INIT_E    ),
 | 
							.INIT_E    (INIT_E    ),
 | 
				
			||||||
		.INIT_F    (INIT_F    )
 | 
							.INIT_F    (INIT_F    ),
 | 
				
			||||||
 | 
							.INIT_FILE (INIT_FILE )
 | 
				
			||||||
	) RAM (
 | 
						) RAM (
 | 
				
			||||||
		.RDATA(RDATA),
 | 
							.RDATA(RDATA),
 | 
				
			||||||
		.RCLK (~RCLKN),
 | 
							.RCLK (~RCLKN),
 | 
				
			||||||
| 
						 | 
					@ -886,59 +881,6 @@ module SB_WARMBOOT (
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UltraPlus feature cells
 | 
					 | 
				
			||||||
(* blackbox *)
 | 
					 | 
				
			||||||
module SB_MAC16 (
 | 
					 | 
				
			||||||
	input CLK,
 | 
					 | 
				
			||||||
	input CE,
 | 
					 | 
				
			||||||
	input [15:0] C,
 | 
					 | 
				
			||||||
	input [15:0] A,
 | 
					 | 
				
			||||||
	input [15:0] B,
 | 
					 | 
				
			||||||
	input [15:0] D,
 | 
					 | 
				
			||||||
	input AHOLD,
 | 
					 | 
				
			||||||
	input BHOLD,
 | 
					 | 
				
			||||||
	input CHOLD,
 | 
					 | 
				
			||||||
	input DHOLD,
 | 
					 | 
				
			||||||
	input IRSTTOP,
 | 
					 | 
				
			||||||
	input IRSTBOT,
 | 
					 | 
				
			||||||
	input ORSTTOP,
 | 
					 | 
				
			||||||
	input ORSTBOT,
 | 
					 | 
				
			||||||
	input OLOADTOP,
 | 
					 | 
				
			||||||
	input OLOADBOT,
 | 
					 | 
				
			||||||
	input ADDSUBTOP,
 | 
					 | 
				
			||||||
	input ADDSUBBOT,
 | 
					 | 
				
			||||||
	input OHOLDTOP,
 | 
					 | 
				
			||||||
	input OHOLDBOT,
 | 
					 | 
				
			||||||
	input CI,
 | 
					 | 
				
			||||||
	input ACCUMCI,
 | 
					 | 
				
			||||||
	input SIGNEXTIN,
 | 
					 | 
				
			||||||
	output [31:0] O,
 | 
					 | 
				
			||||||
	output CO,
 | 
					 | 
				
			||||||
	output ACCUMCO,
 | 
					 | 
				
			||||||
	output SIGNEXTOUT
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
parameter NEG_TRIGGER = 1'b0;
 | 
					 | 
				
			||||||
parameter C_REG = 1'b0;
 | 
					 | 
				
			||||||
parameter A_REG = 1'b0;
 | 
					 | 
				
			||||||
parameter B_REG = 1'b0;
 | 
					 | 
				
			||||||
parameter D_REG = 1'b0;
 | 
					 | 
				
			||||||
parameter TOP_8x8_MULT_REG = 1'b0;
 | 
					 | 
				
			||||||
parameter BOT_8x8_MULT_REG = 1'b0;
 | 
					 | 
				
			||||||
parameter PIPELINE_16x16_MULT_REG1 = 1'b0;
 | 
					 | 
				
			||||||
parameter PIPELINE_16x16_MULT_REG2 = 1'b0;
 | 
					 | 
				
			||||||
parameter TOPOUTPUT_SELECT =  2'b00;
 | 
					 | 
				
			||||||
parameter TOPADDSUB_LOWERINPUT = 2'b00;
 | 
					 | 
				
			||||||
parameter TOPADDSUB_UPPERINPUT = 1'b0;
 | 
					 | 
				
			||||||
parameter TOPADDSUB_CARRYSELECT = 2'b00;
 | 
					 | 
				
			||||||
parameter BOTOUTPUT_SELECT =  2'b00;
 | 
					 | 
				
			||||||
parameter BOTADDSUB_LOWERINPUT = 2'b00;
 | 
					 | 
				
			||||||
parameter BOTADDSUB_UPPERINPUT = 1'b0;
 | 
					 | 
				
			||||||
parameter BOTADDSUB_CARRYSELECT = 2'b00;
 | 
					 | 
				
			||||||
parameter MODE_8x8 = 1'b0;
 | 
					 | 
				
			||||||
parameter A_SIGNED = 1'b0;
 | 
					 | 
				
			||||||
parameter B_SIGNED = 1'b0;
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module SB_SPRAM256KA (
 | 
					module SB_SPRAM256KA (
 | 
				
			||||||
	input [13:0] ADDRESS,
 | 
						input [13:0] ADDRESS,
 | 
				
			||||||
	input [15:0] DATAIN,
 | 
						input [15:0] DATAIN,
 | 
				
			||||||
| 
						 | 
					@ -1273,3 +1215,171 @@ module SB_IO_OD (
 | 
				
			||||||
	endgenerate
 | 
						endgenerate
 | 
				
			||||||
`endif
 | 
					`endif
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module SB_MAC16 (
 | 
				
			||||||
 | 
						input CLK, CE,
 | 
				
			||||||
 | 
						input [15:0] C, A, B, D,
 | 
				
			||||||
 | 
						input AHOLD, BHOLD, CHOLD, DHOLD,
 | 
				
			||||||
 | 
						input IRSTTOP, IRSTBOT,
 | 
				
			||||||
 | 
						input ORSTTOP, ORSTBOT,
 | 
				
			||||||
 | 
						input OLOADTOP, OLOADBOT,
 | 
				
			||||||
 | 
						input ADDSUBTOP, ADDSUBBOT,
 | 
				
			||||||
 | 
						input OHOLDTOP, OHOLDBOT,
 | 
				
			||||||
 | 
						input CI, ACCUMCI, SIGNEXTIN,
 | 
				
			||||||
 | 
						output [31:0] O,
 | 
				
			||||||
 | 
						output CO, ACCUMCO, SIGNEXTOUT
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter [0:0] NEG_TRIGGER = 0;
 | 
				
			||||||
 | 
						parameter [0:0] C_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] A_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] B_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] D_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] TOP_8x8_MULT_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] BOT_8x8_MULT_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0;
 | 
				
			||||||
 | 
						parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0;
 | 
				
			||||||
 | 
						parameter [1:0] TOPOUTPUT_SELECT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] TOPADDSUB_LOWERINPUT = 0;
 | 
				
			||||||
 | 
						parameter [0:0] TOPADDSUB_UPPERINPUT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] TOPADDSUB_CARRYSELECT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] BOTOUTPUT_SELECT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] BOTADDSUB_LOWERINPUT = 0;
 | 
				
			||||||
 | 
						parameter [0:0] BOTADDSUB_UPPERINPUT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] BOTADDSUB_CARRYSELECT = 0;
 | 
				
			||||||
 | 
						parameter [0:0] MODE_8x8 = 0;
 | 
				
			||||||
 | 
						parameter [0:0] A_SIGNED = 0;
 | 
				
			||||||
 | 
						parameter [0:0] B_SIGNED = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire clock = CLK ^ NEG_TRIGGER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// internal wires, compare Figure on page 133 of ICE Technology Library 3.0 and Fig 2 on page 2 of Lattice TN1295-DSP
 | 
				
			||||||
 | 
						// http://www.latticesemi.com/~/media/LatticeSemi/Documents/TechnicalBriefs/SBTICETechnologyLibrary201608.pdf
 | 
				
			||||||
 | 
						// https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/AD/DSPFunctionUsageGuideforICE40Devices.ashx
 | 
				
			||||||
 | 
						wire [15:0] iA, iB, iC, iD;
 | 
				
			||||||
 | 
						wire [15:0] iF, iJ, iK, iG;
 | 
				
			||||||
 | 
						wire [31:0] iL, iH;
 | 
				
			||||||
 | 
						wire [15:0] iW, iX, iP, iQ;
 | 
				
			||||||
 | 
						wire [15:0] iY, iZ, iR, iS;
 | 
				
			||||||
 | 
						wire HCI, LCI, LCO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Regs C and A
 | 
				
			||||||
 | 
						reg [15:0] rC, rA;
 | 
				
			||||||
 | 
						always @(posedge clock, posedge IRSTTOP) begin
 | 
				
			||||||
 | 
							if (IRSTTOP) begin
 | 
				
			||||||
 | 
								rC <= 0;
 | 
				
			||||||
 | 
								rA <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								if (!CHOLD) rC <= C;
 | 
				
			||||||
 | 
								if (!AHOLD) rA <= A;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iC = C_REG ? rC : C;
 | 
				
			||||||
 | 
						assign iA = A_REG ? rA : A;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Regs B and D
 | 
				
			||||||
 | 
						reg [15:0] rB, rD;
 | 
				
			||||||
 | 
						always @(posedge clock, posedge IRSTBOT) begin
 | 
				
			||||||
 | 
							if (IRSTBOT) begin
 | 
				
			||||||
 | 
								rB <= 0;
 | 
				
			||||||
 | 
								rD <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								if (!BHOLD) rB <= B;
 | 
				
			||||||
 | 
								if (!DHOLD) rD <= D;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iB = B_REG ? rB : B;
 | 
				
			||||||
 | 
						assign iD = D_REG ? rD : D;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Multiplier Stage
 | 
				
			||||||
 | 
						wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl;
 | 
				
			||||||
 | 
						wire [15:0] Ah, Al, Bh, Bl;
 | 
				
			||||||
 | 
						assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]};
 | 
				
			||||||
 | 
						assign Al = {A_SIGNED ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
 | 
				
			||||||
 | 
						assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]};
 | 
				
			||||||
 | 
						assign Bl = {B_SIGNED ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
 | 
				
			||||||
 | 
						assign p_Ah_Bh = Ah * Bh;
 | 
				
			||||||
 | 
						assign p_Al_Bh = Al * Bh;
 | 
				
			||||||
 | 
						assign p_Ah_Bl = Ah * Bl;
 | 
				
			||||||
 | 
						assign p_Al_Bl = Al * Bl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Regs F and J
 | 
				
			||||||
 | 
						reg [15:0] rF, rJ;
 | 
				
			||||||
 | 
						always @(posedge clock, posedge IRSTTOP) begin
 | 
				
			||||||
 | 
							if (IRSTTOP) begin
 | 
				
			||||||
 | 
								rF <= 0;
 | 
				
			||||||
 | 
								rJ <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								rF <= p_Ah_Bh;
 | 
				
			||||||
 | 
								if (!MODE_8x8) rJ <= p_Al_Bh;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iF = TOP_8x8_MULT_REG ? rF : p_Ah_Bh;
 | 
				
			||||||
 | 
						assign iJ = PIPELINE_16x16_MULT_REG1 ? rJ : p_Al_Bh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Regs K and G
 | 
				
			||||||
 | 
						reg [15:0] rK, rG;
 | 
				
			||||||
 | 
						always @(posedge clock, posedge IRSTBOT) begin
 | 
				
			||||||
 | 
							if (IRSTBOT) begin
 | 
				
			||||||
 | 
								rK <= 0;
 | 
				
			||||||
 | 
								rG <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								if (!MODE_8x8) rK <= p_Ah_Bl;
 | 
				
			||||||
 | 
								rG <= p_Al_Bl;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iK = PIPELINE_16x16_MULT_REG1 ? rK : p_Ah_Bl;
 | 
				
			||||||
 | 
						assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Adder Stage
 | 
				
			||||||
 | 
						assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reg H
 | 
				
			||||||
 | 
						reg [31:0] rH;
 | 
				
			||||||
 | 
						always @(posedge clock, posedge IRSTBOT) begin
 | 
				
			||||||
 | 
							if (IRSTBOT) begin
 | 
				
			||||||
 | 
								rH <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								if (!MODE_8x8) rH <= iL;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iH = PIPELINE_16x16_MULT_REG2 ? rH : iL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Hi Output Stage
 | 
				
			||||||
 | 
						wire [15:0] XW, Oh;
 | 
				
			||||||
 | 
						reg [15:0] rQ;
 | 
				
			||||||
 | 
						assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ;
 | 
				
			||||||
 | 
						assign iX = (TOPADDSUB_LOWERINPUT == 0) ? iA : (TOPADDSUB_LOWERINPUT == 1) ? iF : (TOPADDSUB_LOWERINPUT == 2) ? iH[31:16] : {16{iZ[15]}};
 | 
				
			||||||
 | 
						assign {ACCUMCO, XW} = iX + (iW ^ {16{ADDSUBTOP}}) + HCI;
 | 
				
			||||||
 | 
						assign CO = ACCUMCO ^ ADDSUBTOP;
 | 
				
			||||||
 | 
						assign iP = OLOADTOP ? iC : XW ^ {16{ADDSUBTOP}};
 | 
				
			||||||
 | 
						always @(posedge clock, posedge ORSTTOP) begin
 | 
				
			||||||
 | 
							if (ORSTTOP) begin
 | 
				
			||||||
 | 
								rQ <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								if (!OHOLDTOP) rQ <= iP;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iQ = rQ;
 | 
				
			||||||
 | 
						assign Oh = (TOPOUTPUT_SELECT == 0) ? iP : (TOPOUTPUT_SELECT == 1) ? iQ : (TOPOUTPUT_SELECT == 2) ? iF : iH[31:16];
 | 
				
			||||||
 | 
						assign HCI = (TOPADDSUB_CARRYSELECT == 0) ? 1'b0 : (TOPADDSUB_CARRYSELECT == 1) ? 1'b1 : (TOPADDSUB_CARRYSELECT == 2) ? LCO : LCO ^ ADDSUBBOT;
 | 
				
			||||||
 | 
						assign SIGNEXTOUT = iX[15];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Lo Output Stage
 | 
				
			||||||
 | 
						wire [15:0] YZ, Ol;
 | 
				
			||||||
 | 
						reg [15:0] rS;
 | 
				
			||||||
 | 
						assign iY = BOTADDSUB_UPPERINPUT ? iD : iS;
 | 
				
			||||||
 | 
						assign iZ = (BOTADDSUB_LOWERINPUT == 0) ? iB : (BOTADDSUB_LOWERINPUT == 1) ? iG : (BOTADDSUB_LOWERINPUT == 2) ? iH[15:0] : {16{SIGNEXTIN}};
 | 
				
			||||||
 | 
						assign {LCO, YZ} = iZ + (iY ^ {16{ADDSUBBOT}}) + LCI;
 | 
				
			||||||
 | 
						assign iR = OLOADBOT ? iD : YZ ^ {16{ADDSUBBOT}};
 | 
				
			||||||
 | 
						always @(posedge clock, posedge ORSTBOT) begin
 | 
				
			||||||
 | 
							if (ORSTBOT) begin
 | 
				
			||||||
 | 
								rS <= 0;
 | 
				
			||||||
 | 
							end else if (CE) begin
 | 
				
			||||||
 | 
								if (!OHOLDBOT) rS <= iR;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						assign iS = rS;
 | 
				
			||||||
 | 
						assign Ol = (BOTOUTPUT_SELECT == 0) ? iR : (BOTOUTPUT_SELECT == 1) ? iS : (BOTOUTPUT_SELECT == 2) ? iG : iH[15:0];
 | 
				
			||||||
 | 
						assign LCI = (BOTADDSUB_CARRYSELECT == 0) ? 1'b0 : (BOTADDSUB_CARRYSELECT == 1) ? 1'b1 : (BOTADDSUB_CARRYSELECT == 2) ? ACCUMCI : CI;
 | 
				
			||||||
 | 
						assign O = {Oh, Ol};
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										159
									
								
								techlibs/ice40/ice40_braminit.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								techlibs/ice40/ice40_braminit.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,159 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.h"
 | 
				
			||||||
 | 
					#include "kernel/sigtools.h"
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <bitset>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void run_ice40_braminit(Module *module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						for (auto cell : module->selected_cells())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uint16_t mem[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Only consider cells we're interested in */
 | 
				
			||||||
 | 
							if (cell->type != "\\SB_RAM40_4K" &&
 | 
				
			||||||
 | 
							    cell->type != "\\SB_RAM40_4KNR" &&
 | 
				
			||||||
 | 
							    cell->type != "\\SB_RAM40_4KNW" &&
 | 
				
			||||||
 | 
							    cell->type != "\\SB_RAM40_4KNRNW")
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (!cell->hasParam("\\INIT_FILE"))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							std::string init_file = cell->getParam("\\INIT_FILE").decode_string();
 | 
				
			||||||
 | 
							cell->unsetParam("\\INIT_FILE");
 | 
				
			||||||
 | 
							if (init_file == "")
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Open file */
 | 
				
			||||||
 | 
							log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::ifstream f;
 | 
				
			||||||
 | 
							f.open(init_file.c_str());
 | 
				
			||||||
 | 
							if (f.fail()) {
 | 
				
			||||||
 | 
								log("Can not open file `%s`.\n", init_file.c_str());
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Defaults to 0 */
 | 
				
			||||||
 | 
							memset(mem, 0x00, sizeof(mem));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Process each line */
 | 
				
			||||||
 | 
							bool in_comment = false;
 | 
				
			||||||
 | 
							int cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while (!f.eof())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								std::string line, token;
 | 
				
			||||||
 | 
								std::getline(f, line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (int i = 0; i < GetSize(line); i++)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (in_comment && line.substr(i, 2) == "*/") {
 | 
				
			||||||
 | 
										line[i] = ' ';
 | 
				
			||||||
 | 
										line[i+1] = ' ';
 | 
				
			||||||
 | 
										in_comment = false;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (!in_comment && line.substr(i, 2) == "/*")
 | 
				
			||||||
 | 
										in_comment = true;
 | 
				
			||||||
 | 
									if (in_comment)
 | 
				
			||||||
 | 
										line[i] = ' ';
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								while (1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									bool set_cursor = false;
 | 
				
			||||||
 | 
									long value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									token = next_token(line, " \t\r\n");
 | 
				
			||||||
 | 
									if (token.empty() || token.substr(0, 2) == "//")
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (token[0] == '@') {
 | 
				
			||||||
 | 
										token = token.substr(1);
 | 
				
			||||||
 | 
										set_cursor = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									const char *nptr = token.c_str();
 | 
				
			||||||
 | 
									char *endptr;
 | 
				
			||||||
 | 
									value = strtol(nptr, &endptr, 16);
 | 
				
			||||||
 | 
									if (!*nptr || *endptr) {
 | 
				
			||||||
 | 
										log("Can not parse %s `%s` for %s.\n",
 | 
				
			||||||
 | 
											set_cursor ? "address" : "value",
 | 
				
			||||||
 | 
											nptr, token.c_str()
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (set_cursor)
 | 
				
			||||||
 | 
										cursor = value;
 | 
				
			||||||
 | 
									else if (cursor >= 0 && cursor < 256)
 | 
				
			||||||
 | 
										mem[cursor++] = value;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										log("Attempt to initialize non existent address %d\n", cursor);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Set attributes */
 | 
				
			||||||
 | 
							const char *hex = "0123456789ABCDEF";
 | 
				
			||||||
 | 
							for (int i=0; i<16; i++) {
 | 
				
			||||||
 | 
								std::string val = "";
 | 
				
			||||||
 | 
								for (int j=15; j>=0; j--)
 | 
				
			||||||
 | 
									val += std::bitset<16>(mem[i*16+j]).to_string();
 | 
				
			||||||
 | 
								cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Ice40BRAMInitPass : public Pass {
 | 
				
			||||||
 | 
						Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { }
 | 
				
			||||||
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    ice40_braminit\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n");
 | 
				
			||||||
 | 
							log("parameter and converts it into the required INIT_x attributes\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log_header(design, "Executing ICE40_BRAMINIT pass.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							size_t argidx;
 | 
				
			||||||
 | 
							for (argidx = 1; argidx < args.size(); argidx++) {
 | 
				
			||||||
 | 
								// if (args[argidx] == "-???") {
 | 
				
			||||||
 | 
								//  continue;
 | 
				
			||||||
 | 
								// }
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto module : design->selected_modules())
 | 
				
			||||||
 | 
								run_ice40_braminit(module);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} Ice40BRAMInitPass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIVATE_NAMESPACE_END
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,9 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
		log("    -nobram\n");
 | 
							log("    -nobram\n");
 | 
				
			||||||
		log("        do not use SB_RAM40_4K* cells in output netlist\n");
 | 
							log("        do not use SB_RAM40_4K* cells in output netlist\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -dsp\n");
 | 
				
			||||||
 | 
							log("        use iCE40 UltraPlus DSP cells for large arithmetic\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
		log("    -noabc\n");
 | 
							log("    -noabc\n");
 | 
				
			||||||
		log("        use built-in Yosys LUT techmapping instead of abc\n");
 | 
							log("        use built-in Yosys LUT techmapping instead of abc\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
| 
						 | 
					@ -96,7 +99,7 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	string top_opt, blif_file, edif_file, json_file;
 | 
						string top_opt, blif_file, edif_file, json_file;
 | 
				
			||||||
	bool nocarry, nodffe, nobram, flatten, retime, relut, noabc, abc2, vpr;
 | 
						bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
 | 
				
			||||||
	int min_ce_use;
 | 
						int min_ce_use;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void clear_flags() YS_OVERRIDE
 | 
						void clear_flags() YS_OVERRIDE
 | 
				
			||||||
| 
						 | 
					@ -109,6 +112,7 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
		nodffe = false;
 | 
							nodffe = false;
 | 
				
			||||||
		min_ce_use = -1;
 | 
							min_ce_use = -1;
 | 
				
			||||||
		nobram = false;
 | 
							nobram = false;
 | 
				
			||||||
 | 
							dsp = false;
 | 
				
			||||||
		flatten = true;
 | 
							flatten = true;
 | 
				
			||||||
		retime = false;
 | 
							retime = false;
 | 
				
			||||||
		relut = false;
 | 
							relut = false;
 | 
				
			||||||
| 
						 | 
					@ -181,6 +185,10 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
				nobram = true;
 | 
									nobram = true;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-dsp") {
 | 
				
			||||||
 | 
									dsp = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (args[argidx] == "-noabc") {
 | 
								if (args[argidx] == "-noabc") {
 | 
				
			||||||
				noabc = true;
 | 
									noabc = true;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
| 
						 | 
					@ -214,11 +222,11 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			run("read_verilog -lib +/ice40/cells_sim.v");
 | 
								run("read_verilog -lib +/ice40/cells_sim.v");
 | 
				
			||||||
			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
 | 
								run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
 | 
				
			||||||
 | 
								run("proc");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (flatten && check_label("flatten", "(unless -noflatten)"))
 | 
							if (flatten && check_label("flatten", "(unless -noflatten)"))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			run("proc");
 | 
					 | 
				
			||||||
			run("flatten");
 | 
								run("flatten");
 | 
				
			||||||
			run("tribuf -logic");
 | 
								run("tribuf -logic");
 | 
				
			||||||
			run("deminout");
 | 
								run("deminout");
 | 
				
			||||||
| 
						 | 
					@ -226,13 +234,30 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (check_label("coarse"))
 | 
							if (check_label("coarse"))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			run("synth -lut 4 -run coarse");
 | 
								run("opt_expr");
 | 
				
			||||||
 | 
								run("opt_clean");
 | 
				
			||||||
 | 
								run("check");
 | 
				
			||||||
 | 
								run("opt");
 | 
				
			||||||
 | 
								run("wreduce");
 | 
				
			||||||
 | 
								run("share");
 | 
				
			||||||
 | 
								run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
 | 
				
			||||||
 | 
								run("opt_expr");
 | 
				
			||||||
 | 
								run("opt_clean");
 | 
				
			||||||
 | 
								if (help_mode || dsp)
 | 
				
			||||||
 | 
									run("ice40_dsp", "(if -dsp)");
 | 
				
			||||||
 | 
								run("alumacc");
 | 
				
			||||||
 | 
								run("opt");
 | 
				
			||||||
 | 
								run("fsm");
 | 
				
			||||||
 | 
								run("opt -fast");
 | 
				
			||||||
 | 
								run("memory -nomap");
 | 
				
			||||||
 | 
								run("opt_clean");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!nobram && check_label("bram", "(skip if -nobram)"))
 | 
							if (!nobram && check_label("bram", "(skip if -nobram)"))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			run("memory_bram -rules +/ice40/brams.txt");
 | 
								run("memory_bram -rules +/ice40/brams.txt");
 | 
				
			||||||
			run("techmap -map +/ice40/brams_map.v");
 | 
								run("techmap -map +/ice40/brams_map.v");
 | 
				
			||||||
 | 
								run("ice40_braminit");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (check_label("map"))
 | 
							if (check_label("map"))
 | 
				
			||||||
| 
						 | 
					@ -282,7 +307,7 @@ struct SynthIce40Pass : public ScriptPass
 | 
				
			||||||
				run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
 | 
									run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (!noabc) {
 | 
								if (!noabc) {
 | 
				
			||||||
				run("abc -lut 4", "(skip if -noabc)");
 | 
									run("abc -dress -lut 4", "(skip if -noabc)");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			run("clean");
 | 
								run("clean");
 | 
				
			||||||
			if (relut || help_mode) {
 | 
								if (relut || help_mode) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								techlibs/ice40/tests/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								techlibs/ice40/tests/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,2 +1,11 @@
 | 
				
			||||||
test_ffs_[01][01][01][01][01]_*
 | 
					/test_ffs_[01][01][01][01][01]_*
 | 
				
			||||||
test_bram_[0-9]*
 | 
					/test_bram_[0-9]*
 | 
				
			||||||
 | 
					/test_dsp_model
 | 
				
			||||||
 | 
					/test_dsp_model.vcd
 | 
				
			||||||
 | 
					/test_dsp_model_ref.v
 | 
				
			||||||
 | 
					/test_dsp_model_uut.v
 | 
				
			||||||
 | 
					/test_dsp_map
 | 
				
			||||||
 | 
					/test_dsp_map.vcd
 | 
				
			||||||
 | 
					/test_dsp_map_tb.v
 | 
				
			||||||
 | 
					/test_dsp_map_top.v
 | 
				
			||||||
 | 
					/test_dsp_map_syn.v
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										107
									
								
								techlibs/ice40/tests/test_dsp_map.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								techlibs/ice40/tests/test_dsp_map.sh
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					set -ex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for iter in {1..100}
 | 
				
			||||||
 | 
					do
 | 
				
			||||||
 | 
						SZA=$(( 3 + $RANDOM % 13 ))
 | 
				
			||||||
 | 
						SZB=$(( 3 + $RANDOM % 13 ))
 | 
				
			||||||
 | 
						SZO=$(( 3 + $RANDOM % 29 ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						C0=clk$(( $RANDOM & 1))
 | 
				
			||||||
 | 
						C1=clk$(( $RANDOM & 1))
 | 
				
			||||||
 | 
						C2=clk$(( $RANDOM & 1))
 | 
				
			||||||
 | 
						C3=clk$(( $RANDOM & 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
 | 
				
			||||||
 | 
						E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
 | 
				
			||||||
 | 
						E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
 | 
				
			||||||
 | 
						E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" )
 | 
				
			||||||
 | 
						RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cat > test_dsp_map_top.v << EOT
 | 
				
			||||||
 | 
					module top (
 | 
				
			||||||
 | 
						input clk0, clk1, reset,
 | 
				
			||||||
 | 
						input  [$SZA:0] A,
 | 
				
			||||||
 | 
						input  [$SZB:0] B,
 | 
				
			||||||
 | 
						output [$SZO:0] O
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						reg [15:0] AA, BB;
 | 
				
			||||||
 | 
						reg [31:0] P, S;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						always @($E0 $C0) AA <= A;
 | 
				
			||||||
 | 
						always @($E1 $C1) BB <= B;
 | 
				
			||||||
 | 
						always @($E2 $C2) P <= AA * BB;
 | 
				
			||||||
 | 
						always @($E3 $C3) S <= $RC ? $RV : S + P;
 | 
				
			||||||
 | 
						assign O = $SP;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					EOT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cat > test_dsp_map_tb.v << EOT
 | 
				
			||||||
 | 
					\`timescale 1ns / 1ps
 | 
				
			||||||
 | 
					module testbench;
 | 
				
			||||||
 | 
						reg clk1, clk0, reset;
 | 
				
			||||||
 | 
						reg [$SZA:0] A;
 | 
				
			||||||
 | 
						reg [$SZB:0] B;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [$SZO:0] O_top, O_syn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						top top_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_top));
 | 
				
			||||||
 | 
						syn syn_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_syn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						initial begin
 | 
				
			||||||
 | 
							// \$dumpfile("test_dsp_map.vcd");
 | 
				
			||||||
 | 
							// \$dumpvars(0, testbench);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#2;
 | 
				
			||||||
 | 
							clk0 = 0;
 | 
				
			||||||
 | 
							clk1 = 0;
 | 
				
			||||||
 | 
							reset = 1;
 | 
				
			||||||
 | 
							reset = $RC;
 | 
				
			||||||
 | 
							A = 0;
 | 
				
			||||||
 | 
							B = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repeat (3) begin
 | 
				
			||||||
 | 
								#2; clk0 = ~clk0;
 | 
				
			||||||
 | 
								#2; clk0 = ~clk0;
 | 
				
			||||||
 | 
								#2; clk1 = ~clk1;
 | 
				
			||||||
 | 
								#2; clk1 = ~clk1;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repeat (100) begin
 | 
				
			||||||
 | 
								#2;
 | 
				
			||||||
 | 
								A = \$urandom;
 | 
				
			||||||
 | 
								B = \$urandom;
 | 
				
			||||||
 | 
								reset = \$urandom & \$urandom & \$urandom & \$urandom;
 | 
				
			||||||
 | 
								if (\$urandom & 1) begin
 | 
				
			||||||
 | 
									#2; clk0 = ~clk0;
 | 
				
			||||||
 | 
									#2; clk0 = ~clk0;
 | 
				
			||||||
 | 
								end else begin
 | 
				
			||||||
 | 
									#2; clk1 = ~clk1;
 | 
				
			||||||
 | 
									#2; clk1 = ~clk1;
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								#2;
 | 
				
			||||||
 | 
								if (O_top !== O_syn) begin
 | 
				
			||||||
 | 
									\$display("ERROR: O_top=%b O_syn=%b", O_top, O_syn);
 | 
				
			||||||
 | 
									\$stop;
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								// \$display("OK O_top=O_syn=%b", O_top);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							\$display("Test passed.");
 | 
				
			||||||
 | 
							\$finish;
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					EOT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v'
 | 
				
			||||||
 | 
						iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v
 | 
				
			||||||
 | 
						vvp -N test_dsp_map
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					: ""
 | 
				
			||||||
 | 
					: "####  All tests passed.  ####"
 | 
				
			||||||
 | 
					: ""
 | 
				
			||||||
							
								
								
									
										11
									
								
								techlibs/ice40/tests/test_dsp_model.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								techlibs/ice40/tests/test_dsp_model.sh
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					set -ex
 | 
				
			||||||
 | 
					sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v
 | 
				
			||||||
 | 
					cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v
 | 
				
			||||||
 | 
					for tb in testbench \
 | 
				
			||||||
 | 
							testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \
 | 
				
			||||||
 | 
							testbench_seq_16x16_A testbench_seq_16x16_B
 | 
				
			||||||
 | 
					do
 | 
				
			||||||
 | 
						iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v
 | 
				
			||||||
 | 
						vvp -N ./test_dsp_model
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
							
								
								
									
										342
									
								
								techlibs/ice40/tests/test_dsp_model.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								techlibs/ice40/tests/test_dsp_model.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,342 @@
 | 
				
			||||||
 | 
					`timescale 1ns / 1ps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module testbench;
 | 
				
			||||||
 | 
						parameter [0:0] NEG_TRIGGER = 0;
 | 
				
			||||||
 | 
						parameter [0:0] C_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] A_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] B_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] D_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] TOP_8x8_MULT_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] BOT_8x8_MULT_REG = 0;
 | 
				
			||||||
 | 
						parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0;
 | 
				
			||||||
 | 
						parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0;
 | 
				
			||||||
 | 
						parameter [1:0] TOPOUTPUT_SELECT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] TOPADDSUB_LOWERINPUT = 0;
 | 
				
			||||||
 | 
						parameter [0:0] TOPADDSUB_UPPERINPUT = 1;
 | 
				
			||||||
 | 
						parameter [1:0] TOPADDSUB_CARRYSELECT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] BOTOUTPUT_SELECT = 0;
 | 
				
			||||||
 | 
						parameter [1:0] BOTADDSUB_LOWERINPUT = 0;
 | 
				
			||||||
 | 
						parameter [0:0] BOTADDSUB_UPPERINPUT = 1;
 | 
				
			||||||
 | 
						parameter [1:0] BOTADDSUB_CARRYSELECT = 0;
 | 
				
			||||||
 | 
						parameter [0:0] MODE_8x8 = 0;
 | 
				
			||||||
 | 
						parameter [0:0] A_SIGNED = 0;
 | 
				
			||||||
 | 
						parameter [0:0] B_SIGNED = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg CLK, CE;
 | 
				
			||||||
 | 
						reg [15:0] C, A, B, D;
 | 
				
			||||||
 | 
						reg AHOLD, BHOLD, CHOLD, DHOLD;
 | 
				
			||||||
 | 
						reg IRSTTOP, IRSTBOT;
 | 
				
			||||||
 | 
						reg ORSTTOP, ORSTBOT;
 | 
				
			||||||
 | 
						reg OLOADTOP, OLOADBOT;
 | 
				
			||||||
 | 
						reg ADDSUBTOP, ADDSUBBOT;
 | 
				
			||||||
 | 
						reg OHOLDTOP, OHOLDBOT;
 | 
				
			||||||
 | 
						reg CI, ACCUMCI, SIGNEXTIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						output [31:0] REF_O, UUT_O;
 | 
				
			||||||
 | 
						output REF_CO, REF_ACCUMCO, REF_SIGNEXTOUT;
 | 
				
			||||||
 | 
						output UUT_CO, UUT_ACCUMCO, UUT_SIGNEXTOUT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						integer errcount = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						task clkcycle;
 | 
				
			||||||
 | 
							begin
 | 
				
			||||||
 | 
								#5;
 | 
				
			||||||
 | 
								CLK = ~CLK;
 | 
				
			||||||
 | 
								#10;
 | 
				
			||||||
 | 
								CLK = ~CLK;
 | 
				
			||||||
 | 
								#2;
 | 
				
			||||||
 | 
								if (REF_O !== UUT_O) begin
 | 
				
			||||||
 | 
									$display("ERROR at %1t: REF_O=%b UUT_O=%b DIFF=%b", $time, REF_O, UUT_O, REF_O ^ UUT_O);
 | 
				
			||||||
 | 
									errcount = errcount + 1;
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								if (REF_CO !== UUT_CO) begin
 | 
				
			||||||
 | 
									$display("ERROR at %1t: REF_CO=%b UUT_CO=%b", $time, REF_CO, UUT_CO);
 | 
				
			||||||
 | 
									errcount = errcount + 1;
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								if (REF_ACCUMCO !== UUT_ACCUMCO) begin
 | 
				
			||||||
 | 
									$display("ERROR at %1t: REF_ACCUMCO=%b UUT_ACCUMCO=%b", $time, REF_ACCUMCO, UUT_ACCUMCO);
 | 
				
			||||||
 | 
									errcount = errcount + 1;
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								if (REF_SIGNEXTOUT !== UUT_SIGNEXTOUT) begin
 | 
				
			||||||
 | 
									$display("ERROR at %1t: REF_SIGNEXTOUT=%b UUT_SIGNEXTOUT=%b", $time, REF_SIGNEXTOUT, UUT_SIGNEXTOUT);
 | 
				
			||||||
 | 
									errcount = errcount + 1;
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								#3;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						endtask
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						initial begin
 | 
				
			||||||
 | 
							$dumpfile("test_dsp_model.vcd");
 | 
				
			||||||
 | 
							$dumpvars(0, testbench);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#2;
 | 
				
			||||||
 | 
							CLK = NEG_TRIGGER;
 | 
				
			||||||
 | 
							CE = 1;
 | 
				
			||||||
 | 
							{C, A, B, D} = 0;
 | 
				
			||||||
 | 
							{AHOLD, BHOLD, CHOLD, DHOLD} = 0;
 | 
				
			||||||
 | 
							{OLOADTOP, OLOADBOT} = 0;
 | 
				
			||||||
 | 
							{ADDSUBTOP, ADDSUBBOT} = 0;
 | 
				
			||||||
 | 
							{OHOLDTOP, OHOLDBOT} = 0;
 | 
				
			||||||
 | 
							{CI, ACCUMCI, SIGNEXTIN} = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{IRSTTOP, IRSTBOT} = ~0;
 | 
				
			||||||
 | 
							{ORSTTOP, ORSTBOT} = ~0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#3;
 | 
				
			||||||
 | 
							{IRSTTOP, IRSTBOT} = 0;
 | 
				
			||||||
 | 
							{ORSTTOP, ORSTBOT} = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repeat (300) begin
 | 
				
			||||||
 | 
								clkcycle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								A = $urandom;
 | 
				
			||||||
 | 
								B = $urandom;
 | 
				
			||||||
 | 
								C = $urandom;
 | 
				
			||||||
 | 
								D = $urandom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								{AHOLD, BHOLD, CHOLD, DHOLD} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
								{OLOADTOP, OLOADBOT} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
								{ADDSUBTOP, ADDSUBBOT} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
								{OHOLDTOP, OHOLDBOT} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
								{CI, ACCUMCI, SIGNEXTIN} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								{IRSTTOP, IRSTBOT} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
								{ORSTTOP, ORSTBOT} = $urandom & $urandom & $urandom;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (errcount == 0) begin
 | 
				
			||||||
 | 
								$display("All tests passed.");
 | 
				
			||||||
 | 
								$finish;
 | 
				
			||||||
 | 
							end else begin
 | 
				
			||||||
 | 
								$display("Caught %1d errors.", errcount);
 | 
				
			||||||
 | 
								$stop;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SB_MAC16 #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER              (NEG_TRIGGER             ),
 | 
				
			||||||
 | 
							.C_REG                    (C_REG                   ),
 | 
				
			||||||
 | 
							.A_REG                    (A_REG                   ),
 | 
				
			||||||
 | 
							.B_REG                    (B_REG                   ),
 | 
				
			||||||
 | 
							.D_REG                    (D_REG                   ),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG         (TOP_8x8_MULT_REG        ),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG         (BOT_8x8_MULT_REG        ),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT         (TOPOUTPUT_SELECT        ),
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT     (TOPADDSUB_LOWERINPUT    ),
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT     (TOPADDSUB_UPPERINPUT    ),
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT    (TOPADDSUB_CARRYSELECT   ),
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT         (BOTOUTPUT_SELECT        ),
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT     (BOTADDSUB_LOWERINPUT    ),
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT     (BOTADDSUB_UPPERINPUT    ),
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT    (BOTADDSUB_CARRYSELECT   ),
 | 
				
			||||||
 | 
							.MODE_8x8                 (MODE_8x8                ),
 | 
				
			||||||
 | 
							.A_SIGNED                 (A_SIGNED                ),
 | 
				
			||||||
 | 
							.B_SIGNED                 (B_SIGNED                )
 | 
				
			||||||
 | 
						) ref (
 | 
				
			||||||
 | 
							.CLK        (CLK           ),
 | 
				
			||||||
 | 
							.CE         (CE            ),
 | 
				
			||||||
 | 
							.C          (C             ),
 | 
				
			||||||
 | 
							.A          (A             ),
 | 
				
			||||||
 | 
							.B          (B             ),
 | 
				
			||||||
 | 
							.D          (D             ),
 | 
				
			||||||
 | 
							.AHOLD      (AHOLD         ),
 | 
				
			||||||
 | 
							.BHOLD      (BHOLD         ),
 | 
				
			||||||
 | 
							.CHOLD      (CHOLD         ),
 | 
				
			||||||
 | 
							.DHOLD      (DHOLD         ),
 | 
				
			||||||
 | 
							.IRSTTOP    (IRSTTOP       ),
 | 
				
			||||||
 | 
							.IRSTBOT    (IRSTBOT       ),
 | 
				
			||||||
 | 
							.ORSTTOP    (ORSTTOP       ),
 | 
				
			||||||
 | 
							.ORSTBOT    (ORSTBOT       ),
 | 
				
			||||||
 | 
							.OLOADTOP   (OLOADTOP      ),
 | 
				
			||||||
 | 
							.OLOADBOT   (OLOADBOT      ),
 | 
				
			||||||
 | 
							.ADDSUBTOP  (ADDSUBTOP     ),
 | 
				
			||||||
 | 
							.ADDSUBBOT  (ADDSUBBOT     ),
 | 
				
			||||||
 | 
							.OHOLDTOP   (OHOLDTOP      ),
 | 
				
			||||||
 | 
							.OHOLDBOT   (OHOLDBOT      ),
 | 
				
			||||||
 | 
							.CI         (CI            ),
 | 
				
			||||||
 | 
							.ACCUMCI    (ACCUMCI       ),
 | 
				
			||||||
 | 
							.SIGNEXTIN  (SIGNEXTIN     ),
 | 
				
			||||||
 | 
							.O          (REF_O         ),
 | 
				
			||||||
 | 
							.CO         (REF_CO        ),
 | 
				
			||||||
 | 
							.ACCUMCO    (REF_ACCUMCO   ),
 | 
				
			||||||
 | 
							.SIGNEXTOUT (REF_SIGNEXTOUT)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SB_MAC16_UUT #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER              (NEG_TRIGGER             ),
 | 
				
			||||||
 | 
							.C_REG                    (C_REG                   ),
 | 
				
			||||||
 | 
							.A_REG                    (A_REG                   ),
 | 
				
			||||||
 | 
							.B_REG                    (B_REG                   ),
 | 
				
			||||||
 | 
							.D_REG                    (D_REG                   ),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG         (TOP_8x8_MULT_REG        ),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG         (BOT_8x8_MULT_REG        ),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT         (TOPOUTPUT_SELECT        ),
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT     (TOPADDSUB_LOWERINPUT    ),
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT     (TOPADDSUB_UPPERINPUT    ),
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT    (TOPADDSUB_CARRYSELECT   ),
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT         (BOTOUTPUT_SELECT        ),
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT     (BOTADDSUB_LOWERINPUT    ),
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT     (BOTADDSUB_UPPERINPUT    ),
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT    (BOTADDSUB_CARRYSELECT   ),
 | 
				
			||||||
 | 
							.MODE_8x8                 (MODE_8x8                ),
 | 
				
			||||||
 | 
							.A_SIGNED                 (A_SIGNED                ),
 | 
				
			||||||
 | 
							.B_SIGNED                 (B_SIGNED                )
 | 
				
			||||||
 | 
						) uut (
 | 
				
			||||||
 | 
							.CLK        (CLK           ),
 | 
				
			||||||
 | 
							.CE         (CE            ),
 | 
				
			||||||
 | 
							.C          (C             ),
 | 
				
			||||||
 | 
							.A          (A             ),
 | 
				
			||||||
 | 
							.B          (B             ),
 | 
				
			||||||
 | 
							.D          (D             ),
 | 
				
			||||||
 | 
							.AHOLD      (AHOLD         ),
 | 
				
			||||||
 | 
							.BHOLD      (BHOLD         ),
 | 
				
			||||||
 | 
							.CHOLD      (CHOLD         ),
 | 
				
			||||||
 | 
							.DHOLD      (DHOLD         ),
 | 
				
			||||||
 | 
							.IRSTTOP    (IRSTTOP       ),
 | 
				
			||||||
 | 
							.IRSTBOT    (IRSTBOT       ),
 | 
				
			||||||
 | 
							.ORSTTOP    (ORSTTOP       ),
 | 
				
			||||||
 | 
							.ORSTBOT    (ORSTBOT       ),
 | 
				
			||||||
 | 
							.OLOADTOP   (OLOADTOP      ),
 | 
				
			||||||
 | 
							.OLOADBOT   (OLOADBOT      ),
 | 
				
			||||||
 | 
							.ADDSUBTOP  (ADDSUBTOP     ),
 | 
				
			||||||
 | 
							.ADDSUBBOT  (ADDSUBBOT     ),
 | 
				
			||||||
 | 
							.OHOLDTOP   (OHOLDTOP      ),
 | 
				
			||||||
 | 
							.OHOLDBOT   (OHOLDBOT      ),
 | 
				
			||||||
 | 
							.CI         (CI            ),
 | 
				
			||||||
 | 
							.ACCUMCI    (ACCUMCI       ),
 | 
				
			||||||
 | 
							.SIGNEXTIN  (SIGNEXTIN     ),
 | 
				
			||||||
 | 
							.O          (UUT_O         ),
 | 
				
			||||||
 | 
							.CO         (UUT_CO        ),
 | 
				
			||||||
 | 
							.ACCUMCO    (UUT_ACCUMCO   ),
 | 
				
			||||||
 | 
							.SIGNEXTOUT (UUT_SIGNEXTOUT)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module testbench_comb_8x8_A;
 | 
				
			||||||
 | 
						testbench #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER               (0),
 | 
				
			||||||
 | 
							.C_REG                     (0),
 | 
				
			||||||
 | 
							.A_REG                     (0),
 | 
				
			||||||
 | 
							.B_REG                     (0),
 | 
				
			||||||
 | 
							.D_REG                     (0),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG          (0),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG          (0),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1  (0),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2  (0),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.MODE_8x8                  (0),
 | 
				
			||||||
 | 
							.A_SIGNED                  (0),
 | 
				
			||||||
 | 
							.B_SIGNED                  (0)
 | 
				
			||||||
 | 
						) testbench ();
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module testbench_comb_8x8_B;
 | 
				
			||||||
 | 
						testbench #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER               (0),
 | 
				
			||||||
 | 
							.C_REG                     (0),
 | 
				
			||||||
 | 
							.A_REG                     (0),
 | 
				
			||||||
 | 
							.B_REG                     (0),
 | 
				
			||||||
 | 
							.D_REG                     (0),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG          (0),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG          (0),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1  (0),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2  (0),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.MODE_8x8                  (0),
 | 
				
			||||||
 | 
							.A_SIGNED                  (0),
 | 
				
			||||||
 | 
							.B_SIGNED                  (0)
 | 
				
			||||||
 | 
						) testbench ();
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module testbench_comb_16x16;
 | 
				
			||||||
 | 
						testbench #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER               (0),
 | 
				
			||||||
 | 
							.C_REG                     (0),
 | 
				
			||||||
 | 
							.A_REG                     (0),
 | 
				
			||||||
 | 
							.B_REG                     (0),
 | 
				
			||||||
 | 
							.D_REG                     (0),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG          (0),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG          (0),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1  (0),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2  (0),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.MODE_8x8                  (0),
 | 
				
			||||||
 | 
							.A_SIGNED                  (0),
 | 
				
			||||||
 | 
							.B_SIGNED                  (0)
 | 
				
			||||||
 | 
						) testbench ();
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module testbench_seq_16x16_A;
 | 
				
			||||||
 | 
						testbench #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER               (0),
 | 
				
			||||||
 | 
							.C_REG                     (1),
 | 
				
			||||||
 | 
							.A_REG                     (1),
 | 
				
			||||||
 | 
							.B_REG                     (1),
 | 
				
			||||||
 | 
							.D_REG                     (1),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG          (1),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG          (1),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1  (1),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2  (1),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.MODE_8x8                  (0),
 | 
				
			||||||
 | 
							.A_SIGNED                  (0),
 | 
				
			||||||
 | 
							.B_SIGNED                  (0)
 | 
				
			||||||
 | 
						) testbench ();
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module testbench_seq_16x16_B;
 | 
				
			||||||
 | 
						testbench #(
 | 
				
			||||||
 | 
							.NEG_TRIGGER               (0),
 | 
				
			||||||
 | 
							.C_REG                     (1),
 | 
				
			||||||
 | 
							.A_REG                     (1),
 | 
				
			||||||
 | 
							.B_REG                     (1),
 | 
				
			||||||
 | 
							.D_REG                     (1),
 | 
				
			||||||
 | 
							.TOP_8x8_MULT_REG          (1),
 | 
				
			||||||
 | 
							.BOT_8x8_MULT_REG          (1),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG1  (1),
 | 
				
			||||||
 | 
							.PIPELINE_16x16_MULT_REG2  (0),
 | 
				
			||||||
 | 
							.TOPOUTPUT_SELECT          (1),   // 0=P, 1=Q, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C
 | 
				
			||||||
 | 
							.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.BOTOUTPUT_SELECT          (1),   // 0=R, 1=S, 2=8x8, 3=16x16
 | 
				
			||||||
 | 
							.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
 | 
				
			||||||
 | 
							.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D
 | 
				
			||||||
 | 
							.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
 | 
				
			||||||
 | 
							.MODE_8x8                  (0),
 | 
				
			||||||
 | 
							.A_SIGNED                  (0),
 | 
				
			||||||
 | 
							.B_SIGNED                  (0)
 | 
				
			||||||
 | 
						) testbench ();
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@ module fa
 | 
				
			||||||
   wire   VCC;
 | 
					   wire   VCC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   assign VCC = 1'b1;
 | 
					   assign VCC = 1'b1;
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x),
 | 
					   cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x),
 | 
				
			||||||
                                   .dataa(a_c),
 | 
					                                   .dataa(a_c),
 | 
				
			||||||
                                   .datab(b_c),
 | 
					                                   .datab(b_c),
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ module fa
 | 
				
			||||||
                                   .datad(VCC));
 | 
					                                   .datad(VCC));
 | 
				
			||||||
   defparam syn__05_.lut_mask = 16'b1001011010010110;
 | 
					   defparam syn__05_.lut_mask = 16'b1001011010010110;
 | 
				
			||||||
   defparam syn__05_.sum_lutc_input = "datac";
 | 
					   defparam syn__05_.sum_lutc_input = "datac";
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t),
 | 
					   cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t),
 | 
				
			||||||
                                    .dataa(cin_c),
 | 
					                                    .dataa(cin_c),
 | 
				
			||||||
                                    .datab(b_c),
 | 
					                                    .datab(b_c),
 | 
				
			||||||
| 
						 | 
					@ -48,11 +48,11 @@ module fa
 | 
				
			||||||
                                    .datad(VCC));
 | 
					                                    .datad(VCC));
 | 
				
			||||||
   defparam syn__06_.lut_mask = 16'b1110000011100000;
 | 
					   defparam syn__06_.lut_mask = 16'b1110000011100000;
 | 
				
			||||||
   defparam syn__06_.sum_lutc_input = "datac";
 | 
					   defparam syn__06_.sum_lutc_input = "datac";
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
endmodule // fa
 | 
					endmodule // fa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module f_stage();
 | 
					module f_stage();
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
endmodule // f_stage
 | 
					endmodule // f_stage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module f_end();
 | 
					module f_end();
 | 
				
			||||||
| 
						 | 
					@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
          .cin_c(C[0]),
 | 
					          .cin_c(C[0]),
 | 
				
			||||||
          .cout_t(C0[1]),
 | 
					          .cout_t(C0[1]),
 | 
				
			||||||
          .sum_x(Y[0]));
 | 
					          .sum_x(Y[0]));
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   genvar i;
 | 
					   genvar i;
 | 
				
			||||||
   generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
 | 
					   generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
 | 
				
			||||||
      cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));
 | 
					      cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ module \$lut (A, Y);
 | 
				
			||||||
   wire              VCC;
 | 
					   wire              VCC;
 | 
				
			||||||
   wire              GND;
 | 
					   wire              GND;
 | 
				
			||||||
   assign {VCC,GND} = {1'b1,1'b0};
 | 
					   assign {VCC,GND} = {1'b1,1'b0};
 | 
				
			||||||
   
 | 
					
 | 
				
			||||||
   generate
 | 
					   generate
 | 
				
			||||||
      if (WIDTH == 1) begin
 | 
					      if (WIDTH == 1) begin
 | 
				
			||||||
	 assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
 | 
						 assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
 | 
				
			||||||
| 
						 | 
					@ -151,7 +151,7 @@ module \$lut (A, Y);
 | 
				
			||||||
                    TODO: There's not a just 7-input function on Cyclone V, see the following note:
 | 
					                    TODO: There's not a just 7-input function on Cyclone V, see the following note:
 | 
				
			||||||
                    **Extended LUT Mode**
 | 
					                    **Extended LUT Mode**
 | 
				
			||||||
                    Use extended LUT mode to implement a specific set of 7-input functions. The set must
 | 
					                    Use extended LUT mode to implement a specific set of 7-input functions. The set must
 | 
				
			||||||
                    be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. 
 | 
					                    be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs.
 | 
				
			||||||
                    [source](Device Interfaces and Integration Basics for Cyclone V Devices).
 | 
					                    [source](Device Interfaces and Integration Basics for Cyclone V Devices).
 | 
				
			||||||
                  end*/
 | 
					                  end*/
 | 
				
			||||||
                  else
 | 
					                  else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,40 +1,54 @@
 | 
				
			||||||
// module  \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
 | 
					module  \$_DFF_N_ (input D, C, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module  \$_DFF_P_ (input D, C, output Q);
 | 
					module  \$_DFF_P_ (input D, C, output Q);
 | 
				
			||||||
  SLE _TECHMAP_REPLACE_ (
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
    .D(D),
 | 
					endmodule
 | 
				
			||||||
    .CLK(C),
 | 
					
 | 
				
			||||||
    .EN(1'b1),
 | 
					module \$_DFF_NN0_ (input D, C, R, output Q);
 | 
				
			||||||
    .ALn(1'b1),
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
    .ADn(1'b1),
 | 
					endmodule
 | 
				
			||||||
    .SLn(1'b1),
 | 
					
 | 
				
			||||||
    .SD(1'b0),
 | 
					module \$_DFF_NN1_ (input D, C, R, output Q);
 | 
				
			||||||
    .LAT(1'b0),
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
    .Q(Q)
 | 
					endmodule
 | 
				
			||||||
  );
 | 
					
 | 
				
			||||||
 | 
					module \$_DFF_NP0_ (input D, C, R, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module \$_DFF_NP1_ (input D, C, R, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module \$_DFF_PN0_ (input D, C, R, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module \$_DFF_PN1_ (input D, C, R, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module \$_DFF_PP0_ (input D, C, R, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module \$_DFF_PP1_ (input D, C, R, output Q);
 | 
				
			||||||
 | 
					  SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// module  \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
 | 
					// module  \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
 | 
				
			||||||
// module  \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
 | 
					// module  \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
 | 
				
			||||||
// 
 | 
					//
 | 
				
			||||||
// module  \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
 | 
					// module  \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
 | 
				
			||||||
// module  \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
 | 
					// module  \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
 | 
				
			||||||
// 
 | 
					//
 | 
				
			||||||
// module  \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
 | 
					 | 
				
			||||||
// module  \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
 | 
					 | 
				
			||||||
// module  \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
 | 
					 | 
				
			||||||
// module  \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
 | 
					 | 
				
			||||||
// 
 | 
					 | 
				
			||||||
// module  \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
 | 
					 | 
				
			||||||
// module  \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
 | 
					 | 
				
			||||||
// module  \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
 | 
					 | 
				
			||||||
// module  \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
 | 
					 | 
				
			||||||
// 
 | 
					 | 
				
			||||||
// module  \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
 | 
					// module  \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
 | 
				
			||||||
// module  \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
 | 
					// module  \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
 | 
				
			||||||
// module  \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
 | 
					// module  \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
 | 
				
			||||||
// module  \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
 | 
					// module  \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
 | 
				
			||||||
// 
 | 
					//
 | 
				
			||||||
// module  \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
 | 
					// module  \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
 | 
				
			||||||
// module  \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
 | 
					// module  \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
 | 
				
			||||||
// module  \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
 | 
					// module  \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,39 +1,25 @@
 | 
				
			||||||
module SLE (
 | 
					// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf
 | 
				
			||||||
	output Q,
 | 
					
 | 
				
			||||||
	input ADn,
 | 
					module ADD2 (
 | 
				
			||||||
	input ALn,
 | 
					
 | 
				
			||||||
	input CLK,
 | 
						input A, B,
 | 
				
			||||||
	input D,
 | 
						output Y
 | 
				
			||||||
	input LAT,
 | 
					 | 
				
			||||||
	input SD,
 | 
					 | 
				
			||||||
	input EN,
 | 
					 | 
				
			||||||
	input SLn
 | 
					 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
	reg q_latch, q_ff;
 | 
						assign Y = A & B;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	always @(posedge CLK, negedge ALn) begin
 | 
					module ADD3 (
 | 
				
			||||||
		if (!ALn) begin
 | 
						input A, B, C,
 | 
				
			||||||
			q_ff <= !ADn;
 | 
						output Y
 | 
				
			||||||
		end else if (EN) begin
 | 
					);
 | 
				
			||||||
			if (!SLn)
 | 
						assign Y = A & B & C;
 | 
				
			||||||
				q_ff <= SD;
 | 
					endmodule
 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				q_ff <= D;
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	always @* begin
 | 
					module ADD4 (
 | 
				
			||||||
		if (!ALn) begin
 | 
						input A, B, C, D,
 | 
				
			||||||
			q_latch <= !ADn;
 | 
						output Y
 | 
				
			||||||
		end else if (CLK && EN) begin
 | 
					);
 | 
				
			||||||
			if (!SLn)
 | 
						assign Y = A & B & C & D;
 | 
				
			||||||
				q_ff <= SD;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				q_ff <= D;
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assign Q = LAT ? q_latch : q_ff;
 | 
					 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module CFG1 (
 | 
					module CFG1 (
 | 
				
			||||||
| 
						 | 
					@ -74,6 +60,238 @@ module CFG4 (
 | 
				
			||||||
	assign Y = INIT >> {D, C, B, A};
 | 
						assign Y = INIT >> {D, C, B, A};
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module BUFF (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module BUFD (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module CLKINT (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module CLKINT_PRESERVE (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module GCLKINT (
 | 
				
			||||||
 | 
						input A, EN,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A & EN;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module RCLKINT (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module RGCLKINT (
 | 
				
			||||||
 | 
						input A, EN,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A & EN;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module SLE (
 | 
				
			||||||
 | 
						output Q,
 | 
				
			||||||
 | 
						input ADn,
 | 
				
			||||||
 | 
						input ALn,
 | 
				
			||||||
 | 
						input CLK,
 | 
				
			||||||
 | 
						input D,
 | 
				
			||||||
 | 
						input LAT,
 | 
				
			||||||
 | 
						input SD,
 | 
				
			||||||
 | 
						input EN,
 | 
				
			||||||
 | 
						input SLn
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						reg q_latch, q_ff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						always @(posedge CLK, negedge ALn) begin
 | 
				
			||||||
 | 
							if (!ALn) begin
 | 
				
			||||||
 | 
								q_ff <= !ADn;
 | 
				
			||||||
 | 
							end else if (EN) begin
 | 
				
			||||||
 | 
								if (!SLn)
 | 
				
			||||||
 | 
									q_ff <= SD;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									q_ff <= D;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						always @* begin
 | 
				
			||||||
 | 
							if (!ALn) begin
 | 
				
			||||||
 | 
								q_latch <= !ADn;
 | 
				
			||||||
 | 
							end else if (CLK && EN) begin
 | 
				
			||||||
 | 
								if (!SLn)
 | 
				
			||||||
 | 
									q_ff <= SD;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									q_ff <= D;
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assign Q = LAT ? q_latch : q_ff;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// module AR1
 | 
				
			||||||
 | 
					// module FCEND_BUFF
 | 
				
			||||||
 | 
					// module FCINIT_BUFF
 | 
				
			||||||
 | 
					// module FLASH_FREEZE
 | 
				
			||||||
 | 
					// module OSCILLATOR
 | 
				
			||||||
 | 
					// module SYSRESET
 | 
				
			||||||
 | 
					// module SYSCTRL_RESET_STATUS
 | 
				
			||||||
 | 
					// module LIVE_PROBE_FB
 | 
				
			||||||
 | 
					// module GCLKBUF
 | 
				
			||||||
 | 
					// module GCLKBUF_DIFF
 | 
				
			||||||
 | 
					// module GCLKBIBUF
 | 
				
			||||||
 | 
					// module DFN1
 | 
				
			||||||
 | 
					// module DFN1C0
 | 
				
			||||||
 | 
					// module DFN1E1
 | 
				
			||||||
 | 
					// module DFN1E1C0
 | 
				
			||||||
 | 
					// module DFN1E1P0
 | 
				
			||||||
 | 
					// module DFN1P0
 | 
				
			||||||
 | 
					// module DLN1
 | 
				
			||||||
 | 
					// module DLN1C0
 | 
				
			||||||
 | 
					// module DLN1P0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module INV (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module INVD (
 | 
				
			||||||
 | 
						input A,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module MX2 (
 | 
				
			||||||
 | 
						input A, B, S,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = S ? B : A;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module MX4 (
 | 
				
			||||||
 | 
						input D0, D1, D2, D3, S0, S1,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module NAND2 (
 | 
				
			||||||
 | 
						input A, B,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !(A & B);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module NAND3 (
 | 
				
			||||||
 | 
						input A, B, C,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !(A & B & C);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module NAND4 (
 | 
				
			||||||
 | 
						input A, B, C, D,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !(A & B & C & D);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module NOR2 (
 | 
				
			||||||
 | 
						input A, B,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !(A | B);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module NOR3 (
 | 
				
			||||||
 | 
						input A, B, C,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !(A | B | C);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module NOR4 (
 | 
				
			||||||
 | 
						input A, B, C, D,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = !(A | B | C | D);
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module OR2 (
 | 
				
			||||||
 | 
						input A, B,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A | B;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module OR3 (
 | 
				
			||||||
 | 
						input A, B, C,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A | B | C;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module OR4 (
 | 
				
			||||||
 | 
						input A, B, C, D,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A | B | C | D;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module XOR2 (
 | 
				
			||||||
 | 
						input A, B,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A ^ B;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module XOR3 (
 | 
				
			||||||
 | 
						input A, B, C,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A ^ B ^ C;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module XOR4 (
 | 
				
			||||||
 | 
						input A, B, C, D,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A ^ B ^ C ^ D;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module XOR8 (
 | 
				
			||||||
 | 
						input A, B, C, D, E, F, G, H,
 | 
				
			||||||
 | 
						output Y
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// module UJTAG
 | 
				
			||||||
 | 
					// module BIBUF
 | 
				
			||||||
 | 
					// module BIBUF_DIFF
 | 
				
			||||||
 | 
					// module CLKBIBUF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module CLKBUF (
 | 
					module CLKBUF (
 | 
				
			||||||
	input PAD,
 | 
						input PAD,
 | 
				
			||||||
	output Y
 | 
						output Y
 | 
				
			||||||
| 
						 | 
					@ -81,6 +299,8 @@ module CLKBUF (
 | 
				
			||||||
	assign Y = PAD;
 | 
						assign Y = PAD;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// module CLKBUF_DIFF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module INBUF (
 | 
					module INBUF (
 | 
				
			||||||
	input PAD,
 | 
						input PAD,
 | 
				
			||||||
	output Y
 | 
						output Y
 | 
				
			||||||
| 
						 | 
					@ -88,9 +308,20 @@ module INBUF (
 | 
				
			||||||
	assign Y = PAD;
 | 
						assign Y = PAD;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// module INBUF_DIFF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module OUTBUF (
 | 
					module OUTBUF (
 | 
				
			||||||
	input D,
 | 
						input D,
 | 
				
			||||||
	output PAD
 | 
						output PAD
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
	assign PAD = D;
 | 
						assign PAD = D;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// module OUTBUF_DIFF
 | 
				
			||||||
 | 
					// module TRIBUFF
 | 
				
			||||||
 | 
					// module TRIBUFF_DIFF
 | 
				
			||||||
 | 
					// module DDR_IN
 | 
				
			||||||
 | 
					// module DDR_OUT
 | 
				
			||||||
 | 
					// module RAM1K18
 | 
				
			||||||
 | 
					// module RAM64x18
 | 
				
			||||||
 | 
					// module MACC
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,136 @@
 | 
				
			||||||
USING_YOSYS_NAMESPACE
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
PRIVATE_NAMESPACE_BEGIN
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_iobufs(Module *module, bool clkbuf_mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SigMap sigmap(module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool<SigBit> clk_bits;
 | 
				
			||||||
 | 
						pool<SigBit> handled_io_bits;
 | 
				
			||||||
 | 
						dict<SigBit, SigBit> rewrite_bits;
 | 
				
			||||||
 | 
						vector<pair<Cell*, SigBit>> pad_bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto cell : module->cells())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (clkbuf_mode && cell->type == "\\SLE") {
 | 
				
			||||||
 | 
								for (auto bit : sigmap(cell->getPort("\\CLK")))
 | 
				
			||||||
 | 
									clk_bits.insert(bit);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF",
 | 
				
			||||||
 | 
									"\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF",
 | 
				
			||||||
 | 
									"\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) {
 | 
				
			||||||
 | 
								for (auto bit : sigmap(cell->getPort("\\PAD")))
 | 
				
			||||||
 | 
									handled_io_bits.insert(bit);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto wire : vector<Wire*>(module->wires()))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!wire->port_input && !wire->port_output)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int index = 0; index < GetSize(wire); index++)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								SigBit bit(wire, index);
 | 
				
			||||||
 | 
								SigBit canonical_bit = sigmap(bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (handled_io_bits.count(canonical_bit))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (wire->port_input && wire->port_output)
 | 
				
			||||||
 | 
									log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								IdString buf_type, buf_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (wire->port_output) {
 | 
				
			||||||
 | 
									buf_type = "\\OUTBUF";
 | 
				
			||||||
 | 
									buf_port = "\\D";
 | 
				
			||||||
 | 
								} else if (clkbuf_mode && clk_bits.count(canonical_bit)) {
 | 
				
			||||||
 | 
									buf_type = "\\CLKBUF";
 | 
				
			||||||
 | 
									buf_port = "\\Y";
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									buf_type = "\\INBUF";
 | 
				
			||||||
 | 
									buf_port = "\\Y";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Cell *c = module->addCell(NEW_ID, buf_type);
 | 
				
			||||||
 | 
								SigBit new_bit = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
								c->setPort(buf_port, new_bit);
 | 
				
			||||||
 | 
								pad_bits.push_back(make_pair(c, bit));
 | 
				
			||||||
 | 
								rewrite_bits[canonical_bit] = new_bit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto rewrite_function = [&](SigSpec &s) {
 | 
				
			||||||
 | 
							for (auto &bit : s) {
 | 
				
			||||||
 | 
								SigBit canonical_bit = sigmap(bit);
 | 
				
			||||||
 | 
								if (rewrite_bits.count(canonical_bit))
 | 
				
			||||||
 | 
									bit = rewrite_bits.at(canonical_bit);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						module->rewrite_sigspecs(rewrite_function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &it : pad_bits)
 | 
				
			||||||
 | 
							it.first->setPort("\\PAD", it.second);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_clkint(Module *module)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SigMap sigmap(module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool<SigBit> clk_bits;
 | 
				
			||||||
 | 
						vector<SigBit> handled_clk_bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto cell : module->cells())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (cell->type == "\\SLE") {
 | 
				
			||||||
 | 
								for (auto bit : sigmap(cell->getPort("\\CLK")))
 | 
				
			||||||
 | 
									clk_bits.insert(bit);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF",
 | 
				
			||||||
 | 
									"\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) {
 | 
				
			||||||
 | 
								for (auto bit : sigmap(cell->getPort("\\Y")))
 | 
				
			||||||
 | 
									handled_clk_bits.push_back(bit);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto bit : handled_clk_bits)
 | 
				
			||||||
 | 
							clk_bits.erase(bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto cell : vector<Cell*>(module->cells()))
 | 
				
			||||||
 | 
						for (auto &conn : cell->connections())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!cell->output(conn.first))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SigSpec sig = conn.second;
 | 
				
			||||||
 | 
							bool did_something = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &bit : sig) {
 | 
				
			||||||
 | 
								SigBit canonical_bit = sigmap(bit);
 | 
				
			||||||
 | 
								if (clk_bits.count(canonical_bit)) {
 | 
				
			||||||
 | 
									Cell *c = module->addCell(NEW_ID, "\\CLKINT");
 | 
				
			||||||
 | 
									SigBit new_bit = module->addWire(NEW_ID);
 | 
				
			||||||
 | 
									c->setPort("\\A", new_bit);
 | 
				
			||||||
 | 
									c->setPort("\\Y", bit);
 | 
				
			||||||
 | 
									log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit));
 | 
				
			||||||
 | 
									clk_bits.erase(canonical_bit);
 | 
				
			||||||
 | 
									did_something = true;
 | 
				
			||||||
 | 
									bit = new_bit;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (did_something)
 | 
				
			||||||
 | 
								cell->setPort(conn.first, sig);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto bit : clk_bits)
 | 
				
			||||||
 | 
							log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Sf2IobsPass : public Pass {
 | 
					struct Sf2IobsPass : public Pass {
 | 
				
			||||||
	Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
 | 
						Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
 | 
				
			||||||
	void help() YS_OVERRIDE
 | 
						void help() YS_OVERRIDE
 | 
				
			||||||
| 
						 | 
					@ -31,20 +161,25 @@ struct Sf2IobsPass : public Pass {
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
		log("    sf2_iobs [options] [selection]\n");
 | 
							log("    sf2_iobs [options] [selection]\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
		log("Add SF2 I/O buffers to top module IOs as needed.\n");
 | 
							log("Add SF2 I/O buffers and global buffers to top module as needed.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -clkbuf\n");
 | 
				
			||||||
 | 
							log("        Insert PAD->global_net clock buffers\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							bool clkbuf_mode = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
 | 
							log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		size_t argidx;
 | 
							size_t argidx;
 | 
				
			||||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
							for (argidx = 1; argidx < args.size(); argidx++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// if (args[argidx] == "-singleton") {
 | 
								if (args[argidx] == "-clkbuf") {
 | 
				
			||||||
			// 	singleton_mode = true;
 | 
									clkbuf_mode = true;
 | 
				
			||||||
			// 	continue;
 | 
									continue;
 | 
				
			||||||
			// }
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		extra_args(args, argidx, design);
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
| 
						 | 
					@ -54,76 +189,8 @@ struct Sf2IobsPass : public Pass {
 | 
				
			||||||
		if (module == nullptr)
 | 
							if (module == nullptr)
 | 
				
			||||||
			log_cmd_error("No top module found.\n");
 | 
								log_cmd_error("No top module found.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		SigMap sigmap(module);
 | 
							handle_iobufs(module, clkbuf_mode);
 | 
				
			||||||
 | 
							handle_clkint(module);
 | 
				
			||||||
		pool<SigBit> clk_bits;
 | 
					 | 
				
			||||||
		pool<SigBit> handled_io_bits;
 | 
					 | 
				
			||||||
		dict<SigBit, SigBit> rewrite_bits;
 | 
					 | 
				
			||||||
		vector<pair<Cell*, SigBit>> pad_bits;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto cell : module->cells())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (cell->type == "\\SLE") {
 | 
					 | 
				
			||||||
				for (auto bit : sigmap(cell->getPort("\\CLK")))
 | 
					 | 
				
			||||||
					clk_bits.insert(bit);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (cell->type.in("\\INBUF", "\\OUTBUF", "\\CLKBUF")) {
 | 
					 | 
				
			||||||
				for (auto bit : sigmap(cell->getPort("\\PAD")))
 | 
					 | 
				
			||||||
					handled_io_bits.insert(bit);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto wire : vector<Wire*>(module->wires()))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (!wire->port_input && !wire->port_output)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for (int index = 0; index < GetSize(wire); index++)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				SigBit bit(wire, index);
 | 
					 | 
				
			||||||
				SigBit canonical_bit = sigmap(bit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (handled_io_bits.count(canonical_bit))
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (wire->port_input && wire->port_output)
 | 
					 | 
				
			||||||
					log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				IdString buf_type, buf_port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (wire->port_output) {
 | 
					 | 
				
			||||||
					buf_type = "\\OUTBUF";
 | 
					 | 
				
			||||||
					buf_port = "\\D";
 | 
					 | 
				
			||||||
				} else if (clk_bits.count(canonical_bit)) {
 | 
					 | 
				
			||||||
					buf_type = "\\CLKBUF";
 | 
					 | 
				
			||||||
					buf_port = "\\Y";
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					buf_type = "\\INBUF";
 | 
					 | 
				
			||||||
					buf_port = "\\Y";
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				Cell *c = module->addCell(NEW_ID, buf_type);
 | 
					 | 
				
			||||||
				SigBit new_bit = module->addWire(NEW_ID);
 | 
					 | 
				
			||||||
				c->setPort(buf_port, new_bit);
 | 
					 | 
				
			||||||
				pad_bits.push_back(make_pair(c, bit));
 | 
					 | 
				
			||||||
				rewrite_bits[canonical_bit] = new_bit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto rewrite_function = [&](SigSpec &s) {
 | 
					 | 
				
			||||||
			for (auto &bit : s) {
 | 
					 | 
				
			||||||
				SigBit canonical_bit = sigmap(bit);
 | 
					 | 
				
			||||||
				if (rewrite_bits.count(canonical_bit))
 | 
					 | 
				
			||||||
					bit = rewrite_bits.at(canonical_bit);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		module->rewrite_sigspecs(rewrite_function);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto &it : pad_bits)
 | 
					 | 
				
			||||||
			it.first->setPort("\\PAD", it.second);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
} Sf2IobsPass;
 | 
					} Sf2IobsPass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,6 +63,9 @@ struct SynthSf2Pass : public ScriptPass
 | 
				
			||||||
		log("    -noiobs\n");
 | 
							log("    -noiobs\n");
 | 
				
			||||||
		log("        run synthesis in \"block mode\", i.e. do not insert IO buffers\n");
 | 
							log("        run synthesis in \"block mode\", i.e. do not insert IO buffers\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -clkbuf\n");
 | 
				
			||||||
 | 
							log("        insert direct PAD->global_net buffers\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
		log("    -retime\n");
 | 
							log("    -retime\n");
 | 
				
			||||||
		log("        run 'abc' with -dff option\n");
 | 
							log("        run 'abc' with -dff option\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
| 
						 | 
					@ -73,7 +76,7 @@ struct SynthSf2Pass : public ScriptPass
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	string top_opt, edif_file, vlog_file, json_file;
 | 
						string top_opt, edif_file, vlog_file, json_file;
 | 
				
			||||||
	bool flatten, retime, iobs;
 | 
						bool flatten, retime, iobs, clkbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void clear_flags() YS_OVERRIDE
 | 
						void clear_flags() YS_OVERRIDE
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -84,6 +87,7 @@ struct SynthSf2Pass : public ScriptPass
 | 
				
			||||||
		flatten = true;
 | 
							flatten = true;
 | 
				
			||||||
		retime = false;
 | 
							retime = false;
 | 
				
			||||||
		iobs = true;
 | 
							iobs = true;
 | 
				
			||||||
 | 
							clkbuf = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
						void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
| 
						 | 
					@ -130,6 +134,10 @@ struct SynthSf2Pass : public ScriptPass
 | 
				
			||||||
				iobs = false;
 | 
									iobs = false;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-clkbuf") {
 | 
				
			||||||
 | 
									clkbuf = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		extra_args(args, argidx, design);
 | 
							extra_args(args, argidx, design);
 | 
				
			||||||
| 
						 | 
					@ -201,8 +209,10 @@ struct SynthSf2Pass : public ScriptPass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (check_label("map_iobs"))
 | 
							if (check_label("map_iobs"))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (iobs || help_mode)
 | 
								if (help_mode)
 | 
				
			||||||
				run("sf2_iobs", "(unless -noiobs)");
 | 
									run("sf2_iobs [-clkbuf]", "(unless -noiobs)");
 | 
				
			||||||
 | 
								else if (iobs)
 | 
				
			||||||
 | 
									run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs");
 | 
				
			||||||
			run("clean");
 | 
								run("clean");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v))
 | 
				
			||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
 | 
					$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
 | 
				
			||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
 | 
					$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
 | 
				
			||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
 | 
					$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
 | 
				
			||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v))
 | 
					$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
 | 
				
			||||||
 | 
					$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
 | 
					$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
 | 
				
			||||||
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
 | 
					$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,9 @@
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ============================================================================
 | 
				
			||||||
 | 
					// LCU
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(* techmap_celltype = "$lcu" *)
 | 
					(* techmap_celltype = "$lcu" *)
 | 
				
			||||||
module _80_xilinx_lcu (P, G, CI, CO);
 | 
					module _80_xilinx_lcu (P, G, CI, CO);
 | 
				
			||||||
	parameter WIDTH = 2;
 | 
						parameter WIDTH = 2;
 | 
				
			||||||
| 
						 | 
					@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wire _TECHMAP_FAIL_ = WIDTH <= 2;
 | 
						wire _TECHMAP_FAIL_ = WIDTH <= 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						genvar i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`ifdef _CLB_CARRY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						localparam CARRY4_COUNT = (WIDTH + 3) / 4;
 | 
				
			||||||
 | 
						localparam MAX_WIDTH    = CARRY4_COUNT * 4;
 | 
				
			||||||
 | 
						localparam PAD_WIDTH    = MAX_WIDTH - WIDTH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [MAX_WIDTH-1:0] S  = {{PAD_WIDTH{1'b0}}, P & ~G};
 | 
				
			||||||
 | 
						wire [MAX_WIDTH-1:0] C  = CO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Partially occupied CARRY4
 | 
				
			||||||
 | 
							if ((i+1)*4 > WIDTH) begin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// First one
 | 
				
			||||||
 | 
								if (i == 0) begin
 | 
				
			||||||
 | 
									CARRY4 carry4_1st_part
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(CI),
 | 
				
			||||||
 | 
									.CI    (1'd0),
 | 
				
			||||||
 | 
									.DI    (G [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								// Another one
 | 
				
			||||||
 | 
								end else begin
 | 
				
			||||||
 | 
									CARRY4 carry4_part
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(1'd0),
 | 
				
			||||||
 | 
									.CI    (C [i*4 - 1]),
 | 
				
			||||||
 | 
									.DI    (G [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Fully occupied CARRY4
 | 
				
			||||||
 | 
							end else begin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// First one
 | 
				
			||||||
 | 
								if (i == 0) begin
 | 
				
			||||||
 | 
									CARRY4 carry4_1st_full
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(CI),
 | 
				
			||||||
 | 
									.CI    (1'd0),
 | 
				
			||||||
 | 
									.DI    (G [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								// Another one
 | 
				
			||||||
 | 
								end else begin
 | 
				
			||||||
 | 
									CARRY4 carry4_full
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(1'd0),
 | 
				
			||||||
 | 
									.CI    (C [i*4 - 1]),
 | 
				
			||||||
 | 
									.DI    (G [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`elsif _EXPLICIT_CARRY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wire [WIDTH-1:0] C = {CO, CI};
 | 
						wire [WIDTH-1:0] C = {CO, CI};
 | 
				
			||||||
	wire [WIDTH-1:0] S = P & ~G;
 | 
						wire [WIDTH-1:0] S = P & ~G;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genvar i;
 | 
					 | 
				
			||||||
	generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
 | 
						generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
 | 
				
			||||||
		MUXCY muxcy (
 | 
							MUXCY muxcy (
 | 
				
			||||||
			.CI(C[i]),
 | 
								.CI(C[i]),
 | 
				
			||||||
| 
						 | 
					@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO);
 | 
				
			||||||
			.O(CO[i])
 | 
								.O(CO[i])
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	end endgenerate
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [WIDTH-1:0] C = {CO, CI};
 | 
				
			||||||
 | 
						wire [WIDTH-1:0] S = P & ~G;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
 | 
				
			||||||
 | 
							MUXCY muxcy (
 | 
				
			||||||
 | 
								.CI(C[i]),
 | 
				
			||||||
 | 
								.DI(G[i]),
 | 
				
			||||||
 | 
								.S(S[i]),
 | 
				
			||||||
 | 
								.O(CO[i])
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						end endgenerate
 | 
				
			||||||
 | 
					`endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ============================================================================
 | 
				
			||||||
 | 
					// ALU
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(* techmap_celltype = "$alu" *)
 | 
					(* techmap_celltype = "$alu" *)
 | 
				
			||||||
module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 | 
					module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
	parameter A_SIGNED = 0;
 | 
						parameter A_SIGNED = 0;
 | 
				
			||||||
| 
						 | 
					@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
	parameter A_WIDTH = 1;
 | 
						parameter A_WIDTH = 1;
 | 
				
			||||||
	parameter B_WIDTH = 1;
 | 
						parameter B_WIDTH = 1;
 | 
				
			||||||
	parameter Y_WIDTH = 1;
 | 
						parameter Y_WIDTH = 1;
 | 
				
			||||||
 | 
						parameter _TECHMAP_CONSTVAL_CI_ = 0;
 | 
				
			||||||
 | 
						parameter _TECHMAP_CONSTMSK_CI_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input [A_WIDTH-1:0] A;
 | 
						input [A_WIDTH-1:0] A;
 | 
				
			||||||
	input [B_WIDTH-1:0] B;
 | 
						input [B_WIDTH-1:0] B;
 | 
				
			||||||
| 
						 | 
					@ -66,16 +159,189 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
	wire [Y_WIDTH-1:0] AA = A_buf;
 | 
						wire [Y_WIDTH-1:0] AA = A_buf;
 | 
				
			||||||
	wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
 | 
						wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wire [Y_WIDTH-1:0] P = AA ^ BB;
 | 
						genvar i;
 | 
				
			||||||
	wire [Y_WIDTH-1:0] G = AA & BB;
 | 
					
 | 
				
			||||||
	wire [Y_WIDTH-1:0] C = {CO, CI};
 | 
					`ifdef _CLB_CARRY
 | 
				
			||||||
	wire [Y_WIDTH-1:0] S = P & ~G;
 | 
					
 | 
				
			||||||
 | 
						localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4;
 | 
				
			||||||
 | 
						localparam MAX_WIDTH    = CARRY4_COUNT * 4;
 | 
				
			||||||
 | 
						localparam PAD_WIDTH    = MAX_WIDTH - Y_WIDTH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [MAX_WIDTH-1:0] S  = {{PAD_WIDTH{1'b0}}, AA ^ BB};
 | 
				
			||||||
 | 
						wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [MAX_WIDTH-1:0] C  = CO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genvar i;
 | 
						genvar i;
 | 
				
			||||||
 | 
						generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Partially occupied CARRY4
 | 
				
			||||||
 | 
							if ((i+1)*4 > Y_WIDTH) begin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// First one
 | 
				
			||||||
 | 
								if (i == 0) begin
 | 
				
			||||||
 | 
									CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(CI),
 | 
				
			||||||
 | 
									.CI    (1'd0),
 | 
				
			||||||
 | 
									.DI    (DI[(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.O     (Y [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[(Y_WIDTH - 1):i*4])
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								// Another one
 | 
				
			||||||
 | 
								end else begin
 | 
				
			||||||
 | 
									CARRY4 carry4_part
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(1'd0),
 | 
				
			||||||
 | 
									.CI    (C [i*4 - 1]),
 | 
				
			||||||
 | 
									.DI    (DI[(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.O     (Y [(Y_WIDTH - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[(Y_WIDTH - 1):i*4])
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Fully occupied CARRY4
 | 
				
			||||||
 | 
							end else begin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// First one
 | 
				
			||||||
 | 
								if (i == 0) begin
 | 
				
			||||||
 | 
									CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(CI),
 | 
				
			||||||
 | 
									.CI    (1'd0),
 | 
				
			||||||
 | 
									.DI    (DI[((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.O     (Y [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[((i+1)*4 - 1):i*4])
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								// Another one
 | 
				
			||||||
 | 
								end else begin
 | 
				
			||||||
 | 
									CARRY4 carry4_full
 | 
				
			||||||
 | 
									(
 | 
				
			||||||
 | 
									.CYINIT(1'd0),
 | 
				
			||||||
 | 
									.CI    (C [i*4 - 1]),
 | 
				
			||||||
 | 
									.DI    (DI[((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.S     (S [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.O     (Y [((i+1)*4 - 1):i*4]),
 | 
				
			||||||
 | 
									.CO    (CO[((i+1)*4 - 1):i*4])
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`elsif _EXPLICIT_CARRY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] S = AA ^ BB;
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] DI = AA & BB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire CINIT;
 | 
				
			||||||
 | 
						// Carry chain.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// VPR requires that the carry chain never hit the fabric.	The CO input
 | 
				
			||||||
 | 
						// to this techmap is the carry outputs for synthesis, e.g. might hit the
 | 
				
			||||||
 | 
						// fabric.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// So we maintain two wire sets, CO_CHAIN is the carry that is for VPR,
 | 
				
			||||||
 | 
						// e.g. off fabric dedicated chain.  CO is the carry outputs that are
 | 
				
			||||||
 | 
						// available to the fabric.
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] CO_CHAIN;
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If carry chain is being initialized to a constant, techmap the constant
 | 
				
			||||||
 | 
						// source.	Otherwise techmap the fabric source.
 | 
				
			||||||
 | 
						generate for (i = 0; i < 1; i = i + 1) begin:slice
 | 
				
			||||||
 | 
							CARRY0 #(.CYINIT_FABRIC(1)) carry(
 | 
				
			||||||
 | 
								.CI_INIT(CI),
 | 
				
			||||||
 | 
								.DI(DI[0]),
 | 
				
			||||||
 | 
								.S(S[0]),
 | 
				
			||||||
 | 
								.CO_CHAIN(CO_CHAIN[0]),
 | 
				
			||||||
 | 
								.CO_FABRIC(CO[0]),
 | 
				
			||||||
 | 
								.O(Y[0])
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice
 | 
				
			||||||
 | 
							if(i % 4 == 0) begin
 | 
				
			||||||
 | 
								CARRY0 carry (
 | 
				
			||||||
 | 
									.CI(C[i]),
 | 
				
			||||||
 | 
									.DI(DI[i]),
 | 
				
			||||||
 | 
									.S(S[i]),
 | 
				
			||||||
 | 
									.CO_CHAIN(CO_CHAIN[i]),
 | 
				
			||||||
 | 
									.CO_FABRIC(CO[i]),
 | 
				
			||||||
 | 
									.O(Y[i])
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							begin
 | 
				
			||||||
 | 
								CARRY carry (
 | 
				
			||||||
 | 
									.CI(C[i]),
 | 
				
			||||||
 | 
									.DI(DI[i]),
 | 
				
			||||||
 | 
									.S(S[i]),
 | 
				
			||||||
 | 
									.CO_CHAIN(CO_CHAIN[i]),
 | 
				
			||||||
 | 
									.CO_FABRIC(CO[i]),
 | 
				
			||||||
 | 
									.O(Y[i])
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice
 | 
				
			||||||
 | 
							if(i % 4 == 0) begin
 | 
				
			||||||
 | 
								CARRY0 top_of_carry (
 | 
				
			||||||
 | 
									.CI(C[i]),
 | 
				
			||||||
 | 
									.DI(DI[i]),
 | 
				
			||||||
 | 
									.S(S[i]),
 | 
				
			||||||
 | 
									.CO_CHAIN(CO_CHAIN[i]),
 | 
				
			||||||
 | 
									.O(Y[i])
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							begin
 | 
				
			||||||
 | 
								CARRY top_of_carry (
 | 
				
			||||||
 | 
									.CI(C[i]),
 | 
				
			||||||
 | 
									.DI(DI[i]),
 | 
				
			||||||
 | 
									.S(S[i]),
 | 
				
			||||||
 | 
									.CO_CHAIN(CO_CHAIN[i]),
 | 
				
			||||||
 | 
									.O(Y[i])
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							// Turns out CO_FABRIC and O both use [ABCD]MUX, so provide
 | 
				
			||||||
 | 
							// a non-congested path to output the top of the carry chain.
 | 
				
			||||||
 | 
							// Registering the output of the CARRY block would solve this, but not
 | 
				
			||||||
 | 
							// all designs do that.
 | 
				
			||||||
 | 
							if((i+1) % 4 == 0) begin
 | 
				
			||||||
 | 
								CARRY0 carry_output (
 | 
				
			||||||
 | 
									.CI(CO_CHAIN[i]),
 | 
				
			||||||
 | 
									.DI(0),
 | 
				
			||||||
 | 
									.S(0),
 | 
				
			||||||
 | 
									.O(CO[i])
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							begin
 | 
				
			||||||
 | 
								CARRY carry_output (
 | 
				
			||||||
 | 
									.CI(CO_CHAIN[i]),
 | 
				
			||||||
 | 
									.DI(0),
 | 
				
			||||||
 | 
									.S(0),
 | 
				
			||||||
 | 
									.O(CO[i])
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] S = AA ^ BB;
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] DI = AA & BB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wire [Y_WIDTH-1:0] C = {CO, CI};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
 | 
						generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
 | 
				
			||||||
		MUXCY muxcy (
 | 
							MUXCY muxcy (
 | 
				
			||||||
			.CI(C[i]),
 | 
								.CI(C[i]),
 | 
				
			||||||
			.DI(G[i]),
 | 
								.DI(DI[i]),
 | 
				
			||||||
			.S(S[i]),
 | 
								.S(S[i]),
 | 
				
			||||||
			.O(CO[i])
 | 
								.O(CO[i])
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
| 
						 | 
					@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	end endgenerate
 | 
						end endgenerate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assign X = P;
 | 
					`endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assign X = S;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,86 +1,20 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module  \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
 | 
					// Empty for now
 | 
				
			||||||
module  \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module  \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module  \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module  \$_DFF_NN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
 | 
					 | 
				
			||||||
module  \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`ifndef NO_LUT
 | 
					 | 
				
			||||||
module \$lut (A, Y);
 | 
					 | 
				
			||||||
  parameter WIDTH = 0;
 | 
					 | 
				
			||||||
  parameter LUT = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  input [WIDTH-1:0] A;
 | 
					 | 
				
			||||||
  output Y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  generate
 | 
					 | 
				
			||||||
    if (WIDTH == 1) begin
 | 
					 | 
				
			||||||
      LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
 | 
					 | 
				
			||||||
        .I0(A[0]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 2) begin
 | 
					 | 
				
			||||||
      LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 3) begin
 | 
					 | 
				
			||||||
      LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 4) begin
 | 
					 | 
				
			||||||
      LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 5) begin
 | 
					 | 
				
			||||||
      LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 6) begin
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 7) begin
 | 
					 | 
				
			||||||
      wire T0, T1;
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
      MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
 | 
					 | 
				
			||||||
    end else
 | 
					 | 
				
			||||||
    if (WIDTH == 8) begin
 | 
					 | 
				
			||||||
      wire T0, T1, T2, T3, T4, T5;
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
      LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
 | 
					 | 
				
			||||||
        .I0(A[0]), .I1(A[1]), .I2(A[2]),
 | 
					 | 
				
			||||||
        .I3(A[3]), .I4(A[4]), .I5(A[5]));
 | 
					 | 
				
			||||||
      MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
 | 
					 | 
				
			||||||
      MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
 | 
					 | 
				
			||||||
      MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
 | 
					 | 
				
			||||||
    end else begin
 | 
					 | 
				
			||||||
      wire _TECHMAP_FAIL_ = 1;
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  endgenerate
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
`endif
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,21 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// See Xilinx UG953 and UG474 for a description of the cell types below.
 | 
					// See Xilinx UG953 and UG474 for a description of the cell types below.
 | 
				
			||||||
// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
 | 
					// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
 | 
				
			||||||
| 
						 | 
					@ -104,6 +122,29 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
 | 
				
			||||||
  assign CO[3] = S[3] ? CO[2] : DI[3];
 | 
					  assign CO[3] = S[3] ? CO[2] : DI[3];
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`ifdef _EXPLICIT_CARRY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
 | 
				
			||||||
 | 
					  parameter CYINIT_FABRIC = 0;
 | 
				
			||||||
 | 
					  wire CI_COMBINE;
 | 
				
			||||||
 | 
					  if(CYINIT_FABRIC) begin
 | 
				
			||||||
 | 
					    assign CI_COMBINE = CI_INIT;
 | 
				
			||||||
 | 
					  end else begin
 | 
				
			||||||
 | 
					    assign CI_COMBINE = CI;
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  assign CO_CHAIN = S ? CI_COMBINE : DI;
 | 
				
			||||||
 | 
					  assign CO_FABRIC = S ? CI_COMBINE : DI;
 | 
				
			||||||
 | 
					  assign O = S ^ CI_COMBINE;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
 | 
				
			||||||
 | 
					  assign CO_CHAIN = S ? CI : DI;
 | 
				
			||||||
 | 
					  assign CO_FABRIC = S ? CI : DI;
 | 
				
			||||||
 | 
					  assign O = S ^ CI;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module FDRE (output reg Q, input C, CE, D, R);
 | 
					module FDRE (output reg Q, input C, CE, D, R);
 | 
				
			||||||
  parameter [0:0] INIT = 1'b0;
 | 
					  parameter [0:0] INIT = 1'b0;
 | 
				
			||||||
  parameter [0:0] IS_C_INVERTED = 1'b0;
 | 
					  parameter [0:0] IS_C_INVERTED = 1'b0;
 | 
				
			||||||
| 
						 | 
					@ -156,6 +197,30 @@ module FDPE (output reg Q, input C, CE, D, PRE);
 | 
				
			||||||
  endcase endgenerate
 | 
					  endcase endgenerate
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module FDRE_1 (output reg Q, input C, CE, D, R);
 | 
				
			||||||
 | 
					  parameter [0:0] INIT = 1'b0;
 | 
				
			||||||
 | 
					  initial Q <= INIT;
 | 
				
			||||||
 | 
					  always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module FDSE_1 (output reg Q, input C, CE, D, S);
 | 
				
			||||||
 | 
					  parameter [0:0] INIT = 1'b1;
 | 
				
			||||||
 | 
					  initial Q <= INIT;
 | 
				
			||||||
 | 
					  always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module FDCE_1 (output reg Q, input C, CE, D, CLR);
 | 
				
			||||||
 | 
					  parameter [0:0] INIT = 1'b0;
 | 
				
			||||||
 | 
					  initial Q <= INIT;
 | 
				
			||||||
 | 
					  always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module FDPE_1 (output reg Q, input C, CE, D, PRE);
 | 
				
			||||||
 | 
					  parameter [0:0] INIT = 1'b1;
 | 
				
			||||||
 | 
					  initial Q <= INIT;
 | 
				
			||||||
 | 
					  always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module RAM64X1D (
 | 
					module RAM64X1D (
 | 
				
			||||||
  output DPO, SPO,
 | 
					  output DPO, SPO,
 | 
				
			||||||
  input  D, WCLK, WE,
 | 
					  input  D, WCLK, WE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,7 +115,7 @@ function xtract_cell_decl()
 | 
				
			||||||
	xtract_cell_decl PS7
 | 
						xtract_cell_decl PS7
 | 
				
			||||||
	xtract_cell_decl PULLDOWN
 | 
						xtract_cell_decl PULLDOWN
 | 
				
			||||||
	xtract_cell_decl PULLUP
 | 
						xtract_cell_decl PULLUP
 | 
				
			||||||
	# xtract_cell_decl RAM128X1D
 | 
						xtract_cell_decl RAM128X1D
 | 
				
			||||||
	xtract_cell_decl RAM128X1S
 | 
						xtract_cell_decl RAM128X1S
 | 
				
			||||||
	xtract_cell_decl RAM256X1S
 | 
						xtract_cell_decl RAM256X1S
 | 
				
			||||||
	xtract_cell_decl RAM32M
 | 
						xtract_cell_decl RAM32M
 | 
				
			||||||
| 
						 | 
					@ -124,7 +124,7 @@ function xtract_cell_decl()
 | 
				
			||||||
	xtract_cell_decl RAM32X1S_1
 | 
						xtract_cell_decl RAM32X1S_1
 | 
				
			||||||
	xtract_cell_decl RAM32X2S
 | 
						xtract_cell_decl RAM32X2S
 | 
				
			||||||
	xtract_cell_decl RAM64M
 | 
						xtract_cell_decl RAM64M
 | 
				
			||||||
	# xtract_cell_decl RAM64X1D
 | 
						xtract_cell_decl RAM64X1D
 | 
				
			||||||
	xtract_cell_decl RAM64X1S
 | 
						xtract_cell_decl RAM64X1S
 | 
				
			||||||
	xtract_cell_decl RAM64X1S_1
 | 
						xtract_cell_decl RAM64X1S_1
 | 
				
			||||||
	xtract_cell_decl RAM64X2S
 | 
						xtract_cell_decl RAM64X2S
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3695,6 +3695,25 @@ module RAM128X1S (...);
 | 
				
			||||||
    input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE;
 | 
					    input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE;
 | 
				
			||||||
endmodule
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module RAM128X1D (
 | 
				
			||||||
 | 
					  output       DPO, SPO,
 | 
				
			||||||
 | 
					  input        D, WCLK, WE,
 | 
				
			||||||
 | 
					  input  [6:0] A, DPRA
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter [127:0] INIT = 128'bx;
 | 
				
			||||||
 | 
						parameter IS_WCLK_INVERTED = 0;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module RAM64X1D (
 | 
				
			||||||
 | 
					  output DPO, SPO,
 | 
				
			||||||
 | 
					  input  D, WCLK, WE,
 | 
				
			||||||
 | 
					  input  A0, A1, A2, A3, A4, A5,
 | 
				
			||||||
 | 
					  input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
						parameter [63:0] INIT = 64'bx;
 | 
				
			||||||
 | 
						parameter IS_WCLK_INVERTED = 0;
 | 
				
			||||||
 | 
					endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module RAM256X1S (...);
 | 
					module RAM256X1S (...);
 | 
				
			||||||
    parameter [255:0] INIT = 256'h0;
 | 
					    parameter [255:0] INIT = 256'h0;
 | 
				
			||||||
    parameter [0:0] IS_WCLK_INVERTED = 1'b0;
 | 
					    parameter [0:0] IS_WCLK_INVERTED = 1'b0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										42
									
								
								techlibs/xilinx/ff_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								techlibs/xilinx/ff_map.v
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  yosys -- Yosys Open SYnthesis Suite
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ============================================================================
 | 
				
			||||||
 | 
					// FF mapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`ifndef _NO_FFS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module  \$_DFF_N_   (input D, C, output Q);    FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_P_   (input D, C, output Q);    FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module  \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFFE_PP_ (input D, C, E, output Q); FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module  \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_PN0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_PP0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module  \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_PN1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
 | 
				
			||||||
 | 
					module  \$_DFF_PP1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,65 +0,0 @@
 | 
				
			||||||
module LUT1(output O, input I0);
 | 
					 | 
				
			||||||
  parameter [1:0] INIT = 0;
 | 
					 | 
				
			||||||
  \$lut #(
 | 
					 | 
				
			||||||
    .WIDTH(1),
 | 
					 | 
				
			||||||
    .LUT(INIT)
 | 
					 | 
				
			||||||
  ) _TECHMAP_REPLACE_ (
 | 
					 | 
				
			||||||
    .A(I0),
 | 
					 | 
				
			||||||
    .Y(O)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module LUT2(output O, input I0, I1);
 | 
					 | 
				
			||||||
  parameter [3:0] INIT = 0;
 | 
					 | 
				
			||||||
  \$lut #(
 | 
					 | 
				
			||||||
    .WIDTH(2),
 | 
					 | 
				
			||||||
    .LUT(INIT)
 | 
					 | 
				
			||||||
  ) _TECHMAP_REPLACE_ (
 | 
					 | 
				
			||||||
    .A({I1, I0}),
 | 
					 | 
				
			||||||
    .Y(O)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module LUT3(output O, input I0, I1, I2);
 | 
					 | 
				
			||||||
  parameter [7:0] INIT = 0;
 | 
					 | 
				
			||||||
  \$lut #(
 | 
					 | 
				
			||||||
    .WIDTH(3),
 | 
					 | 
				
			||||||
    .LUT(INIT)
 | 
					 | 
				
			||||||
  ) _TECHMAP_REPLACE_ (
 | 
					 | 
				
			||||||
    .A({I2, I1, I0}),
 | 
					 | 
				
			||||||
    .Y(O)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module LUT4(output O, input I0, I1, I2, I3);
 | 
					 | 
				
			||||||
  parameter [15:0] INIT = 0;
 | 
					 | 
				
			||||||
  \$lut #(
 | 
					 | 
				
			||||||
    .WIDTH(4),
 | 
					 | 
				
			||||||
    .LUT(INIT)
 | 
					 | 
				
			||||||
  ) _TECHMAP_REPLACE_ (
 | 
					 | 
				
			||||||
    .A({I3, I2, I1, I0}),
 | 
					 | 
				
			||||||
    .Y(O)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module LUT5(output O, input I0, I1, I2, I3, I4);
 | 
					 | 
				
			||||||
  parameter [31:0] INIT = 0;
 | 
					 | 
				
			||||||
  \$lut #(
 | 
					 | 
				
			||||||
    .WIDTH(5),
 | 
					 | 
				
			||||||
    .LUT(INIT)
 | 
					 | 
				
			||||||
  ) _TECHMAP_REPLACE_ (
 | 
					 | 
				
			||||||
    .A({I4, I3, I2, I1, I0}),
 | 
					 | 
				
			||||||
    .Y(O)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module LUT6(output O, input I0, I1, I2, I3, I4, I5);
 | 
					 | 
				
			||||||
  parameter [63:0] INIT = 0;
 | 
					 | 
				
			||||||
  \$lut #(
 | 
					 | 
				
			||||||
    .WIDTH(6),
 | 
					 | 
				
			||||||
    .LUT(INIT)
 | 
					 | 
				
			||||||
  ) _TECHMAP_REPLACE_ (
 | 
					 | 
				
			||||||
    .A({I5, I4, I3, I2, I1, I0}),
 | 
					 | 
				
			||||||
    .Y(O)
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
endmodule
 | 
					 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue