mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +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 | ||||
|             - pkg-config | ||||
|             - python | ||||
|             - python3 | ||||
|             - libboost-system-dev | ||||
|             - libboost-python-dev | ||||
|             - libboost-filesystem-dev | ||||
|       env: | ||||
|         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" | ||||
| 
 | ||||
|  | @ -56,6 +60,10 @@ matrix: | |||
|             - xdot | ||||
|             - pkg-config | ||||
|             - python | ||||
|             - python3 | ||||
|             - libboost-system-dev | ||||
|             - libboost-python-dev | ||||
|             - libboost-filesystem-dev | ||||
|       env: | ||||
|         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6" | ||||
| 
 | ||||
|  | @ -80,6 +88,10 @@ matrix: | |||
|             - xdot | ||||
|             - pkg-config | ||||
|             - python | ||||
|             - python3 | ||||
|             - libboost-system-dev | ||||
|             - libboost-python-dev | ||||
|             - libboost-filesystem-dev | ||||
|       env: | ||||
|         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" | ||||
| 
 | ||||
|  | @ -105,6 +117,10 @@ matrix: | |||
|             - xdot | ||||
|             - pkg-config | ||||
|             - python | ||||
|             - python3 | ||||
|             - libboost-system-dev | ||||
|             - libboost-python-dev | ||||
|             - libboost-filesystem-dev | ||||
|       env: | ||||
|         - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" | ||||
| 
 | ||||
|  | @ -129,6 +145,10 @@ matrix: | |||
|             - xdot | ||||
|             - pkg-config | ||||
|             - python | ||||
|             - python3 | ||||
|             - libboost-system-dev | ||||
|             - libboost-python-dev | ||||
|             - libboost-filesystem-dev | ||||
|       env: | ||||
|         - 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_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
 | ||||
| ENABLE_GCOV := 0 | ||||
| ENABLE_GPROF := 0 | ||||
|  | @ -261,6 +269,34 @@ ifeq ($(ENABLE_LIBYOSYS),1) | |||
| TARGETS += libyosys.so | ||||
| 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) | ||||
| CXXFLAGS += -DYOSYS_ENABLE_READLINE | ||||
| ifeq ($(OS), FreeBSD) | ||||
|  | @ -511,6 +547,14 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) | |||
| 	$(Q) mkdir -p $(dir $@) | ||||
| 	$(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 | ||||
| 	$(Q) mkdir -p $(dir $@) | ||||
| 	$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< | ||||
|  | @ -639,6 +683,11 @@ ifeq ($(ENABLE_LIBYOSYS),1) | |||
| 	$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) | ||||
| 	$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so | ||||
| 	$(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 | ||||
| 
 | ||||
| uninstall: | ||||
|  | @ -646,6 +695,11 @@ uninstall: | |||
| 	$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) | ||||
| ifeq ($(ENABLE_LIBYOSYS),1) | ||||
| 	$(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 | ||||
| 
 | ||||
| update-manual: $(TARGETS) $(EXTRA_TARGETS) | ||||
|  | @ -658,8 +712,9 @@ manual: $(TARGETS) $(EXTRA_TARGETS) | |||
| 
 | ||||
| clean: | ||||
| 	rm -rf share | ||||
| 	rm -rf kernel/*.pyh | ||||
| 	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 libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d | ||||
| 	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 \ | ||||
| 		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: | ||||
| 
 | ||||
| 	$ brew tap Homebrew/bundle && brew bundle | ||||
| 	$ 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: | ||||
| 
 | ||||
| 	# 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: | ||||
|     % MAKE=gmake CC=cc gmake test | ||||
| 
 | ||||
| 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 | ||||
| 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) | ||||
| 		width = data.bits.size() - offset; | ||||
| 	if (width == 0) { | ||||
| 		f << "\"\""; | ||||
| 		return; | ||||
| 	} | ||||
| 	if (nostr) | ||||
| 		goto dump_hex; | ||||
| 	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) | ||||
| { | ||||
| 	if (GetSize(sig) == 0) { | ||||
| 		f << "\"\""; | ||||
| 		return; | ||||
| 	} | ||||
| 	if (sig.is_chunk()) { | ||||
| 		dump_sigchunk(f, sig.as_chunk()); | ||||
| 	} 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 | ||||
| 
 | ||||
| //#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) | ||||
|     : 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"); | ||||
| 
 | ||||
| 	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
 | ||||
| 	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
 | ||||
| 		AstNode *varbuf = init_ast->children[1]->clone(); | ||||
| 		{ | ||||
| 			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) | ||||
| 			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
 | ||||
| 			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) | ||||
| 				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
 | ||||
| 			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) | ||||
| 				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::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); | ||||
| 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) | ||||
| { | ||||
| 	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) | ||||
| { | ||||
|  |  | |||
|  | @ -110,6 +110,10 @@ int main(int argc, char **argv) | |||
| 	log_error_stderr = true; | ||||
| 	yosys_banner(); | ||||
| 	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) | ||||
| 	{ | ||||
|  | @ -291,6 +295,9 @@ int main(int argc, char **argv) | |||
| 		printf("    -E <depsfile>\n"); | ||||
| 		printf("        write a Makefile dependencies file with in- and output file names\n"); | ||||
| 		printf("\n"); | ||||
| 		printf("    -g\n"); | ||||
| 		printf("        globally enable debug log messages\n"); | ||||
| 		printf("\n"); | ||||
| 		printf("    -V\n"); | ||||
| 		printf("        print version information and exit\n"); | ||||
| 		printf("\n"); | ||||
|  | @ -311,7 +318,7 @@ int main(int argc, char **argv) | |||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| 		{ | ||||
|  | @ -336,6 +343,9 @@ int main(int argc, char **argv) | |||
| 		case 'S': | ||||
| 			passes_commands.push_back("synth"); | ||||
| 			break; | ||||
| 		case 'g': | ||||
| 			log_force_debug++; | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			plugin_filenames.push_back(optarg); | ||||
| 			break; | ||||
|  | @ -469,6 +479,10 @@ int main(int argc, char **argv) | |||
| #endif | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	for (auto &fn : plugin_filenames) | ||||
|  |  | |||
|  | @ -56,6 +56,10 @@ int log_verbose_level; | |||
| string log_last_error; | ||||
| void (*log_error_atexit)() = NULL; | ||||
| 
 | ||||
| int log_make_debug = 0; | ||||
| int log_force_debug = 0; | ||||
| int log_debug_suppressed = 0; | ||||
| 
 | ||||
| vector<int> header_count; | ||||
| pool<RTLIL::IdString> log_id_cache; | ||||
| vector<shared_str> string_buf; | ||||
|  | @ -92,6 +96,9 @@ void logv(const char *format, va_list ap) | |||
| 		format++; | ||||
| 	} | ||||
| 
 | ||||
| 	if (log_make_debug && !ys_debug(1)) | ||||
| 		return; | ||||
| 
 | ||||
| 	std::string str = vstringf(format, ap); | ||||
| 
 | ||||
| 	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 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_header(RTLIL::Design *design, 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); | ||||
| 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_push(); | ||||
| 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) | ||||
| { | ||||
| 	IdString::checkpoint(); | ||||
| 	log_suppressed(); | ||||
| 
 | ||||
| 	int64_t time_ns = PerformanceTimer::query() - state.begin_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); | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
| 	if (bits.size() != other.bits.size()) | ||||
|  | @ -363,6 +370,10 @@ RTLIL::Design::Design() | |||
| 
 | ||||
| 	refcount_modules_ = 0; | ||||
| 	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() | ||||
|  | @ -373,8 +384,19 @@ RTLIL::Design::~Design() | |||
| 		delete n; | ||||
| 	for (auto n : verilog_globals) | ||||
| 		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() | ||||
| { | ||||
| 	return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_); | ||||
|  | @ -630,6 +652,10 @@ RTLIL::Module::Module() | |||
| 	design = nullptr; | ||||
| 	refcount_wires_ = 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() | ||||
|  | @ -642,8 +668,19 @@ RTLIL::Module::~Module() | |||
| 		delete it->second; | ||||
| 	for (auto it = processes.begin(); it != processes.end(); ++it) | ||||
| 		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() | ||||
| { | ||||
| 	pool<RTLIL::Wire*> delwires; | ||||
|  | @ -2229,8 +2266,27 @@ RTLIL::Wire::Wire() | |||
| 	port_input = false; | ||||
| 	port_output = 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() | ||||
| { | ||||
| 	static unsigned int hashidx_count = 123456789; | ||||
|  | @ -2240,6 +2296,9 @@ RTLIL::Memory::Memory() | |||
| 	width = 1; | ||||
| 	start_offset = 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) | ||||
|  | @ -2250,8 +2309,27 @@ RTLIL::Cell::Cell() : module(nullptr) | |||
| 
 | ||||
| 	// log("#memtrace# %p\n", this);
 | ||||
| 	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 | ||||
| { | ||||
| 	return connections_.count(portname) != 0; | ||||
|  | @ -2511,6 +2589,14 @@ RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit) | |||
| 	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 ret; | ||||
|  | @ -3895,5 +3981,15 @@ RTLIL::Process *RTLIL::Process::clone() const | |||
| 	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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -523,6 +523,7 @@ struct RTLIL::Const | |||
| 	Const(RTLIL::State bit, int width = 1); | ||||
| 	Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } | ||||
| 	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; | ||||
|  | @ -601,6 +602,7 @@ struct RTLIL::SigChunk | |||
| 	SigChunk(int val, int width = 32); | ||||
| 	SigChunk(RTLIL::State bit, int width = 1); | ||||
| 	SigChunk(RTLIL::SigBit bit); | ||||
| 	SigChunk(const RTLIL::SigChunk &sigchunk); | ||||
| 
 | ||||
| 	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, int index); | ||||
| 	SigBit(const RTLIL::SigSpec &sig); | ||||
| 	SigBit(const RTLIL::SigBit &sigbit); | ||||
| 
 | ||||
| 	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_whole_modules() 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 | ||||
|  | @ -1205,6 +1212,10 @@ public: | |||
| 	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 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 | ||||
|  | @ -1216,7 +1227,7 @@ protected: | |||
| 	// use module->addWire() and module->remove() to create or destroy wires
 | ||||
| 	friend struct RTLIL::Module; | ||||
| 	Wire(); | ||||
| 	~Wire() { }; | ||||
| 	~Wire(); | ||||
| 
 | ||||
| public: | ||||
| 	// do not simply copy wires
 | ||||
|  | @ -1227,6 +1238,10 @@ public: | |||
| 	RTLIL::IdString name; | ||||
| 	int width, start_offset, port_id; | ||||
| 	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 | ||||
|  | @ -1238,6 +1253,10 @@ struct RTLIL::Memory : public RTLIL::AttrObject | |||
| 
 | ||||
| 	RTLIL::IdString name; | ||||
| 	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 | ||||
|  | @ -1249,6 +1268,7 @@ protected: | |||
| 	// use module->addCell() and module->remove() to create or destroy cells
 | ||||
| 	friend struct RTLIL::Module; | ||||
| 	Cell(); | ||||
| 	~Cell(); | ||||
| 
 | ||||
| public: | ||||
| 	// do not simply copy cells
 | ||||
|  | @ -1289,6 +1309,10 @@ public: | |||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
|  | @ -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(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::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){if(wire) offset = sigbit.offset;} | ||||
| 
 | ||||
| inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { | ||||
| 	if (wire == other.wire) | ||||
|  |  | |||
|  | @ -57,6 +57,16 @@ | |||
| #  include <sys/sysctl.h> | ||||
| #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 <errno.h> | ||||
| 
 | ||||
|  | @ -477,21 +487,42 @@ int GetSize(RTLIL::Wire *wire) | |||
| 	return wire->width; | ||||
| } | ||||
| 
 | ||||
| bool already_setup = false; | ||||
| 
 | ||||
| void yosys_setup() | ||||
| { | ||||
| 	if(already_setup) | ||||
| 		return; | ||||
| 	already_setup = true; | ||||
| 	// if there are already IdString objects then we have a global initialization order bug
 | ||||
| 	IdString empty_id; | ||||
| 	log_assert(empty_id.index_ == 0); | ||||
| 	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(); | ||||
| 	yosys_design = new RTLIL::Design; | ||||
| 	yosys_celltypes.setup(); | ||||
| 	log_push(); | ||||
| } | ||||
| 
 | ||||
| bool yosys_already_setup() | ||||
| { | ||||
| 	return already_setup; | ||||
| } | ||||
| 
 | ||||
| bool already_shutdown = false; | ||||
| 
 | ||||
| void yosys_shutdown() | ||||
| { | ||||
| 	if(already_shutdown) | ||||
| 		return; | ||||
| 	already_shutdown = true; | ||||
| 	log_pop(); | ||||
| 
 | ||||
| 	delete yosys_design; | ||||
|  | @ -519,9 +550,16 @@ void yosys_shutdown() | |||
| 		dlclose(it.second); | ||||
| 
 | ||||
| 	loaded_plugins.clear(); | ||||
| #ifdef WITH_PYTHON | ||||
| 	loaded_python_plugins.clear(); | ||||
| #endif | ||||
| 	loaded_plugin_aliases.clear(); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef WITH_PYTHON | ||||
| 	Py_Finalize(); | ||||
| #endif | ||||
| 
 | ||||
| 	IdString empty_id; | ||||
| 	IdString::put_reference(empty_id.index_); | ||||
| } | ||||
|  |  | |||
|  | @ -66,6 +66,10 @@ | |||
| #include <stdio.h> | ||||
| #include <limits.h> | ||||
| 
 | ||||
| #ifdef WITH_PYTHON | ||||
| #include <Python.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifndef _YOSYS_ | ||||
| #  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 \ | ||||
|  | @ -115,6 +119,7 @@ extern const char *Tcl_GetStringResult(Tcl_Interp *interp); | |||
| #  define PATH_MAX 4096 | ||||
| #endif | ||||
| 
 | ||||
| #define YOSYS_NAMESPACE          Yosys | ||||
| #define PRIVATE_NAMESPACE_BEGIN  namespace { | ||||
| #define PRIVATE_NAMESPACE_END    } | ||||
| #define YOSYS_NAMESPACE_BEGIN    namespace Yosys { | ||||
|  | @ -276,6 +281,11 @@ namespace hashlib { | |||
| } | ||||
| 
 | ||||
| void yosys_setup(); | ||||
| 
 | ||||
| #ifdef WITH_PYTHON | ||||
| bool yosys_already_setup(); | ||||
| #endif | ||||
| 
 | ||||
| void yosys_shutdown(); | ||||
| 
 | ||||
| #ifdef YOSYS_ENABLE_TCL | ||||
|  | @ -317,6 +327,9 @@ extern std::vector<RTLIL::Design*> pushed_designs; | |||
| 
 | ||||
| // from passes/cmds/pluginc.cc
 | ||||
| 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; | ||||
| void load_plugin(std::string filename, std::vector<std::string> aliases); | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,9 +23,18 @@ | |||
| #  include <dlfcn.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef WITH_PYTHON | ||||
| #  include <boost/algorithm/string/predicate.hpp> | ||||
| #  include <Python.h> | ||||
| #  include <boost/filesystem.hpp> | ||||
| #endif | ||||
| 
 | ||||
| YOSYS_NAMESPACE_BEGIN | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| #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) | ||||
| 		filename = "./" + filename; | ||||
| 
 | ||||
| 	#ifdef WITH_PYTHON | ||||
| 	if (!loaded_plugins.count(filename) && !loaded_python_plugins.count(filename)) { | ||||
| 	#else | ||||
| 	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); | ||||
| 		if (hdl == NULL && orig_filename.find('/') == std::string::npos) | ||||
| 			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()); | ||||
| 		loaded_plugins[orig_filename] = hdl; | ||||
| 		Pass::init_register(); | ||||
| 
 | ||||
| 		#ifdef WITH_PYTHON | ||||
| 		} | ||||
| 		#endif | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto &alias : aliases) | ||||
|  | @ -107,7 +148,11 @@ struct PluginPass : public Pass { | |||
| 		if (list_mode) | ||||
| 		{ | ||||
| 			log("\n"); | ||||
| #ifdef WITH_PYTHON | ||||
| 			if (loaded_plugins.empty() and loaded_python_plugins.empty()) | ||||
| #else | ||||
| 			if (loaded_plugins.empty()) | ||||
| #endif | ||||
| 				log("No plugins loaded.\n"); | ||||
| 			else | ||||
| 				log("Loaded plugins:\n"); | ||||
|  | @ -115,6 +160,11 @@ struct PluginPass : public Pass { | |||
| 			for (auto &it : loaded_plugins) | ||||
| 				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()) { | ||||
| 				log("\n"); | ||||
| 				int max_alias_len = 1; | ||||
|  |  | |||
|  | @ -94,4 +94,38 @@ struct TracePass : public Pass { | |||
| 	} | ||||
| } 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 | ||||
|  |  | |||
|  | @ -13,5 +13,6 @@ OBJS += passes/opt/wreduce.o | |||
| OBJS += passes/opt/opt_demorgan.o | ||||
| OBJS += passes/opt/rmports.o | ||||
| OBJS += passes/opt/opt_lut.o | ||||
| OBJS += passes/opt/pmux2shiftx.o | ||||
| endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -137,7 +137,7 @@ void rmunused_module_cells(Module *module, bool verbose) | |||
| 
 | ||||
| 	for (auto cell : unused) { | ||||
| 		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->remove(cell); | ||||
| 		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) | ||||
| 		if (!used_signals.check_any(RTLIL::SigSpec(wire))) { | ||||
| 			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_count++; | ||||
|  | @ -336,7 +336,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos | |||
| 	count_rm_wires += del_wires.size(); | ||||
| 
 | ||||
| 	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) | ||||
|  | @ -399,7 +399,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool 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"); | ||||
| 		did_something = true; | ||||
|  | @ -426,7 +426,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool | |||
| 		} | ||||
| 	for (auto cell : delcells) { | ||||
| 		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"))); | ||||
| 		module->remove(cell); | ||||
| 	} | ||||
|  | @ -551,6 +551,7 @@ struct CleanPass : public Pass { | |||
| 			rmunused_module(module, purge_mode, false, false); | ||||
| 		} | ||||
| 
 | ||||
| 		log_suppressed(); | ||||
| 		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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) | |||
| 		if (sig.size() == 0) | ||||
| 			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))); | ||||
| 		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); | ||||
| 	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(), | ||||
| 			module->name.c_str(), log_signal(Y), log_signal(out_val)); | ||||
| 	// 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)) | ||||
| 			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)); | ||||
| 
 | ||||
| 	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) { | ||||
| 			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_conn); | ||||
| 			continue; | ||||
|  | @ -180,10 +180,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ | |||
| 
 | ||||
| 		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") | ||||
| 			log(", B=%s", log_signal(new_b)); | ||||
| 		log("\n"); | ||||
| 			log_debug(", B=%s", log_signal(new_b)); | ||||
| 		log_debug("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	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)); | ||||
| 	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_signal(sig), log_signal(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)) { | ||||
| 		SigSpec sig = assign_map(cell->getPort(port)); | ||||
| 		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_signal(sig), log_signal(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") { | ||||
| 				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)); | ||||
| 				cell->type = "$not"; | ||||
| 				did_something = true; | ||||
| 			} else { | ||||
| 				cover("opt.opt_expr.unary_buffer"); | ||||
| 				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)) { | ||||
| 					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->setPort("\\A", 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)) { | ||||
| 					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->setPort("\\B", 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) { | ||||
| 					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->setPort("\\A", sig_a = new_a); | ||||
| 					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) { | ||||
| 					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->setPort("\\A", sig_a = new_a); | ||||
| 					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) { | ||||
| 					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->setPort("\\B", sig_b = new_b); | ||||
| 					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) { | ||||
| 			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"); | ||||
| 			cell->setPort("\\A", cell->getPort("\\B")); | ||||
| 			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")); | ||||
| 			if (input == State::S0 && !a.is_fully_undef()) { | ||||
| 				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->setPort("\\A", SigSpec(State::Sx, GetSize(a))); | ||||
| 				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")); | ||||
| 				} else { | ||||
| 					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->parameters.erase("\\B_WIDTH"); | ||||
| 					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())) | ||||
| 		{ | ||||
| 			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"); | ||||
| 			cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; | ||||
| 			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()); | ||||
| 
 | ||||
| 			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)); | ||||
| 
 | ||||
| 			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) | ||||
| 					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'); | ||||
| 
 | ||||
| 				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_") && | ||||
| 				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()); | ||||
| 			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->unsetPort("\\B"); | ||||
| 			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)) { | ||||
| 			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->unsetPort("\\S"); | ||||
| 			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)) { | ||||
| 			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->unsetPort("\\S"); | ||||
| 			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()) { | ||||
| 				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)); | ||||
| 				cell->setPort("\\A", new_a); | ||||
| 				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"); | ||||
| 
 | ||||
| 					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()); | ||||
| 
 | ||||
| 					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 | ||||
| 							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); | ||||
| 
 | ||||
| 						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"); | ||||
| 
 | ||||
| 					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()); | ||||
| 
 | ||||
| 					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"); | ||||
| 
 | ||||
| 							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); | ||||
| 
 | ||||
| 							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"); | ||||
| 
 | ||||
| 							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()); | ||||
| 
 | ||||
| 							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"); | ||||
| 				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)); | ||||
| 
 | ||||
| 				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) | ||||
| 			{ | ||||
| 				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)); | ||||
| 
 | ||||
| 				cell->setPort("\\A", sig_a); | ||||
|  | @ -1493,7 +1494,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | |||
| 
 | ||||
| 				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()); | ||||
| 					if (replace) | ||||
| 						module->connect(cell->getPort("\\Y"), replace_sig); | ||||
|  | @ -1599,8 +1600,14 @@ struct OptExprPass : public Pass { | |||
| 
 | ||||
| 		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); | ||||
| 				if (did_something) | ||||
| 					design->scratchpad_set_bool("opt.did_something", true); | ||||
| 			} | ||||
| 
 | ||||
| 			do { | ||||
| 				do { | ||||
|  | @ -1610,7 +1617,11 @@ struct OptExprPass : public Pass { | |||
| 						design->scratchpad_set_bool("opt.did_something", true); | ||||
| 				} while (did_something); | ||||
| 				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); | ||||
| 
 | ||||
| 			log_suppressed(); | ||||
| 		} | ||||
| 
 | ||||
| 		log_pop(); | ||||
|  |  | |||
|  | @ -315,17 +315,17 @@ struct OptMergeWorker | |||
| 			{ | ||||
| 				if (sharemap.count(cell) > 0) { | ||||
| 					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()) { | ||||
| 						if (cell->output(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)); | ||||
| 							module->connect(RTLIL::SigSig(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 | ||||
| 					cell_hash_cache.erase(cell); | ||||
| #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++) | ||||
| 			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); | ||||
| 				eval_root_mux(mux_idx); | ||||
| 			} | ||||
| 
 | ||||
| 		while (!root_mux_rerun.empty()) { | ||||
| 			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)); | ||||
| 			root_mux_rerun.erase(mux_idx); | ||||
| 			eval_root_mux(mux_idx); | ||||
|  | @ -326,7 +326,7 @@ struct OptMuxtreeWorker | |||
| 				if (abort_count == 0) { | ||||
| 					root_mux_rerun.insert(m); | ||||
| 					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 | ||||
| 					eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); | ||||
| 			} 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 { | ||||
| 	bool has_value; | ||||
| 	string name, value; | ||||
| 	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; | ||||
| 				action->name = arg1; | ||||
| 				action->has_value = (p != string::npos); | ||||
| 				action->value = val1; | ||||
| 				actions.push_back(std::unique_ptr<AttrmapAction>(action)); | ||||
| 				continue; | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ struct TechmapWorker | |||
| 	pool<IdString> flatten_done_list; | ||||
| 	pool<Cell*> flatten_keep_list; | ||||
| 
 | ||||
| 	pool<string> log_msg_cache; | ||||
| 
 | ||||
| 	struct TechmapWireData { | ||||
| 		RTLIL::Wire *wire; | ||||
| 		RTLIL::SigSpec value; | ||||
|  | @ -390,6 +392,7 @@ struct TechmapWorker | |||
| 
 | ||||
| 		bool log_continue = false; | ||||
| 		bool did_something = false; | ||||
| 		LogMakeDebugHdl mkdebug; | ||||
| 
 | ||||
| 		SigMap sigmap(module); | ||||
| 
 | ||||
|  | @ -547,6 +550,7 @@ struct TechmapWorker | |||
| 								if (extmapper_name == "wrap") { | ||||
| 									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)); | ||||
| 									mkdebug.on(); | ||||
| 									Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); | ||||
| 									log_continue = true; | ||||
| 								} | ||||
|  | @ -560,11 +564,21 @@ struct TechmapWorker | |||
| 								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 | ||||
| 						{ | ||||
| 							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 (simplemap_mappers.count(cell->type) == 0) | ||||
|  | @ -662,6 +676,7 @@ struct TechmapWorker | |||
| 						tpl = techmap_cache[key]; | ||||
| 					} else { | ||||
| 						if (parameters.size() != 0) { | ||||
| 							mkdebug.on(); | ||||
| 							derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); | ||||
| 							tpl = map->module(derived_name); | ||||
| 							log_continue = true; | ||||
|  | @ -831,6 +846,7 @@ struct TechmapWorker | |||
| 						if (log_continue) { | ||||
| 							log_header(design, "Continuing TECHMAP pass.\n"); | ||||
| 							log_continue = false; | ||||
| 							mkdebug.off(); | ||||
| 						} | ||||
| 						while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } | ||||
| 					} | ||||
|  | @ -842,6 +858,7 @@ struct TechmapWorker | |||
| 				if (log_continue) { | ||||
| 					log_header(design, "Continuing TECHMAP pass.\n"); | ||||
| 					log_continue = false; | ||||
| 					mkdebug.off(); | ||||
| 				} | ||||
| 
 | ||||
| 				if (extern_mode && !in_recursion) | ||||
|  | @ -861,13 +878,18 @@ struct TechmapWorker | |||
| 						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->parameters.clear(); | ||||
| 				} | ||||
| 				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); | ||||
| 					cell = NULL; | ||||
| 				} | ||||
|  | @ -885,6 +907,7 @@ struct TechmapWorker | |||
| 		if (log_continue) { | ||||
| 			log_header(design, "Continuing TECHMAP pass.\n"); | ||||
| 			log_continue = false; | ||||
| 			mkdebug.off(); | ||||
| 		} | ||||
| 
 | ||||
| 		return did_something; | ||||
|  | @ -1085,7 +1108,7 @@ struct TechmapPass : public Pass { | |||
| 		if (map_files.empty()) { | ||||
| 			std::istringstream f(stdcells_code); | ||||
| 			Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); | ||||
| 		} else | ||||
| 		} else { | ||||
| 			for (auto &fn : map_files) | ||||
| 				if (fn.substr(0, 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()); | ||||
| 					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; | ||||
| 		for (auto &it : map->modules_) { | ||||
|  | @ -1211,6 +1237,7 @@ struct FlattenPass : public Pass { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		log_suppressed(); | ||||
| 		log("No more expansions possible.\n"); | ||||
| 
 | ||||
| 		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/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_sim.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_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); | ||||
|   parameter WIDTH = 0; | ||||
|  |  | |||
|  | @ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D); | |||
| 		Q <= D; | ||||
| 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); | ||||
| 	assign V = 1; | ||||
| 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; | ||||
| 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("        synonymous to the end of the command list.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nodffe\n"); | ||||
| 		log("        do not use flipflops with CE in output netlist\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nobram\n"); | ||||
| 		log("        do not use BRAM cells in output netlist\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nodram\n"); | ||||
| 		log("        do not use distributed RAM cells in output netlist\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noflatten\n"); | ||||
| 		log("        do not flatten design before synthesis\n"); | ||||
| 		log("\n"); | ||||
|  | @ -65,7 +71,7 @@ struct SynthGowinPass : public ScriptPass | |||
| 	} | ||||
| 
 | ||||
| 	string top_opt, vout_file; | ||||
| 	bool retime, flatten, nobram; | ||||
| 	bool retime, nobram, nodram, flatten, nodffe; | ||||
| 
 | ||||
| 	void clear_flags() YS_OVERRIDE | ||||
| 	{ | ||||
|  | @ -73,7 +79,9 @@ struct SynthGowinPass : public ScriptPass | |||
| 		vout_file = ""; | ||||
| 		retime = false; | ||||
| 		flatten = true; | ||||
| 		nobram = true; | ||||
| 		nobram = false; | ||||
| 		nodffe = false; | ||||
| 		nodram = false; | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
|  | @ -108,6 +116,14 @@ struct SynthGowinPass : public ScriptPass | |||
| 				nobram = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nodram") { | ||||
| 				nodram = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nodffe") { | ||||
| 				nodffe = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-noflatten") { | ||||
| 				flatten = false; | ||||
| 				continue; | ||||
|  | @ -147,25 +163,43 @@ struct SynthGowinPass : public ScriptPass | |||
| 		{ | ||||
| 			run("synth -run coarse"); | ||||
| 		} | ||||
| 		 | ||||
|                 if (!nobram && check_label("bram", "(skip if -nobram)")) | ||||
| 		{ | ||||
| 			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")) | ||||
| 		{ | ||||
| 			run("opt -fast -mux_undef -undriven -fine"); | ||||
| 			run("memory_map"); | ||||
| 			run("opt -undriven -fine"); | ||||
| 			run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); | ||||
| 			run("opt -fine"); | ||||
| 			run("clean -purge"); | ||||
| 			run("splitnets -ports"); | ||||
| 			run("setundef -undriven -zero"); | ||||
| 			run("techmap -map +/techmap.v"); | ||||
| 			if (retime || help_mode) | ||||
| 				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")) | ||||
| 		{ | ||||
| 			run("abc -lut 4"); | ||||
|  | @ -176,8 +210,10 @@ struct SynthGowinPass : public ScriptPass | |||
| 		{ | ||||
| 			run("techmap -map +/gowin/cells_map.v"); | ||||
| 			run("hilomap -hicell VCC V -locell GND G"); | ||||
| 			run("iopadmap -inpad IBUF O:I -outpad OBUF I:O"); | ||||
| 			run("clean -purge"); | ||||
| 			run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)"); | ||||
| 			run("dffinit  -ff DFF Q INIT"); | ||||
| 			run("clean"); | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("check")) | ||||
|  |  | |||
|  | @ -27,18 +27,27 @@ module SB_IO ( | |||
| 	reg dout_q_0, dout_q_1; | ||||
| 	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 | ||||
| 		always @(posedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_0  <= PACKAGE_PIN; | ||||
| 		always @(negedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_1  <= PACKAGE_PIN; | ||||
| 		always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; | ||||
| 		always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; | ||||
| 		always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; | ||||
| 		always @(posedge INPUT_CLK)                       clken_pulled_ri <= clken_pulled; | ||||
| 		always @(posedge INPUT_CLK)  if (clken_pulled)    din_q_0         <= PACKAGE_PIN; | ||||
| 		always @(negedge INPUT_CLK)  if (clken_pulled_ri) din_q_1         <= PACKAGE_PIN; | ||||
| 		always @(posedge OUTPUT_CLK)                      clken_pulled_ro <= clken_pulled; | ||||
| 		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 | ||||
| 		always @(negedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_0  <= PACKAGE_PIN; | ||||
| 		always @(posedge INPUT_CLK)  if (CLOCK_ENABLE) din_q_1  <= PACKAGE_PIN; | ||||
| 		always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; | ||||
| 		always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; | ||||
| 		always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; | ||||
| 		always @(negedge INPUT_CLK)                       clken_pulled_ri <= clken_pulled; | ||||
| 		always @(negedge INPUT_CLK)  if (clken_pulled)    din_q_0         <= PACKAGE_PIN; | ||||
| 		always @(posedge INPUT_CLK)  if (clken_pulled_ri) din_q_1         <= PACKAGE_PIN; | ||||
| 		always @(negedge OUTPUT_CLK)                      clken_pulled_ro <= clken_pulled; | ||||
| 		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 | ||||
| 
 | ||||
| 	always @* begin | ||||
|  |  | |||
|  | @ -116,14 +116,15 @@ struct SynthXilinxPass : public Pass | |||
| 		log("        techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); | ||||
| 		log("        opt -fast\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("        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("        clean\n"); | ||||
| 		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("                -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); | ||||
| 		log("        clean\n"); | ||||
|  | @ -274,17 +275,18 @@ struct SynthXilinxPass : public Pass | |||
| 			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")) | ||||
| 		{ | ||||
| 			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, "clean"); | ||||
| 			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 " | ||||
| 					"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); | ||||
| 			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