mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/xc7srl' into xc7mux
This commit is contained in:
		
						commit
						4486a98fd5
					
				
					 77 changed files with 4701 additions and 347 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" | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev | |||
|     - Added "gate2lut.v" techmap rule | ||||
|     - Added "rename -src" | ||||
|     - Added "equiv_opt" pass | ||||
|     - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" | ||||
| 
 | ||||
| 
 | ||||
| Yosys 0.7 .. Yosys 0.8 | ||||
|  |  | |||
							
								
								
									
										60
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										60
									
								
								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 | ||||
|  | @ -111,7 +119,7 @@ OBJS = kernel/version_$(GIT_REV).o | |||
| # is just a symlink to your actual ABC working directory, as 'make mrproper'
 | ||||
| # will remove the 'abc' directory and you do not want to accidentally
 | ||||
| # delete your work on ABC..
 | ||||
| ABCREV = 2ddc57d | ||||
| ABCREV = 3709744 | ||||
| ABCPULL = 1 | ||||
| ABCURL ?= https://github.com/berkeley-abc/abc | ||||
| ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 | ||||
|  | @ -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) | ||||
|  | @ -435,7 +471,6 @@ $(eval $(call add_include_file,backends/ilang/ilang_backend.h)) | |||
| 
 | ||||
| OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o | ||||
| OBJS += kernel/cellaigs.o kernel/celledges.o | ||||
| OBJS += kernel/cost.o | ||||
| 
 | ||||
| kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' | ||||
| kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' | ||||
|  | @ -511,6 +546,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 +682,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 +694,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 +711,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 | ||||
|  |  | |||
							
								
								
									
										23
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										23
									
								
								README.md
									
										
									
									
									
								
							|  | @ -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 | ||||
|  | @ -310,7 +311,19 @@ Verilog Attributes and non-standard features | |||
|   that have the same ports as the real thing but do not contain information | ||||
|   on the internal configuration. This modules are only used by the synthesis | ||||
|   passes to identify input and output ports of cells. The Verilog backend | ||||
|   also does not output blackbox modules on default. | ||||
|   also does not output blackbox modules on default. ``read_verilog``, unless | ||||
|   called with ``-noblackbox`` will automatically set the blackbox attribute | ||||
|   on any empty module it reads. | ||||
| 
 | ||||
| - The ``noblackbox`` attribute set on an empty module prevents ``read_verilog`` | ||||
|   from automatically setting the blackbox attribute on the module. | ||||
| 
 | ||||
| - The ``whitebox`` attribute on modules triggers the same behavior as | ||||
|   ``blackbox``, but is for whitebox modules, i.e. library modules that | ||||
|   contain a behavioral model of the cell type. | ||||
| 
 | ||||
| - The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog`` | ||||
|   is run in `-lib` mode. Otherwise it's automatically removed. | ||||
| 
 | ||||
| - The ``dynports`` attribute is used by the Verilog front-end to mark modules | ||||
|   that have ports with a width that depends on a parameter. | ||||
|  |  | |||
							
								
								
									
										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"] | ||||
|  | @ -140,7 +140,7 @@ struct BlifDumper | |||
| 			return "subckt"; | ||||
| 		if (!design->modules_.count(RTLIL::escape_id(cell_type))) | ||||
| 			return "gate"; | ||||
| 		if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox")) | ||||
| 		if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute()) | ||||
| 			return "gate"; | ||||
| 		return "subckt"; | ||||
| 	} | ||||
|  | @ -196,7 +196,7 @@ struct BlifDumper | |||
| 		} | ||||
| 		f << stringf("\n"); | ||||
| 
 | ||||
| 		if (module->get_bool_attribute("\\blackbox")) { | ||||
| 		if (module->get_blackbox_attribute()) { | ||||
| 			f << stringf(".blackbox\n"); | ||||
| 			f << stringf(".end\n"); | ||||
| 			return; | ||||
|  | @ -640,7 +640,7 @@ struct BlifBackend : public Backend { | |||
| 		for (auto module_it : design->modules_) | ||||
| 		{ | ||||
| 			RTLIL::Module *module = module_it.second; | ||||
| 			if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode) | ||||
| 			if (module->get_blackbox_attribute() && !config.blackbox_mode) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (module->processes.size() != 0) | ||||
|  |  | |||
|  | @ -340,7 +340,7 @@ struct BtorWorker | |||
| 			if (cell->type == "$lt") btor_op = "lt"; | ||||
| 			if (cell->type == "$le") btor_op = "lte"; | ||||
| 			if (cell->type.in("$eq", "$eqx")) btor_op = "eq"; | ||||
| 			if (cell->type.in("$ne", "$nex")) btor_op = "ne"; | ||||
| 			if (cell->type.in("$ne", "$nex")) btor_op = "neq"; | ||||
| 			if (cell->type == "$ge") btor_op = "gte"; | ||||
| 			if (cell->type == "$gt") btor_op = "gt"; | ||||
| 			log_assert(!btor_op.empty()); | ||||
|  |  | |||
|  | @ -178,7 +178,7 @@ struct EdifBackend : public Backend { | |||
| 		for (auto module_it : design->modules_) | ||||
| 		{ | ||||
| 			RTLIL::Module *module = module_it.second; | ||||
| 			if (module->get_bool_attribute("\\blackbox")) | ||||
| 			if (module->get_blackbox_attribute()) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (top_module_name.empty()) | ||||
|  | @ -192,7 +192,7 @@ struct EdifBackend : public Backend { | |||
| 			for (auto cell_it : module->cells_) | ||||
| 			{ | ||||
| 				RTLIL::Cell *cell = cell_it.second; | ||||
| 				if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { | ||||
| 				if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) { | ||||
| 					lib_cell_ports[cell->type]; | ||||
| 					for (auto p : cell->connections()) | ||||
| 						lib_cell_ports[cell->type][p.first] = GetSize(p.second); | ||||
|  | @ -302,7 +302,7 @@ struct EdifBackend : public Backend { | |||
| 		*f << stringf("    (technology (numberDefinition))\n"); | ||||
| 		for (auto module : sorted_modules) | ||||
| 		{ | ||||
| 			if (module->get_bool_attribute("\\blackbox")) | ||||
| 			if (module->get_blackbox_attribute()) | ||||
| 				continue; | ||||
| 
 | ||||
| 			SigMap sigmap(module); | ||||
|  |  | |||
|  | @ -127,7 +127,7 @@ struct IntersynthBackend : public Backend { | |||
| 			RTLIL::Module *module = module_it.second; | ||||
| 			SigMap sigmap(module); | ||||
| 
 | ||||
| 			if (module->get_bool_attribute("\\blackbox")) | ||||
| 			if (module->get_blackbox_attribute()) | ||||
| 				continue; | ||||
| 			if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0) | ||||
| 				continue; | ||||
|  |  | |||
|  | @ -1543,7 +1543,7 @@ struct Smt2Backend : public Backend { | |||
| 
 | ||||
| 		for (auto module : sorted_modules) | ||||
| 		{ | ||||
| 			if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn()) | ||||
| 			if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn()) | ||||
| 				continue; | ||||
| 
 | ||||
| 			log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); | ||||
|  |  | |||
|  | @ -739,7 +739,7 @@ struct SmvBackend : public Backend { | |||
| 		pool<Module*> modules; | ||||
| 
 | ||||
| 		for (auto module : design->modules()) | ||||
| 			if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn()) | ||||
| 			if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn()) | ||||
| 				modules.insert(module); | ||||
| 
 | ||||
| 		if (template_f.is_open()) | ||||
|  |  | |||
|  | @ -212,7 +212,7 @@ struct SpiceBackend : public Backend { | |||
| 		for (auto module_it : design->modules_) | ||||
| 		{ | ||||
| 			RTLIL::Module *module = module_it.second; | ||||
| 			if (module->get_bool_attribute("\\blackbox")) | ||||
| 			if (module->get_blackbox_attribute()) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (module->processes.size() != 0) | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ struct TableBackend : public Backend { | |||
| 
 | ||||
| 		for (auto module : design->modules()) | ||||
| 		{ | ||||
| 			if (module->get_bool_attribute("\\blackbox")) | ||||
| 			if (module->get_blackbox_attribute()) | ||||
| 				continue; | ||||
| 
 | ||||
| 			SigMap sigmap(module); | ||||
|  |  | |||
|  | @ -1770,7 +1770,7 @@ struct VerilogBackend : public Backend { | |||
| 
 | ||||
| 		*f << stringf("/* Generated by %s */\n", yosys_version_str); | ||||
| 		for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { | ||||
| 			if (it->second->get_bool_attribute("\\blackbox") != blackboxes) | ||||
| 			if (it->second->get_blackbox_attribute() != blackboxes) | ||||
| 				continue; | ||||
| 			if (selected && !design->selected_whole_module(it->first)) { | ||||
| 				if (design->selected_module(it->first)) | ||||
|  |  | |||
							
								
								
									
										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() | ||||
|  | @ -46,7 +46,7 @@ namespace AST { | |||
| // instantiate global variables (private API)
 | ||||
| namespace AST_INTERNAL { | ||||
| 	bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; | ||||
| 	bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; | ||||
| 	bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire; | ||||
| 	AstNode *current_ast, *current_ast_mod; | ||||
| 	std::map<std::string, AstNode*> current_scope; | ||||
| 	const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL; | ||||
|  | @ -942,6 +942,20 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 
 | ||||
| 	if (!defer) | ||||
| 	{ | ||||
| 		bool blackbox_module = flag_lib; | ||||
| 
 | ||||
| 		if (!blackbox_module && !flag_noblackbox) { | ||||
| 			blackbox_module = true; | ||||
| 			for (auto child : ast->children) { | ||||
| 				if (child->type == AST_WIRE && (child->is_input || child->is_output)) | ||||
| 					continue; | ||||
| 				if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) | ||||
| 					continue; | ||||
| 				blackbox_module = false; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } | ||||
| 
 | ||||
| 		if (flag_dump_ast2) { | ||||
|  | @ -956,7 +970,63 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 			log("--- END OF AST DUMP ---\n"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (flag_lib) { | ||||
| 		if (flag_nowb && ast->attributes.count("\\whitebox")) { | ||||
| 			delete ast->attributes.at("\\whitebox"); | ||||
| 			ast->attributes.erase("\\whitebox"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (ast->attributes.count("\\lib_whitebox")) { | ||||
| 			if (!flag_lib || flag_nowb) { | ||||
| 				delete ast->attributes.at("\\lib_whitebox"); | ||||
| 				ast->attributes.erase("\\lib_whitebox"); | ||||
| 			} else { | ||||
| 				if (ast->attributes.count("\\whitebox")) { | ||||
| 					delete ast->attributes.at("\\whitebox"); | ||||
| 					ast->attributes.erase("\\whitebox"); | ||||
| 				} | ||||
| 				AstNode *n = ast->attributes.at("\\lib_whitebox"); | ||||
| 				ast->attributes["\\whitebox"] = n; | ||||
| 				ast->attributes.erase("\\lib_whitebox"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (!blackbox_module && ast->attributes.count("\\blackbox")) { | ||||
| 			AstNode *n = ast->attributes.at("\\blackbox"); | ||||
| 			if (n->type != AST_CONSTANT) | ||||
| 				log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n"); | ||||
| 			blackbox_module = n->asBool(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (blackbox_module && ast->attributes.count("\\whitebox")) { | ||||
| 			AstNode *n = ast->attributes.at("\\whitebox"); | ||||
| 			if (n->type != AST_CONSTANT) | ||||
| 				log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n"); | ||||
| 			blackbox_module = !n->asBool(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (ast->attributes.count("\\noblackbox")) { | ||||
| 			if (blackbox_module) { | ||||
| 				AstNode *n = ast->attributes.at("\\noblackbox"); | ||||
| 				if (n->type != AST_CONSTANT) | ||||
| 					log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n"); | ||||
| 				blackbox_module = !n->asBool(); | ||||
| 			} | ||||
| 			delete ast->attributes.at("\\noblackbox"); | ||||
| 			ast->attributes.erase("\\noblackbox"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (blackbox_module) | ||||
| 		{ | ||||
| 			if (ast->attributes.count("\\whitebox")) { | ||||
| 				delete ast->attributes.at("\\whitebox"); | ||||
| 				ast->attributes.erase("\\whitebox"); | ||||
| 			} | ||||
| 
 | ||||
| 			if (ast->attributes.count("\\lib_whitebox")) { | ||||
| 				delete ast->attributes.at("\\lib_whitebox"); | ||||
| 				ast->attributes.erase("\\lib_whitebox"); | ||||
| 			} | ||||
| 
 | ||||
| 			std::vector<AstNode*> new_children; | ||||
| 			for (auto child : ast->children) { | ||||
| 				if (child->type == AST_WIRE && (child->is_input || child->is_output)) { | ||||
|  | @ -969,8 +1039,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 					delete child; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			ast->children.swap(new_children); | ||||
| 			ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); | ||||
| 
 | ||||
| 			if (ast->attributes.count("\\blackbox") == 0) { | ||||
| 				ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		ignoreThisSignalsInInitial = RTLIL::SigSpec(); | ||||
|  | @ -1009,7 +1083,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 	current_module->nomeminit = flag_nomeminit; | ||||
| 	current_module->nomem2reg = flag_nomem2reg; | ||||
| 	current_module->mem2reg = flag_mem2reg; | ||||
| 	current_module->noblackbox = flag_noblackbox; | ||||
| 	current_module->lib = flag_lib; | ||||
| 	current_module->nowb = flag_nowb; | ||||
| 	current_module->noopt = flag_noopt; | ||||
| 	current_module->icells = flag_icells; | ||||
| 	current_module->autowire = flag_autowire; | ||||
|  | @ -1026,7 +1102,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 
 | ||||
| // create AstModule instances for all modules in the AST tree and add them to 'design'
 | ||||
| void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, | ||||
| 		bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) | ||||
| 		bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) | ||||
| { | ||||
| 	current_ast = ast; | ||||
| 	flag_dump_ast1 = dump_ast1; | ||||
|  | @ -1039,7 +1115,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump | |||
| 	flag_nomeminit = nomeminit; | ||||
| 	flag_nomem2reg = nomem2reg; | ||||
| 	flag_mem2reg = mem2reg; | ||||
| 	flag_noblackbox = noblackbox; | ||||
| 	flag_lib = lib; | ||||
| 	flag_nowb = nowb; | ||||
| 	flag_noopt = noopt; | ||||
| 	flag_icells = icells; | ||||
| 	flag_autowire = autowire; | ||||
|  | @ -1373,7 +1451,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString | |||
| 	flag_nomeminit = nomeminit; | ||||
| 	flag_nomem2reg = nomem2reg; | ||||
| 	flag_mem2reg = mem2reg; | ||||
| 	flag_noblackbox = noblackbox; | ||||
| 	flag_lib = lib; | ||||
| 	flag_nowb = nowb; | ||||
| 	flag_noopt = noopt; | ||||
| 	flag_icells = icells; | ||||
| 	flag_autowire = autowire; | ||||
|  |  | |||
|  | @ -283,13 +283,13 @@ namespace AST | |||
| 
 | ||||
| 	// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
 | ||||
| 	void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit, | ||||
| 			bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire); | ||||
| 			bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire); | ||||
| 
 | ||||
| 	// parametric modules are supported directly by the AST library
 | ||||
| 	// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
 | ||||
| 	struct AstModule : RTLIL::Module { | ||||
| 		AstNode *ast; | ||||
| 		bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire; | ||||
| 		bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, autowire; | ||||
| 		~AstModule() YS_OVERRIDE; | ||||
| 		RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; | ||||
| 		RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE; | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -145,8 +145,18 @@ struct VerilogFrontend : public Frontend { | |||
| 		log("    -nodpi\n"); | ||||
| 		log("        disable DPI-C support\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noblackbox\n"); | ||||
| 		log("        do not automatically add a (* blackbox *) attribute to an\n"); | ||||
| 		log("        empty module.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -lib\n"); | ||||
| 		log("        only create empty blackbox modules. This implies -DBLACKBOX.\n"); | ||||
| 		log("        modules with the (* whitebox *) attribute will be preserved.\n"); | ||||
| 		log("        (* lib_whitebox *) will be treated like (* whitebox *).\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nowb\n"); | ||||
| 		log("        delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); | ||||
| 		log("        all modules.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noopt\n"); | ||||
| 		log("        don't perform basic optimizations (such as const folding) in the\n"); | ||||
|  | @ -227,7 +237,9 @@ struct VerilogFrontend : public Frontend { | |||
| 		formal_mode = false; | ||||
| 		norestrict_mode = false; | ||||
| 		assume_asserts_mode = false; | ||||
| 		noblackbox_mode = false; | ||||
| 		lib_mode = false; | ||||
| 		nowb_mode = false; | ||||
| 		default_nettype_wire = true; | ||||
| 
 | ||||
| 		log_header(design, "Executing Verilog-2005 frontend.\n"); | ||||
|  | @ -329,11 +341,19 @@ struct VerilogFrontend : public Frontend { | |||
| 				flag_nodpi = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-noblackbox") { | ||||
| 				noblackbox_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-lib") { | ||||
| 				lib_mode = true; | ||||
| 				defines_map["BLACKBOX"] = string(); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-nowb") { | ||||
| 				nowb_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-noopt") { | ||||
| 				flag_noopt = true; | ||||
| 				continue; | ||||
|  | @ -429,7 +449,8 @@ struct VerilogFrontend : public Frontend { | |||
| 		if (flag_nodpi) | ||||
| 			error_on_dpi_function(current_ast); | ||||
| 
 | ||||
| 		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); | ||||
| 		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, | ||||
| 				flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); | ||||
| 
 | ||||
| 		if (!flag_nopp) | ||||
| 			delete lexin; | ||||
|  |  | |||
|  | @ -69,9 +69,15 @@ namespace VERILOG_FRONTEND | |||
| 	// running in -assert-assumes mode
 | ||||
| 	extern bool assert_assumes_mode; | ||||
| 
 | ||||
| 	// running in -noblackbox mode
 | ||||
| 	extern bool noblackbox_mode; | ||||
| 
 | ||||
| 	// running in -lib mode
 | ||||
| 	extern bool lib_mode; | ||||
| 
 | ||||
| 	// running in -nowb mode
 | ||||
| 	extern bool nowb_mode; | ||||
| 
 | ||||
| 	// lexer input stream
 | ||||
| 	extern std::istream *lexin; | ||||
| } | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ namespace VERILOG_FRONTEND { | |||
| 	std::vector<char> case_type_stack; | ||||
| 	bool do_not_require_port_stubs; | ||||
| 	bool default_nettype_wire; | ||||
| 	bool sv_mode, formal_mode, lib_mode; | ||||
| 	bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode; | ||||
| 	bool noassert_mode, noassume_mode, norestrict_mode; | ||||
| 	bool assume_asserts_mode, assert_assumes_mode; | ||||
| 	bool current_wire_rand, current_wire_const; | ||||
|  |  | |||
|  | @ -1,75 +0,0 @@ | |||
| /*
 | ||||
|  *  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/cost.h" | ||||
| 
 | ||||
| YOSYS_NAMESPACE_BEGIN | ||||
| 
 | ||||
| int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, | ||||
| 		RTLIL::Design *design, dict<RTLIL::IdString, int> *mod_cost_cache) | ||||
| { | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| YOSYS_NAMESPACE_END | ||||
|  | @ -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) | ||||
| 	{ | ||||
|  | @ -469,6 +473,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) | ||||
|  |  | |||
							
								
								
									
										111
									
								
								kernel/rtlil.cc
									
										
									
									
									
								
							
							
						
						
									
										111
									
								
								kernel/rtlil.cc
									
										
									
									
									
								
							|  | @ -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()) | ||||
|  | @ -207,9 +214,12 @@ bool RTLIL::Const::is_fully_undef() const | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id) | ||||
| void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) | ||||
| { | ||||
| 	attributes[id] = RTLIL::Const(1); | ||||
| 	if (value) | ||||
| 		attributes[id] = RTLIL::Const(1); | ||||
| 	else if (attributes.count(id)) | ||||
| 		attributes.erase(id); | ||||
| } | ||||
| 
 | ||||
| bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const | ||||
|  | @ -360,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() | ||||
|  | @ -370,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_); | ||||
|  | @ -589,7 +614,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const | |||
| 	std::vector<RTLIL::Module*> result; | ||||
| 	result.reserve(modules_.size()); | ||||
| 	for (auto &it : modules_) | ||||
| 		if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) | ||||
| 		if (selected_module(it.first) && !it.second->get_blackbox_attribute()) | ||||
| 			result.push_back(it.second); | ||||
| 	return result; | ||||
| } | ||||
|  | @ -599,7 +624,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const | |||
| 	std::vector<RTLIL::Module*> result; | ||||
| 	result.reserve(modules_.size()); | ||||
| 	for (auto &it : modules_) | ||||
| 		if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) | ||||
| 		if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute()) | ||||
| 			result.push_back(it.second); | ||||
| 	return result; | ||||
| } | ||||
|  | @ -609,7 +634,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const | |||
| 	std::vector<RTLIL::Module*> result; | ||||
| 	result.reserve(modules_.size()); | ||||
| 	for (auto &it : modules_) | ||||
| 		if (it.second->get_bool_attribute("\\blackbox")) | ||||
| 		if (it.second->get_blackbox_attribute()) | ||||
| 			continue; | ||||
| 		else if (selected_whole_module(it.first)) | ||||
| 			result.push_back(it.second); | ||||
|  | @ -627,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() | ||||
|  | @ -639,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; | ||||
|  | @ -2226,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; | ||||
|  | @ -2237,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) | ||||
|  | @ -2247,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; | ||||
|  | @ -2508,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; | ||||
|  | @ -3892,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; | ||||
|  | @ -572,9 +573,13 @@ struct RTLIL::AttrObject | |||
| { | ||||
| 	dict<RTLIL::IdString, RTLIL::Const> attributes; | ||||
| 
 | ||||
| 	void set_bool_attribute(RTLIL::IdString id); | ||||
| 	void set_bool_attribute(RTLIL::IdString id, bool value=true); | ||||
| 	bool get_bool_attribute(RTLIL::IdString id) const; | ||||
| 
 | ||||
| 	bool get_blackbox_attribute(bool ignore_wb=false) const { | ||||
| 		return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox")); | ||||
| 	} | ||||
| 
 | ||||
| 	void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data); | ||||
| 	void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data); | ||||
| 	pool<string> get_strpool_attribute(RTLIL::IdString id) const; | ||||
|  | @ -597,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; | ||||
| 
 | ||||
|  | @ -621,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; | ||||
|  | @ -942,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 | ||||
|  | @ -1201,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 | ||||
|  | @ -1212,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
 | ||||
|  | @ -1223,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 | ||||
|  | @ -1234,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 | ||||
|  | @ -1245,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
 | ||||
|  | @ -1285,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 | ||||
|  | @ -1345,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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n | |||
| 		RTLIL::Module *mod = design->modules_.at(it.second->type); | ||||
| 		if (!design->selected_whole_module(mod->name)) | ||||
| 			continue; | ||||
| 		if (mod->get_bool_attribute("\\blackbox")) | ||||
| 		if (mod->get_blackbox_attribute()) | ||||
| 			continue; | ||||
| 		if (it.second->hasPort(name)) | ||||
| 			continue; | ||||
|  |  | |||
|  | @ -128,7 +128,7 @@ struct BugpointPass : public Pass { | |||
| 		{ | ||||
| 			for (auto &it : design_copy->modules_) | ||||
| 			{ | ||||
| 				if (it.second->get_bool_attribute("\\blackbox")) | ||||
| 				if (it.second->get_blackbox_attribute()) | ||||
| 					continue; | ||||
| 
 | ||||
| 				if (index++ == seed) | ||||
|  | @ -143,7 +143,7 @@ struct BugpointPass : public Pass { | |||
| 		{ | ||||
| 			for (auto mod : design_copy->modules()) | ||||
| 			{ | ||||
| 				if (mod->get_bool_attribute("\\blackbox")) | ||||
| 				if (mod->get_blackbox_attribute()) | ||||
| 					continue; | ||||
| 
 | ||||
| 				for (auto wire : mod->wires()) | ||||
|  | @ -168,7 +168,7 @@ struct BugpointPass : public Pass { | |||
| 		{ | ||||
| 			for (auto mod : design_copy->modules()) | ||||
| 			{ | ||||
| 				if (mod->get_bool_attribute("\\blackbox")) | ||||
| 				if (mod->get_blackbox_attribute()) | ||||
| 					continue; | ||||
| 
 | ||||
| 				for (auto &it : mod->cells_) | ||||
|  | @ -186,7 +186,7 @@ struct BugpointPass : public Pass { | |||
| 		{ | ||||
| 			for (auto mod : design_copy->modules()) | ||||
| 			{ | ||||
| 				if (mod->get_bool_attribute("\\blackbox")) | ||||
| 				if (mod->get_blackbox_attribute()) | ||||
| 					continue; | ||||
| 
 | ||||
| 				for (auto cell : mod->cells()) | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -128,6 +128,45 @@ struct SetattrPass : public Pass { | |||
| 	} | ||||
| } SetattrPass; | ||||
| 
 | ||||
| struct WbflipPass : public Pass { | ||||
| 	WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    wbflip [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n"); | ||||
| 		log("vice-versa. Blackbox cells are not effected by this command.\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++) | ||||
| 		{ | ||||
| 			std::string arg = args[argidx]; | ||||
| 			// if (arg == "-mod") {
 | ||||
| 			// 	flag_mod = true;
 | ||||
| 			// 	continue;
 | ||||
| 			// }
 | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (Module *module : design->modules()) | ||||
| 		{ | ||||
| 			if (!design->selected(module)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (module->get_bool_attribute("\\blackbox")) | ||||
| 				continue; | ||||
| 
 | ||||
| 			module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox")); | ||||
| 		} | ||||
| 	} | ||||
| } WbflipPass; | ||||
| 
 | ||||
| struct SetparamPass : public Pass { | ||||
| 	SetparamPass() : Pass("setparam", "set/unset parameters on objects") { } | ||||
| 	void help() YS_OVERRIDE | ||||
|  |  | |||
|  | @ -237,15 +237,34 @@ struct ShowWorker | |||
| 			int idx = single_idx_count++; | ||||
| 			for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) { | ||||
| 				const RTLIL::SigChunk &c = sig.chunks().at(i); | ||||
| 				net = gen_signode_simple(c, false); | ||||
| 				log_assert(!net.empty()); | ||||
| 				if (!driver && c.wire == nullptr) { | ||||
| 					RTLIL::State s1 = c.data.front(); | ||||
| 					for (auto s2 : c.data) | ||||
| 						if (s1 != s2) | ||||
| 							goto not_const_stream; | ||||
| 					net.clear(); | ||||
| 				} else { | ||||
| 			not_const_stream: | ||||
| 					net = gen_signode_simple(c, false); | ||||
| 					log_assert(!net.empty()); | ||||
| 				} | ||||
| 				for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {} | ||||
| 				std::string repinfo = rep > 1 ? stringf("%dx ", rep) : ""; | ||||
| 				if (driver) { | ||||
| 					log_assert(!net.empty()); | ||||
| 					label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset); | ||||
| 					net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i)); | ||||
| 					net_conn_map[net].bits = rep*c.width; | ||||
| 					net_conn_map[net].color = nextColor(c, net_conn_map[net].color); | ||||
| 				} else | ||||
| 				if (net.empty()) { | ||||
| 					log_assert(rep == 1); | ||||
| 					label_string += stringf("%c -> %d:%d |", | ||||
| 							c.data.front() == State::S0 ? '0' : | ||||
| 							c.data.front() == State::S1 ? '1' : | ||||
| 							c.data.front() == State::Sx ? 'X' : | ||||
| 							c.data.front() == State::Sz ? 'Z' : '?', | ||||
| 							pos, pos-rep*c.width+1); | ||||
| 				} else { | ||||
| 					label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1); | ||||
| 					net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i)); | ||||
|  | @ -555,7 +574,7 @@ struct ShowWorker | |||
| 			if (!design->selected_module(module->name)) | ||||
| 				continue; | ||||
| 			if (design->selected_whole_module(module->name)) { | ||||
| 				if (module->get_bool_attribute("\\blackbox")) { | ||||
| 				if (module->get_blackbox_attribute()) { | ||||
| 					// log("Skipping blackbox module %s.\n", id2cstr(module->name));
 | ||||
| 					continue; | ||||
| 				} else | ||||
|  | @ -771,7 +790,7 @@ struct ShowPass : public Pass { | |||
| 		if (format != "ps" && format != "dot") { | ||||
| 			int modcount = 0; | ||||
| 			for (auto &mod_it : design->modules_) { | ||||
| 				if (mod_it.second->get_bool_attribute("\\blackbox")) | ||||
| 				if (mod_it.second->get_blackbox_attribute()) | ||||
| 					continue; | ||||
| 				if (mod_it.second->cells_.empty() && mod_it.second->connections().empty()) | ||||
| 					continue; | ||||
|  |  | |||
|  | @ -134,7 +134,7 @@ struct EquivOptPass:public ScriptPass | |||
| 				opts = " -map <filename> ..."; | ||||
| 			else | ||||
| 				opts = techmap_opts; | ||||
| 			run("techmap -D EQUIV -autoproc" + opts); | ||||
| 			run("techmap -wb -D EQUIV -autoproc" + opts); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("prove")) { | ||||
|  |  | |||
|  | @ -346,9 +346,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check | |||
| 		} | ||||
| 		RTLIL::Module *mod = design->modules_[cell->type]; | ||||
| 
 | ||||
| 		if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { | ||||
| 		if (design->modules_.at(cell->type)->get_blackbox_attribute()) { | ||||
| 			if (flag_simcheck) | ||||
| 				log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n", | ||||
| 				log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n", | ||||
| 						cell->type.c_str(), module->name.c_str(), cell->name.c_str()); | ||||
| 			continue; | ||||
| 		} | ||||
|  | @ -451,7 +451,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString:: | |||
| 
 | ||||
| 	if (indent == 0) | ||||
| 		log("Top module:  %s\n", mod->name.c_str()); | ||||
| 	else if (!mod->get_bool_attribute("\\blackbox")) | ||||
| 	else if (!mod->get_blackbox_attribute()) | ||||
| 		log("Used module: %*s%s\n", indent, "", mod->name.c_str()); | ||||
| 	used.insert(mod); | ||||
| 
 | ||||
|  | @ -491,7 +491,7 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) | |||
| 
 | ||||
| 	int del_counter = 0; | ||||
| 	for (auto mod : del_modules) { | ||||
| 		if (!purge_lib && mod->get_bool_attribute("\\blackbox")) | ||||
| 		if (!purge_lib && mod->get_blackbox_attribute()) | ||||
| 			continue; | ||||
| 		log("Removing unused module `%s'.\n", mod->name.c_str()); | ||||
| 		design->modules_.erase(mod->name); | ||||
|  | @ -910,7 +910,7 @@ struct HierarchyPass : public Pass { | |||
| 			if (m == nullptr) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { | ||||
| 			if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { | ||||
| 				IdString new_m_name = m->derive(design, cell->parameters, true); | ||||
| 				if (new_m_name.empty()) | ||||
| 					continue; | ||||
|  |  | |||
|  | @ -75,7 +75,7 @@ struct UniquifyPass : public Pass { | |||
| 					if (tmod == nullptr) | ||||
| 						continue; | ||||
| 
 | ||||
| 					if (tmod->get_bool_attribute("\\blackbox")) | ||||
| 					if (tmod->get_blackbox_attribute()) | ||||
| 						continue; | ||||
| 
 | ||||
| 					if (tmod->get_bool_attribute("\\unique") && newname == tmod->name) | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										831
									
								
								passes/opt/pmux2shiftx.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										831
									
								
								passes/opt/pmux2shiftx.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,831 @@ | |||
| /*
 | ||||
|  *  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 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; | ||||
| 					} | ||||
| 
 | ||||
| 					// 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); | ||||
| 
 | ||||
| 					bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (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); | ||||
| 					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 | ||||
|  | @ -108,6 +108,7 @@ struct SigSnippets | |||
| 
 | ||||
| struct SnippetSwCache | ||||
| { | ||||
| 	dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache; | ||||
| 	dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache; | ||||
| 	const SigSnippets *snippets; | ||||
| 	int current_snippet; | ||||
|  | @ -268,6 +269,49 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve | |||
| 	last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size(); | ||||
| } | ||||
| 
 | ||||
| const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw) | ||||
| { | ||||
| 	if (!swcache.full_case_bits_cache.count(sw)) | ||||
| 	{ | ||||
| 		pool<SigBit> bits; | ||||
| 
 | ||||
| 		if (sw->get_bool_attribute("\\full_case")) | ||||
| 		{ | ||||
| 			bool first_case = true; | ||||
| 
 | ||||
| 			for (auto cs : sw->cases) | ||||
| 			{ | ||||
| 				pool<SigBit> case_bits; | ||||
| 
 | ||||
| 				for (auto it : cs->actions) { | ||||
| 					for (auto bit : it.first) | ||||
| 						case_bits.insert(bit); | ||||
| 				} | ||||
| 
 | ||||
| 				for (auto it : cs->switches) { | ||||
| 					for (auto bit : get_full_case_bits(swcache, it)) | ||||
| 						case_bits.insert(bit); | ||||
| 				} | ||||
| 
 | ||||
| 				if (first_case) { | ||||
| 					first_case = false; | ||||
| 					bits = case_bits; | ||||
| 				} else { | ||||
| 					pool<SigBit> new_bits; | ||||
| 					for (auto bit : bits) | ||||
| 						if (case_bits.count(bit)) | ||||
| 							new_bits.insert(bit); | ||||
| 					bits.swap(new_bits); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		bits.swap(swcache.full_case_bits_cache[sw]); | ||||
| 	} | ||||
| 
 | ||||
| 	return swcache.full_case_bits_cache.at(sw); | ||||
| } | ||||
| 
 | ||||
| RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara, | ||||
| 		RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode) | ||||
| { | ||||
|  | @ -337,10 +381,15 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// mask default bits that are irrelevant because the output is driven by a full case
 | ||||
| 		const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw); | ||||
| 		for (int i = 0; i < GetSize(sig); i++) | ||||
| 			if (full_case_bits.count(sig[i])) | ||||
| 				result[i] = State::Sx; | ||||
| 
 | ||||
| 		// evaluate in reverse order to give the first entry the top priority
 | ||||
| 		RTLIL::SigSpec initial_val = result; | ||||
| 		RTLIL::Cell *last_mux_cell = NULL; | ||||
| 		bool shiftx = initial_val.is_fully_undef(); | ||||
| 		for (size_t i = 0; i < sw->cases.size(); i++) { | ||||
| 			int case_idx = sw->cases.size() - i - 1; | ||||
| 			RTLIL::CaseRule *cs2 = sw->cases[case_idx]; | ||||
|  | @ -349,33 +398,6 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d | |||
| 				append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); | ||||
| 			else | ||||
| 				result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); | ||||
| 
 | ||||
| 			// Ignore output values which are entirely don't care
 | ||||
| 			if (shiftx && !value.is_fully_undef()) { | ||||
| 				// Keep checking if case condition is the same as the current case index
 | ||||
| 				if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const()) | ||||
| 					shiftx = (cs2->compare.front().as_int() == case_idx); | ||||
| 				else | ||||
| 					shiftx = false; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Transform into a $shiftx where possible
 | ||||
| 		if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") { | ||||
| 			// Create bit-blasted $shiftx-es that shifts by the address line used in the case statement
 | ||||
| 			auto pmux_b_port = last_mux_cell->getPort("\\B"); | ||||
| 			auto pmux_y_port = last_mux_cell->getPort("\\Y"); | ||||
| 			int width = last_mux_cell->getParam("\\WIDTH").as_int(); | ||||
| 			for (int i = 0; i < width; ++i) { | ||||
| 				RTLIL::SigSpec a_port; | ||||
| 				// Because we went in reverse order above, un-reverse $pmux's B port here
 | ||||
| 				for (int j = pmux_b_port.size()/width-1; j >= 0; --j) | ||||
| 					a_port.append(pmux_b_port.extract(j*width+i, 1)); | ||||
| 				// Create a $shiftx that shifts by the address line used in the case statement
 | ||||
| 				mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1)); | ||||
| 			} | ||||
| 			// Disconnect $pmux by replacing its output port with a floating wire
 | ||||
| 			last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ | |||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) | ||||
| void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter) | ||||
| { | ||||
| 	BitPatternPool pool(sw->signal); | ||||
| 
 | ||||
|  | @ -56,11 +56,16 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) | |||
| 		} | ||||
| 
 | ||||
| 		for (auto switch_it : sw->cases[i]->switches) | ||||
| 			proc_rmdead(switch_it, counter); | ||||
| 			proc_rmdead(switch_it, counter, full_case_counter); | ||||
| 
 | ||||
| 		if (is_default) | ||||
| 			pool.take_all(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (pool.empty() && !sw->get_bool_attribute("\\full_case")) { | ||||
| 		sw->set_bool_attribute("\\full_case"); | ||||
| 		full_case_counter++; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct ProcRmdeadPass : public Pass { | ||||
|  | @ -87,12 +92,15 @@ struct ProcRmdeadPass : public Pass { | |||
| 			for (auto &proc_it : mod->processes) { | ||||
| 				if (!design->selected(mod, proc_it.second)) | ||||
| 					continue; | ||||
| 				int counter = 0; | ||||
| 				int counter = 0, full_case_counter = 0; | ||||
| 				for (auto switch_it : proc_it.second->root_case.switches) | ||||
| 					proc_rmdead(switch_it, counter); | ||||
| 					proc_rmdead(switch_it, counter, full_case_counter); | ||||
| 				if (counter > 0) | ||||
| 					log("Removed %d dead cases from process %s in module %s.\n", counter, | ||||
| 							proc_it.first.c_str(), log_id(mod)); | ||||
| 							log_id(proc_it.first), log_id(mod)); | ||||
| 				if (full_case_counter > 0) | ||||
| 					log("Marked %d switch rules as full_case in process %s in module %s.\n", | ||||
| 							full_case_counter, log_id(proc_it.first), log_id(mod)); | ||||
| 				total_counter += counter; | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
|  | @ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 
 | ||||
| 	if (flag_flatten) { | ||||
| 		log_push(); | ||||
| 		Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;"); | ||||
| 		Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;"); | ||||
| 		log_pop(); | ||||
| 	} | ||||
| } | ||||
|  | @ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL | |||
| 
 | ||||
| 	if (flag_flatten) { | ||||
| 		log_push(); | ||||
| 		Pass::call_on_module(design, module, "flatten;;"); | ||||
| 		Pass::call_on_module(design, module, "flatten -wb;;"); | ||||
| 		log_pop(); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -385,7 +385,7 @@ struct MiterPass : public Pass { | |||
| 		log("        also create an 'assert' cell that checks if trigger is always low.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -flatten\n"); | ||||
| 		log("        call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); | ||||
| 		log("        call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("    miter -assert [options] module [miter_name]\n"); | ||||
|  | @ -399,7 +399,7 @@ struct MiterPass : public Pass { | |||
| 		log("        keep module output ports.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -flatten\n"); | ||||
| 		log("        call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); | ||||
| 		log("        call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
|  |  | |||
|  | @ -38,7 +38,6 @@ OBJS += passes/techmap/attrmap.o | |||
| OBJS += passes/techmap/zinit.o | ||||
| OBJS += passes/techmap/dff2dffs.o | ||||
| OBJS += passes/techmap/flowmap.o | ||||
| OBJS += passes/techmap/pmux2shiftx.o | ||||
| endif | ||||
| 
 | ||||
| GENFILES += passes/techmap/techmap.inc | ||||
|  |  | |||
|  | @ -29,17 +29,17 @@ | |||
| // Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
 | ||||
| // http://en.wikipedia.org/wiki/Topological_sorting
 | ||||
| 
 | ||||
| #define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" | ||||
| #define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" | ||||
| #define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2" | ||||
| #define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}" | ||||
| #define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" | ||||
| #define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put" | ||||
| #define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" | ||||
| #define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2" | ||||
| #define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}" | ||||
| #define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put" | ||||
| 
 | ||||
| #define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}" | ||||
| #define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" | ||||
| #define ABC_FAST_COMMAND_LUT "strash; dretime; if" | ||||
| #define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}" | ||||
| #define ABC_FAST_COMMAND_DFL "strash; dretime; map" | ||||
| #define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}" | ||||
| #define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" | ||||
| #define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if" | ||||
| #define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}" | ||||
| #define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map" | ||||
| 
 | ||||
| #include "kernel/register.h" | ||||
| #include "kernel/sigtools.h" | ||||
|  | @ -331,19 +331,23 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp | |||
| { | ||||
| 	std::string abc_sname = abc_name.substr(1); | ||||
| 	if (abc_sname.substr(0, 5) == "ys__n") { | ||||
| 		int sid = std::stoi(abc_sname.substr(5)); | ||||
| 		bool inv = abc_sname.back() == 'v'; | ||||
| 		for (auto sig : signal_list) { | ||||
| 			if (sig.id == sid && sig.bit.wire != nullptr) { | ||||
| 				std::stringstream sstr; | ||||
| 				sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); | ||||
| 				if (sig.bit.wire->width != 1) | ||||
| 					sstr << "[" << sig.bit.offset << "]"; | ||||
| 				if (inv) | ||||
| 					sstr << "_inv"; | ||||
| 				if (orig_wire != nullptr) | ||||
| 					*orig_wire = sig.bit.wire; | ||||
| 				return sstr.str(); | ||||
| 		if (inv) abc_sname.pop_back(); | ||||
| 		abc_sname.erase(0, 5); | ||||
| 		if (abc_sname.find_last_not_of("012345689") == std::string::npos) { | ||||
| 			int sid = std::stoi(abc_sname); | ||||
| 			for (auto sig : signal_list) { | ||||
| 				if (sig.id == sid && sig.bit.wire != nullptr) { | ||||
| 					std::stringstream sstr; | ||||
| 					sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); | ||||
| 					if (sig.bit.wire->width != 1) | ||||
| 						sstr << "[" << sig.bit.offset << "]"; | ||||
| 					if (inv) | ||||
| 						sstr << "_inv"; | ||||
| 					if (orig_wire != nullptr) | ||||
| 						*orig_wire = sig.bit.wire; | ||||
| 					return sstr.str(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -731,10 +735,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin | |||
| 	else | ||||
| 		abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; | ||||
| 
 | ||||
| 	if (script_file.empty() && !delay_target.empty()) | ||||
| 		for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) | ||||
| 			abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); | ||||
| 
 | ||||
| 	for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) | ||||
| 		abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); | ||||
| 
 | ||||
|  | @ -1726,7 +1726,7 @@ struct AbcPass : public Pass { | |||
| 								signal_init[initsig[i]] = State::S0; | ||||
| 								break; | ||||
| 							case State::S1: | ||||
| 								signal_init[initsig[i]] = State::S0; | ||||
| 								signal_init[initsig[i]] = State::S1; | ||||
| 								break; | ||||
| 							default: | ||||
| 								break; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -664,7 +664,7 @@ struct DfflibmapPass : public Pass { | |||
| 		logmap_all(); | ||||
| 
 | ||||
| 		for (auto &it : design->modules_) | ||||
| 			if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) | ||||
| 			if (design->selected(it.second) && !it.second->get_blackbox_attribute()) | ||||
| 				dfflibmap(design, it.second, prepare_mode); | ||||
| 
 | ||||
| 		cell_mappings.clear(); | ||||
|  |  | |||
|  | @ -1,82 +0,0 @@ | |||
| /*
 | ||||
|  *  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 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 [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This pass transforms $pmux cells to $shiftx cells.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing PMUX2SHIFTX pass.\n"); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		for (auto cell : module->selected_cells()) | ||||
| 		{ | ||||
| 			if (cell->type != "$pmux") | ||||
| 				continue; | ||||
| 
 | ||||
| 			// Create a new encoder, out of a $pmux, that takes
 | ||||
| 			// the existing pmux's 'S' input and transforms it
 | ||||
| 			// back into a binary value
 | ||||
| 			RTLIL::SigSpec shiftx_a; | ||||
| 			RTLIL::SigSpec pmux_s; | ||||
| 
 | ||||
| 			int s_width = cell->getParam("\\S_WIDTH").as_int(); | ||||
| 			if (!cell->getPort("\\A").is_fully_undef()) { | ||||
| 				++s_width; | ||||
| 				shiftx_a.append(cell->getPort("\\A")); | ||||
| 				pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S")))); | ||||
| 			} | ||||
| 			const int clog2width = ceil(log2(s_width)); | ||||
| 
 | ||||
| 			RTLIL::SigSpec pmux_b; | ||||
| 			pmux_b.append(RTLIL::Const(0, clog2width)); | ||||
| 			for (int i = s_width-1; i > 0; i--) | ||||
| 				pmux_b.append(RTLIL::Const(i, clog2width)); | ||||
| 			shiftx_a.append(cell->getPort("\\B")); | ||||
| 			pmux_s.append(cell->getPort("\\S")); | ||||
| 
 | ||||
| 			RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); | ||||
| 			module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y); | ||||
| 			module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); | ||||
| 			module->remove(cell); | ||||
| 		} | ||||
| 	} | ||||
| } Pmux2ShiftxPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN | |||
| struct ShregmapTech | ||||
| { | ||||
| 	virtual ~ShregmapTech() { } | ||||
| 	virtual bool analyze(vector<int> &taps) = 0; | ||||
| 	virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {} | ||||
| 	virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {} | ||||
| 	virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0; | ||||
| 	virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0; | ||||
| }; | ||||
| 
 | ||||
|  | @ -54,7 +56,7 @@ struct ShregmapOptions | |||
| 
 | ||||
| struct ShregmapTechGreenpak4 : ShregmapTech | ||||
| { | ||||
| 	bool analyze(vector<int> &taps) | ||||
| 	bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/) | ||||
| 	{ | ||||
| 		if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { | ||||
| 			taps.clear(); | ||||
|  | @ -91,6 +93,145 @@ struct ShregmapTechGreenpak4 : ShregmapTech | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct ShregmapTechXilinx7 : ShregmapTech | ||||
| { | ||||
| 	dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset; | ||||
| 	const ShregmapOptions &opts; | ||||
| 
 | ||||
| 	ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} | ||||
| 
 | ||||
| 	virtual void init(const Module* module, const SigMap &sigmap) override | ||||
| 	{ | ||||
| 		for (const auto &i : module->cells_) { | ||||
| 			auto cell = i.second; | ||||
| 			if (cell->type == "$shiftx") { | ||||
| 				if (cell->getParam("\\Y_WIDTH") != 1) continue; | ||||
| 				int j = 0; | ||||
| 				for (auto bit : sigmap(cell->getPort("\\A"))) | ||||
| 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0); | ||||
| 				log_assert(j == cell->getParam("\\A_WIDTH").as_int()); | ||||
| 			} | ||||
| 			else if (cell->type == "$mux") { | ||||
| 				int j = 0; | ||||
| 				for (auto bit : sigmap(cell->getPort("\\A"))) | ||||
| 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); | ||||
| 				j = 0; | ||||
| 				for (auto bit : sigmap(cell->getPort("\\B"))) | ||||
| 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override | ||||
| 	{ | ||||
| 		auto it = sigbit_to_shiftx_offset.find(bit); | ||||
| 		if (it == sigbit_to_shiftx_offset.end()) | ||||
| 			return; | ||||
| 		if (cell) { | ||||
| 			if (cell->type == "$shiftx" && port == "\\A") | ||||
| 				return; | ||||
| 			if (cell->type == "$mux" && (port == "\\A" || port == "\\B")) | ||||
| 				return; | ||||
| 		} | ||||
| 		sigbit_to_shiftx_offset.erase(it); | ||||
| 	} | ||||
| 
 | ||||
| 	virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override | ||||
| 	{ | ||||
| 		if (GetSize(taps) == 1) | ||||
| 			return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]); | ||||
| 
 | ||||
| 		if (taps.back() < opts.minlen-1) | ||||
| 			return false; | ||||
| 
 | ||||
| 		Cell *shiftx = nullptr; | ||||
| 		int group = 0; | ||||
| 		for (int i = 0; i < GetSize(taps); ++i) { | ||||
| 			auto it = sigbit_to_shiftx_offset.find(qbits[i]); | ||||
| 			if (it == sigbit_to_shiftx_offset.end()) | ||||
| 				return false; | ||||
| 
 | ||||
| 			// Check taps are sequential
 | ||||
| 			if (i != taps[i]) | ||||
| 				return false; | ||||
| 			// Check taps are not connected to a shift register,
 | ||||
| 			// or sequential to the same shift register
 | ||||
| 			if (i == 0) { | ||||
| 				int offset; | ||||
| 				std::tie(shiftx,offset,group) = it->second; | ||||
| 				if (offset != i) | ||||
| 					return false; | ||||
| 			} | ||||
| 			else { | ||||
| 				Cell *shiftx_ = std::get<0>(it->second); | ||||
| 				if (shiftx_ != shiftx) | ||||
| 					return false; | ||||
| 				int offset = std::get<1>(it->second); | ||||
| 				if (offset != i) | ||||
| 					return false; | ||||
| 				int group_ = std::get<2>(it->second); | ||||
| 				if (group_ != group) | ||||
| 					return false; | ||||
| 			} | ||||
| 		} | ||||
| 		log_assert(shiftx); | ||||
| 
 | ||||
| 		// Only map if $shiftx exclusively covers the shift register
 | ||||
| 		if (shiftx->type == "$shiftx") { | ||||
| 			if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) | ||||
| 				return false; | ||||
| 		} | ||||
| 		else if (shiftx->type == "$mux") { | ||||
| 			if (GetSize(taps) != 2) | ||||
| 				return false; | ||||
| 		} | ||||
| 		else log_abort(); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override | ||||
| 	{ | ||||
| 		const auto &tap = *taps.begin(); | ||||
| 		auto bit = tap.second; | ||||
| 
 | ||||
| 		auto it = sigbit_to_shiftx_offset.find(bit); | ||||
| 		log_assert(it != sigbit_to_shiftx_offset.end()); | ||||
| 
 | ||||
| 		auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_"); | ||||
| 		newcell->set_src_attribute(cell->get_src_attribute()); | ||||
| 		newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH")); | ||||
| 		newcell->setParam("\\INIT", cell->getParam("\\INIT")); | ||||
| 		newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL")); | ||||
| 		newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL")); | ||||
| 
 | ||||
| 		newcell->setPort("\\C", cell->getPort("\\C")); | ||||
| 		newcell->setPort("\\D", cell->getPort("\\D")); | ||||
| 		if (cell->hasPort("\\E")) | ||||
| 			newcell->setPort("\\E", cell->getPort("\\E")); | ||||
| 
 | ||||
| 		Cell* shiftx = std::get<0>(it->second); | ||||
| 		RTLIL::SigSpec l_wire, q_wire; | ||||
| 		if (shiftx->type == "$shiftx") { | ||||
| 			l_wire = shiftx->getPort("\\B"); | ||||
| 			q_wire = shiftx->getPort("\\Y"); | ||||
| 			shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); | ||||
| 		} | ||||
| 		else if (shiftx->type == "$mux") { | ||||
| 			l_wire = shiftx->getPort("\\S"); | ||||
| 			q_wire = shiftx->getPort("\\Y"); | ||||
| 			shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); | ||||
| 		} | ||||
| 		else log_abort(); | ||||
| 
 | ||||
| 		newcell->setPort("\\Q", q_wire); | ||||
| 		newcell->setPort("\\L", l_wire); | ||||
| 
 | ||||
| 		return false; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct ShregmapWorker | ||||
| { | ||||
| 	Module *module; | ||||
|  | @ -113,8 +254,10 @@ struct ShregmapWorker | |||
| 		for (auto wire : module->wires()) | ||||
| 		{ | ||||
| 			if (wire->port_output || wire->get_bool_attribute("\\keep")) { | ||||
| 				for (auto bit : sigmap(wire)) | ||||
| 				for (auto bit : sigmap(wire)) { | ||||
| 					sigbit_with_non_chain_users.insert(bit); | ||||
| 					if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {}); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (wire->attributes.count("\\init")) { | ||||
|  | @ -152,8 +295,10 @@ struct ShregmapWorker | |||
| 
 | ||||
| 			for (auto conn : cell->connections()) | ||||
| 				if (cell->input(conn.first)) | ||||
| 					for (auto bit : sigmap(conn.second)) | ||||
| 					for (auto bit : sigmap(conn.second)) { | ||||
| 						sigbit_with_non_chain_users.insert(bit); | ||||
| 						if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first); | ||||
| 					} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -258,7 +403,7 @@ struct ShregmapWorker | |||
| 					if (taps.empty() || taps.back() < depth-1) | ||||
| 						taps.push_back(depth-1); | ||||
| 
 | ||||
| 					if (opts.tech->analyze(taps)) | ||||
| 					if (opts.tech->analyze(taps, qbits)) | ||||
| 						break; | ||||
| 
 | ||||
| 					taps.pop_back(); | ||||
|  | @ -377,6 +522,9 @@ struct ShregmapWorker | |||
| 	ShregmapWorker(Module *module, const ShregmapOptions &opts) : | ||||
| 			module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) | ||||
| 	{ | ||||
| 		if (opts.tech) | ||||
| 			opts.tech->init(module, sigmap); | ||||
| 
 | ||||
| 		make_sigbit_chain_next_prev(); | ||||
| 		find_chain_start_cells(); | ||||
| 
 | ||||
|  | @ -501,6 +649,12 @@ struct ShregmapPass : public Pass { | |||
| 					clkpol = "pos"; | ||||
| 					opts.zinit = true; | ||||
| 					opts.tech = new ShregmapTechGreenpak4; | ||||
| 				} | ||||
| 				else if (tech == "xilinx") { | ||||
| 					opts.init = true; | ||||
| 					opts.params = true; | ||||
| 					enpol = "any_or_none"; | ||||
| 					opts.tech = new ShregmapTechXilinx7(opts); | ||||
| 				} else { | ||||
| 					argidx--; | ||||
| 					break; | ||||
|  |  | |||
|  | @ -599,7 +599,7 @@ struct SimplemapPass : public Pass { | |||
| 		simplemap_get_mappers(mappers); | ||||
| 
 | ||||
| 		for (auto mod : design->modules()) { | ||||
| 			if (!design->selected(mod)) | ||||
| 			if (!design->selected(mod) || mod->get_blackbox_attribute()) | ||||
| 				continue; | ||||
| 			std::vector<RTLIL::Cell*> cells = mod->cells(); | ||||
| 			for (auto cell : cells) { | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ struct TechmapWorker | |||
| 	bool flatten_mode; | ||||
| 	bool recursive_mode; | ||||
| 	bool autoproc_mode; | ||||
| 	bool ignore_wb; | ||||
| 
 | ||||
| 	TechmapWorker() | ||||
| 	{ | ||||
|  | @ -92,6 +93,7 @@ struct TechmapWorker | |||
| 		flatten_mode = false; | ||||
| 		recursive_mode = false; | ||||
| 		autoproc_mode = false; | ||||
| 		ignore_wb = false; | ||||
| 	} | ||||
| 
 | ||||
| 	std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) | ||||
|  | @ -383,7 +385,7 @@ struct TechmapWorker | |||
| 	{ | ||||
| 		std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; | ||||
| 
 | ||||
| 		if (!design->selected(module)) | ||||
| 		if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb)) | ||||
| 			return false; | ||||
| 
 | ||||
| 		bool log_continue = false; | ||||
|  | @ -472,7 +474,7 @@ struct TechmapWorker | |||
| 				RTLIL::Module *tpl = map->modules_[tpl_name]; | ||||
| 				std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end()); | ||||
| 
 | ||||
| 				if (tpl->get_bool_attribute("\\blackbox")) | ||||
| 				if (tpl->get_blackbox_attribute(ignore_wb)) | ||||
| 					continue; | ||||
| 
 | ||||
| 				if (!flatten_mode) | ||||
|  | @ -925,6 +927,9 @@ struct TechmapPass : public Pass { | |||
| 		log("    -autoproc\n"); | ||||
| 		log("        Automatically call \"proc\" on implementations that contain processes.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -wb\n"); | ||||
| 		log("        Ignore the 'whitebox' attribute on cell implementations.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -assert\n"); | ||||
| 		log("        this option will cause techmap to exit with an error if it can't map\n"); | ||||
| 		log("        a selected cell. only cell types that end on an underscore are accepted\n"); | ||||
|  | @ -1031,7 +1036,7 @@ struct TechmapPass : public Pass { | |||
| 		simplemap_get_mappers(worker.simplemap_mappers); | ||||
| 
 | ||||
| 		std::vector<std::string> map_files; | ||||
| 		std::string verilog_frontend = "verilog -nooverwrite"; | ||||
| 		std::string verilog_frontend = "verilog -nooverwrite -noblackbox"; | ||||
| 		int max_iter = -1; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
|  | @ -1068,6 +1073,10 @@ struct TechmapPass : public Pass { | |||
| 				worker.autoproc_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-wb") { | ||||
| 				worker.ignore_wb = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
|  | @ -1145,7 +1154,7 @@ struct FlattenPass : public Pass { | |||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    flatten [selection]\n"); | ||||
| 		log("    flatten [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This pass flattens the design by replacing cells by their implementation. This\n"); | ||||
| 		log("pass is very similar to the 'techmap' pass. The only difference is that this\n"); | ||||
|  | @ -1154,17 +1163,29 @@ struct FlattenPass : public Pass { | |||
| 		log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n"); | ||||
| 		log("flattened by this command.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -wb\n"); | ||||
| 		log("        Ignore the 'whitebox' attribute on cell implementations.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing FLATTEN pass (flatten design).\n"); | ||||
| 		log_push(); | ||||
| 
 | ||||
| 		extra_args(args, 1, design); | ||||
| 
 | ||||
| 		TechmapWorker worker; | ||||
| 		worker.flatten_mode = true; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||
| 			if (args[argidx] == "-wb") { | ||||
| 				worker.ignore_wb = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 
 | ||||
| 		std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; | ||||
| 		for (auto module : design->modules()) | ||||
| 			celltypeMap[module->name].insert(module->name); | ||||
|  | @ -1209,7 +1230,7 @@ struct FlattenPass : public Pass { | |||
| 
 | ||||
| 			dict<RTLIL::IdString, RTLIL::Module*> new_modules; | ||||
| 			for (auto mod : vector<Module*>(design->modules())) | ||||
| 				if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) { | ||||
| 				if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) { | ||||
| 					new_modules[mod->name] = mod; | ||||
| 				} else { | ||||
| 					log("Deleting now unused module %s.\n", log_id(mod)); | ||||
|  |  | |||
							
								
								
									
										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)")) | ||||
| 		 | ||||
|                 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 | ||||
|  |  | |||
|  | @ -17,6 +17,131 @@ | |||
|  * | ||||
|  */ | ||||
| 
 | ||||
| module \$__SHREG_ (input C, input D, input E, output Q); | ||||
|   parameter DEPTH = 0; | ||||
|   parameter [DEPTH-1:0] INIT = 0; | ||||
|   parameter CLKPOL = 1; | ||||
|   parameter ENPOL = 2; | ||||
| 
 | ||||
|   \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q)); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO); | ||||
|   parameter DEPTH = 0; | ||||
|   parameter [DEPTH-1:0] INIT = 0; | ||||
|   parameter CLKPOL = 1; | ||||
|   parameter ENPOL = 2; | ||||
| 
 | ||||
|   // shregmap's INIT parameter shifts out LSB first; | ||||
|   // however Xilinx expects MSB first | ||||
|   function [DEPTH-1:0] brev; | ||||
|     input [DEPTH-1:0] din; | ||||
|     integer i; | ||||
|     begin | ||||
|       for (i = 0; i < DEPTH; i=i+1) | ||||
|         brev[i] = din[DEPTH-1-i]; | ||||
|     end | ||||
|   endfunction | ||||
|   localparam [DEPTH-1:0] INIT_R = brev(INIT); | ||||
| 
 | ||||
|   parameter _TECHMAP_CONSTMSK_L_ = 0; | ||||
|   parameter _TECHMAP_CONSTVAL_L_ = 0; | ||||
| 
 | ||||
|   wire CE; | ||||
|   generate | ||||
|     if (ENPOL == 0) | ||||
|       assign CE = ~E; | ||||
|     else if (ENPOL == 1) | ||||
|       assign CE = E; | ||||
|     else | ||||
|       assign CE = 1'b1; | ||||
|     if (DEPTH == 1) begin | ||||
|       if (CLKPOL) | ||||
|           FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); | ||||
|       else | ||||
|           FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); | ||||
|     end else | ||||
|     if (DEPTH <= 16) begin | ||||
|       SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); | ||||
|     end else | ||||
|     if (DEPTH > 17 && DEPTH <= 32) begin | ||||
|       SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q)); | ||||
|     end else | ||||
|     if (DEPTH > 33 && DEPTH <= 64) begin | ||||
|       wire T0, T1, T2; | ||||
|       SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); | ||||
|       \$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2)); | ||||
|       if (&_TECHMAP_CONSTMSK_L_) | ||||
|         assign Q = T2; | ||||
|       else | ||||
|         MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5])); | ||||
|     end else | ||||
|     if (DEPTH > 65 && DEPTH <= 96) begin | ||||
|       wire T0, T1, T2, T3, T4, T5, T6; | ||||
|       SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); | ||||
|       SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); | ||||
|       \$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4)); | ||||
|       if (&_TECHMAP_CONSTMSK_L_) | ||||
|         assign Q = T4; | ||||
|       else begin | ||||
|         MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); | ||||
|         MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5])); | ||||
|         MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6])); | ||||
|       end | ||||
|     end else | ||||
|     if (DEPTH > 97 && DEPTH < 128) begin | ||||
|       wire T0, T1, T2, T3, T4, T5, T6, T7, T8; | ||||
|       SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); | ||||
|       SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); | ||||
|       SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); | ||||
|       \$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6)); | ||||
|       if (&_TECHMAP_CONSTMSK_L_) | ||||
|         assign Q = T6; | ||||
|       else begin | ||||
|         MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); | ||||
|         MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); | ||||
|         MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); | ||||
|       end | ||||
|     end | ||||
|     else if (DEPTH == 128) begin | ||||
|       wire T0, T1, T2, T3, T4, T5, T6; | ||||
|       SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); | ||||
|       SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); | ||||
|       SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); | ||||
|       SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO)); | ||||
|       if (&_TECHMAP_CONSTMSK_L_) | ||||
|         assign Q = T6; | ||||
|       else begin | ||||
|         wire T7, T8; | ||||
|         MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); | ||||
|         MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); | ||||
|         MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); | ||||
|       end | ||||
|     end | ||||
|     else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin | ||||
|       // Handle cases where fixed-length depth is | ||||
|       // just 1 over a convenient value | ||||
|       \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); | ||||
|     end | ||||
|     else begin | ||||
|       localparam lower_clog2 = $clog2((DEPTH+1)/2); | ||||
|       localparam lower_depth = 2 ** lower_clog2; | ||||
|       wire T0, T1, T2, T3; | ||||
|       if (&_TECHMAP_CONSTMSK_L_) begin | ||||
|         \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0)); | ||||
|         \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3)); | ||||
|       end | ||||
|       else begin | ||||
|         \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); | ||||
|         \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); | ||||
|         assign Q = L[lower_clog2] ? T2 : T0; | ||||
|       end | ||||
|       if (DEPTH == 2 * lower_depth) | ||||
|           assign SO = T3; | ||||
|     end | ||||
|   endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module \$shiftx (A, B, Y); | ||||
|   parameter A_SIGNED = 0; | ||||
|   parameter B_SIGNED = 0; | ||||
|  |  | |||
|  | @ -308,3 +308,42 @@ module RAM128X1D ( | |||
|   wire clk = WCLK ^ IS_WCLK_INVERTED; | ||||
|   always @(posedge clk) if (WE) mem[A] <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SRL16E ( | ||||
|   output Q, | ||||
|   input A0, A1, A2, A3, CE, CLK, D | ||||
| ); | ||||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| 
 | ||||
|   reg [15:0] r = INIT; | ||||
|   assign Q = r[{A3,A2,A1,A0}]; | ||||
|   generate | ||||
|     if (IS_CLK_INVERTED) begin | ||||
|       always @(negedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|     end | ||||
|     else | ||||
|         always @(posedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|   endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC32E ( | ||||
|   output Q, | ||||
|   output Q31, | ||||
|   input [4:0] A, | ||||
|   input CE, CLK, D | ||||
| ); | ||||
|   parameter [31:0] INIT = 32'h00000000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| 
 | ||||
|   reg [31:0] r = INIT; | ||||
|   assign Q31 = r[31]; | ||||
|   assign Q = r[A]; | ||||
|   generate | ||||
|     if (IS_CLK_INVERTED) begin | ||||
|       always @(negedge CLK) if (CE) r <= { r[30:0], D }; | ||||
|     end | ||||
|     else | ||||
|       always @(posedge CLK) if (CE) r <= { r[30:0], D }; | ||||
|   endgenerate | ||||
| endmodule | ||||
|  |  | |||
|  | @ -135,8 +135,8 @@ function xtract_cell_decl() | |||
| 	xtract_cell_decl ROM256X1 | ||||
| 	xtract_cell_decl ROM32X1 | ||||
| 	xtract_cell_decl ROM64X1 | ||||
| 	xtract_cell_decl SRL16E | ||||
| 	xtract_cell_decl SRLC32E | ||||
| 	#xtract_cell_decl SRL16E | ||||
| 	#xtract_cell_decl SRLC32E | ||||
| 	xtract_cell_decl STARTUPE2 "(* keep *)" | ||||
| 	xtract_cell_decl USR_ACCESSE2 | ||||
| 	xtract_cell_decl XADC | ||||
|  |  | |||
|  | @ -3809,22 +3809,6 @@ module ROM64X1 (...); | |||
|     input A0, A1, A2, A3, A4, A5; | ||||
| endmodule | ||||
| 
 | ||||
| module SRL16E (...); | ||||
|     parameter [15:0] INIT = 16'h0000; | ||||
|     parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|     output Q; | ||||
|     input A0, A1, A2, A3, CE, CLK, D; | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC32E (...); | ||||
|     parameter [31:0] INIT = 32'h00000000; | ||||
|     parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|     output Q; | ||||
|     output Q31; | ||||
|     input [4:0] A; | ||||
|     input CE, CLK, D; | ||||
| endmodule | ||||
| 
 | ||||
| (* keep *) | ||||
| module STARTUPE2 (...); | ||||
|     parameter PROG_USR = "FALSE"; | ||||
|  |  | |||
|  | @ -22,21 +22,26 @@ | |||
| 
 | ||||
| `ifndef _NO_FFS | ||||
| 
 | ||||
| `ifndef _NO_POS_SR | ||||
| module  \$_DFF_N_   (input D, C, output Q);    FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule | ||||
| module  \$_DFF_P_   (input D, C, output Q);    FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule | ||||
| 
 | ||||
| module  \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule | ||||
| module  \$_DFFE_PP_ (input D, C, E, output Q); FDRE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E),    .R(1'b0)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule | ||||
| module  \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule | ||||
| module  \$_DFF_PN0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule | ||||
| module  \$_DFF_PP0_ (input D, C, R, output Q); FDCE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule | ||||
| module  \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule | ||||
| module  \$_DFF_PN1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule | ||||
| module  \$_DFF_PP1_ (input D, C, R, output Q); FDPE   #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule | ||||
| `endif | ||||
| 
 | ||||
| module  \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule | ||||
| module  \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_         _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule | ||||
| module  \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1          _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C),              .R(~R)); endmodule | ||||
| `endif | ||||
| 
 | ||||
| `endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -64,10 +64,13 @@ struct SynthXilinxPass : public Pass | |||
| 		log("        (this feature is experimental and incomplete)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nobram\n"); | ||||
| 		log("        disable infering of block rams\n"); | ||||
| 		log("        disable inference of block rams\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nodram\n"); | ||||
| 		log("        disable infering of distributed rams\n"); | ||||
| 		log("        disable inference of distributed rams\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nosrl\n"); | ||||
| 		log("        disable inference of shift registers\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -run <from_label>:<to_label>\n"); | ||||
| 		log("        only run the commands between the labels (see below). an empty\n"); | ||||
|  | @ -108,23 +111,28 @@ struct SynthXilinxPass : public Pass | |||
| 		log("        techmap -map +/xilinx/drams_map.v\n"); | ||||
| 		log("\n"); | ||||
| 		log("    fine:\n"); | ||||
| 		log("        opt -fast -full\n"); | ||||
| 		log("        opt -fast\n"); | ||||
| 		log("        memory_map\n"); | ||||
| 		log("        dffsr2dff\n"); | ||||
| 		log("        dff2dffe\n"); | ||||
| 		log("        opt -full\n"); | ||||
| 		log("        techmap -map +/xilinx/arith_map.v\n"); | ||||
| 		log("        opt -fast\n"); | ||||
| 		log("\n"); | ||||
| 		log("    map_cells:\n"); | ||||
| 		log("        simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); | ||||
| 		log("        pmux2shiftx (without '-nosrl' only)\n"); | ||||
| 		log("        opt_expr -mux_undef (without '-nosrl' only)\n"); | ||||
| 		log("        shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); | ||||
| 		log("        techmap -map +/xilinx/cells_map.v\n"); | ||||
| 		log("        opt -fast\n"); | ||||
| 		log("        clean\n"); | ||||
| 		log("\n"); | ||||
| 		log("    map_luts:\n"); | ||||
| 		log("        techmap -map +/techmap.v\n"); | ||||
| 		log("        opt -full\n"); | ||||
| 		log("        techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\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\n"); | ||||
| 		log("        shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n"); | ||||
| 		log("        techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); | ||||
| 		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("\n"); | ||||
|  | @ -152,6 +160,7 @@ struct SynthXilinxPass : public Pass | |||
| 		bool vpr = false; | ||||
| 		bool nobram = false; | ||||
| 		bool nodram = false; | ||||
| 		bool nosrl = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
|  | @ -196,6 +205,10 @@ struct SynthXilinxPass : public Pass | |||
| 				nodram = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nosrl") { | ||||
| 				nosrl = true; | ||||
|                 continue; | ||||
|             } | ||||
| 			if (args[argidx] == "-abc9") { | ||||
| 				abc = "abc9"; | ||||
| 				continue; | ||||
|  | @ -275,6 +288,21 @@ struct SynthXilinxPass : public Pass | |||
| 
 | ||||
| 		if (check_label(active, run_from, run_to, "map_cells")) | ||||
| 		{ | ||||
| 			if (!nosrl) { | ||||
| 				// shregmap operates on bit-level flops, not word-level,
 | ||||
| 				//   so break those down here
 | ||||
| 				Pass::call(design, "simplemap t:$dff t:$dffe"); | ||||
| 				// shregmap -tech xilinx can cope with $shiftx and $mux
 | ||||
| 				//   cells for identifiying variable-length shift registers,
 | ||||
| 				//   so attempt to convert $pmux-es to the former
 | ||||
| 				Pass::call(design, "pmux2shiftx"); | ||||
| 				// pmux2shiftx can leave behind a $pmux with a single entry
 | ||||
| 				//   -- need this to clean that up before shregmap
 | ||||
| 				Pass::call(design, "opt_expr -mux_undef"); | ||||
| 				// shregmap with '-tech xilinx' infers variable length shift regs
 | ||||
| 				Pass::call(design, "shregmap -tech xilinx -minlen 3"); | ||||
| 			} | ||||
| 
 | ||||
| 			Pass::call(design, "techmap -map +/xilinx/cells_map.v"); | ||||
| 			Pass::call(design, "clean"); | ||||
| 		} | ||||
|  | @ -282,14 +310,18 @@ struct SynthXilinxPass : public Pass | |||
| 		if (check_label(active, run_from, run_to, "map_luts")) | ||||
| 		{ | ||||
| 			Pass::call(design, "opt -full"); | ||||
| 			Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); | ||||
| 			Pass::call(design, "read_verilog +/xilinx/cells_box.v"); | ||||
| 			Pass::call(design, "techmap -map +/techmap.v"); | ||||
| 			if (abc == "abc9") | ||||
| 				Pass::call(design, abc + " -lut +/xilinx/cells.lut -box +/xilinx/cells.box" + string(retime ? " -dff" : "")); | ||||
| 			else | ||||
| 				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"); | ||||
| 			// This shregmap call infers fixed length shift registers after abc
 | ||||
| 			//   has performed any necessary retiming
 | ||||
| 			if (!nosrl) | ||||
| 				Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none"); | ||||
| 			Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -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"); | ||||
| 		} | ||||
|  |  | |||
							
								
								
									
										2
									
								
								tests/aiger/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/aiger/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| *.log | ||||
| *.out | ||||
							
								
								
									
										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 | ||||
| 
 | ||||
							
								
								
									
										6
									
								
								tests/simple/retime.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/simple/retime.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| module retime_test(input clk, input [7:0] a, output z); | ||||
|     reg [7:0] ff = 8'hF5; | ||||
|     always @(posedge clk) | ||||
|         ff <= {ff[6:0], ^a}; | ||||
|     assign z = ff[7]; | ||||
| endmodule | ||||
|  | @ -7,7 +7,7 @@ use_modelsim=false | |||
| verbose=false | ||||
| keeprunning=false | ||||
| makejmode=false | ||||
| frontend="verilog" | ||||
| frontend="verilog -noblackbox" | ||||
| backend_opts="-noattr -noexpr -siminit" | ||||
| autotb_opts="" | ||||
| include_opts="" | ||||
|  | @ -136,7 +136,7 @@ do | |||
| 			egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext} | ||||
| 		else | ||||
| 			"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn} | ||||
| 			frontend="verilog" | ||||
| 			frontend="verilog -noblackbox" | ||||
| 		fi | ||||
| 		rm -f ${bn}_ref.fir | ||||
| 
 | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ echo -n "  no explicit top - " | |||
|     module noTop(a, y); | ||||
|       input a; | ||||
|       output [31:0] y; | ||||
|       assign y = a; | ||||
|     endmodule | ||||
|   EOV | ||||
|   hierarchy -auto-top | ||||
|  |  | |||
							
								
								
									
										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 2 t:$mux | ||||
| select -assert-count 2 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