mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into xaig
This commit is contained in:
		
						commit
						4883391b63
					
				
					 46 changed files with 4201 additions and 97 deletions
				
			
		
							
								
								
									
										20
									
								
								.travis.yml
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								.travis.yml
									
										
									
									
									
								
							|  | @ -32,6 +32,10 @@ matrix: | ||||||
|             - xdot |             - xdot | ||||||
|             - pkg-config |             - pkg-config | ||||||
|             - python |             - python | ||||||
|  |             - python3 | ||||||
|  |             - libboost-system-dev | ||||||
|  |             - libboost-python-dev | ||||||
|  |             - libboost-filesystem-dev | ||||||
|       env: |       env: | ||||||
|         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" |         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" | ||||||
| 
 | 
 | ||||||
|  | @ -56,6 +60,10 @@ matrix: | ||||||
|             - xdot |             - xdot | ||||||
|             - pkg-config |             - pkg-config | ||||||
|             - python |             - python | ||||||
|  |             - python3 | ||||||
|  |             - libboost-system-dev | ||||||
|  |             - libboost-python-dev | ||||||
|  |             - libboost-filesystem-dev | ||||||
|       env: |       env: | ||||||
|         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6" |         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6" | ||||||
| 
 | 
 | ||||||
|  | @ -80,6 +88,10 @@ matrix: | ||||||
|             - xdot |             - xdot | ||||||
|             - pkg-config |             - pkg-config | ||||||
|             - python |             - python | ||||||
|  |             - python3 | ||||||
|  |             - libboost-system-dev | ||||||
|  |             - libboost-python-dev | ||||||
|  |             - libboost-filesystem-dev | ||||||
|       env: |       env: | ||||||
|         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" |         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" | ||||||
| 
 | 
 | ||||||
|  | @ -105,6 +117,10 @@ matrix: | ||||||
|             - xdot |             - xdot | ||||||
|             - pkg-config |             - pkg-config | ||||||
|             - python |             - python | ||||||
|  |             - python3 | ||||||
|  |             - libboost-system-dev | ||||||
|  |             - libboost-python-dev | ||||||
|  |             - libboost-filesystem-dev | ||||||
|       env: |       env: | ||||||
|         - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" |         - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" | ||||||
| 
 | 
 | ||||||
|  | @ -129,6 +145,10 @@ matrix: | ||||||
|             - xdot |             - xdot | ||||||
|             - pkg-config |             - pkg-config | ||||||
|             - python |             - python | ||||||
|  |             - python3 | ||||||
|  |             - libboost-system-dev | ||||||
|  |             - libboost-python-dev | ||||||
|  |             - libboost-filesystem-dev | ||||||
|       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" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										57
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										57
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -19,6 +19,14 @@ ENABLE_COVER := 1 | ||||||
| ENABLE_LIBYOSYS := 0 | ENABLE_LIBYOSYS := 0 | ||||||
| ENABLE_PROTOBUF := 0 | ENABLE_PROTOBUF := 0 | ||||||
| 
 | 
 | ||||||
|  | # python wrappers
 | ||||||
|  | ENABLE_PYOSYS := 0 | ||||||
|  | PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" | ||||||
|  | PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) | ||||||
|  | PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") | ||||||
|  | PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) | ||||||
|  | PYTHON_DESTDIR := `$(PYTHON_EXECUTABLE)-config --prefix`/lib/python$(PYTHON_VERSION)/dist-packages | ||||||
|  | 
 | ||||||
| # other configuration flags
 | # other configuration flags
 | ||||||
| ENABLE_GCOV := 0 | ENABLE_GCOV := 0 | ||||||
| ENABLE_GPROF := 0 | ENABLE_GPROF := 0 | ||||||
|  | @ -261,6 +269,34 @@ ifeq ($(ENABLE_LIBYOSYS),1) | ||||||
| TARGETS += libyosys.so | TARGETS += libyosys.so | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | ifeq ($(ENABLE_PYOSYS),1) | ||||||
|  | 
 | ||||||
|  | #Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
 | ||||||
|  | BOOST_PYTHON_LIB ?= $(shell \
 | ||||||
|  | 	if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1;        then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))";       else \
 | ||||||
|  | 	if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1;  then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
 | ||||||
|  | 	if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1;           then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))";          else \
 | ||||||
|  | 	if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1;     then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))";    else \
 | ||||||
|  |                                                                                                                                                                                         echo ""; fi; fi; fi; fi;) | ||||||
|  | 
 | ||||||
|  | ifeq ($(BOOST_PYTHON_LIB),) | ||||||
|  | $(error BOOST_PYTHON_LIB could not be detected. Please define manualy) | ||||||
|  | endif | ||||||
|  | 
 | ||||||
|  | ifeq ($(PYTHON_MAJOR_VERSION),3) | ||||||
|  | LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem | ||||||
|  | CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON | ||||||
|  | else | ||||||
|  | LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem | ||||||
|  | CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON | ||||||
|  | endif | ||||||
|  | 
 | ||||||
|  | PY_WRAPPER_FILE = kernel/python_wrappers | ||||||
|  | OBJS += $(PY_WRAPPER_FILE).o | ||||||
|  | PY_GEN_SCRIPT= py_wrap_generator | ||||||
|  | PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| ifeq ($(ENABLE_READLINE),1) | ifeq ($(ENABLE_READLINE),1) | ||||||
| CXXFLAGS += -DYOSYS_ENABLE_READLINE | CXXFLAGS += -DYOSYS_ENABLE_READLINE | ||||||
| ifeq ($(OS), FreeBSD) | ifeq ($(OS), FreeBSD) | ||||||
|  | @ -511,6 +547,14 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) | ||||||
| 	$(Q) mkdir -p $(dir $@) | 	$(Q) mkdir -p $(dir $@) | ||||||
| 	$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< | 	$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< | ||||||
| 
 | 
 | ||||||
|  | %.pyh: %.h | ||||||
|  | 	$(Q) mkdir -p $(dir $@) | ||||||
|  | 	$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P - | ||||||
|  | 
 | ||||||
|  | $(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) | ||||||
|  | 	$(Q) mkdir -p $(dir $@) | ||||||
|  | 	$(P) python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" | ||||||
|  | 
 | ||||||
| %.o: %.cpp | %.o: %.cpp | ||||||
| 	$(Q) mkdir -p $(dir $@) | 	$(Q) mkdir -p $(dir $@) | ||||||
| 	$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< | 	$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< | ||||||
|  | @ -639,6 +683,11 @@ ifeq ($(ENABLE_LIBYOSYS),1) | ||||||
| 	$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) | 	$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) | ||||||
| 	$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so | 	$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so | ||||||
| 	$(INSTALL_SUDO) ldconfig | 	$(INSTALL_SUDO) ldconfig | ||||||
|  | ifeq ($(ENABLE_PYOSYS),1) | ||||||
|  | 	$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys | ||||||
|  | 	$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys | ||||||
|  | 	$(INSTALL_SUDO) cp __init__.py $(PYTHON_DESTDIR)/pyosys | ||||||
|  | endif | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| uninstall: | uninstall: | ||||||
|  | @ -646,6 +695,11 @@ uninstall: | ||||||
| 	$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) | 	$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) | ||||||
| ifeq ($(ENABLE_LIBYOSYS),1) | ifeq ($(ENABLE_LIBYOSYS),1) | ||||||
| 	$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so | 	$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so | ||||||
|  | ifeq ($(ENABLE_PYOSYS),1) | ||||||
|  | 	$(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/libyosys.so | ||||||
|  | 	$(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/__init__.py | ||||||
|  | 	$(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/pyosys | ||||||
|  | endif | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| update-manual: $(TARGETS) $(EXTRA_TARGETS) | update-manual: $(TARGETS) $(EXTRA_TARGETS) | ||||||
|  | @ -658,8 +712,9 @@ manual: $(TARGETS) $(EXTRA_TARGETS) | ||||||
| 
 | 
 | ||||||
| clean: | clean: | ||||||
| 	rm -rf share | 	rm -rf share | ||||||
|  | 	rm -rf kernel/*.pyh | ||||||
| 	if test -d manual; then cd manual && sh clean.sh; fi | 	if test -d manual; then cd manual && sh clean.sh; fi | ||||||
| 	rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) | 	rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc | ||||||
| 	rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a | 	rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a | ||||||
| 	rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d | 	rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d | ||||||
| 	rm -rf tests/asicworld/*.out tests/asicworld/*.log | 	rm -rf tests/asicworld/*.out tests/asicworld/*.log | ||||||
|  |  | ||||||
|  | @ -66,25 +66,26 @@ prerequisites for building yosys: | ||||||
| 
 | 
 | ||||||
| 	$ sudo apt-get install build-essential clang bison flex \ | 	$ sudo apt-get install build-essential clang bison flex \ | ||||||
| 		libreadline-dev gawk tcl-dev libffi-dev git \ | 		libreadline-dev gawk tcl-dev libffi-dev git \ | ||||||
| 		graphviz xdot pkg-config python3 | 		graphviz xdot pkg-config python3 libboost-system-dev \ | ||||||
|  | 		libboost-python-dev libboost-filesystem-dev | ||||||
| 
 | 
 | ||||||
| Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: | Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: | ||||||
| 
 | 
 | ||||||
| 	$ brew tap Homebrew/bundle && brew bundle | 	$ brew tap Homebrew/bundle && brew bundle | ||||||
| 	$ sudo port install bison flex readline gawk libffi \ | 	$ sudo port install bison flex readline gawk libffi \ | ||||||
| 		git graphviz pkgconfig python36 | 		git graphviz pkgconfig python36 boost | ||||||
| 
 | 
 | ||||||
| On FreeBSD use the following command to install all prerequisites: | On FreeBSD use the following command to install all prerequisites: | ||||||
| 
 | 
 | ||||||
| 	# pkg install bison flex readline gawk libffi\ | 	# pkg install bison flex readline gawk libffi\ | ||||||
| 		git graphviz pkgconfig python3 python36 tcl-wrapper | 		git graphviz pkgconfig python3 python36 tcl-wrapper boost-libs | ||||||
| 
 | 
 | ||||||
| On FreeBSD system use gmake instead of make. To run tests use: | On FreeBSD system use gmake instead of make. To run tests use: | ||||||
|     % MAKE=gmake CC=cc gmake test |     % MAKE=gmake CC=cc gmake test | ||||||
| 
 | 
 | ||||||
| For Cygwin use the following command to install all prerequisites, or select these additional packages: | For Cygwin use the following command to install all prerequisites, or select these additional packages: | ||||||
| 
 | 
 | ||||||
| 	setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel | 	setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build | ||||||
| 
 | 
 | ||||||
| There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well | There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well | ||||||
| as a source distribution for Visual Studio. Visit the Yosys download page for | as a source distribution for Visual Studio. Visit the Yosys download page for | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | import os | ||||||
|  | import sys | ||||||
|  | sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) | ||||||
|  | 
 | ||||||
|  | __all__ = ["libyosys"] | ||||||
|  | @ -187,6 +187,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o | ||||||
| { | { | ||||||
| 	if (width < 0) | 	if (width < 0) | ||||||
| 		width = data.bits.size() - offset; | 		width = data.bits.size() - offset; | ||||||
|  | 	if (width == 0) { | ||||||
|  | 		f << "\"\""; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	if (nostr) | 	if (nostr) | ||||||
| 		goto dump_hex; | 		goto dump_hex; | ||||||
| 	if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { | 	if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { | ||||||
|  | @ -340,6 +344,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima | ||||||
| 
 | 
 | ||||||
| void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) | void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) | ||||||
| { | { | ||||||
|  | 	if (GetSize(sig) == 0) { | ||||||
|  | 		f << "\"\""; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	if (sig.is_chunk()) { | 	if (sig.is_chunk()) { | ||||||
| 		dump_sigchunk(f, sig.as_chunk()); | 		dump_sigchunk(f, sig.as_chunk()); | ||||||
| 	} else { | 	} else { | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								examples/python-api/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/python-api/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | out/** | ||||||
							
								
								
									
										32
									
								
								examples/python-api/pass.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								examples/python-api/pass.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | #!/usr/bin/python3 | ||||||
|  | 
 | ||||||
|  | from pyosys import libyosys as ys | ||||||
|  | 
 | ||||||
|  | import matplotlib.pyplot as plt | ||||||
|  | import numpy as np | ||||||
|  | 
 | ||||||
|  | class CellStatsPass(ys.Pass): | ||||||
|  | 
 | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__("cell_stats", "Shows cell stats as plot") | ||||||
|  | 
 | ||||||
|  |     def py_help(self): | ||||||
|  |         ys.log("This pass uses the matplotlib library to display cell stats\n") | ||||||
|  | 
 | ||||||
|  |     def py_execute(self, args, design): | ||||||
|  |         ys.log_header(design, "Plotting cell stats\n") | ||||||
|  |         cell_stats = {} | ||||||
|  |         for module in design.selected_whole_modules_warn(): | ||||||
|  |             for cell in module.selected_cells(): | ||||||
|  |                 if cell.type.str() in cell_stats: | ||||||
|  |                     cell_stats[cell.type.str()] += 1 | ||||||
|  |                 else: | ||||||
|  |                     cell_stats[cell.type.str()] = 1 | ||||||
|  |         plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center') | ||||||
|  |         plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) | ||||||
|  |         plt.show() | ||||||
|  | 
 | ||||||
|  |     def py_clear_flags(self): | ||||||
|  |         ys.log("Clear Flags - CellStatsPass\n") | ||||||
|  | 
 | ||||||
|  | p = CellStatsPass() | ||||||
							
								
								
									
										22
									
								
								examples/python-api/script.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										22
									
								
								examples/python-api/script.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | #!/usr/bin/python3 | ||||||
|  | 
 | ||||||
|  | from pyosys import libyosys as ys | ||||||
|  | 
 | ||||||
|  | import matplotlib.pyplot as plt | ||||||
|  | import numpy as np | ||||||
|  | 
 | ||||||
|  | design = ys.Design() | ||||||
|  | ys.run_pass("read_verilog ../../tests/simple/fiedler-cooley.v", design); | ||||||
|  | ys.run_pass("prep", design) | ||||||
|  | ys.run_pass("opt -full", design) | ||||||
|  | 
 | ||||||
|  | cell_stats = {} | ||||||
|  | for module in design.selected_whole_modules_warn(): | ||||||
|  |   for cell in module.selected_cells(): | ||||||
|  |     if cell.type.str() in cell_stats: | ||||||
|  |       cell_stats[cell.type.str()] += 1 | ||||||
|  |     else: | ||||||
|  |       cell_stats[cell.type.str()] = 1 | ||||||
|  | plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center') | ||||||
|  | plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) | ||||||
|  | plt.show() | ||||||
|  | @ -35,9 +35,6 @@ | ||||||
| 
 | 
 | ||||||
| YOSYS_NAMESPACE_BEGIN | YOSYS_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
| //#define log_debug log
 |  | ||||||
| #define log_debug(...) ; |  | ||||||
| 
 |  | ||||||
| AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) | AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) | ||||||
|     : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) |     : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -1030,7 +1030,26 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 		log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); | 		log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); | ||||||
| 
 | 
 | ||||||
| 	if (type == AST_REPEAT) | 	if (type == AST_REPEAT) | ||||||
| 		log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n"); | 	{ | ||||||
|  | 		AstNode *count = children[0]; | ||||||
|  | 		AstNode *body = children[1]; | ||||||
|  | 
 | ||||||
|  | 		// eval count expression
 | ||||||
|  | 		while (count->simplify(true, false, false, stage, 32, true, false)) { } | ||||||
|  | 
 | ||||||
|  | 		if (count->type != AST_CONSTANT) | ||||||
|  | 			log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n"); | ||||||
|  | 
 | ||||||
|  | 		// convert to a block with the body repeated n times
 | ||||||
|  | 		type = AST_BLOCK; | ||||||
|  | 		children.clear(); | ||||||
|  | 		for (int i = 0; i < count->bitsAsConst().as_int(); i++) | ||||||
|  | 			children.insert(children.begin(), body->clone()); | ||||||
|  | 
 | ||||||
|  | 		delete count; | ||||||
|  | 		delete body; | ||||||
|  | 		did_something = true; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// unroll for loops and generate-for blocks
 | 	// unroll for loops and generate-for blocks
 | ||||||
| 	if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) | 	if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) | ||||||
|  | @ -1066,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 
 | 
 | ||||||
| 		// eval 1st expression
 | 		// eval 1st expression
 | ||||||
| 		AstNode *varbuf = init_ast->children[1]->clone(); | 		AstNode *varbuf = init_ast->children[1]->clone(); | ||||||
| 		while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } | 		{ | ||||||
|  | 			int expr_width_hint = -1; | ||||||
|  | 			bool expr_sign_hint = true; | ||||||
|  | 			varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); | ||||||
|  | 			while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		if (varbuf->type != AST_CONSTANT) | 		if (varbuf->type != AST_CONSTANT) | ||||||
| 			log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); | 			log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); | ||||||
|  | @ -1088,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 		{ | 		{ | ||||||
| 			// eval 2nd expression
 | 			// eval 2nd expression
 | ||||||
| 			AstNode *buf = while_ast->clone(); | 			AstNode *buf = while_ast->clone(); | ||||||
| 			while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | 			{ | ||||||
|  | 				int expr_width_hint = -1; | ||||||
|  | 				bool expr_sign_hint = true; | ||||||
|  | 				buf->detectSignWidth(expr_width_hint, expr_sign_hint); | ||||||
|  | 				while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { } | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (buf->type != AST_CONSTANT) | 			if (buf->type != AST_CONSTANT) | ||||||
| 				log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); | 				log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); | ||||||
|  | @ -1129,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | ||||||
| 
 | 
 | ||||||
| 			// eval 3rd expression
 | 			// eval 3rd expression
 | ||||||
| 			buf = next_ast->children[1]->clone(); | 			buf = next_ast->children[1]->clone(); | ||||||
| 			while (buf->simplify(true, false, false, stage, 32, true, false)) { } | 			{ | ||||||
|  | 				int expr_width_hint = -1; | ||||||
|  | 				bool expr_sign_hint = true; | ||||||
|  | 				buf->detectSignWidth(expr_width_hint, expr_sign_hint); | ||||||
|  | 				while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { } | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (buf->type != AST_CONSTANT) | 			if (buf->type != AST_CONSTANT) | ||||||
| 				log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); | 				log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); | ||||||
|  |  | ||||||
|  | @ -26,8 +26,55 @@ YOSYS_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
| int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr); | int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr); | ||||||
| 
 | 
 | ||||||
| int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters = dict<RTLIL::IdString, RTLIL::Const>(), | inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters = dict<RTLIL::IdString, RTLIL::Const>(), | ||||||
| 		RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr); | 		RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr) | ||||||
|  | { | ||||||
|  | 	static dict<RTLIL::IdString, int> gate_cost = { | ||||||
|  | 		{ "$_BUF_",    1 }, | ||||||
|  | 		{ "$_NOT_",    2 }, | ||||||
|  | 		{ "$_AND_",    4 }, | ||||||
|  | 		{ "$_NAND_",   4 }, | ||||||
|  | 		{ "$_OR_",     4 }, | ||||||
|  | 		{ "$_NOR_",    4 }, | ||||||
|  | 		{ "$_ANDNOT_", 4 }, | ||||||
|  | 		{ "$_ORNOT_",  4 }, | ||||||
|  | 		{ "$_XOR_",    8 }, | ||||||
|  | 		{ "$_XNOR_",   8 }, | ||||||
|  | 		{ "$_AOI3_",   6 }, | ||||||
|  | 		{ "$_OAI3_",   6 }, | ||||||
|  | 		{ "$_AOI4_",   8 }, | ||||||
|  | 		{ "$_OAI4_",   8 }, | ||||||
|  | 		{ "$_MUX_",    4 } | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	if (gate_cost.count(type)) | ||||||
|  | 		return gate_cost.at(type); | ||||||
|  | 
 | ||||||
|  | 	if (parameters.empty() && design && design->module(type)) | ||||||
|  | 	{ | ||||||
|  | 		RTLIL::Module *mod = design->module(type); | ||||||
|  | 
 | ||||||
|  | 		if (mod->attributes.count("\\cost")) | ||||||
|  | 			return mod->attributes.at("\\cost").as_int(); | ||||||
|  | 
 | ||||||
|  | 		dict<RTLIL::IdString, int> local_mod_cost_cache; | ||||||
|  | 		if (mod_cost_cache == nullptr) | ||||||
|  | 			mod_cost_cache = &local_mod_cost_cache; | ||||||
|  | 
 | ||||||
|  | 		if (mod_cost_cache->count(mod->name)) | ||||||
|  | 			return mod_cost_cache->at(mod->name); | ||||||
|  | 
 | ||||||
|  | 		int module_cost = 1; | ||||||
|  | 		for (auto c : mod->cells()) | ||||||
|  | 			module_cost += get_cell_cost(c, mod_cost_cache); | ||||||
|  | 
 | ||||||
|  | 		(*mod_cost_cache)[mod->name] = module_cost; | ||||||
|  | 		return module_cost; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache) | inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -110,6 +110,10 @@ int main(int argc, char **argv) | ||||||
| 	log_error_stderr = true; | 	log_error_stderr = true; | ||||||
| 	yosys_banner(); | 	yosys_banner(); | ||||||
| 	yosys_setup(); | 	yosys_setup(); | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); | ||||||
|  | 	PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	if (argc == 2) | 	if (argc == 2) | ||||||
| 	{ | 	{ | ||||||
|  | @ -291,6 +295,9 @@ int main(int argc, char **argv) | ||||||
| 		printf("    -E <depsfile>\n"); | 		printf("    -E <depsfile>\n"); | ||||||
| 		printf("        write a Makefile dependencies file with in- and output file names\n"); | 		printf("        write a Makefile dependencies file with in- and output file names\n"); | ||||||
| 		printf("\n"); | 		printf("\n"); | ||||||
|  | 		printf("    -g\n"); | ||||||
|  | 		printf("        globally enable debug log messages\n"); | ||||||
|  | 		printf("\n"); | ||||||
| 		printf("    -V\n"); | 		printf("    -V\n"); | ||||||
| 		printf("        print version information and exit\n"); | 		printf("        print version information and exit\n"); | ||||||
| 		printf("\n"); | 		printf("\n"); | ||||||
|  | @ -311,7 +318,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:P:E:")) != -1) | 	while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) | ||||||
| 	{ | 	{ | ||||||
| 		switch (opt) | 		switch (opt) | ||||||
| 		{ | 		{ | ||||||
|  | @ -336,6 +343,9 @@ int main(int argc, char **argv) | ||||||
| 		case 'S': | 		case 'S': | ||||||
| 			passes_commands.push_back("synth"); | 			passes_commands.push_back("synth"); | ||||||
| 			break; | 			break; | ||||||
|  | 		case 'g': | ||||||
|  | 			log_force_debug++; | ||||||
|  | 			break; | ||||||
| 		case 'm': | 		case 'm': | ||||||
| 			plugin_filenames.push_back(optarg); | 			plugin_filenames.push_back(optarg); | ||||||
| 			break; | 			break; | ||||||
|  | @ -469,6 +479,10 @@ int main(int argc, char **argv) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	yosys_setup(); | 	yosys_setup(); | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); | ||||||
|  | 	PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); | ||||||
|  | #endif | ||||||
| 	log_error_atexit = yosys_atexit; | 	log_error_atexit = yosys_atexit; | ||||||
| 
 | 
 | ||||||
| 	for (auto &fn : plugin_filenames) | 	for (auto &fn : plugin_filenames) | ||||||
|  |  | ||||||
|  | @ -56,6 +56,10 @@ int log_verbose_level; | ||||||
| string log_last_error; | string log_last_error; | ||||||
| void (*log_error_atexit)() = NULL; | void (*log_error_atexit)() = NULL; | ||||||
| 
 | 
 | ||||||
|  | int log_make_debug = 0; | ||||||
|  | int log_force_debug = 0; | ||||||
|  | int log_debug_suppressed = 0; | ||||||
|  | 
 | ||||||
| vector<int> header_count; | vector<int> header_count; | ||||||
| pool<RTLIL::IdString> log_id_cache; | pool<RTLIL::IdString> log_id_cache; | ||||||
| vector<shared_str> string_buf; | vector<shared_str> string_buf; | ||||||
|  | @ -92,6 +96,9 @@ void logv(const char *format, va_list ap) | ||||||
| 		format++; | 		format++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (log_make_debug && !ys_debug(1)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	std::string str = vstringf(format, ap); | 	std::string str = vstringf(format, ap); | ||||||
| 
 | 
 | ||||||
| 	if (str.empty()) | 	if (str.empty()) | ||||||
|  |  | ||||||
							
								
								
									
										43
									
								
								kernel/log.h
									
										
									
									
									
								
							
							
						
						
									
										43
									
								
								kernel/log.h
									
										
									
									
									
								
							|  | @ -64,6 +64,10 @@ extern int log_verbose_level; | ||||||
| extern string log_last_error; | extern string log_last_error; | ||||||
| extern void (*log_error_atexit)(); | extern void (*log_error_atexit)(); | ||||||
| 
 | 
 | ||||||
|  | extern int log_make_debug; | ||||||
|  | extern int log_force_debug; | ||||||
|  | extern int log_debug_suppressed; | ||||||
|  | 
 | ||||||
| void logv(const char *format, va_list ap); | void logv(const char *format, va_list ap); | ||||||
| void logv_header(RTLIL::Design *design, const char *format, va_list ap); | void logv_header(RTLIL::Design *design, const char *format, va_list ap); | ||||||
| void logv_warning(const char *format, va_list ap); | void logv_warning(const char *format, va_list ap); | ||||||
|  | @ -82,6 +86,45 @@ YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, | ||||||
| void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); | void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); | ||||||
| YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); | YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); | ||||||
| 
 | 
 | ||||||
|  | #ifndef NDEBUG | ||||||
|  | static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } | ||||||
|  | #  define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) | ||||||
|  | #else | ||||||
|  | static inline bool ys_debug(int n = 0) { return false; } | ||||||
|  | #  define log_debug(_fmt, ...) do { } while (0) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static inline void log_suppressed() { | ||||||
|  | 	if (log_debug_suppressed && !log_make_debug) { | ||||||
|  | 		log("<suppressed ~%d debug messages>\n", log_debug_suppressed); | ||||||
|  | 		log_debug_suppressed = 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct LogMakeDebugHdl { | ||||||
|  | 	bool status = false; | ||||||
|  | 	LogMakeDebugHdl(bool start_on = false) { | ||||||
|  | 		if (start_on) | ||||||
|  | 			on(); | ||||||
|  | 	} | ||||||
|  | 	~LogMakeDebugHdl() { | ||||||
|  | 		off(); | ||||||
|  | 	} | ||||||
|  | 	void on() { | ||||||
|  | 		if (status) return; | ||||||
|  | 		status=true; | ||||||
|  | 		log_make_debug++; | ||||||
|  | 	} | ||||||
|  | 	void off_silent() { | ||||||
|  | 		if (!status) return; | ||||||
|  | 		status=false; | ||||||
|  | 		log_make_debug--; | ||||||
|  | 	} | ||||||
|  | 	void off() { | ||||||
|  | 		off_silent(); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void log_spacer(); | void log_spacer(); | ||||||
| void log_push(); | void log_push(); | ||||||
| void log_pop(); | void log_pop(); | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ 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(); | 	IdString::checkpoint(); | ||||||
|  | 	log_suppressed(); | ||||||
| 
 | 
 | ||||||
| 	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; | ||||||
|  |  | ||||||
|  | @ -76,6 +76,13 @@ RTLIL::Const::Const(const std::vector<bool> &bits) | ||||||
| 		this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0); | 		this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | RTLIL::Const::Const(const RTLIL::Const &c) | ||||||
|  | { | ||||||
|  | 	flags = c.flags; | ||||||
|  | 	for (auto b : c.bits) | ||||||
|  | 		this->bits.push_back(b); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool RTLIL::Const::operator <(const RTLIL::Const &other) const | bool RTLIL::Const::operator <(const RTLIL::Const &other) const | ||||||
| { | { | ||||||
| 	if (bits.size() != other.bits.size()) | 	if (bits.size() != other.bits.size()) | ||||||
|  | @ -363,6 +370,10 @@ RTLIL::Design::Design() | ||||||
| 
 | 
 | ||||||
| 	refcount_modules_ = 0; | 	refcount_modules_ = 0; | ||||||
| 	selection_stack.push_back(RTLIL::Selection()); | 	selection_stack.push_back(RTLIL::Selection()); | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Design::get_all_designs()->insert(std::pair<unsigned int, RTLIL::Design*>(hashidx_, this)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RTLIL::Design::~Design() | RTLIL::Design::~Design() | ||||||
|  | @ -373,8 +384,19 @@ RTLIL::Design::~Design() | ||||||
| 		delete n; | 		delete n; | ||||||
| 	for (auto n : verilog_globals) | 	for (auto n : verilog_globals) | ||||||
| 		delete n; | 		delete n; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Design::get_all_designs()->erase(hashidx_); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | static std::map<unsigned int, RTLIL::Design*> all_designs; | ||||||
|  | std::map<unsigned int, RTLIL::Design*> *RTLIL::Design::get_all_designs(void) | ||||||
|  | { | ||||||
|  | 	return &all_designs; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() | RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() | ||||||
| { | { | ||||||
| 	return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_); | 	return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_); | ||||||
|  | @ -630,6 +652,10 @@ RTLIL::Module::Module() | ||||||
| 	design = nullptr; | 	design = nullptr; | ||||||
| 	refcount_wires_ = 0; | 	refcount_wires_ = 0; | ||||||
| 	refcount_cells_ = 0; | 	refcount_cells_ = 0; | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Module::get_all_modules()->insert(std::pair<unsigned int, RTLIL::Module*>(hashidx_, this)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RTLIL::Module::~Module() | RTLIL::Module::~Module() | ||||||
|  | @ -642,8 +668,19 @@ RTLIL::Module::~Module() | ||||||
| 		delete it->second; | 		delete it->second; | ||||||
| 	for (auto it = processes.begin(); it != processes.end(); ++it) | 	for (auto it = processes.begin(); it != processes.end(); ++it) | ||||||
| 		delete it->second; | 		delete it->second; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Module::get_all_modules()->erase(hashidx_); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | static std::map<unsigned int, RTLIL::Module*> all_modules; | ||||||
|  | std::map<unsigned int, RTLIL::Module*> *RTLIL::Module::get_all_modules(void) | ||||||
|  | { | ||||||
|  | 	return &all_modules; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| void RTLIL::Module::makeblackbox() | void RTLIL::Module::makeblackbox() | ||||||
| { | { | ||||||
| 	pool<RTLIL::Wire*> delwires; | 	pool<RTLIL::Wire*> delwires; | ||||||
|  | @ -2229,8 +2266,27 @@ RTLIL::Wire::Wire() | ||||||
| 	port_input = false; | 	port_input = false; | ||||||
| 	port_output = false; | 	port_output = false; | ||||||
| 	upto = false; | 	upto = false; | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Wire::get_all_wires()->insert(std::pair<unsigned int, RTLIL::Wire*>(hashidx_, this)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | RTLIL::Wire::~Wire() | ||||||
|  | { | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Wire::get_all_wires()->erase(hashidx_); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | static std::map<unsigned int, RTLIL::Wire*> all_wires; | ||||||
|  | std::map<unsigned int, RTLIL::Wire*> *RTLIL::Wire::get_all_wires(void) | ||||||
|  | { | ||||||
|  | 	return &all_wires; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| RTLIL::Memory::Memory() | RTLIL::Memory::Memory() | ||||||
| { | { | ||||||
| 	static unsigned int hashidx_count = 123456789; | 	static unsigned int hashidx_count = 123456789; | ||||||
|  | @ -2240,6 +2296,9 @@ RTLIL::Memory::Memory() | ||||||
| 	width = 1; | 	width = 1; | ||||||
| 	start_offset = 0; | 	start_offset = 0; | ||||||
| 	size = 0; | 	size = 0; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Memory::get_all_memorys()->insert(std::pair<unsigned int, RTLIL::Memory*>(hashidx_, this)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RTLIL::Cell::Cell() : module(nullptr) | RTLIL::Cell::Cell() : module(nullptr) | ||||||
|  | @ -2250,8 +2309,27 @@ RTLIL::Cell::Cell() : module(nullptr) | ||||||
| 
 | 
 | ||||||
| 	// log("#memtrace# %p\n", this);
 | 	// log("#memtrace# %p\n", this);
 | ||||||
| 	memhasher(); | 	memhasher(); | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Cell::get_all_cells()->insert(std::pair<unsigned int, RTLIL::Cell*>(hashidx_, this)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | RTLIL::Cell::~Cell() | ||||||
|  | { | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	RTLIL::Cell::get_all_cells()->erase(hashidx_); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | static std::map<unsigned int, RTLIL::Cell*> all_cells; | ||||||
|  | std::map<unsigned int, RTLIL::Cell*> *RTLIL::Cell::get_all_cells(void) | ||||||
|  | { | ||||||
|  | 	return &all_cells; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const | bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const | ||||||
| { | { | ||||||
| 	return connections_.count(portname) != 0; | 	return connections_.count(portname) != 0; | ||||||
|  | @ -2511,6 +2589,14 @@ RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit) | ||||||
| 	width = 1; | 	width = 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk) : data(sigchunk.data) | ||||||
|  | { | ||||||
|  | 	wire = sigchunk.wire; | ||||||
|  | 	data = sigchunk.data; | ||||||
|  | 	width = sigchunk.width; | ||||||
|  | 	offset = sigchunk.offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const | RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const | ||||||
| { | { | ||||||
| 	RTLIL::SigChunk ret; | 	RTLIL::SigChunk ret; | ||||||
|  | @ -3895,5 +3981,15 @@ RTLIL::Process *RTLIL::Process::clone() const | ||||||
| 	return new_proc; | 	return new_proc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | RTLIL::Memory::~Memory() | ||||||
|  | { | ||||||
|  | 	RTLIL::Memory::get_all_memorys()->erase(hashidx_); | ||||||
|  | } | ||||||
|  | static std::map<unsigned int, RTLIL::Memory*> all_memorys; | ||||||
|  | std::map<unsigned int, RTLIL::Memory*> *RTLIL::Memory::get_all_memorys(void) | ||||||
|  | { | ||||||
|  | 	return &all_memorys; | ||||||
|  | } | ||||||
|  | #endif | ||||||
| YOSYS_NAMESPACE_END | YOSYS_NAMESPACE_END | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -523,6 +523,7 @@ struct RTLIL::Const | ||||||
| 	Const(RTLIL::State bit, int width = 1); | 	Const(RTLIL::State bit, int width = 1); | ||||||
| 	Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } | 	Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } | ||||||
| 	Const(const std::vector<bool> &bits); | 	Const(const std::vector<bool> &bits); | ||||||
|  | 	Const(const RTLIL::Const &c); | ||||||
| 
 | 
 | ||||||
| 	bool operator <(const RTLIL::Const &other) const; | 	bool operator <(const RTLIL::Const &other) const; | ||||||
| 	bool operator ==(const RTLIL::Const &other) const; | 	bool operator ==(const RTLIL::Const &other) const; | ||||||
|  | @ -601,6 +602,7 @@ struct RTLIL::SigChunk | ||||||
| 	SigChunk(int val, int width = 32); | 	SigChunk(int val, int width = 32); | ||||||
| 	SigChunk(RTLIL::State bit, int width = 1); | 	SigChunk(RTLIL::State bit, int width = 1); | ||||||
| 	SigChunk(RTLIL::SigBit bit); | 	SigChunk(RTLIL::SigBit bit); | ||||||
|  | 	SigChunk(const RTLIL::SigChunk &sigchunk); | ||||||
| 
 | 
 | ||||||
| 	RTLIL::SigChunk extract(int offset, int length) const; | 	RTLIL::SigChunk extract(int offset, int length) const; | ||||||
| 
 | 
 | ||||||
|  | @ -625,6 +627,7 @@ struct RTLIL::SigBit | ||||||
| 	SigBit(const RTLIL::SigChunk &chunk); | 	SigBit(const RTLIL::SigChunk &chunk); | ||||||
| 	SigBit(const RTLIL::SigChunk &chunk, int index); | 	SigBit(const RTLIL::SigChunk &chunk, int index); | ||||||
| 	SigBit(const RTLIL::SigSpec &sig); | 	SigBit(const RTLIL::SigSpec &sig); | ||||||
|  | 	SigBit(const RTLIL::SigBit &sigbit); | ||||||
| 
 | 
 | ||||||
| 	bool operator <(const RTLIL::SigBit &other) const; | 	bool operator <(const RTLIL::SigBit &other) const; | ||||||
| 	bool operator ==(const RTLIL::SigBit &other) const; | 	bool operator ==(const RTLIL::SigBit &other) const; | ||||||
|  | @ -946,9 +949,13 @@ struct RTLIL::Design | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	std::vector<RTLIL::Module*> selected_modules() const; | 	std::vector<RTLIL::Module*> selected_modules() const; | ||||||
| 	std::vector<RTLIL::Module*> selected_whole_modules() const; | 	std::vector<RTLIL::Module*> selected_whole_modules() const; | ||||||
| 	std::vector<RTLIL::Module*> selected_whole_modules_warn() const; | 	std::vector<RTLIL::Module*> selected_whole_modules_warn() const; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void); | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct RTLIL::Module : public RTLIL::AttrObject | struct RTLIL::Module : public RTLIL::AttrObject | ||||||
|  | @ -1205,6 +1212,10 @@ public: | ||||||
| 	RTLIL::SigSpec Allconst  (RTLIL::IdString name, int width = 1, const std::string &src = ""); | 	RTLIL::SigSpec Allconst  (RTLIL::IdString name, int width = 1, const std::string &src = ""); | ||||||
| 	RTLIL::SigSpec Allseq    (RTLIL::IdString name, int width = 1, const std::string &src = ""); | 	RTLIL::SigSpec Allseq    (RTLIL::IdString name, int width = 1, const std::string &src = ""); | ||||||
| 	RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); | 	RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	static std::map<unsigned int, RTLIL::Module*> *get_all_modules(void); | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct RTLIL::Wire : public RTLIL::AttrObject | struct RTLIL::Wire : public RTLIL::AttrObject | ||||||
|  | @ -1216,7 +1227,7 @@ protected: | ||||||
| 	// use module->addWire() and module->remove() to create or destroy wires
 | 	// use module->addWire() and module->remove() to create or destroy wires
 | ||||||
| 	friend struct RTLIL::Module; | 	friend struct RTLIL::Module; | ||||||
| 	Wire(); | 	Wire(); | ||||||
| 	~Wire() { }; | 	~Wire(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	// do not simply copy wires
 | 	// do not simply copy wires
 | ||||||
|  | @ -1227,6 +1238,10 @@ public: | ||||||
| 	RTLIL::IdString name; | 	RTLIL::IdString name; | ||||||
| 	int width, start_offset, port_id; | 	int width, start_offset, port_id; | ||||||
| 	bool port_input, port_output, upto; | 	bool port_input, port_output, upto; | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void); | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct RTLIL::Memory : public RTLIL::AttrObject | struct RTLIL::Memory : public RTLIL::AttrObject | ||||||
|  | @ -1238,6 +1253,10 @@ struct RTLIL::Memory : public RTLIL::AttrObject | ||||||
| 
 | 
 | ||||||
| 	RTLIL::IdString name; | 	RTLIL::IdString name; | ||||||
| 	int width, start_offset, size; | 	int width, start_offset, size; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	~Memory(); | ||||||
|  | 	static std::map<unsigned int, RTLIL::Memory*> *get_all_memorys(void); | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct RTLIL::Cell : public RTLIL::AttrObject | struct RTLIL::Cell : public RTLIL::AttrObject | ||||||
|  | @ -1249,6 +1268,7 @@ protected: | ||||||
| 	// use module->addCell() and module->remove() to create or destroy cells
 | 	// use module->addCell() and module->remove() to create or destroy cells
 | ||||||
| 	friend struct RTLIL::Module; | 	friend struct RTLIL::Module; | ||||||
| 	Cell(); | 	Cell(); | ||||||
|  | 	~Cell(); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	// do not simply copy cells
 | 	// do not simply copy cells
 | ||||||
|  | @ -1289,6 +1309,10 @@ public: | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	template<typename T> void rewrite_sigspecs(T &functor); | 	template<typename T> void rewrite_sigspecs(T &functor); | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void); | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct RTLIL::CaseRule | struct RTLIL::CaseRule | ||||||
|  | @ -1349,6 +1373,7 @@ inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_as | ||||||
| inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } | inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } | ||||||
| inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } | inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } | ||||||
| inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } | inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } | ||||||
|  | inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){if(wire) offset = sigbit.offset;} | ||||||
| 
 | 
 | ||||||
| inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { | inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { | ||||||
| 	if (wire == other.wire) | 	if (wire == other.wire) | ||||||
|  |  | ||||||
|  | @ -57,6 +57,16 @@ | ||||||
| #  include <sys/sysctl.h> | #  include <sys/sysctl.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | #if PY_MAJOR_VERSION >= 3 | ||||||
|  | #   define INIT_MODULE PyInit_libyosys | ||||||
|  |     extern "C" PyObject* INIT_MODULE(); | ||||||
|  | #else | ||||||
|  | #   define INIT_MODULE initlibyosys | ||||||
|  | 	extern "C" void INIT_MODULE(); | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| 
 | 
 | ||||||
|  | @ -477,21 +487,42 @@ int GetSize(RTLIL::Wire *wire) | ||||||
| 	return wire->width; | 	return wire->width; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool already_setup = false; | ||||||
|  | 
 | ||||||
| void yosys_setup() | void yosys_setup() | ||||||
| { | { | ||||||
|  | 	if(already_setup) | ||||||
|  | 		return; | ||||||
|  | 	already_setup = true; | ||||||
| 	// if there are already IdString objects then we have a global initialization order bug
 | 	// if there are already IdString objects then we have a global initialization order bug
 | ||||||
| 	IdString empty_id; | 	IdString empty_id; | ||||||
| 	log_assert(empty_id.index_ == 0); | 	log_assert(empty_id.index_ == 0); | ||||||
| 	IdString::get_reference(empty_id.index_); | 	IdString::get_reference(empty_id.index_); | ||||||
| 
 | 
 | ||||||
|  | 	#ifdef WITH_PYTHON | ||||||
|  | 		PyImport_AppendInittab((char*)"libyosys", INIT_MODULE); | ||||||
|  | 		Py_Initialize(); | ||||||
|  | 		PyRun_SimpleString("import sys"); | ||||||
|  | 	#endif | ||||||
|  | 
 | ||||||
| 	Pass::init_register(); | 	Pass::init_register(); | ||||||
| 	yosys_design = new RTLIL::Design; | 	yosys_design = new RTLIL::Design; | ||||||
| 	yosys_celltypes.setup(); | 	yosys_celltypes.setup(); | ||||||
| 	log_push(); | 	log_push(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool yosys_already_setup() | ||||||
|  | { | ||||||
|  | 	return already_setup; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool already_shutdown = false; | ||||||
|  | 
 | ||||||
| void yosys_shutdown() | void yosys_shutdown() | ||||||
| { | { | ||||||
|  | 	if(already_shutdown) | ||||||
|  | 		return; | ||||||
|  | 	already_shutdown = true; | ||||||
| 	log_pop(); | 	log_pop(); | ||||||
| 
 | 
 | ||||||
| 	delete yosys_design; | 	delete yosys_design; | ||||||
|  | @ -519,9 +550,16 @@ void yosys_shutdown() | ||||||
| 		dlclose(it.second); | 		dlclose(it.second); | ||||||
| 
 | 
 | ||||||
| 	loaded_plugins.clear(); | 	loaded_plugins.clear(); | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	loaded_python_plugins.clear(); | ||||||
|  | #endif | ||||||
| 	loaded_plugin_aliases.clear(); | 	loaded_plugin_aliases.clear(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	Py_Finalize(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	IdString empty_id; | 	IdString empty_id; | ||||||
| 	IdString::put_reference(empty_id.index_); | 	IdString::put_reference(empty_id.index_); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -66,6 +66,10 @@ | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | #include <Python.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifndef _YOSYS_ | #ifndef _YOSYS_ | ||||||
| #  error It looks like you are trying to build Yosys without the config defines set. \ | #  error It looks like you are trying to build Yosys without the config defines set. \ | ||||||
|          When building Yosys with a custom make system, make sure you set all the \ |          When building Yosys with a custom make system, make sure you set all the \ | ||||||
|  | @ -115,6 +119,7 @@ extern const char *Tcl_GetStringResult(Tcl_Interp *interp); | ||||||
| #  define PATH_MAX 4096 | #  define PATH_MAX 4096 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #define YOSYS_NAMESPACE          Yosys | ||||||
| #define PRIVATE_NAMESPACE_BEGIN  namespace { | #define PRIVATE_NAMESPACE_BEGIN  namespace { | ||||||
| #define PRIVATE_NAMESPACE_END    } | #define PRIVATE_NAMESPACE_END    } | ||||||
| #define YOSYS_NAMESPACE_BEGIN    namespace Yosys { | #define YOSYS_NAMESPACE_BEGIN    namespace Yosys { | ||||||
|  | @ -276,6 +281,11 @@ namespace hashlib { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void yosys_setup(); | void yosys_setup(); | ||||||
|  | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | bool yosys_already_setup(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| void yosys_shutdown(); | void yosys_shutdown(); | ||||||
| 
 | 
 | ||||||
| #ifdef YOSYS_ENABLE_TCL | #ifdef YOSYS_ENABLE_TCL | ||||||
|  | @ -317,6 +327,9 @@ extern std::vector<RTLIL::Design*> pushed_designs; | ||||||
| 
 | 
 | ||||||
| // from passes/cmds/pluginc.cc
 | // from passes/cmds/pluginc.cc
 | ||||||
| extern std::map<std::string, void*> loaded_plugins; | extern std::map<std::string, void*> loaded_plugins; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | extern std::map<std::string, void*> loaded_python_plugins; | ||||||
|  | #endif | ||||||
| extern std::map<std::string, std::string> loaded_plugin_aliases; | extern std::map<std::string, std::string> loaded_plugin_aliases; | ||||||
| void load_plugin(std::string filename, std::vector<std::string> aliases); | void load_plugin(std::string filename, std::vector<std::string> aliases); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,9 +23,18 @@ | ||||||
| #  include <dlfcn.h> | #  include <dlfcn.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | #  include <boost/algorithm/string/predicate.hpp> | ||||||
|  | #  include <Python.h> | ||||||
|  | #  include <boost/filesystem.hpp> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| YOSYS_NAMESPACE_BEGIN | YOSYS_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
| std::map<std::string, void*> loaded_plugins; | std::map<std::string, void*> loaded_plugins; | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | std::map<std::string, void*> loaded_python_plugins; | ||||||
|  | #endif | ||||||
| std::map<std::string, std::string> loaded_plugin_aliases; | std::map<std::string, std::string> loaded_plugin_aliases; | ||||||
| 
 | 
 | ||||||
| #ifdef YOSYS_ENABLE_PLUGINS | #ifdef YOSYS_ENABLE_PLUGINS | ||||||
|  | @ -36,7 +45,35 @@ void load_plugin(std::string filename, std::vector<std::string> aliases) | ||||||
| 	if (filename.find('/') == std::string::npos) | 	if (filename.find('/') == std::string::npos) | ||||||
| 		filename = "./" + filename; | 		filename = "./" + filename; | ||||||
| 
 | 
 | ||||||
|  | 	#ifdef WITH_PYTHON | ||||||
|  | 	if (!loaded_plugins.count(filename) && !loaded_python_plugins.count(filename)) { | ||||||
|  | 	#else | ||||||
| 	if (!loaded_plugins.count(filename)) { | 	if (!loaded_plugins.count(filename)) { | ||||||
|  | 	#endif | ||||||
|  | 
 | ||||||
|  | 		#ifdef WITH_PYTHON | ||||||
|  | 
 | ||||||
|  | 		boost::filesystem::path full_path(filename); | ||||||
|  | 
 | ||||||
|  | 		if(strcmp(full_path.extension().c_str(), ".py") == 0) | ||||||
|  | 		{ | ||||||
|  | 			std::string path(full_path.parent_path().c_str()); | ||||||
|  | 			filename = full_path.filename().c_str(); | ||||||
|  | 			filename = filename.substr(0,filename.size()-3); | ||||||
|  | 			PyRun_SimpleString(("sys.path.insert(0,\""+path+"\")").c_str()); | ||||||
|  | 			PyErr_Print(); | ||||||
|  | 			PyObject *module_p = PyImport_ImportModule(filename.c_str()); | ||||||
|  | 			if(module_p == NULL) | ||||||
|  | 			{ | ||||||
|  | 				PyErr_Print(); | ||||||
|  | 				log_cmd_error("Can't load python module `%s'\n", full_path.filename().c_str()); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			loaded_python_plugins[orig_filename] = module_p; | ||||||
|  | 			Pass::init_register(); | ||||||
|  | 		} else { | ||||||
|  | 		#endif | ||||||
|  | 
 | ||||||
| 		void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL); | 		void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL); | ||||||
| 		if (hdl == NULL && orig_filename.find('/') == std::string::npos) | 		if (hdl == NULL && orig_filename.find('/') == std::string::npos) | ||||||
| 			hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL); | 			hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL); | ||||||
|  | @ -44,6 +81,10 @@ void load_plugin(std::string filename, std::vector<std::string> aliases) | ||||||
| 			log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror()); | 			log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror()); | ||||||
| 		loaded_plugins[orig_filename] = hdl; | 		loaded_plugins[orig_filename] = hdl; | ||||||
| 		Pass::init_register(); | 		Pass::init_register(); | ||||||
|  | 
 | ||||||
|  | 		#ifdef WITH_PYTHON | ||||||
|  | 		} | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for (auto &alias : aliases) | 	for (auto &alias : aliases) | ||||||
|  | @ -107,7 +148,11 @@ struct PluginPass : public Pass { | ||||||
| 		if (list_mode) | 		if (list_mode) | ||||||
| 		{ | 		{ | ||||||
| 			log("\n"); | 			log("\n"); | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 			if (loaded_plugins.empty() and loaded_python_plugins.empty()) | ||||||
|  | #else | ||||||
| 			if (loaded_plugins.empty()) | 			if (loaded_plugins.empty()) | ||||||
|  | #endif | ||||||
| 				log("No plugins loaded.\n"); | 				log("No plugins loaded.\n"); | ||||||
| 			else | 			else | ||||||
| 				log("Loaded plugins:\n"); | 				log("Loaded plugins:\n"); | ||||||
|  | @ -115,6 +160,11 @@ struct PluginPass : public Pass { | ||||||
| 			for (auto &it : loaded_plugins) | 			for (auto &it : loaded_plugins) | ||||||
| 				log("  %s\n", it.first.c_str()); | 				log("  %s\n", it.first.c_str()); | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 			for (auto &it : loaded_python_plugins) | ||||||
|  | 				log("  %s\n", it.first.c_str()); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 			if (!loaded_plugin_aliases.empty()) { | 			if (!loaded_plugin_aliases.empty()) { | ||||||
| 				log("\n"); | 				log("\n"); | ||||||
| 				int max_alias_len = 1; | 				int max_alias_len = 1; | ||||||
|  |  | ||||||
|  | @ -94,4 +94,38 @@ struct TracePass : public Pass { | ||||||
| 	} | 	} | ||||||
| } TracePass; | } TracePass; | ||||||
| 
 | 
 | ||||||
|  | struct DebugPass : public Pass { | ||||||
|  | 	DebugPass() : Pass("debug", "run command with debug log messages enabled") { } | ||||||
|  | 	void help() YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    debug cmd\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Execute the specified command with debug log messages enabled\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		size_t argidx; | ||||||
|  | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | 		{ | ||||||
|  | 			// .. parse options ..
 | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		log_force_debug++; | ||||||
|  | 
 | ||||||
|  | 		try { | ||||||
|  | 			std::vector<std::string> new_args(args.begin() + argidx, args.end()); | ||||||
|  | 			Pass::call(design, new_args); | ||||||
|  | 		} catch (...) { | ||||||
|  | 			log_force_debug--; | ||||||
|  | 			throw; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		log_force_debug--; | ||||||
|  | 	} | ||||||
|  | } DebugPass; | ||||||
|  | 
 | ||||||
| PRIVATE_NAMESPACE_END | PRIVATE_NAMESPACE_END | ||||||
|  |  | ||||||
|  | @ -13,5 +13,6 @@ OBJS += passes/opt/wreduce.o | ||||||
| OBJS += passes/opt/opt_demorgan.o | OBJS += passes/opt/opt_demorgan.o | ||||||
| OBJS += passes/opt/rmports.o | OBJS += passes/opt/rmports.o | ||||||
| OBJS += passes/opt/opt_lut.o | OBJS += passes/opt/opt_lut.o | ||||||
|  | OBJS += passes/opt/pmux2shiftx.o | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -137,7 +137,7 @@ void rmunused_module_cells(Module *module, bool verbose) | ||||||
| 
 | 
 | ||||||
| 	for (auto cell : unused) { | 	for (auto cell : unused) { | ||||||
| 		if (verbose) | 		if (verbose) | ||||||
| 			log("  removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); | 			log_debug("  removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); | ||||||
| 		module->design->scratchpad_set_bool("opt.did_something", true); | 		module->design->scratchpad_set_bool("opt.did_something", true); | ||||||
| 		module->remove(cell); | 		module->remove(cell); | ||||||
| 		count_rm_cells++; | 		count_rm_cells++; | ||||||
|  | @ -326,7 +326,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | ||||||
| 	for (auto wire : maybe_del_wires) | 	for (auto wire : maybe_del_wires) | ||||||
| 		if (!used_signals.check_any(RTLIL::SigSpec(wire))) { | 		if (!used_signals.check_any(RTLIL::SigSpec(wire))) { | ||||||
| 			if (check_public_name(wire->name) && verbose) { | 			if (check_public_name(wire->name) && verbose) { | ||||||
| 				log("  removing unused non-port wire %s.\n", wire->name.c_str()); | 				log_debug("  removing unused non-port wire %s.\n", wire->name.c_str()); | ||||||
| 			} | 			} | ||||||
| 			del_wires.insert(wire); | 			del_wires.insert(wire); | ||||||
| 			del_wires_count++; | 			del_wires_count++; | ||||||
|  | @ -336,7 +336,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | ||||||
| 	count_rm_wires += del_wires.size(); | 	count_rm_wires += del_wires.size(); | ||||||
| 
 | 
 | ||||||
| 	if (verbose && del_wires_count > 0) | 	if (verbose && del_wires_count > 0) | ||||||
| 		log("  removed %d unused temporary wires.\n", del_wires_count); | 		log_debug("  removed %d unused temporary wires.\n", del_wires_count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) | bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) | ||||||
|  | @ -399,7 +399,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (verbose) | 		if (verbose) | ||||||
| 			log("  removing redundant init attribute on %s.\n", log_id(wire)); | 			log_debug("  removing redundant init attribute on %s.\n", log_id(wire)); | ||||||
| 
 | 
 | ||||||
| 		wire->attributes.erase("\\init"); | 		wire->attributes.erase("\\init"); | ||||||
| 		did_something = true; | 		did_something = true; | ||||||
|  | @ -426,7 +426,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool | ||||||
| 		} | 		} | ||||||
| 	for (auto cell : delcells) { | 	for (auto cell : delcells) { | ||||||
| 		if (verbose) | 		if (verbose) | ||||||
| 			log("  removing buffer cell `%s': %s = %s\n", cell->name.c_str(), | 			log_debug("  removing buffer cell `%s': %s = %s\n", cell->name.c_str(), | ||||||
| 					log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A"))); | 					log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A"))); | ||||||
| 		module->remove(cell); | 		module->remove(cell); | ||||||
| 	} | 	} | ||||||
|  | @ -551,6 +551,7 @@ struct CleanPass : public Pass { | ||||||
| 			rmunused_module(module, purge_mode, false, false); | 			rmunused_module(module, purge_mode, false, false); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		log_suppressed(); | ||||||
| 		if (count_rm_cells > 0 || count_rm_wires > 0) | 		if (count_rm_cells > 0 || count_rm_wires > 0) | ||||||
| 			log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires); | 			log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -67,7 +67,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| 		if (sig.size() == 0) | 		if (sig.size() == 0) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); | 		log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); | ||||||
| 		module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); | 		module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); | ||||||
| 		did_something = true; | 		did_something = true; | ||||||
| 	} | 	} | ||||||
|  | @ -78,7 +78,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, | ||||||
| 	RTLIL::SigSpec Y = cell->getPort(out_port); | 	RTLIL::SigSpec Y = cell->getPort(out_port); | ||||||
| 	out_val.extend_u0(Y.size(), false); | 	out_val.extend_u0(Y.size(), false); | ||||||
| 
 | 
 | ||||||
| 	log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", | 	log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", | ||||||
| 			cell->type.c_str(), cell->name.c_str(), info.c_str(), | 			cell->type.c_str(), cell->name.c_str(), info.c_str(), | ||||||
| 			module->name.c_str(), log_signal(Y), log_signal(out_val)); | 			module->name.c_str(), log_signal(Y), log_signal(out_val)); | ||||||
| 	// log_cell(cell);
 | 	// log_cell(cell);
 | ||||||
|  | @ -134,7 +134,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ | ||||||
| 		if (GetSize(grouped_bits[i]) == GetSize(bits_y)) | 		if (GetSize(grouped_bits[i]) == GetSize(bits_y)) | ||||||
| 			return false; | 			return false; | ||||||
| 
 | 
 | ||||||
| 	log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", | 	log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", | ||||||
| 			log_id(cell->type), log_id(cell), log_id(module)); | 			log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < GRP_N; i++) | 	for (int i = 0; i < GRP_N; i++) | ||||||
|  | @ -156,7 +156,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (cell->type.in("$and", "$or") && i == GRP_CONST_A) { | 		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)); | 			log_debug("  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_y, new_b); | ||||||
| 			module->connect(new_conn); | 			module->connect(new_conn); | ||||||
| 			continue; | 			continue; | ||||||
|  | @ -180,10 +180,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ | ||||||
| 
 | 
 | ||||||
| 		module->connect(new_conn); | 		module->connect(new_conn); | ||||||
| 
 | 
 | ||||||
| 		log("  New cell `%s': A=%s", log_id(c), log_signal(new_a)); | 		log_debug("  New cell `%s': A=%s", log_id(c), log_signal(new_a)); | ||||||
| 		if (b_name == "\\B") | 		if (b_name == "\\B") | ||||||
| 			log(", B=%s", log_signal(new_b)); | 			log_debug(", B=%s", log_signal(new_b)); | ||||||
| 		log("\n"); | 		log_debug("\n"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); | 	cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); | ||||||
|  | @ -197,7 +197,7 @@ void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap | ||||||
| { | { | ||||||
| 	SigSpec sig = assign_map(cell->getPort(port)); | 	SigSpec sig = assign_map(cell->getPort(port)); | ||||||
| 	if (invert_map.count(sig)) { | 	if (invert_map.count(sig)) { | ||||||
| 		log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", | 		log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", | ||||||
| 				log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), | 				log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), | ||||||
| 				log_signal(sig), log_signal(invert_map.at(sig))); | 				log_signal(sig), log_signal(invert_map.at(sig))); | ||||||
| 		cell->setPort(port, (invert_map.at(sig))); | 		cell->setPort(port, (invert_map.at(sig))); | ||||||
|  | @ -226,7 +226,7 @@ void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdStrin | ||||||
| 	if (cell->type.in(type1, type2)) { | 	if (cell->type.in(type1, type2)) { | ||||||
| 		SigSpec sig = assign_map(cell->getPort(port)); | 		SigSpec sig = assign_map(cell->getPort(port)); | ||||||
| 		if (invert_map.count(sig)) { | 		if (invert_map.count(sig)) { | ||||||
| 			log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", | 			log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", | ||||||
| 					log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), | 					log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), | ||||||
| 					log_signal(sig), log_signal(invert_map.at(sig))); | 					log_signal(sig), log_signal(invert_map.at(sig))); | ||||||
| 			cell->setPort(port, (invert_map.at(sig))); | 			cell->setPort(port, (invert_map.at(sig))); | ||||||
|  | @ -455,9 +455,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 		{ | 		{ | ||||||
| 			if (cell->type == "$reduce_xnor") { | 			if (cell->type == "$reduce_xnor") { | ||||||
| 				cover("opt.opt_expr.reduce_xnor_not"); | 				cover("opt.opt_expr.reduce_xnor_not"); | ||||||
| 				log("Replacing %s cell `%s' in module `%s' with $not cell.\n", | 				log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n", | ||||||
| 						log_id(cell->type), log_id(cell->name), log_id(module)); | 						log_id(cell->type), log_id(cell->name), log_id(module)); | ||||||
| 				cell->type = "$not"; | 				cell->type = "$not"; | ||||||
|  | 				did_something = true; | ||||||
| 			} else { | 			} else { | ||||||
| 				cover("opt.opt_expr.unary_buffer"); | 				cover("opt.opt_expr.unary_buffer"); | ||||||
| 				replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); | 				replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); | ||||||
|  | @ -488,7 +489,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 				if (GetSize(new_sig_a) < GetSize(sig_a)) { | 				if (GetSize(new_sig_a) < GetSize(sig_a)) { | ||||||
| 					cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); | 					cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); | ||||||
| 					log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", | 					log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", | ||||||
| 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); | ||||||
| 					cell->setPort("\\A", new_sig_a); | 					cell->setPort("\\A", new_sig_a); | ||||||
| 					cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a); | 					cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a); | ||||||
|  | @ -511,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 				if (GetSize(new_sig_b) < GetSize(sig_b)) { | 				if (GetSize(new_sig_b) < GetSize(sig_b)) { | ||||||
| 					cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); | 					cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); | ||||||
| 					log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", | 					log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", | ||||||
| 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); | ||||||
| 					cell->setPort("\\B", new_sig_b); | 					cell->setPort("\\B", new_sig_b); | ||||||
| 					cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b); | 					cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b); | ||||||
|  | @ -537,7 +538,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 				if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { | 				if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { | ||||||
| 					cover("opt.opt_expr.fine.$reduce_and"); | 					cover("opt.opt_expr.fine.$reduce_and"); | ||||||
| 					log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | 					log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | ||||||
| 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); | ||||||
| 					cell->setPort("\\A", sig_a = new_a); | 					cell->setPort("\\A", sig_a = new_a); | ||||||
| 					cell->parameters.at("\\A_WIDTH") = 1; | 					cell->parameters.at("\\A_WIDTH") = 1; | ||||||
|  | @ -563,7 +564,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 				if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { | 				if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { | ||||||
| 					cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); | 					cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); | ||||||
| 					log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | 					log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | ||||||
| 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); | ||||||
| 					cell->setPort("\\A", sig_a = new_a); | 					cell->setPort("\\A", sig_a = new_a); | ||||||
| 					cell->parameters.at("\\A_WIDTH") = 1; | 					cell->parameters.at("\\A_WIDTH") = 1; | ||||||
|  | @ -589,7 +590,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 				if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { | 				if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { | ||||||
| 					cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); | 					cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); | ||||||
| 					log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | 					log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", | ||||||
| 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); | 							cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); | ||||||
| 					cell->setPort("\\B", sig_b = new_b); | 					cell->setPort("\\B", sig_b = new_b); | ||||||
| 					cell->parameters.at("\\B_WIDTH") = 1; | 					cell->parameters.at("\\B_WIDTH") = 1; | ||||||
|  | @ -640,7 +641,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 		if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { | 		if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { | ||||||
| 			cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); | 			cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); | ||||||
| 			log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); | 			log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 			RTLIL::SigSpec tmp = cell->getPort("\\A"); | 			RTLIL::SigSpec tmp = cell->getPort("\\A"); | ||||||
| 			cell->setPort("\\A", cell->getPort("\\B")); | 			cell->setPort("\\A", cell->getPort("\\B")); | ||||||
| 			cell->setPort("\\B", tmp); | 			cell->setPort("\\B", tmp); | ||||||
|  | @ -750,7 +751,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 				ACTION_DO("\\Y", cell->getPort("\\A")); | 				ACTION_DO("\\Y", cell->getPort("\\A")); | ||||||
| 			if (input == State::S0 && !a.is_fully_undef()) { | 			if (input == State::S0 && !a.is_fully_undef()) { | ||||||
| 				cover("opt.opt_expr.action_" S__LINE__); | 				cover("opt.opt_expr.action_" S__LINE__); | ||||||
| 				log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", | 				log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", | ||||||
| 					cell->type.c_str(), cell->name.c_str(), module->name.c_str()); | 					cell->type.c_str(), cell->name.c_str(), module->name.c_str()); | ||||||
| 				cell->setPort("\\A", SigSpec(State::Sx, GetSize(a))); | 				cell->setPort("\\A", SigSpec(State::Sx, GetSize(a))); | ||||||
| 				did_something = true; | 				did_something = true; | ||||||
|  | @ -822,7 +823,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 					ACTION_DO("\\Y", cell->getPort("\\A")); | 					ACTION_DO("\\Y", cell->getPort("\\A")); | ||||||
| 				} else { | 				} else { | ||||||
| 					cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); | 					cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); | ||||||
| 					log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); | 					log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 					cell->type = "$not"; | 					cell->type = "$not"; | ||||||
| 					cell->parameters.erase("\\B_WIDTH"); | 					cell->parameters.erase("\\B_WIDTH"); | ||||||
| 					cell->parameters.erase("\\B_SIGNED"); | 					cell->parameters.erase("\\B_SIGNED"); | ||||||
|  | @ -837,7 +838,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 				(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) | 				(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) | ||||||
| 		{ | 		{ | ||||||
| 			cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); | 			cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); | ||||||
| 			log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), | 			log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), | ||||||
| 					log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); | 					log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); | ||||||
| 			cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; | 			cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; | ||||||
| 			if (assign_map(cell->getPort("\\A")).is_fully_zero()) { | 			if (assign_map(cell->getPort("\\A")).is_fully_zero()) { | ||||||
|  | @ -876,7 +877,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 			cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); | 			cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); | ||||||
| 
 | 
 | ||||||
| 			log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", | 			log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", | ||||||
| 					log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); | 					log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); | ||||||
| 
 | 
 | ||||||
| 			module->connect(cell->getPort("\\Y"), sig_y); | 			module->connect(cell->getPort("\\Y"), sig_y); | ||||||
|  | @ -939,7 +940,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 				if (identity_wrt_b) | 				if (identity_wrt_b) | ||||||
| 					cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); | 					cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); | ||||||
| 
 | 
 | ||||||
| 				log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", | 				log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", | ||||||
| 					cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); | 					cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); | ||||||
| 
 | 
 | ||||||
| 				if (!identity_wrt_a) { | 				if (!identity_wrt_a) { | ||||||
|  | @ -969,7 +970,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 		if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && | 		if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && | ||||||
| 				cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { | 				cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { | ||||||
| 			cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); | 			cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); | ||||||
| 			log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); | 			log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 			cell->setPort("\\A", cell->getPort("\\S")); | 			cell->setPort("\\A", cell->getPort("\\S")); | ||||||
| 			cell->unsetPort("\\B"); | 			cell->unsetPort("\\B"); | ||||||
| 			cell->unsetPort("\\S"); | 			cell->unsetPort("\\S"); | ||||||
|  | @ -988,7 +989,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 		if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { | 		if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { | ||||||
| 			cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); | 			cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); | ||||||
| 			log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); | 			log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 			cell->setPort("\\A", cell->getPort("\\S")); | 			cell->setPort("\\A", cell->getPort("\\S")); | ||||||
| 			cell->unsetPort("\\S"); | 			cell->unsetPort("\\S"); | ||||||
| 			if (cell->type == "$mux") { | 			if (cell->type == "$mux") { | ||||||
|  | @ -1008,7 +1009,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 		if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { | 		if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { | ||||||
| 			cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); | 			cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); | ||||||
| 			log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); | 			log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 			cell->setPort("\\B", cell->getPort("\\S")); | 			cell->setPort("\\B", cell->getPort("\\S")); | ||||||
| 			cell->unsetPort("\\S"); | 			cell->unsetPort("\\S"); | ||||||
| 			if (cell->type == "$mux") { | 			if (cell->type == "$mux") { | ||||||
|  | @ -1061,7 +1062,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 			} | 			} | ||||||
| 			if (cell->getPort("\\S").size() != new_s.size()) { | 			if (cell->getPort("\\S").size() != new_s.size()) { | ||||||
| 				cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); | 				cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); | ||||||
| 				log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", | 				log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", | ||||||
| 						GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); | 						GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 				cell->setPort("\\A", new_a); | 				cell->setPort("\\A", new_a); | ||||||
| 				cell->setPort("\\B", new_b); | 				cell->setPort("\\B", new_b); | ||||||
|  | @ -1179,7 +1180,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 				{ | 				{ | ||||||
| 					cover("opt.opt_expr.mul_shift.zero"); | 					cover("opt.opt_expr.mul_shift.zero"); | ||||||
| 
 | 
 | ||||||
| 					log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", | 					log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", | ||||||
| 							cell->name.c_str(), module->name.c_str()); | 							cell->name.c_str(), module->name.c_str()); | ||||||
| 
 | 
 | ||||||
| 					module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); | 					module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); | ||||||
|  | @ -1197,7 +1198,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 						else | 						else | ||||||
| 							cover("opt.opt_expr.mul_shift.unswapped"); | 							cover("opt.opt_expr.mul_shift.unswapped"); | ||||||
| 
 | 
 | ||||||
| 						log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", | 						log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", | ||||||
| 								a_val, cell->name.c_str(), module->name.c_str(), i); | 								a_val, cell->name.c_str(), module->name.c_str(), i); | ||||||
| 
 | 
 | ||||||
| 						if (!swapped_ab) { | 						if (!swapped_ab) { | ||||||
|  | @ -1237,7 +1238,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 				{ | 				{ | ||||||
| 					cover("opt.opt_expr.divmod_zero"); | 					cover("opt.opt_expr.divmod_zero"); | ||||||
| 
 | 
 | ||||||
| 					log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", | 					log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", | ||||||
| 							cell->name.c_str(), module->name.c_str()); | 							cell->name.c_str(), module->name.c_str()); | ||||||
| 
 | 
 | ||||||
| 					module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); | 					module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); | ||||||
|  | @ -1254,7 +1255,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 						{ | 						{ | ||||||
| 							cover("opt.opt_expr.div_shift"); | 							cover("opt.opt_expr.div_shift"); | ||||||
| 
 | 
 | ||||||
| 							log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", | 							log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", | ||||||
| 									b_val, cell->name.c_str(), module->name.c_str(), i); | 									b_val, cell->name.c_str(), module->name.c_str(), i); | ||||||
| 
 | 
 | ||||||
| 							std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); | 							std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); | ||||||
|  | @ -1272,7 +1273,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 						{ | 						{ | ||||||
| 							cover("opt.opt_expr.mod_mask"); | 							cover("opt.opt_expr.mod_mask"); | ||||||
| 
 | 
 | ||||||
| 							log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", | 							log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", | ||||||
| 									b_val, cell->name.c_str(), module->name.c_str()); | 									b_val, cell->name.c_str(), module->name.c_str()); | ||||||
| 
 | 
 | ||||||
| 							std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); | 							std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); | ||||||
|  | @ -1342,7 +1343,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 				SigSpec y_sig = cell->getPort("\\Y"); | 				SigSpec y_sig = cell->getPort("\\Y"); | ||||||
| 				Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig)); | 				Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig)); | ||||||
| 
 | 
 | ||||||
| 				log("Replacing cell `%s' in module `%s' with constant driver %s.\n", | 				log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n", | ||||||
| 					log_id(cell), log_id(module), log_signal(y_value)); | 					log_id(cell), log_id(module), log_signal(y_value)); | ||||||
| 
 | 
 | ||||||
| 				module->connect(y_sig, y_value); | 				module->connect(y_sig, y_value); | ||||||
|  | @ -1354,7 +1355,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 			if (redundant_bits) | 			if (redundant_bits) | ||||||
| 			{ | 			{ | ||||||
| 				log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", | 				log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", | ||||||
| 						redundant_bits, log_id(cell->type), log_id(cell), log_id(module)); | 						redundant_bits, log_id(cell->type), log_id(cell), log_id(module)); | ||||||
| 
 | 
 | ||||||
| 				cell->setPort("\\A", sig_a); | 				cell->setPort("\\A", sig_a); | ||||||
|  | @ -1493,7 +1494,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | ||||||
| 
 | 
 | ||||||
| 				if (replace || remove) | 				if (replace || remove) | ||||||
| 				{ | 				{ | ||||||
| 					log("Replacing %s cell `%s' (implementing %s) with %s.\n", | 					log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n", | ||||||
| 							log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); | 							log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); | ||||||
| 					if (replace) | 					if (replace) | ||||||
| 						module->connect(cell->getPort("\\Y"), replace_sig); | 						module->connect(cell->getPort("\\Y"), replace_sig); | ||||||
|  | @ -1599,8 +1600,14 @@ struct OptExprPass : public Pass { | ||||||
| 
 | 
 | ||||||
| 		for (auto module : design->selected_modules()) | 		for (auto module : design->selected_modules()) | ||||||
| 		{ | 		{ | ||||||
| 			if (undriven) | 			log("Optimizing module %s.\n", log_id(module)); | ||||||
|  | 
 | ||||||
|  | 			if (undriven) { | ||||||
|  | 				did_something = false; | ||||||
| 				replace_undriven(design, module); | 				replace_undriven(design, module); | ||||||
|  | 				if (did_something) | ||||||
|  | 					design->scratchpad_set_bool("opt.did_something", true); | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			do { | 			do { | ||||||
| 				do { | 				do { | ||||||
|  | @ -1610,7 +1617,11 @@ struct OptExprPass : public Pass { | ||||||
| 						design->scratchpad_set_bool("opt.did_something", true); | 						design->scratchpad_set_bool("opt.did_something", true); | ||||||
| 				} while (did_something); | 				} while (did_something); | ||||||
| 				replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); | 				replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); | ||||||
|  | 				if (did_something) | ||||||
|  | 					design->scratchpad_set_bool("opt.did_something", true); | ||||||
| 			} while (did_something); | 			} while (did_something); | ||||||
|  | 
 | ||||||
|  | 			log_suppressed(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log_pop(); | 		log_pop(); | ||||||
|  |  | ||||||
|  | @ -315,17 +315,17 @@ struct OptMergeWorker | ||||||
| 			{ | 			{ | ||||||
| 				if (sharemap.count(cell) > 0) { | 				if (sharemap.count(cell) > 0) { | ||||||
| 					did_something = true; | 					did_something = true; | ||||||
| 					log("  Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); | 					log_debug("  Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); | ||||||
| 					for (auto &it : cell->connections()) { | 					for (auto &it : cell->connections()) { | ||||||
| 						if (cell->output(it.first)) { | 						if (cell->output(it.first)) { | ||||||
| 							RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); | 							RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); | ||||||
| 							log("    Redirecting output %s: %s = %s\n", it.first.c_str(), | 							log_debug("    Redirecting output %s: %s = %s\n", it.first.c_str(), | ||||||
| 									log_signal(it.second), log_signal(other_sig)); | 									log_signal(it.second), log_signal(other_sig)); | ||||||
| 							module->connect(RTLIL::SigSig(it.second, other_sig)); | 							module->connect(RTLIL::SigSig(it.second, other_sig)); | ||||||
| 							assign_map.add(it.second, other_sig); | 							assign_map.add(it.second, other_sig); | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 					log("    Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); | 					log_debug("    Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); | ||||||
| #ifdef USE_CELL_HASH_CACHE | #ifdef USE_CELL_HASH_CACHE | ||||||
| 					cell_hash_cache.erase(cell); | 					cell_hash_cache.erase(cell); | ||||||
| #endif | #endif | ||||||
|  | @ -336,6 +336,8 @@ struct OptMergeWorker | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		log_suppressed(); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -181,14 +181,14 @@ struct OptMuxtreeWorker | ||||||
| 
 | 
 | ||||||
| 		for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) | 		for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) | ||||||
| 			if (root_muxes.at(mux_idx)) { | 			if (root_muxes.at(mux_idx)) { | ||||||
| 				log("    Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); | 				log_debug("    Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); | ||||||
| 				root_mux_rerun.erase(mux_idx); | 				root_mux_rerun.erase(mux_idx); | ||||||
| 				eval_root_mux(mux_idx); | 				eval_root_mux(mux_idx); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 		while (!root_mux_rerun.empty()) { | 		while (!root_mux_rerun.empty()) { | ||||||
| 			int mux_idx = *root_mux_rerun.begin(); | 			int mux_idx = *root_mux_rerun.begin(); | ||||||
| 			log("    Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); | 			log_debug("    Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); | ||||||
| 			log_assert(root_enable_muxes.at(mux_idx)); | 			log_assert(root_enable_muxes.at(mux_idx)); | ||||||
| 			root_mux_rerun.erase(mux_idx); | 			root_mux_rerun.erase(mux_idx); | ||||||
| 			eval_root_mux(mux_idx); | 			eval_root_mux(mux_idx); | ||||||
|  | @ -326,7 +326,7 @@ struct OptMuxtreeWorker | ||||||
| 				if (abort_count == 0) { | 				if (abort_count == 0) { | ||||||
| 					root_mux_rerun.insert(m); | 					root_mux_rerun.insert(m); | ||||||
| 					root_enable_muxes.at(m) = true; | 					root_enable_muxes.at(m) = true; | ||||||
| 					log("      Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); | 					log_debug("      Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); | ||||||
| 				} else | 				} else | ||||||
| 					eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); | 					eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); | ||||||
| 			} else | 			} else | ||||||
|  |  | ||||||
							
								
								
									
										852
									
								
								passes/opt/pmux2shiftx.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										852
									
								
								passes/opt/pmux2shiftx.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,852 @@ | ||||||
|  | /*
 | ||||||
|  |  *  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 OnehotDatabase | ||||||
|  | { | ||||||
|  | 	Module *module; | ||||||
|  | 	const SigMap &sigmap; | ||||||
|  | 	bool verbose = false; | ||||||
|  | 	bool initialized = false; | ||||||
|  | 
 | ||||||
|  | 	pool<SigBit> init_ones; | ||||||
|  | 	dict<SigSpec, pool<SigSpec>> sig_sources_db; | ||||||
|  | 	dict<SigSpec, bool> sig_onehot_cache; | ||||||
|  | 	pool<SigSpec> recursion_guard; | ||||||
|  | 
 | ||||||
|  | 	OnehotDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void initialize() | ||||||
|  | 	{ | ||||||
|  | 		log_assert(!initialized); | ||||||
|  | 		initialized = true; | ||||||
|  | 
 | ||||||
|  | 		for (auto wire : module->wires()) | ||||||
|  | 		{ | ||||||
|  | 			auto it = wire->attributes.find("\\init"); | ||||||
|  | 			if (it == wire->attributes.end()) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			auto &val = it->second; | ||||||
|  | 			int width = std::max(GetSize(wire), GetSize(val)); | ||||||
|  | 
 | ||||||
|  | 			for (int i = 0; i < width; i++) | ||||||
|  | 				if (val[i] == State::S1) | ||||||
|  | 					init_ones.insert(sigmap(SigBit(wire, i))); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for (auto cell : module->cells()) | ||||||
|  | 		{ | ||||||
|  | 			vector<SigSpec> inputs; | ||||||
|  | 			SigSpec output; | ||||||
|  | 
 | ||||||
|  | 			if (cell->type.in("$adff", "$dff", "$dffe", "$dlatch", "$ff")) | ||||||
|  | 			{ | ||||||
|  | 				output = cell->getPort("\\Q"); | ||||||
|  | 				if (cell->type == "$adff") | ||||||
|  | 					inputs.push_back(cell->getParam("\\ARST_VALUE")); | ||||||
|  | 				inputs.push_back(cell->getPort("\\D")); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (cell->type.in("$mux", "$pmux")) | ||||||
|  | 			{ | ||||||
|  | 				output = cell->getPort("\\Y"); | ||||||
|  | 				inputs.push_back(cell->getPort("\\A")); | ||||||
|  | 				SigSpec B = cell->getPort("\\B"); | ||||||
|  | 				for (int i = 0; i < GetSize(B); i += GetSize(output)) | ||||||
|  | 					inputs.push_back(B.extract(i, GetSize(output))); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (!output.empty()) | ||||||
|  | 			{ | ||||||
|  | 				output = sigmap(output); | ||||||
|  | 				auto &srcs = sig_sources_db[output]; | ||||||
|  | 				for (auto src : inputs) { | ||||||
|  | 					while (!src.empty() && src[GetSize(src)-1] == State::S0) | ||||||
|  | 						src.remove(GetSize(src)-1); | ||||||
|  | 					srcs.insert(sigmap(src)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void query_worker(const SigSpec &sig, bool &retval, bool &cache, int indent) | ||||||
|  | 	{ | ||||||
|  | 		if (verbose) | ||||||
|  | 			log("%*s %s\n", indent, "", log_signal(sig)); | ||||||
|  | 		log_assert(retval); | ||||||
|  | 
 | ||||||
|  | 		if (recursion_guard.count(sig)) { | ||||||
|  | 			if (verbose) | ||||||
|  | 				log("%*s   - recursion\n", indent, ""); | ||||||
|  | 			cache = false; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		auto it = sig_onehot_cache.find(sig); | ||||||
|  | 		if (it != sig_onehot_cache.end()) { | ||||||
|  | 			if (verbose) | ||||||
|  | 				log("%*s   - cached (%s)\n", indent, "", it->second ? "true" : "false"); | ||||||
|  | 			if (!it->second) | ||||||
|  | 				retval = false; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		bool found_init_ones = false; | ||||||
|  | 		for (auto bit : sig) { | ||||||
|  | 			if (init_ones.count(bit)) { | ||||||
|  | 				if (found_init_ones) { | ||||||
|  | 					if (verbose) | ||||||
|  | 						log("%*s   - non-onehot init value\n", indent, ""); | ||||||
|  | 					retval = false; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				found_init_ones = true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (retval) | ||||||
|  | 		{ | ||||||
|  | 			if (sig.is_fully_const()) | ||||||
|  | 			{ | ||||||
|  | 				bool found_ones = false; | ||||||
|  | 				for (auto bit : sig) { | ||||||
|  | 					if (bit == State::S1) { | ||||||
|  | 						if (found_ones) { | ||||||
|  | 							if (verbose) | ||||||
|  | 								log("%*s   - non-onehot constant\n", indent, ""); | ||||||
|  | 							retval = false; | ||||||
|  | 							break; | ||||||
|  | 						} | ||||||
|  | 						found_ones = true; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				auto srcs = sig_sources_db.find(sig); | ||||||
|  | 				if (srcs == sig_sources_db.end()) { | ||||||
|  | 					if (verbose) | ||||||
|  | 						log("%*s   - no sources for non-const signal\n", indent, ""); | ||||||
|  | 					retval = false; | ||||||
|  | 				} else { | ||||||
|  | 					for (auto &src : srcs->second) { | ||||||
|  | 						bool child_cache = true; | ||||||
|  | 						recursion_guard.insert(sig); | ||||||
|  | 						query_worker(src, retval, child_cache, indent+4); | ||||||
|  | 						recursion_guard.erase(sig); | ||||||
|  | 						if (!child_cache) | ||||||
|  | 							cache = false; | ||||||
|  | 						if (!retval) | ||||||
|  | 							break; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// it is always safe to cache a negative result
 | ||||||
|  | 		if (cache || !retval) | ||||||
|  | 			sig_onehot_cache[sig] = retval; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool query(const SigSpec &sig) | ||||||
|  | 	{ | ||||||
|  | 		bool retval = true; | ||||||
|  | 		bool cache = true; | ||||||
|  | 
 | ||||||
|  | 		if (verbose) | ||||||
|  | 			log("** ONEHOT QUERY START (%s)\n", log_signal(sig)); | ||||||
|  | 
 | ||||||
|  | 		if (!initialized) | ||||||
|  | 			initialize(); | ||||||
|  | 
 | ||||||
|  | 		query_worker(sig, retval, cache, 3); | ||||||
|  | 
 | ||||||
|  | 		if (verbose) | ||||||
|  | 			log("** ONEHOT QUERY RESULT = %s\n", retval ? "true" : "false"); | ||||||
|  | 
 | ||||||
|  | 		// it is always safe to cache the root result of a query
 | ||||||
|  | 		if (!cache) | ||||||
|  | 			sig_onehot_cache[sig] = retval; | ||||||
|  | 
 | ||||||
|  | 		return retval; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Pmux2ShiftxPass : public Pass { | ||||||
|  | 	Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { } | ||||||
|  | 	void help() YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    pmux2shiftx [options] [selection]\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("This pass transforms $pmux cells to $shiftx cells.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    -v, -vv\n"); | ||||||
|  | 		log("        verbose output\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    -min_density <percentage>\n"); | ||||||
|  | 		log("        specifies the minimum density for the shifter\n"); | ||||||
|  | 		log("        default: 50\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    -min_choices <int>\n"); | ||||||
|  | 		log("        specified the minimum number of choices for a control signal\n"); | ||||||
|  | 		log("        default: 3\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    -onehot ignore|pmux|shiftx\n"); | ||||||
|  | 		log("        select strategy for one-hot encoded control signals\n"); | ||||||
|  | 		log("        default: pmux\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		int min_density = 50; | ||||||
|  | 		int min_choices = 3; | ||||||
|  | 		bool allow_onehot = false; | ||||||
|  | 		bool optimize_onehot = true; | ||||||
|  | 		bool verbose = false; | ||||||
|  | 		bool verbose_onehot = false; | ||||||
|  | 
 | ||||||
|  | 		log_header(design, "Executing PMUX2SHIFTX pass.\n"); | ||||||
|  | 
 | ||||||
|  | 		size_t argidx; | ||||||
|  | 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||||
|  | 			if (args[argidx] == "-min_density" && argidx+1 < args.size()) { | ||||||
|  | 				min_density = atoi(args[++argidx].c_str()); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-min_choices" && argidx+1 < args.size()) { | ||||||
|  | 				min_choices = atoi(args[++argidx].c_str()); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "ignore") { | ||||||
|  | 				argidx++; | ||||||
|  | 				allow_onehot = false; | ||||||
|  | 				optimize_onehot = false; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "pmux") { | ||||||
|  | 				argidx++; | ||||||
|  | 				allow_onehot = false; | ||||||
|  | 				optimize_onehot = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "shiftx") { | ||||||
|  | 				argidx++; | ||||||
|  | 				allow_onehot = true; | ||||||
|  | 				optimize_onehot = false; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-v") { | ||||||
|  | 				verbose = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-vv") { | ||||||
|  | 				verbose = true; | ||||||
|  | 				verbose_onehot = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		extra_args(args, argidx, design); | ||||||
|  | 
 | ||||||
|  | 		for (auto module : design->selected_modules()) | ||||||
|  | 		{ | ||||||
|  | 			SigMap sigmap(module); | ||||||
|  | 			OnehotDatabase onehot_db(module, sigmap); | ||||||
|  | 			onehot_db.verbose = verbose_onehot; | ||||||
|  | 
 | ||||||
|  | 			dict<SigBit, pair<SigSpec, Const>> eqdb; | ||||||
|  | 
 | ||||||
|  | 			for (auto cell : module->cells()) | ||||||
|  | 			{ | ||||||
|  | 				if (cell->type == "$eq") | ||||||
|  | 				{ | ||||||
|  | 					dict<SigBit, State> bits; | ||||||
|  | 
 | ||||||
|  | 					SigSpec A = sigmap(cell->getPort("\\A")); | ||||||
|  | 					SigSpec B = sigmap(cell->getPort("\\B")); | ||||||
|  | 
 | ||||||
|  | 					int a_width = cell->getParam("\\A_WIDTH").as_int(); | ||||||
|  | 					int b_width = cell->getParam("\\B_WIDTH").as_int(); | ||||||
|  | 
 | ||||||
|  | 					if (a_width < b_width) { | ||||||
|  | 						bool a_signed = cell->getParam("\\A_SIGNED").as_int(); | ||||||
|  | 						A.extend_u0(b_width, a_signed); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (b_width < a_width) { | ||||||
|  | 						bool b_signed = cell->getParam("\\B_SIGNED").as_int(); | ||||||
|  | 						B.extend_u0(a_width, b_signed); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					for (int i = 0; i < GetSize(A); i++) { | ||||||
|  | 						SigBit a_bit = A[i], b_bit = B[i]; | ||||||
|  | 						if (b_bit.wire && !a_bit.wire) { | ||||||
|  | 							std::swap(a_bit, b_bit); | ||||||
|  | 						} | ||||||
|  | 						if (!a_bit.wire || b_bit.wire) | ||||||
|  | 							goto next_cell; | ||||||
|  | 						if (bits.count(a_bit)) | ||||||
|  | 							goto next_cell; | ||||||
|  | 						bits[a_bit] = b_bit.data; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (GetSize(bits) > 20) | ||||||
|  | 						goto next_cell; | ||||||
|  | 
 | ||||||
|  | 					bits.sort(); | ||||||
|  | 					pair<SigSpec, Const> entry; | ||||||
|  | 
 | ||||||
|  | 					for (auto it : bits) { | ||||||
|  | 						entry.first.append_bit(it.first); | ||||||
|  | 						entry.second.bits.push_back(it.second); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					eqdb[sigmap(cell->getPort("\\Y")[0])] = entry; | ||||||
|  | 					goto next_cell; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (cell->type == "$logic_not") | ||||||
|  | 				{ | ||||||
|  | 					dict<SigBit, State> bits; | ||||||
|  | 
 | ||||||
|  | 					SigSpec A = sigmap(cell->getPort("\\A")); | ||||||
|  | 
 | ||||||
|  | 					for (int i = 0; i < GetSize(A); i++) | ||||||
|  | 						bits[A[i]] = State::S0; | ||||||
|  | 
 | ||||||
|  | 					bits.sort(); | ||||||
|  | 					pair<SigSpec, Const> entry; | ||||||
|  | 
 | ||||||
|  | 					for (auto it : bits) { | ||||||
|  | 						entry.first.append_bit(it.first); | ||||||
|  | 						entry.second.bits.push_back(it.second); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					eqdb[sigmap(cell->getPort("\\Y")[0])] = entry; | ||||||
|  | 					goto next_cell; | ||||||
|  | 				} | ||||||
|  | 		next_cell:; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			for (auto cell : module->selected_cells()) | ||||||
|  | 			{ | ||||||
|  | 				if (cell->type != "$pmux") | ||||||
|  | 					continue; | ||||||
|  | 
 | ||||||
|  | 				string src = cell->get_src_attribute(); | ||||||
|  | 				int width = cell->getParam("\\WIDTH").as_int(); | ||||||
|  | 				int width_bits = ceil_log2(width); | ||||||
|  | 				int extwidth = width; | ||||||
|  | 
 | ||||||
|  | 				while (extwidth & (extwidth-1)) | ||||||
|  | 					extwidth++; | ||||||
|  | 
 | ||||||
|  | 				dict<SigSpec, pool<int>> seldb; | ||||||
|  | 
 | ||||||
|  | 				SigSpec A = cell->getPort("\\A"); | ||||||
|  | 				SigSpec B = cell->getPort("\\B"); | ||||||
|  | 				SigSpec S = sigmap(cell->getPort("\\S")); | ||||||
|  | 				for (int i = 0; i < GetSize(S); i++) | ||||||
|  | 				{ | ||||||
|  | 					if (!eqdb.count(S[i])) | ||||||
|  | 						continue; | ||||||
|  | 
 | ||||||
|  | 					auto &entry = eqdb.at(S[i]); | ||||||
|  | 					seldb[entry.first].insert(i); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (seldb.empty()) | ||||||
|  | 					continue; | ||||||
|  | 
 | ||||||
|  | 				bool printed_pmux_header = false; | ||||||
|  | 
 | ||||||
|  | 				if (verbose) { | ||||||
|  | 					printed_pmux_header = true; | ||||||
|  | 					log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); | ||||||
|  | 					log("  data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				SigSpec updated_S = cell->getPort("\\S"); | ||||||
|  | 				SigSpec updated_B = cell->getPort("\\B"); | ||||||
|  | 
 | ||||||
|  | 				while (!seldb.empty()) | ||||||
|  | 				{ | ||||||
|  | 					// pick the largest entry in seldb
 | ||||||
|  | 					SigSpec sig = seldb.begin()->first; | ||||||
|  | 					for (auto &it : seldb) { | ||||||
|  | 						if (GetSize(sig) < GetSize(it.first)) | ||||||
|  | 							sig = it.first; | ||||||
|  | 						else if (GetSize(seldb.at(sig)) < GetSize(it.second)) | ||||||
|  | 							sig = it.first; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// find the relevant choices
 | ||||||
|  | 					bool is_onehot = GetSize(sig) > 2; | ||||||
|  | 					dict<Const, int> choices; | ||||||
|  | 					for (int i : seldb.at(sig)) { | ||||||
|  | 						Const val = eqdb.at(S[i]).second; | ||||||
|  | 						int onebits = 0; | ||||||
|  | 						for (auto b : val.bits) | ||||||
|  | 							if (b == State::S1) | ||||||
|  | 								onebits++; | ||||||
|  | 						if (onebits > 1) | ||||||
|  | 							is_onehot = false; | ||||||
|  | 						choices[val] = i; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					bool full_pmux = GetSize(choices) == GetSize(S); | ||||||
|  | 
 | ||||||
|  | 					// TBD: also find choices that are using signals that are subsets of the bits in "sig"
 | ||||||
|  | 
 | ||||||
|  | 					if (!verbose) | ||||||
|  | 					{ | ||||||
|  | 						if (is_onehot && !allow_onehot && !optimize_onehot) { | ||||||
|  | 							seldb.erase(sig); | ||||||
|  | 							continue; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						if (GetSize(choices) < min_choices) { | ||||||
|  | 							seldb.erase(sig); | ||||||
|  | 							continue; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (!printed_pmux_header) { | ||||||
|  | 						printed_pmux_header = true; | ||||||
|  | 						log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); | ||||||
|  | 						log("  data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					log("  checking ctrl signal %s\n", log_signal(sig)); | ||||||
|  | 
 | ||||||
|  | 					auto print_choices = [&]() { | ||||||
|  | 						log("    table of choices:\n"); | ||||||
|  | 						for (auto &it : choices) | ||||||
|  | 							log("    %3d: %s: %s\n", it.second, log_signal(it.first), | ||||||
|  | 									log_signal(B.extract(it.second*width, width))); | ||||||
|  | 					}; | ||||||
|  | 
 | ||||||
|  | 					if (verbose) | ||||||
|  | 					{ | ||||||
|  | 						if (is_onehot && !allow_onehot && !optimize_onehot) { | ||||||
|  | 							print_choices(); | ||||||
|  | 							log("    ignoring one-hot encoding.\n"); | ||||||
|  | 							seldb.erase(sig); | ||||||
|  | 							continue; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						if (GetSize(choices) < min_choices) { | ||||||
|  | 							print_choices(); | ||||||
|  | 							log("    insufficient choices.\n"); | ||||||
|  | 							seldb.erase(sig); | ||||||
|  | 							continue; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (is_onehot && optimize_onehot) | ||||||
|  | 					{ | ||||||
|  | 						print_choices(); | ||||||
|  | 						if (!onehot_db.query(sig)) | ||||||
|  | 						{ | ||||||
|  | 							log("    failed to detect onehot driver. do not optimize.\n"); | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							log("    optimizing one-hot encoding.\n"); | ||||||
|  | 							for (auto &it : choices) | ||||||
|  | 							{ | ||||||
|  | 								const Const &val = it.first; | ||||||
|  | 								int index = -1; | ||||||
|  | 
 | ||||||
|  | 								for (int i = 0; i < GetSize(val); i++) | ||||||
|  | 									if (val[i] == State::S1) { | ||||||
|  | 										log_assert(index < 0); | ||||||
|  | 										index = i; | ||||||
|  | 									} | ||||||
|  | 
 | ||||||
|  | 								if (index < 0) { | ||||||
|  | 									log("    %3d: zero encoding.\n", it.second); | ||||||
|  | 									continue; | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								SigBit new_ctrl = sig[index]; | ||||||
|  | 								log("    %3d: new crtl signal is %s.\n", it.second, log_signal(new_ctrl)); | ||||||
|  | 								updated_S[it.second] = new_ctrl; | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 						seldb.erase(sig); | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// find the best permutation
 | ||||||
|  | 					vector<int> perm_new_from_old(GetSize(sig)); | ||||||
|  | 					Const perm_xormask(State::S0, GetSize(sig)); | ||||||
|  | 					{ | ||||||
|  | 						vector<int> values(GetSize(choices)); | ||||||
|  | 						vector<bool> used_src_columns(GetSize(sig)); | ||||||
|  | 						vector<vector<bool>> columns(GetSize(sig), vector<bool>(GetSize(values))); | ||||||
|  | 
 | ||||||
|  | 						for (int i = 0; i < GetSize(choices); i++) { | ||||||
|  | 							Const val = choices.element(i)->first; | ||||||
|  | 							for (int k = 0; k < GetSize(val); k++) | ||||||
|  | 								if (val[k] == State::S1) | ||||||
|  | 									columns[k][i] = true; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						for (int dst_col = GetSize(sig)-1; dst_col >= 0; dst_col--) | ||||||
|  | 						{ | ||||||
|  | 							int best_src_col = -1; | ||||||
|  | 							bool best_inv = false; | ||||||
|  | 							int best_maxval = 0; | ||||||
|  | 							int best_delta = 0; | ||||||
|  | 
 | ||||||
|  | 							// find best src column for this dst column
 | ||||||
|  | 							for (int src_col = 0; src_col < GetSize(sig); src_col++) | ||||||
|  | 							{ | ||||||
|  | 								if (used_src_columns[src_col]) | ||||||
|  | 									continue; | ||||||
|  | 
 | ||||||
|  | 								int this_maxval = 0; | ||||||
|  | 								int this_minval = 1 << 30; | ||||||
|  | 
 | ||||||
|  | 								int this_inv_maxval = 0; | ||||||
|  | 								int this_inv_minval = 1 << 30; | ||||||
|  | 
 | ||||||
|  | 								for (int i = 0; i < GetSize(values); i++) | ||||||
|  | 								{ | ||||||
|  | 									int val = values[i]; | ||||||
|  | 									int inv_val = val; | ||||||
|  | 
 | ||||||
|  | 									if (columns[src_col][i]) | ||||||
|  | 										val |= 1 << dst_col; | ||||||
|  | 									else | ||||||
|  | 										inv_val |= 1 << dst_col; | ||||||
|  | 
 | ||||||
|  | 									this_maxval = std::max(this_maxval, val); | ||||||
|  | 									this_minval = std::min(this_minval, val); | ||||||
|  | 
 | ||||||
|  | 									this_inv_maxval = std::max(this_inv_maxval, inv_val); | ||||||
|  | 									this_inv_minval = std::min(this_inv_minval, inv_val); | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								int this_delta = this_maxval - this_minval; | ||||||
|  | 								int this_inv_delta = this_maxval - this_minval; | ||||||
|  | 								bool this_inv = false; | ||||||
|  | 
 | ||||||
|  | 								if (this_delta != this_inv_delta) | ||||||
|  | 									this_inv = this_inv_delta < this_delta; | ||||||
|  | 								else if (this_maxval != this_inv_maxval) | ||||||
|  | 									this_inv = this_inv_maxval < this_maxval; | ||||||
|  | 
 | ||||||
|  | 								if (this_inv) { | ||||||
|  | 									this_delta = this_inv_delta; | ||||||
|  | 									this_maxval = this_inv_maxval; | ||||||
|  | 									this_minval = this_inv_minval; | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								bool this_is_better = false; | ||||||
|  | 
 | ||||||
|  | 								if (best_src_col < 0) | ||||||
|  | 									this_is_better = true; | ||||||
|  | 								else if (this_delta != best_delta) | ||||||
|  | 									this_is_better = this_delta < best_delta; | ||||||
|  | 								else if (this_maxval != best_maxval) | ||||||
|  | 									this_is_better = this_maxval < best_maxval; | ||||||
|  | 								else | ||||||
|  | 									this_is_better = sig[best_src_col] < sig[src_col]; | ||||||
|  | 
 | ||||||
|  | 								if (this_is_better) { | ||||||
|  | 									best_src_col = src_col; | ||||||
|  | 									best_inv = this_inv; | ||||||
|  | 									best_maxval = this_maxval; | ||||||
|  | 									best_delta = this_delta; | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
|  | 							used_src_columns[best_src_col] = true; | ||||||
|  | 							perm_new_from_old[dst_col] = best_src_col; | ||||||
|  | 							perm_xormask[dst_col] = best_inv ? State::S1 : State::S0; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// permutated sig
 | ||||||
|  | 					SigSpec perm_sig(State::S0, GetSize(sig)); | ||||||
|  | 					for (int i = 0; i < GetSize(sig); i++) | ||||||
|  | 						perm_sig[i] = sig[perm_new_from_old[i]]; | ||||||
|  | 
 | ||||||
|  | 					log("    best permutation: %s\n", log_signal(perm_sig)); | ||||||
|  | 					log("    best xor mask: %s\n", log_signal(perm_xormask)); | ||||||
|  | 
 | ||||||
|  | 					// permutated choices
 | ||||||
|  | 					int min_choice = 1 << 30; | ||||||
|  | 					int max_choice = -1; | ||||||
|  | 					dict<Const, int> perm_choices; | ||||||
|  | 
 | ||||||
|  | 					for (auto &it : choices) | ||||||
|  | 					{ | ||||||
|  | 						Const &old_c = it.first; | ||||||
|  | 						Const new_c(State::S0, GetSize(old_c)); | ||||||
|  | 
 | ||||||
|  | 						for (int i = 0; i < GetSize(old_c); i++) | ||||||
|  | 							new_c[i] = old_c[perm_new_from_old[i]]; | ||||||
|  | 
 | ||||||
|  | 						Const new_c_before_xor = new_c; | ||||||
|  | 						new_c = const_xor(new_c, perm_xormask, false, false, GetSize(new_c)); | ||||||
|  | 
 | ||||||
|  | 						perm_choices[new_c] = it.second; | ||||||
|  | 
 | ||||||
|  | 						min_choice = std::min(min_choice, new_c.as_int()); | ||||||
|  | 						max_choice = std::max(max_choice, new_c.as_int()); | ||||||
|  | 
 | ||||||
|  | 						log("    %3d: %s -> %s -> %s: %s\n", it.second, log_signal(old_c), log_signal(new_c_before_xor), | ||||||
|  | 								log_signal(new_c), log_signal(B.extract(it.second*width, width))); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					int range_density = 100*GetSize(choices) / (max_choice-min_choice+1); | ||||||
|  | 					int absolute_density = 100*GetSize(choices) / (max_choice+1); | ||||||
|  | 
 | ||||||
|  | 					log("    choices: %d\n", GetSize(choices)); | ||||||
|  | 					log("    min choice: %d\n", min_choice); | ||||||
|  | 					log("    max choice: %d\n", max_choice); | ||||||
|  | 					log("    range density: %d%%\n", range_density); | ||||||
|  | 					log("    absolute density: %d%%\n", absolute_density); | ||||||
|  | 
 | ||||||
|  | 					if (full_pmux) { | ||||||
|  | 						int full_density = 100*GetSize(choices) / (1 << GetSize(sig)); | ||||||
|  | 						log("    full density: %d%%\n", full_density); | ||||||
|  | 						if (full_density < min_density) { | ||||||
|  | 							full_pmux = false; | ||||||
|  | 						} else { | ||||||
|  | 							min_choice = 0; | ||||||
|  | 							max_choice = (1 << GetSize(sig))-1; | ||||||
|  | 							log("    update to full case.\n"); | ||||||
|  | 							log("    new min choice: %d\n", min_choice); | ||||||
|  | 							log("    new max choice: %d\n", max_choice); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (full_pmux || max_choice+1 == GetSize(choices)); | ||||||
|  | 					log("    full case: %s\n", full_case ? "true" : "false"); | ||||||
|  | 
 | ||||||
|  | 					// check density percentages
 | ||||||
|  | 					Const offset(State::S0, GetSize(sig)); | ||||||
|  | 					if (absolute_density < min_density && range_density >= min_density) | ||||||
|  | 					{ | ||||||
|  | 						offset = Const(min_choice, GetSize(sig)); | ||||||
|  | 						log("    offset: %s\n", log_signal(offset)); | ||||||
|  | 
 | ||||||
|  | 						min_choice -= offset.as_int(); | ||||||
|  | 						max_choice -= offset.as_int(); | ||||||
|  | 
 | ||||||
|  | 						dict<Const, int> new_perm_choices; | ||||||
|  | 						for (auto &it : perm_choices) | ||||||
|  | 							new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second; | ||||||
|  | 						perm_choices.swap(new_perm_choices); | ||||||
|  | 					} else | ||||||
|  | 					if (absolute_density < min_density) { | ||||||
|  | 						log("    insufficient density.\n"); | ||||||
|  | 						seldb.erase(sig); | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// creat cmp signal
 | ||||||
|  | 					SigSpec cmp = perm_sig; | ||||||
|  | 					if (perm_xormask.as_bool()) | ||||||
|  | 						cmp = module->Xor(NEW_ID, cmp, perm_xormask, false, src); | ||||||
|  | 					if (offset.as_bool()) | ||||||
|  | 						cmp = module->Sub(NEW_ID, cmp, offset, false, src); | ||||||
|  | 
 | ||||||
|  | 					// create enable signal
 | ||||||
|  | 					SigBit en = State::S1; | ||||||
|  | 					if (!full_case) { | ||||||
|  | 						Const enable_mask(State::S0, max_choice+1); | ||||||
|  | 						for (auto &it : perm_choices) | ||||||
|  | 							enable_mask[it.first.as_int()] = State::S1; | ||||||
|  | 						en = module->addWire(NEW_ID); | ||||||
|  | 						module->addShift(NEW_ID, enable_mask, cmp, en, false, src); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// create data signal
 | ||||||
|  | 					SigSpec data(State::Sx, (max_choice+1)*extwidth); | ||||||
|  | 					if (full_pmux) { | ||||||
|  | 						for (int i = 0; i <= max_choice; i++) | ||||||
|  | 							data.replace(i*extwidth, A); | ||||||
|  | 					} | ||||||
|  | 					for (auto &it : perm_choices) { | ||||||
|  | 						int position = it.first.as_int()*extwidth; | ||||||
|  | 						int data_index = it.second; | ||||||
|  | 						data.replace(position, B.extract(data_index*width, width)); | ||||||
|  | 						updated_S[data_index] = State::S0; | ||||||
|  | 						updated_B.replace(data_index*width, SigSpec(State::Sx, width)); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// create shiftx cell
 | ||||||
|  | 					SigSpec shifted_cmp = {cmp, SigSpec(State::S0, width_bits)}; | ||||||
|  | 					SigSpec outsig = module->addWire(NEW_ID, width); | ||||||
|  | 					Cell *c = module->addShiftx(NEW_ID, data, shifted_cmp, outsig, false, src); | ||||||
|  | 					updated_S.append(en); | ||||||
|  | 					updated_B.append(outsig); | ||||||
|  | 					log("    created $shiftx cell %s.\n", log_id(c)); | ||||||
|  | 
 | ||||||
|  | 					// remove this sig and continue with the next block
 | ||||||
|  | 					seldb.erase(sig); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				// update $pmux cell
 | ||||||
|  | 				cell->setPort("\\S", updated_S); | ||||||
|  | 				cell->setPort("\\B", updated_B); | ||||||
|  | 				cell->setParam("\\S_WIDTH", GetSize(updated_S)); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } Pmux2ShiftxPass; | ||||||
|  | 
 | ||||||
|  | struct OnehotPass : public Pass { | ||||||
|  | 	OnehotPass() : Pass("onehot", "optimize $eq cells for onehot signals") { } | ||||||
|  | 	void help() YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    onehot [options] [selection]\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("This pass optimizes $eq cells that compare one-hot signals against constants\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    -v, -vv\n"); | ||||||
|  | 		log("        verbose output\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		bool verbose = false; | ||||||
|  | 		bool verbose_onehot = false; | ||||||
|  | 
 | ||||||
|  | 		log_header(design, "Executing ONEHOT pass.\n"); | ||||||
|  | 
 | ||||||
|  | 		size_t argidx; | ||||||
|  | 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||||
|  | 			if (args[argidx] == "-v") { | ||||||
|  | 				verbose = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-vv") { | ||||||
|  | 				verbose = true; | ||||||
|  | 				verbose_onehot = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		extra_args(args, argidx, design); | ||||||
|  | 
 | ||||||
|  | 		for (auto module : design->selected_modules()) | ||||||
|  | 		{ | ||||||
|  | 			SigMap sigmap(module); | ||||||
|  | 			OnehotDatabase onehot_db(module, sigmap); | ||||||
|  | 			onehot_db.verbose = verbose_onehot; | ||||||
|  | 
 | ||||||
|  | 			for (auto cell : module->selected_cells()) | ||||||
|  | 			{ | ||||||
|  | 				if (cell->type != "$eq") | ||||||
|  | 					continue; | ||||||
|  | 
 | ||||||
|  | 				SigSpec A = sigmap(cell->getPort("\\A")); | ||||||
|  | 				SigSpec B = sigmap(cell->getPort("\\B")); | ||||||
|  | 
 | ||||||
|  | 				int a_width = cell->getParam("\\A_WIDTH").as_int(); | ||||||
|  | 				int b_width = cell->getParam("\\B_WIDTH").as_int(); | ||||||
|  | 
 | ||||||
|  | 				if (a_width < b_width) { | ||||||
|  | 					bool a_signed = cell->getParam("\\A_SIGNED").as_int(); | ||||||
|  | 					A.extend_u0(b_width, a_signed); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (b_width < a_width) { | ||||||
|  | 					bool b_signed = cell->getParam("\\B_SIGNED").as_int(); | ||||||
|  | 					B.extend_u0(a_width, b_signed); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (A.is_fully_const()) | ||||||
|  | 					std::swap(A, B); | ||||||
|  | 
 | ||||||
|  | 				if (!B.is_fully_const()) | ||||||
|  | 					continue; | ||||||
|  | 
 | ||||||
|  | 				if (verbose) | ||||||
|  | 					log("Checking $eq(%s, %s) cell %s/%s.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell)); | ||||||
|  | 
 | ||||||
|  | 				if (!onehot_db.query(A)) { | ||||||
|  | 					if (verbose) | ||||||
|  | 						log("  onehot driver test on %s failed.\n", log_signal(A)); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				int index = -1; | ||||||
|  | 				bool not_onehot = false; | ||||||
|  | 
 | ||||||
|  | 				for (int i = 0; i < GetSize(B); i++) { | ||||||
|  | 					if (B[i] != State::S1) | ||||||
|  | 						continue; | ||||||
|  | 					if (index >= 0) | ||||||
|  | 						not_onehot = true; | ||||||
|  | 					index = i; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (index < 0) { | ||||||
|  | 					if (verbose) | ||||||
|  | 						log("  not optimizing the zero pattern.\n"); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				SigSpec Y = cell->getPort("\\Y"); | ||||||
|  | 
 | ||||||
|  | 				if (not_onehot) | ||||||
|  | 				{ | ||||||
|  | 					if (verbose) | ||||||
|  | 						log("  replacing with constant 0 driver.\n"); | ||||||
|  | 					else | ||||||
|  | 						log("Replacing one-hot $eq(%s, %s) cell %s/%s with constant 0 driver.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell)); | ||||||
|  | 					module->connect(Y, SigSpec(1, GetSize(Y))); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					SigSpec sig = A[index]; | ||||||
|  | 					if (verbose) | ||||||
|  | 						log("  replacing with signal %s.\n", log_signal(sig)); | ||||||
|  | 					else | ||||||
|  | 						log("Replacing one-hot $eq(%s, %s) cell %s/%s with signal %s.\n",log_signal(A), log_signal(B), log_id(module), log_id(cell), log_signal(sig)); | ||||||
|  | 					sig.extend_u0(GetSize(Y)); | ||||||
|  | 					module->connect(Y, sig); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				module->remove(cell); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } OnehotPass; | ||||||
|  | 
 | ||||||
|  | PRIVATE_NAMESPACE_END | ||||||
|  | @ -111,9 +111,10 @@ struct AttrmapMap : AttrmapAction { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct AttrmapRemove : AttrmapAction { | struct AttrmapRemove : AttrmapAction { | ||||||
|  | 	bool has_value; | ||||||
| 	string name, value; | 	string name, value; | ||||||
| 	bool apply(IdString &id, Const &val) YS_OVERRIDE { | 	bool apply(IdString &id, Const &val) YS_OVERRIDE { | ||||||
| 		return !(match_name(name, id) && match_value(value, val)); | 		return !(match_name(name, id) && (!has_value || match_value(value, val))); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -235,6 +236,7 @@ struct AttrmapPass : public Pass { | ||||||
| 				} | 				} | ||||||
| 				auto action = new AttrmapRemove; | 				auto action = new AttrmapRemove; | ||||||
| 				action->name = arg1; | 				action->name = arg1; | ||||||
|  | 				action->has_value = (p != string::npos); | ||||||
| 				action->value = val1; | 				action->value = val1; | ||||||
| 				actions.push_back(std::unique_ptr<AttrmapAction>(action)); | 				actions.push_back(std::unique_ptr<AttrmapAction>(action)); | ||||||
| 				continue; | 				continue; | ||||||
|  |  | ||||||
|  | @ -72,6 +72,8 @@ struct TechmapWorker | ||||||
| 	pool<IdString> flatten_done_list; | 	pool<IdString> flatten_done_list; | ||||||
| 	pool<Cell*> flatten_keep_list; | 	pool<Cell*> flatten_keep_list; | ||||||
| 
 | 
 | ||||||
|  | 	pool<string> log_msg_cache; | ||||||
|  | 
 | ||||||
| 	struct TechmapWireData { | 	struct TechmapWireData { | ||||||
| 		RTLIL::Wire *wire; | 		RTLIL::Wire *wire; | ||||||
| 		RTLIL::SigSpec value; | 		RTLIL::SigSpec value; | ||||||
|  | @ -390,6 +392,7 @@ struct TechmapWorker | ||||||
| 
 | 
 | ||||||
| 		bool log_continue = false; | 		bool log_continue = false; | ||||||
| 		bool did_something = false; | 		bool did_something = false; | ||||||
|  | 		LogMakeDebugHdl mkdebug; | ||||||
| 
 | 
 | ||||||
| 		SigMap sigmap(module); | 		SigMap sigmap(module); | ||||||
| 
 | 
 | ||||||
|  | @ -547,6 +550,7 @@ struct TechmapWorker | ||||||
| 								if (extmapper_name == "wrap") { | 								if (extmapper_name == "wrap") { | ||||||
| 									std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); | 									std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); | ||||||
| 									log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); | 									log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); | ||||||
|  | 									mkdebug.on(); | ||||||
| 									Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); | 									Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); | ||||||
| 									log_continue = true; | 									log_continue = true; | ||||||
| 								} | 								} | ||||||
|  | @ -560,11 +564,21 @@ struct TechmapWorker | ||||||
| 								goto use_wrapper_tpl; | 								goto use_wrapper_tpl; | ||||||
| 							} | 							} | ||||||
| 
 | 
 | ||||||
| 							log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); | 							auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); | ||||||
|  | 							if (!log_msg_cache.count(msg)) { | ||||||
|  | 								log_msg_cache.insert(msg); | ||||||
|  | 								log("%s\n", msg.c_str()); | ||||||
|  | 							} | ||||||
|  | 							log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); | ||||||
| 						} | 						} | ||||||
| 						else | 						else | ||||||
| 						{ | 						{ | ||||||
| 							log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); | 							auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); | ||||||
|  | 							if (!log_msg_cache.count(msg)) { | ||||||
|  | 								log_msg_cache.insert(msg); | ||||||
|  | 								log("%s\n", msg.c_str()); | ||||||
|  | 							} | ||||||
|  | 							log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); | ||||||
| 
 | 
 | ||||||
| 							if (extmapper_name == "simplemap") { | 							if (extmapper_name == "simplemap") { | ||||||
| 								if (simplemap_mappers.count(cell->type) == 0) | 								if (simplemap_mappers.count(cell->type) == 0) | ||||||
|  | @ -662,6 +676,7 @@ struct TechmapWorker | ||||||
| 						tpl = techmap_cache[key]; | 						tpl = techmap_cache[key]; | ||||||
| 					} else { | 					} else { | ||||||
| 						if (parameters.size() != 0) { | 						if (parameters.size() != 0) { | ||||||
|  | 							mkdebug.on(); | ||||||
| 							derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); | 							derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); | ||||||
| 							tpl = map->module(derived_name); | 							tpl = map->module(derived_name); | ||||||
| 							log_continue = true; | 							log_continue = true; | ||||||
|  | @ -831,6 +846,7 @@ struct TechmapWorker | ||||||
| 						if (log_continue) { | 						if (log_continue) { | ||||||
| 							log_header(design, "Continuing TECHMAP pass.\n"); | 							log_header(design, "Continuing TECHMAP pass.\n"); | ||||||
| 							log_continue = false; | 							log_continue = false; | ||||||
|  | 							mkdebug.off(); | ||||||
| 						} | 						} | ||||||
| 						while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } | 						while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } | ||||||
| 					} | 					} | ||||||
|  | @ -842,6 +858,7 @@ struct TechmapWorker | ||||||
| 				if (log_continue) { | 				if (log_continue) { | ||||||
| 					log_header(design, "Continuing TECHMAP pass.\n"); | 					log_header(design, "Continuing TECHMAP pass.\n"); | ||||||
| 					log_continue = false; | 					log_continue = false; | ||||||
|  | 					mkdebug.off(); | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				if (extern_mode && !in_recursion) | 				if (extern_mode && !in_recursion) | ||||||
|  | @ -861,13 +878,18 @@ struct TechmapWorker | ||||||
| 						module_queue.insert(m); | 						module_queue.insert(m); | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); | 					log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); | ||||||
| 					cell->type = m_name; | 					cell->type = m_name; | ||||||
| 					cell->parameters.clear(); | 					cell->parameters.clear(); | ||||||
| 				} | 				} | ||||||
| 				else | 				else | ||||||
| 				{ | 				{ | ||||||
| 					log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); | 					auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); | ||||||
|  | 					if (!log_msg_cache.count(msg)) { | ||||||
|  | 						log_msg_cache.insert(msg); | ||||||
|  | 						log("%s\n", msg.c_str()); | ||||||
|  | 					} | ||||||
|  | 					log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); | ||||||
| 					techmap_module_worker(design, module, cell, tpl); | 					techmap_module_worker(design, module, cell, tpl); | ||||||
| 					cell = NULL; | 					cell = NULL; | ||||||
| 				} | 				} | ||||||
|  | @ -885,6 +907,7 @@ struct TechmapWorker | ||||||
| 		if (log_continue) { | 		if (log_continue) { | ||||||
| 			log_header(design, "Continuing TECHMAP pass.\n"); | 			log_header(design, "Continuing TECHMAP pass.\n"); | ||||||
| 			log_continue = false; | 			log_continue = false; | ||||||
|  | 			mkdebug.off(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return did_something; | 		return did_something; | ||||||
|  | @ -1085,7 +1108,7 @@ struct TechmapPass : public Pass { | ||||||
| 		if (map_files.empty()) { | 		if (map_files.empty()) { | ||||||
| 			std::istringstream f(stdcells_code); | 			std::istringstream f(stdcells_code); | ||||||
| 			Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); | 			Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); | ||||||
| 		} else | 		} else { | ||||||
| 			for (auto &fn : map_files) | 			for (auto &fn : map_files) | ||||||
| 				if (fn.substr(0, 1) == "%") { | 				if (fn.substr(0, 1) == "%") { | ||||||
| 					if (!saved_designs.count(fn.substr(1))) { | 					if (!saved_designs.count(fn.substr(1))) { | ||||||
|  | @ -1104,6 +1127,9 @@ struct TechmapPass : public Pass { | ||||||
| 						log_cmd_error("Can't open map file `%s'\n", fn.c_str()); | 						log_cmd_error("Can't open map file `%s'\n", fn.c_str()); | ||||||
| 					Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); | 					Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); | ||||||
| 				} | 				} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		log_header(design, "Continuing TECHMAP pass.\n"); | ||||||
| 
 | 
 | ||||||
| 		std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; | 		std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; | ||||||
| 		for (auto &it : map->modules_) { | 		for (auto &it : map->modules_) { | ||||||
|  | @ -1211,6 +1237,7 @@ struct FlattenPass : public Pass { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		log_suppressed(); | ||||||
| 		log("No more expansions possible.\n"); | 		log("No more expansions possible.\n"); | ||||||
| 
 | 
 | ||||||
| 		if (top_mod != NULL) | 		if (top_mod != NULL) | ||||||
|  |  | ||||||
							
								
								
									
										2096
									
								
								py_wrap_generator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2096
									
								
								py_wrap_generator.py
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,7 +1,17 @@ | ||||||
| 
 | 
 | ||||||
| OBJS += techlibs/gowin/synth_gowin.o | OBJS += techlibs/gowin/synth_gowin.o | ||||||
|  | OBJS += techlibs/gowin/determine_init.o | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) | $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) | ||||||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) | $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) | ||||||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) | $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) | ||||||
|  | $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) | ||||||
|  | $(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt)) | ||||||
|  | $(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v)) | ||||||
|  | $(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh)) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								techlibs/gowin/bram.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								techlibs/gowin/bram.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | bram $__GW1NR_SDP | ||||||
|  | # uncomment when done | ||||||
|  | #  init 1 | ||||||
|  |   abits 10 @a10d18 | ||||||
|  |   dbits 16 @a10d18 | ||||||
|  |   abits 11 @a11d9 | ||||||
|  |   dbits 8  @a11d9 | ||||||
|  |   abits 12 @a12d4 | ||||||
|  |   dbits 4  @a12d4 | ||||||
|  |   abits 13 @a13d2 | ||||||
|  |   dbits 2  @a13d2 | ||||||
|  |   abits 14 @a14d1 | ||||||
|  |   dbits 1  @a14d1 | ||||||
|  |   groups 2 | ||||||
|  |   ports  1 1 | ||||||
|  |   wrmode 1 0 | ||||||
|  |   enable 1 1 @a10d18 | ||||||
|  |   enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1 | ||||||
|  |   transp 0 0 | ||||||
|  |   clocks 2 3 | ||||||
|  |   clkpol 2 3 | ||||||
|  | endbram | ||||||
|  | 
 | ||||||
|  | match $__GW1NR_SDP | ||||||
|  |   min bits 2048 | ||||||
|  |   min efficiency 5 | ||||||
|  |   shuffle_enable B | ||||||
|  |   make_transp | ||||||
|  | endmatch | ||||||
							
								
								
									
										12
									
								
								techlibs/gowin/brams_init3.vh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								techlibs/gowin/brams_init3.vh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | localparam [15:0] INIT_0 = { | ||||||
|  |   INIT[  60], INIT[  56], INIT[  52], INIT[  48], INIT[  44], INIT[  40], INIT[  36], INIT[  32], INIT[  28], INIT[  24], INIT[  20], INIT[  16], INIT[  12], INIT[   8], INIT[   4], INIT[   0] | ||||||
|  | }; | ||||||
|  | localparam [15:0] INIT_1 = { | ||||||
|  |   INIT[  61], INIT[  57], INIT[  53], INIT[  49], INIT[  45], INIT[  41], INIT[  37], INIT[  33], INIT[  29], INIT[  25], INIT[  21], INIT[  17], INIT[  13], INIT[   9], INIT[   5], INIT[   1] | ||||||
|  | }; | ||||||
|  | localparam [15:0] INIT_2 = { | ||||||
|  |   INIT[  62], INIT[  58], INIT[  54], INIT[  50], INIT[  46], INIT[  42], INIT[  38], INIT[  34], INIT[  30], INIT[  26], INIT[  22], INIT[  18], INIT[  14], INIT[  10], INIT[   6], INIT[   2] | ||||||
|  | }; | ||||||
|  | localparam [15:0] INIT_3 = { | ||||||
|  |   INIT[  63], INIT[  59], INIT[  55], INIT[  51], INIT[  47], INIT[  43], INIT[  39], INIT[  35], INIT[  31], INIT[  27], INIT[  23], INIT[  19], INIT[  15], INIT[  11], INIT[   7], INIT[   3] | ||||||
|  | }; | ||||||
							
								
								
									
										103
									
								
								techlibs/gowin/brams_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								techlibs/gowin/brams_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | ||||||
|  | /* Semi Dual Port (SDP) memory have the following configurations: | ||||||
|  |  * Memory Config    RAM(BIT)   Port Mode   Memory Depth   Data Depth | ||||||
|  |  * ----------------|---------| ----------|--------------|------------| | ||||||
|  |  * B-SRAM_16K_SD1      16K      16Kx1       16,384           1 | ||||||
|  |  * B-SRAM_8K_SD2       16K       8Kx2        8,192           2 | ||||||
|  |  * B-SRAM_4K_SD4       16K       4Kx2        4,096           4 | ||||||
|  |  */ | ||||||
|  | module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | ||||||
|  | 	parameter CFG_ABITS = 10; | ||||||
|  | 	parameter CFG_DBITS = 16; | ||||||
|  | 	parameter CFG_ENABLE_A = 3; | ||||||
|  | 
 | ||||||
|  |         parameter [16383:0] INIT = 16384'hx; | ||||||
|  |         parameter CLKPOL2 = 1; | ||||||
|  |         parameter CLKPOL3 = 1; | ||||||
|  | 
 | ||||||
|  | 	input CLK2; | ||||||
|  | 	input CLK3; | ||||||
|  | 
 | ||||||
|  | 	input [CFG_ABITS-1:0] A1ADDR; | ||||||
|  | 	input [CFG_DBITS-1:0] A1DATA;    | ||||||
|  |         input [CFG_ENABLE_A-1:0] A1EN; | ||||||
|  | 
 | ||||||
|  | 	input [CFG_ABITS-1:0] B1ADDR; | ||||||
|  | 	output [CFG_DBITS-1:0] B1DATA; | ||||||
|  | 	input B1EN; | ||||||
|  | 
 | ||||||
|  | 	 | ||||||
|  | 	generate if (CFG_DBITS == 1) begin | ||||||
|  | 		SDP   #( | ||||||
|  | 			.READ_MODE(0), | ||||||
|  | 			.BIT_WIDTH_0(1), | ||||||
|  | 			.BIT_WIDTH_1(1), | ||||||
|  | 			.BLK_SEL(3'b000), | ||||||
|  | 			.RESET_MODE("SYNC") | ||||||
|  | 		) _TECHMAP_REPLACE_ ( | ||||||
|  | 			.CLKA(CLK2),   .CLKB(CLK3), | ||||||
|  | 			.WREA(A1EN),   .OCE(1'b0), .CEA(1'b1), | ||||||
|  | 			.WREB(1'b0),   .CEB(B1EN), | ||||||
|  | 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), | ||||||
|  | 			.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) | ||||||
|  | 		); | ||||||
|  | 	end else if (CFG_DBITS == 2) begin | ||||||
|  | 		SDP    #( | ||||||
|  | 			.READ_MODE(0), | ||||||
|  | 			.BIT_WIDTH_0(2), | ||||||
|  | 			.BIT_WIDTH_1(2), | ||||||
|  | 			.BLK_SEL(3'b000), | ||||||
|  | 			.RESET_MODE("SYNC") | ||||||
|  | 		) _TECHMAP_REPLACE_ ( | ||||||
|  | 			.CLKA(CLK2),   .CLKB(CLK3), | ||||||
|  | 			.WREA(A1EN),   .OCE(1'b0), .CEA(1'b1), | ||||||
|  | 			.WREB(1'b0),   .CEB(B1EN), | ||||||
|  | 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), | ||||||
|  |                         .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) | ||||||
|  | 		); | ||||||
|  | 	end else if (CFG_DBITS <= 4) begin | ||||||
|  | 		SDP    #( | ||||||
|  | 			.READ_MODE(0), | ||||||
|  | 			.BIT_WIDTH_0(4), | ||||||
|  | 			.BIT_WIDTH_1(4), | ||||||
|  | 			.BLK_SEL(3'b000), | ||||||
|  | 			.RESET_MODE("SYNC") | ||||||
|  | 		) _TECHMAP_REPLACE_ ( | ||||||
|  | 			.CLKA(CLK2),   .CLKB(CLK3), | ||||||
|  | 			.WREA(A1EN),   .OCE(1'b0), | ||||||
|  | 			.WREB(1'b0),   .CEB(B1EN), .CEA(1'b1), | ||||||
|  | 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), | ||||||
|  |                         .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) | ||||||
|  | 		); | ||||||
|  | 	end else if (CFG_DBITS <= 8) begin | ||||||
|  | 		SDP    #( | ||||||
|  | 			.READ_MODE(0), | ||||||
|  | 			.BIT_WIDTH_0(8), | ||||||
|  | 			.BIT_WIDTH_1(8), | ||||||
|  | 			.BLK_SEL(3'b000), | ||||||
|  | 			.RESET_MODE("SYNC") | ||||||
|  | 		) _TECHMAP_REPLACE_ ( | ||||||
|  | 			.CLKA(CLK2),   .CLKB(CLK3), | ||||||
|  | 			.WREA(A1EN),   .OCE(1'b0), .CEA(1'b1), | ||||||
|  | 			.WREB(1'b0),   .CEB(B1EN), | ||||||
|  | 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), | ||||||
|  |                         .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) | ||||||
|  | 		); | ||||||
|  | 	end else if (CFG_DBITS <= 16) begin | ||||||
|  | 		SDP    #( | ||||||
|  | 			.READ_MODE(0), | ||||||
|  | 			.BIT_WIDTH_0(16), | ||||||
|  | 			.BIT_WIDTH_1(16), | ||||||
|  | 			.BLK_SEL(3'b000), | ||||||
|  | 			.RESET_MODE("SYNC") | ||||||
|  | 		) _TECHMAP_REPLACE_ ( | ||||||
|  | 			.CLKA(CLK2),   .CLKB(CLK3), | ||||||
|  | 			.WREA(A1EN),   .OCE(1'b0), | ||||||
|  | 			.WREB(1'b0),   .CEB(B1EN), .CEA(1'b1), | ||||||
|  | 			.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), | ||||||
|  |                         .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) | ||||||
|  | 		); | ||||||
|  | 	end else begin | ||||||
|  | 		wire TECHMAP_FAIL = 1'b1; | ||||||
|  | 	end endgenerate | ||||||
|  | 	 | ||||||
|  | endmodule | ||||||
|  | @ -1,5 +1,9 @@ | ||||||
| module  \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule | module  \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule | ||||||
| module  \$_DFF_P_ (input D, C, output Q); DFF  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule | module  \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF  #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule | ||||||
|  | 
 | ||||||
|  | module  \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule | ||||||
|  | module  \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule | ||||||
|  | module  \$__DFFS_PP1_ (input D, C, R, output Q); DFFR  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule | ||||||
| 
 | 
 | ||||||
| module \$lut (A, Y); | module \$lut (A, Y); | ||||||
|   parameter WIDTH = 0; |   parameter WIDTH = 0; | ||||||
|  |  | ||||||
|  | @ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D); | ||||||
| 		Q <= D; | 		Q <= D; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | module DFFR (output reg Q, input D, CLK, RESET); | ||||||
|  | 	parameter [0:0] INIT = 1'b0; | ||||||
|  | 	initial Q = INIT; | ||||||
|  | 	always @(posedge CLK) begin | ||||||
|  |         if (RESET) | ||||||
|  |                 Q <= 1'b0; | ||||||
|  |         else | ||||||
|  |                 Q <= D; | ||||||
|  | 	end | ||||||
|  | endmodule // DFFR (positive clock edge; synchronous reset) | ||||||
|  | 
 | ||||||
| module VCC(output V); | module VCC(output V); | ||||||
| 	assign V = 1; | 	assign V = 1; | ||||||
| endmodule | endmodule | ||||||
|  | @ -63,3 +74,126 @@ module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM); | ||||||
|    assign  {COUT, SUM} = CIN + I1 + I0; |    assign  {COUT, SUM} = CIN + I1 + I0; | ||||||
| endmodule // alu | endmodule // alu | ||||||
| 
 | 
 | ||||||
|  | module RAM16S4 (DO, DI, AD, WRE, CLK); | ||||||
|  |    parameter WIDTH  = 4; | ||||||
|  |    parameter INIT_0 = 16'h0000; | ||||||
|  |    parameter INIT_1 = 16'h0000; | ||||||
|  |    parameter INIT_2 = 16'h0000; | ||||||
|  |    parameter INIT_3 = 16'h0000; | ||||||
|  |     | ||||||
|  |    input  [WIDTH-1:0] AD; | ||||||
|  |    input  [WIDTH-1:0] DI; | ||||||
|  |    output [WIDTH-1:0] DO; | ||||||
|  |    input 	      CLK; | ||||||
|  |    input 	      WRE; | ||||||
|  | 
 | ||||||
|  |    reg [15:0] 	    mem0, mem1, mem2, mem3; | ||||||
|  |     | ||||||
|  |    initial begin | ||||||
|  |       mem0 = INIT_0; | ||||||
|  |       mem1 = INIT_1; | ||||||
|  |       mem2 = INIT_2; | ||||||
|  |       mem3 = INIT_3;	 | ||||||
|  |    end | ||||||
|  |     | ||||||
|  |    assign	DO[0] = mem0[AD]; | ||||||
|  |    assign	DO[1] = mem1[AD]; | ||||||
|  |    assign	DO[2] = mem2[AD]; | ||||||
|  |    assign	DO[3] = mem3[AD]; | ||||||
|  |     | ||||||
|  |    always @(posedge CLK) begin | ||||||
|  |       if (WRE) begin | ||||||
|  | 	 mem0[AD] <= DI[0]; | ||||||
|  | 	 mem1[AD] <= DI[1]; | ||||||
|  | 	 mem2[AD] <= DI[2]; | ||||||
|  | 	 mem3[AD] <= DI[3]; | ||||||
|  |       end | ||||||
|  |    end | ||||||
|  |     | ||||||
|  | endmodule // RAM16S4 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | (* blackbox *) | ||||||
|  | module SDP (DO, DI, BLKSEL, ADA, ADB, WREA, WREB, CLKA, CLKB, CEA, CEB, OCE, RESETA, RESETB); | ||||||
|  | //1'b0: Bypass mode; 1'b1 Pipeline mode | ||||||
|  | parameter READ_MODE = 1'b0; | ||||||
|  | parameter BIT_WIDTH_0 = 32; // 1, 2, 4, 8, 16, 32 | ||||||
|  | parameter BIT_WIDTH_1 = 32; // 1, 2, 4, 8, 16, 32 | ||||||
|  | parameter BLK_SEL = 3'b000; | ||||||
|  | parameter RESET_MODE = "SYNC"; | ||||||
|  | parameter INIT_RAM_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | parameter INIT_RAM_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||||
|  | 
 | ||||||
|  | input CLKA, CEA, CLKB, CEB; | ||||||
|  | input OCE; // clock enable of memory output register | ||||||
|  | input RESETA, RESETB; // resets output registers, not memory contents | ||||||
|  | input WREA, WREB; // 1'b0: read enabled; 1'b1: write enabled | ||||||
|  | input [13:0] ADA, ADB; | ||||||
|  | input [31:0] DI; | ||||||
|  | input [2:0] BLKSEL; | ||||||
|  | output [31:0] DO; | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  |  | ||||||
							
								
								
									
										72
									
								
								techlibs/gowin/determine_init.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								techlibs/gowin/determine_init.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | ||||||
|  | /*
 | ||||||
|  |  *  yosys -- Yosys Open SYnthesis Suite | ||||||
|  |  * | ||||||
|  |  *  Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> | ||||||
|  |  * | ||||||
|  |  *  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 DetermineInitPass : public Pass { | ||||||
|  | 	DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { } | ||||||
|  | 	void help() YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    determine_init [selection]\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Determine the init value of cells that doesn't allow unknown init value.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Const determine_init(Const init) | ||||||
|  | 	{ | ||||||
|  | 		for (int i = 0; i < GetSize(init); i++) { | ||||||
|  | 			if (init[i] != State::S0 && init[i] != State::S1) | ||||||
|  | 				init[i] = State::S0; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return init; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||||
|  | 	{ | ||||||
|  | 		log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n"); | ||||||
|  | 
 | ||||||
|  | 		extra_args(args, args.size(), design); | ||||||
|  | 
 | ||||||
|  | 		size_t cnt = 0; | ||||||
|  | 		for (auto module : design->selected_modules()) | ||||||
|  | 		{ | ||||||
|  | 			for (auto cell : module->selected_cells()) | ||||||
|  | 			{ | ||||||
|  | 				if (cell->type == "\\RAM16S4") | ||||||
|  | 				{ | ||||||
|  | 					cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0"))); | ||||||
|  | 					cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1"))); | ||||||
|  | 					cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2"))); | ||||||
|  | 					cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3"))); | ||||||
|  | 					cnt++; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		log_header(design, "Updated %lu cells with determined init value.\n", cnt); | ||||||
|  | 	} | ||||||
|  | } DetermineInitPass; | ||||||
|  | 
 | ||||||
|  | PRIVATE_NAMESPACE_END | ||||||
							
								
								
									
										17
									
								
								techlibs/gowin/dram.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								techlibs/gowin/dram.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | bram $__GW1NR_RAM16S4 | ||||||
|  |   init 1 | ||||||
|  |   abits 4 | ||||||
|  |   dbits 4 | ||||||
|  |   groups 2 | ||||||
|  |   ports  1 1 | ||||||
|  |   wrmode 0 1 | ||||||
|  |   enable 0 1 | ||||||
|  |   transp 0 1 | ||||||
|  |   clocks 0 1 | ||||||
|  |   clkpol 0 1 | ||||||
|  | endbram | ||||||
|  | 
 | ||||||
|  | match $__GW1NR_RAM16S4 | ||||||
|  |   make_outreg | ||||||
|  |   min wports 1 | ||||||
|  | endmatch | ||||||
							
								
								
									
										31
									
								
								techlibs/gowin/drams_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								techlibs/gowin/drams_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | ||||||
|  | 	parameter CFG_ABITS = 4; | ||||||
|  | 	parameter CFG_DBITS = 4; | ||||||
|  | 
 | ||||||
|  |         parameter [63:0] INIT = 64'bx; | ||||||
|  | 	input CLK1; | ||||||
|  | 
 | ||||||
|  | 	input  [CFG_ABITS-1:0] A1ADDR; | ||||||
|  | 	output [CFG_DBITS-1:0] A1DATA;    | ||||||
|  |         input                  A1EN; | ||||||
|  | 
 | ||||||
|  | 	input  [CFG_ABITS-1:0] B1ADDR; | ||||||
|  | 	input  [CFG_DBITS-1:0] B1DATA; | ||||||
|  | 	input  B1EN; | ||||||
|  | 
 | ||||||
|  |         `include "brams_init3.vh" | ||||||
|  | 
 | ||||||
|  |   RAM16S4 | ||||||
|  |    #(.INIT_0(INIT_0), | ||||||
|  |      .INIT_1(INIT_1), | ||||||
|  |      .INIT_2(INIT_2), | ||||||
|  |      .INIT_3(INIT_3)) | ||||||
|  |    _TECHMAP_REPLACE_ | ||||||
|  |      (.AD(B1ADDR), | ||||||
|  |       .DI(B1DATA), | ||||||
|  |       .DO(A1DATA), | ||||||
|  |       .CLK(CLK1), | ||||||
|  |       .WRE(B1EN)); | ||||||
|  | 
 | ||||||
|  | 	 | ||||||
|  | endmodule | ||||||
|  | @ -49,9 +49,15 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 		log("        from label is synonymous to 'begin', and empty to label is\n"); | 		log("        from label is synonymous to 'begin', and empty to label is\n"); | ||||||
| 		log("        synonymous to the end of the command list.\n"); | 		log("        synonymous to the end of the command list.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    -nodffe\n"); | ||||||
|  | 		log("        do not use flipflops with CE in output netlist\n"); | ||||||
|  | 		log("\n"); | ||||||
| 		log("    -nobram\n"); | 		log("    -nobram\n"); | ||||||
| 		log("        do not use BRAM cells in output netlist\n"); | 		log("        do not use BRAM cells in output netlist\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    -nodram\n"); | ||||||
|  | 		log("        do not use distributed RAM cells in output netlist\n"); | ||||||
|  | 		log("\n"); | ||||||
| 		log("    -noflatten\n"); | 		log("    -noflatten\n"); | ||||||
| 		log("        do not flatten design before synthesis\n"); | 		log("        do not flatten design before synthesis\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | @ -65,7 +71,7 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	string top_opt, vout_file; | 	string top_opt, vout_file; | ||||||
| 	bool retime, flatten, nobram; | 	bool retime, nobram, nodram, flatten, nodffe; | ||||||
| 
 | 
 | ||||||
| 	void clear_flags() YS_OVERRIDE | 	void clear_flags() YS_OVERRIDE | ||||||
| 	{ | 	{ | ||||||
|  | @ -73,7 +79,9 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 		vout_file = ""; | 		vout_file = ""; | ||||||
| 		retime = false; | 		retime = false; | ||||||
| 		flatten = true; | 		flatten = true; | ||||||
| 		nobram = true; | 		nobram = false; | ||||||
|  | 		nodffe = false; | ||||||
|  | 		nodram = 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 | ||||||
|  | @ -108,6 +116,14 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 				nobram = true; | 				nobram = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-nodram") { | ||||||
|  | 				nodram = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (args[argidx] == "-nodffe") { | ||||||
|  | 				nodffe = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			if (args[argidx] == "-noflatten") { | 			if (args[argidx] == "-noflatten") { | ||||||
| 				flatten = false; | 				flatten = false; | ||||||
| 				continue; | 				continue; | ||||||
|  | @ -147,25 +163,43 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 		{ | 		{ | ||||||
| 			run("synth -run coarse"); | 			run("synth -run coarse"); | ||||||
| 		} | 		} | ||||||
| 		if (!nobram && check_label("bram", "(skip if -nobram)")) | 		 | ||||||
|  |                 if (!nobram && check_label("bram", "(skip if -nobram)")) | ||||||
| 		{ | 		{ | ||||||
| 			run("memory_bram -rules +/gowin/bram.txt"); | 			run("memory_bram -rules +/gowin/bram.txt"); | ||||||
| 			run("techmap -map +/gowin/brams_map.v"); | 			run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v"); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!nodram && check_label("dram", "(skip if -nodram)")) | ||||||
|  | 		{ | ||||||
|  | 			run("memory_bram -rules +/gowin/dram.txt"); | ||||||
|  | 			run("techmap -map +/gowin/drams_map.v"); | ||||||
|  | 			run("determine_init"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if (check_label("fine")) | 		if (check_label("fine")) | ||||||
| 		{ | 		{ | ||||||
| 			run("opt -fast -mux_undef -undriven -fine"); | 			run("opt -fast -mux_undef -undriven -fine"); | ||||||
| 			run("memory_map"); | 			run("memory_map"); | ||||||
| 			run("opt -undriven -fine"); | 			run("opt -undriven -fine"); | ||||||
| 			run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); | 			run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); | ||||||
| 			run("opt -fine"); | 			run("techmap -map +/techmap.v"); | ||||||
| 			run("clean -purge"); |  | ||||||
| 			run("splitnets -ports"); |  | ||||||
| 			run("setundef -undriven -zero"); |  | ||||||
| 			if (retime || help_mode) | 			if (retime || help_mode) | ||||||
| 				run("abc -dff", "(only if -retime)"); | 				run("abc -dff", "(only if -retime)"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (check_label("map_ffs")) | ||||||
|  | 		{ | ||||||
|  | 			run("dffsr2dff"); | ||||||
|  | 			run("dff2dffs"); | ||||||
|  | 			run("opt_clean"); | ||||||
|  | 			if (!nodffe) | ||||||
|  | 				run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); | ||||||
|  | 			run("techmap -map +/gowin/cells_map.v"); | ||||||
|  | 			run("opt_expr -mux_undef"); | ||||||
|  | 			run("simplemap"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if (check_label("map_luts")) | 		if (check_label("map_luts")) | ||||||
| 		{ | 		{ | ||||||
| 			run("abc -lut 4"); | 			run("abc -lut 4"); | ||||||
|  | @ -176,8 +210,10 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 		{ | 		{ | ||||||
| 			run("techmap -map +/gowin/cells_map.v"); | 			run("techmap -map +/gowin/cells_map.v"); | ||||||
| 			run("hilomap -hicell VCC V -locell GND G"); | 			run("hilomap -hicell VCC V -locell GND G"); | ||||||
| 			run("iopadmap -inpad IBUF O:I -outpad OBUF I:O"); | 			run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)"); | ||||||
| 			run("clean -purge"); | 			run("dffinit  -ff DFF Q INIT"); | ||||||
|  | 			run("clean"); | ||||||
|  | 
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("check")) | 		if (check_label("check")) | ||||||
|  |  | ||||||
|  | @ -27,18 +27,27 @@ module SB_IO ( | ||||||
| 	reg dout_q_0, dout_q_1; | 	reg dout_q_0, dout_q_1; | ||||||
| 	reg outena_q; | 	reg outena_q; | ||||||
| 
 | 
 | ||||||
|  | 	// IO tile generates a constant 1'b1 internally if global_cen is not connected | ||||||
|  | 	wire clken_pulled = CLOCK_ENABLE || CLOCK_ENABLE === 1'bz; | ||||||
|  | 	reg  clken_pulled_ri; | ||||||
|  | 	reg  clken_pulled_ro; | ||||||
|  | 
 | ||||||
| 	generate if (!NEG_TRIGGER) begin | 	generate if (!NEG_TRIGGER) begin | ||||||
| 		always @(posedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_0  <= PACKAGE_PIN; | 		always @(posedge INPUT_CLK)                       clken_pulled_ri <= clken_pulled; | ||||||
| 		always @(negedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_1  <= PACKAGE_PIN; | 		always @(posedge INPUT_CLK)  if (clken_pulled)    din_q_0         <= PACKAGE_PIN; | ||||||
| 		always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; | 		always @(negedge INPUT_CLK)  if (clken_pulled_ri) din_q_1         <= PACKAGE_PIN; | ||||||
| 		always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; | 		always @(posedge OUTPUT_CLK)                      clken_pulled_ro <= clken_pulled; | ||||||
| 		always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; | 		always @(posedge OUTPUT_CLK) if (clken_pulled)    dout_q_0        <= D_OUT_0; | ||||||
|  | 		always @(negedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1        <= D_OUT_1; | ||||||
|  | 		always @(posedge OUTPUT_CLK) if (clken_pulled)    outena_q        <= OUTPUT_ENABLE; | ||||||
| 	end else begin | 	end else begin | ||||||
| 		always @(negedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_0  <= PACKAGE_PIN; | 		always @(negedge INPUT_CLK)                       clken_pulled_ri <= clken_pulled; | ||||||
| 		always @(posedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_1  <= PACKAGE_PIN; | 		always @(negedge INPUT_CLK)  if (clken_pulled)    din_q_0         <= PACKAGE_PIN; | ||||||
| 		always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; | 		always @(posedge INPUT_CLK)  if (clken_pulled_ri) din_q_1         <= PACKAGE_PIN; | ||||||
| 		always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; | 		always @(negedge OUTPUT_CLK)                      clken_pulled_ro <= clken_pulled; | ||||||
| 		always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; | 		always @(negedge OUTPUT_CLK) if (clken_pulled)    dout_q_0        <= D_OUT_0; | ||||||
|  | 		always @(posedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1        <= D_OUT_1; | ||||||
|  | 		always @(negedge OUTPUT_CLK) if (clken_pulled)    outena_q        <= OUTPUT_ENABLE; | ||||||
| 	end endgenerate | 	end endgenerate | ||||||
| 
 | 
 | ||||||
| 	always @* begin | 	always @* begin | ||||||
|  |  | ||||||
|  | @ -116,14 +116,15 @@ struct SynthXilinxPass : public Pass | ||||||
| 		log("        techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); | 		log("        techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); | ||||||
| 		log("        opt -fast\n"); | 		log("        opt -fast\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    map_cells:\n"); | ||||||
|  | 		log("        techmap -map +/xilinx/cells_map.v\n"); | ||||||
|  | 		log("        clean\n"); | ||||||
|  | 		log("\n"); | ||||||
| 		log("    map_luts:\n"); | 		log("    map_luts:\n"); | ||||||
| 		log("        techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); | 		log("        techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); | ||||||
| 		log("        abc -luts 2:2,3,6:5,10,20 [-dff]\n"); | 		log("        abc -luts 2:2,3,6:5,10,20 [-dff]\n"); | ||||||
| 		log("        clean\n"); | 		log("        clean\n"); | ||||||
| 		log("        techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); | 		log("        techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); | ||||||
| 		log("\n"); |  | ||||||
| 		log("    map_cells:\n"); |  | ||||||
| 		log("        techmap -map +/xilinx/cells_map.v\n"); |  | ||||||
| 		log("        dffinit -ff FDRE   Q INIT -ff FDCE   Q INIT -ff FDPE   Q INIT -ff FDSE   Q INIT \\\n"); | 		log("        dffinit -ff FDRE   Q INIT -ff FDCE   Q INIT -ff FDPE   Q INIT -ff FDSE   Q INIT \\\n"); | ||||||
| 		log("                -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); | 		log("                -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); | ||||||
| 		log("        clean\n"); | 		log("        clean\n"); | ||||||
|  | @ -274,17 +275,18 @@ struct SynthXilinxPass : public Pass | ||||||
| 			Pass::call(design, "opt -fast"); | 			Pass::call(design, "opt -fast"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (check_label(active, run_from, run_to, "map_cells")) | ||||||
|  | 		{ | ||||||
|  | 			Pass::call(design, "techmap -map +/xilinx/cells_map.v"); | ||||||
|  | 			Pass::call(design, "clean"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if (check_label(active, run_from, run_to, "map_luts")) | 		if (check_label(active, run_from, run_to, "map_luts")) | ||||||
| 		{ | 		{ | ||||||
| 			Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); | 			Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); | ||||||
| 			Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); | 			Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); | ||||||
| 			Pass::call(design, "clean"); | 			Pass::call(design, "clean"); | ||||||
| 			Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); | 			Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (check_label(active, run_from, run_to, "map_cells")) |  | ||||||
| 		{ |  | ||||||
| 			Pass::call(design, "techmap -map +/xilinx/cells_map.v"); |  | ||||||
| 			Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " | 			Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " | ||||||
| 					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); | 					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); | ||||||
| 			Pass::call(design, "clean"); | 			Pass::call(design, "clean"); | ||||||
|  |  | ||||||
							
								
								
									
										38
									
								
								tests/sat/counters-repeat.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/sat/counters-repeat.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | // coverage for repeat loops outside of constant functions | ||||||
|  | 
 | ||||||
|  | module counter1(clk, rst, ping); | ||||||
|  | 	input clk, rst; | ||||||
|  | 	output ping; | ||||||
|  | 	reg [31:0] count; | ||||||
|  | 
 | ||||||
|  | 	always @(posedge clk) begin | ||||||
|  | 		if (rst) | ||||||
|  | 			count <= 0; | ||||||
|  | 		else | ||||||
|  | 			count <= count + 1; | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	assign ping = &count; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module counter2(clk, rst, ping); | ||||||
|  | 	input clk, rst; | ||||||
|  | 	output ping; | ||||||
|  | 	reg [31:0] count; | ||||||
|  | 
 | ||||||
|  | 	integer i; | ||||||
|  | 	reg carry; | ||||||
|  | 
 | ||||||
|  | 	always @(posedge clk) begin | ||||||
|  | 		carry = 1; | ||||||
|  | 		i = 0; | ||||||
|  | 		repeat (32) begin | ||||||
|  | 			count[i] <= !rst & (count[i] ^ carry); | ||||||
|  | 			carry = count[i] & carry; | ||||||
|  | 			i = i+1; | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	assign ping = &count; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
							
								
								
									
										10
									
								
								tests/sat/counters-repeat.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/sat/counters-repeat.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | 
 | ||||||
|  | read_verilog counters-repeat.v | ||||||
|  | proc; opt | ||||||
|  | 
 | ||||||
|  | expose -shared counter1 counter2 | ||||||
|  | miter -equiv -make_assert -make_outputs counter1 counter2 miter | ||||||
|  | 
 | ||||||
|  | cd miter; flatten; opt | ||||||
|  | sat -verify -prove-asserts -tempinduct -set-at 1 in_rst 1 -seq 1 -show-inputs -show-outputs | ||||||
|  | 
 | ||||||
							
								
								
									
										34
									
								
								tests/various/pmux2shiftx.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tests/various/pmux2shiftx.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | module pmux2shiftx_test ( | ||||||
|  | 	input [2:0] S1, | ||||||
|  | 	input [5:0] S2, | ||||||
|  | 	input [1:0] S3, | ||||||
|  | 	input [9:0] A, B, C, D, D, E, F, G, H, | ||||||
|  | 	input [9:0] I, J, K, L, M, N, O, P, Q, | ||||||
|  | 	output reg [9:0] X | ||||||
|  | ); | ||||||
|  | 	always @* begin | ||||||
|  | 		case (S1) | ||||||
|  | 			3'd 0: X = A; | ||||||
|  | 			3'd 1: X = B; | ||||||
|  | 			3'd 2: X = C; | ||||||
|  | 			3'd 3: X = D; | ||||||
|  | 			3'd 4: X = E; | ||||||
|  | 			3'd 5: X = F; | ||||||
|  | 			3'd 6: X = G; | ||||||
|  | 			3'd 7: X = H; | ||||||
|  | 		endcase | ||||||
|  | 		case (S2) | ||||||
|  | 			6'd 45: X = I; | ||||||
|  | 			6'd 47: X = J; | ||||||
|  | 			6'd 49: X = K; | ||||||
|  | 			6'd 55: X = L; | ||||||
|  | 			6'd 57: X = M; | ||||||
|  | 			6'd 59: X = N; | ||||||
|  | 		endcase | ||||||
|  | 		case (S3) | ||||||
|  | 			2'd 1: X = O; | ||||||
|  | 			2'd 2: X = P; | ||||||
|  | 			2'd 3: X = Q; | ||||||
|  | 		endcase | ||||||
|  | 	end | ||||||
|  | endmodule | ||||||
							
								
								
									
										28
									
								
								tests/various/pmux2shiftx.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/various/pmux2shiftx.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | read_verilog pmux2shiftx.v | ||||||
|  | prep | ||||||
|  | design -save gold | ||||||
|  | 
 | ||||||
|  | pmux2shiftx -min_density 70 | ||||||
|  | 
 | ||||||
|  | opt | ||||||
|  | 
 | ||||||
|  | stat | ||||||
|  | # show -width | ||||||
|  | select -assert-count 1 t:$sub | ||||||
|  | select -assert-count 1 t:$mux | ||||||
|  | select -assert-count 1 t:$shift | ||||||
|  | select -assert-count 3 t:$shiftx | ||||||
|  | 
 | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | 
 | ||||||
|  | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
|  | sat -verify -prove-asserts -show-ports miter | ||||||
|  | 
 | ||||||
|  | design -load gold | ||||||
|  | stat | ||||||
|  | 
 | ||||||
|  | design -load gate | ||||||
|  | stat | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue