mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge branch 'YosysHQ:master' into master
This commit is contained in:
		
						commit
						15d41041d8
					
				
					 28 changed files with 1270 additions and 85 deletions
				
			
		
							
								
								
									
										2
									
								
								.github/workflows/codeql.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/codeql.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -14,7 +14,7 @@ jobs: | |||
|       run: sudo apt-get install bison flex libreadline-dev tcl-dev libffi-dev | ||||
| 
 | ||||
|     - name: Checkout repository | ||||
|       uses: actions/checkout@v3.0.0 | ||||
|       uses: actions/checkout@v3 | ||||
| 
 | ||||
|     - name: Initialize CodeQL | ||||
|       uses: github/codeql-action/init@v2 | ||||
|  |  | |||
							
								
								
									
										21
									
								
								.github/workflows/deprecated.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								.github/workflows/deprecated.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| name: Deprecated compilers | ||||
| 
 | ||||
| on: [push, pull_request] | ||||
| 
 | ||||
| jobs: | ||||
|   gcc48: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - name: Build GCC 4.8 | ||||
|         run: | | ||||
|           docker run --rm -v $(pwd):/work yosyshq/deprecated-compilers:1.0 make config-gcc-4.8 | ||||
|           docker run --rm -v $(pwd):/work yosyshq/deprecated-compilers:1.0 make -j8 | ||||
| 
 | ||||
|   clang39: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - name: Build Clang 3.9 | ||||
|         run: | | ||||
|           docker run --rm -v $(pwd):/work yosyshq/deprecated-compilers:1.0 make CC=clang-3.9 CXX=clang-3.9 LD=clang-3.9 -j8 | ||||
							
								
								
									
										6
									
								
								.github/workflows/emcc.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/emcc.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -7,10 +7,10 @@ jobs: | |||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: mymindstorm/setup-emsdk@v11 | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: actions/checkout@v3 | ||||
|       - name: Cache sources | ||||
|         id: cache-sources | ||||
|         uses: actions/cache@v2 | ||||
|         uses: actions/cache@v3 | ||||
|         with: | ||||
|           path: . | ||||
|           key: cache-yosys | ||||
|  | @ -18,7 +18,7 @@ jobs: | |||
|         run: | | ||||
|           make config-emcc | ||||
|           make YOSYS_VER=latest | ||||
|       - uses: actions/upload-artifact@v2 | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: yosysjs | ||||
|           path: yosysjs-latest.zip | ||||
|  |  | |||
							
								
								
									
										18
									
								
								.github/workflows/test-linux.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.github/workflows/test-linux.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -25,12 +25,6 @@ jobs: | |||
|           - os: { id: ubuntu-20.04, name: focal } | ||||
|             compiler: 'gcc-10' | ||||
|             cpp_std: 'c++11' | ||||
|           - os: { id: ubuntu-18.04, name: bionic } | ||||
|             compiler: 'clang-3.9' | ||||
|             cpp_std: 'c++11' | ||||
|           - os: { id: ubuntu-18.04, name: bionic } | ||||
|             compiler: 'gcc-4.8' | ||||
|             cpp_std: 'c++11' | ||||
|       fail-fast: false | ||||
|     steps: | ||||
|       - name: Install Dependencies | ||||
|  | @ -84,7 +78,7 @@ jobs: | |||
|           $CXX --version | ||||
| 
 | ||||
|       - name: Checkout Yosys | ||||
|         uses: actions/checkout@v2 | ||||
|         uses: actions/checkout@v3 | ||||
| 
 | ||||
|       - name: Get iverilog | ||||
|         shell: bash | ||||
|  | @ -93,7 +87,7 @@ jobs: | |||
| 
 | ||||
|       - name: Cache iverilog | ||||
|         id: cache-iverilog | ||||
|         uses: actions/cache@v2 | ||||
|         uses: actions/cache@v3 | ||||
|         with: | ||||
|           path: .local/ | ||||
|           key: ${{ matrix.os.id }}-${{ hashFiles('iverilog/.git/refs/heads/master') }} | ||||
|  | @ -109,15 +103,7 @@ jobs: | |||
|           make -j${{ env.procs }} | ||||
|           make install | ||||
| 
 | ||||
|       - name: Build yosys (gcc-4.8) | ||||
|         if: matrix.compiler == 'gcc-4.8' | ||||
|         shell: bash | ||||
|         run: | | ||||
|           make config-${{ matrix.compiler }} | ||||
|           make -j${{ env.procs }} CCXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC | ||||
| 
 | ||||
|       - name: Build yosys | ||||
|         if: matrix.compiler != 'gcc-4.8' | ||||
|         shell: bash | ||||
|         run: | | ||||
|           make config-${CC%%-*} | ||||
|  |  | |||
							
								
								
									
										4
									
								
								.github/workflows/test-macos.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/test-macos.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -35,7 +35,7 @@ jobs: | |||
|           cc --version | ||||
| 
 | ||||
|       - name: Checkout Yosys | ||||
|         uses: actions/checkout@v2 | ||||
|         uses: actions/checkout@v3 | ||||
| 
 | ||||
|       - name: Get iverilog | ||||
|         shell: bash | ||||
|  | @ -44,7 +44,7 @@ jobs: | |||
| 
 | ||||
|       - name: Cache iverilog | ||||
|         id: cache-iverilog | ||||
|         uses: actions/cache@v2 | ||||
|         uses: actions/cache@v3 | ||||
|         with: | ||||
|           path: .local/ | ||||
|           key: ${{ matrix.os.id }}-${{ hashFiles('iverilog/.git/refs/heads/master') }} | ||||
|  |  | |||
							
								
								
									
										6
									
								
								.github/workflows/version.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/version.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -10,15 +10,15 @@ jobs: | |||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - name: Take last commit | ||||
|         id: log | ||||
|         run: echo "::set-output name=message::$(git log --no-merges -1 --oneline)" | ||||
|         run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT | ||||
|       - name: Take repository | ||||
|         id: repo | ||||
|         run: echo "::set-output name=message::$GITHUB_REPOSITORY" | ||||
|         run: echo "message=$GITHUB_REPOSITORY" >> $GITHUB_OUTPUT | ||||
|       - name: Bump version | ||||
|         if: "!contains(steps.log.outputs.message, 'Bump version') && contains(steps.repo.outputs.message, 'YosysHQ/yosys')" | ||||
|         run: | | ||||
|  |  | |||
							
								
								
									
										8
									
								
								.github/workflows/vs.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/vs.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -6,16 +6,16 @@ jobs: | |||
|   yosys-vcxsrc: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: actions/checkout@v3 | ||||
|       - name: Cache sources | ||||
|         id: cache-sources | ||||
|         uses: actions/cache@v2 | ||||
|         uses: actions/cache@v3 | ||||
|         with: | ||||
|           path: . | ||||
|           key: cache-yosys | ||||
|       - name: Build | ||||
|         run: make vcxsrc YOSYS_VER=latest | ||||
|       - uses: actions/upload-artifact@v2 | ||||
|       - uses: actions/upload-artifact@v3 | ||||
|         with: | ||||
|           name: vcxsrc | ||||
|           path: yosys-win32-vcxsrc-latest.zip | ||||
|  | @ -24,7 +24,7 @@ jobs: | |||
|     runs-on: windows-2019 | ||||
|     needs: yosys-vcxsrc | ||||
|     steps:   | ||||
|       - uses: actions/download-artifact@v2 | ||||
|       - uses: actions/download-artifact@v3 | ||||
|         with: | ||||
|           name: vcxsrc | ||||
|           path: . | ||||
|  |  | |||
							
								
								
									
										20
									
								
								CHANGELOG
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								CHANGELOG
									
										
									
									
									
								
							|  | @ -2,9 +2,27 @@ | |||
| List of major changes and improvements between releases | ||||
| ======================================================= | ||||
| 
 | ||||
| Yosys 0.22 .. Yosys 0.22-dev | ||||
| Yosys 0.23 .. Yosys 0.23-dev | ||||
| -------------------------- | ||||
| 
 | ||||
| Yosys 0.22 .. Yosys 0.23 | ||||
| -------------------------- | ||||
|  * New commands and options | ||||
|     - Added option "-cross" to "miter" pass. | ||||
|     - Added option "-nocheck" to "equiv_opt" pass. | ||||
| 
 | ||||
|  * Formal Verification | ||||
|     - yosys-smtbmc: Added "--detect-loops" option for checking if states are | ||||
|       unique in temporal induction counter examples. | ||||
| 
 | ||||
|  * Verific support | ||||
|     - Added support for reading Liberty files using Verific library. | ||||
|       (Optinally enabled with ENABLE_VERIFIC_LIBERTY) | ||||
|     - Added option "-cells" to "verific -import" enabling import of | ||||
|       all cells from verific design. | ||||
| 
 | ||||
|  * Various | ||||
|     - MinGW build (Windows) plugin support. | ||||
|     - Added YOSYS_ABORT_ON_LOG_ERROR environment variable for debugging. | ||||
|       Setting it to 1 causes abort() to be called when Yosys terminates with an | ||||
|       error message. | ||||
|  |  | |||
							
								
								
									
										43
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										43
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -19,6 +19,7 @@ ENABLE_EDITLINE := 0 | |||
| ENABLE_GHDL := 0 | ||||
| ENABLE_VERIFIC := 0 | ||||
| ENABLE_VERIFIC_EDIF := 0 | ||||
| ENABLE_VERIFIC_LIBERTY := 0 | ||||
| DISABLE_VERIFIC_EXTENSIONS := 0 | ||||
| DISABLE_VERIFIC_VHDL := 0 | ||||
| ENABLE_COVER := 1 | ||||
|  | @ -56,6 +57,9 @@ PROGRAM_PREFIX := | |||
| OS := $(shell uname -s) | ||||
| PREFIX ?= /usr/local | ||||
| INSTALL_SUDO := | ||||
| ifneq ($(filter MINGW%,$(OS)),) | ||||
| OS := MINGW | ||||
| endif | ||||
| 
 | ||||
| ifneq ($(wildcard Makefile.conf),) | ||||
| include Makefile.conf | ||||
|  | @ -91,6 +95,13 @@ CXXSTD ?= c++11 | |||
| CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include | ||||
| LDLIBS := $(LDLIBS) -lstdc++ -lm | ||||
| PLUGIN_LDFLAGS := | ||||
| PLUGIN_LDLIBS := | ||||
| EXE_LDFLAGS := | ||||
| ifeq ($(OS), MINGW) | ||||
| EXE_LDFLAGS := -Wl,--export-all-symbols -Wl,--out-implib,libyosys_exe.a | ||||
| PLUGIN_LDFLAGS += -L"$(LIBDIR)" | ||||
| PLUGIN_LDLIBS := -lyosys_exe | ||||
| endif | ||||
| 
 | ||||
| PKG_CONFIG ?= pkg-config | ||||
| SED ?= sed | ||||
|  | @ -131,7 +142,7 @@ LDLIBS += -lrt | |||
| endif | ||||
| endif | ||||
| 
 | ||||
| YOSYS_VER := 0.22+37 | ||||
| YOSYS_VER := 0.23+0 | ||||
| 
 | ||||
| # Note: We arrange for .gitcommit to contain the (short) commit hash in
 | ||||
| # tarballs generated with git-archive(1) using .gitattributes. The git repo
 | ||||
|  | @ -147,7 +158,7 @@ endif | |||
| OBJS = kernel/version_$(GIT_REV).o | ||||
| 
 | ||||
| bumpversion: | ||||
| 	sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline f109fa3.. | wc -l`/;" Makefile | ||||
| 	sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 7ce5011.. | wc -l`/;" Makefile | ||||
| 
 | ||||
| # set 'ABCREV = default' to use abc/ as it is
 | ||||
| #
 | ||||
|  | @ -436,8 +447,11 @@ endif | |||
| 
 | ||||
| ifeq ($(ENABLE_PLUGINS),1) | ||||
| CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS | ||||
| ifeq ($(OS), MINGW) | ||||
| CXXFLAGS += -Ilibs/dlfcn-win32 | ||||
| endif | ||||
| LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) | ||||
| ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) | ||||
| ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD MINGW)) | ||||
| LDLIBS += -ldl | ||||
| endif | ||||
| endif | ||||
|  | @ -531,6 +545,10 @@ ifeq ($(ENABLE_VERIFIC_EDIF),1) | |||
| VERIFIC_COMPONENTS += edif | ||||
| CXXFLAGS += -DVERIFIC_EDIF_SUPPORT | ||||
| endif | ||||
| ifeq ($(ENABLE_VERIFIC_LIBERTY),1) | ||||
| VERIFIC_COMPONENTS += synlib | ||||
| CXXFLAGS += -DVERIFIC_LIBERTY_SUPPORT | ||||
| endif | ||||
| ifneq ($(DISABLE_VERIFIC_EXTENSIONS),1) | ||||
| VERIFIC_COMPONENTS += extensions | ||||
| CXXFLAGS += -DYOSYSHQ_VERIFIC_EXTENSIONS | ||||
|  | @ -646,6 +664,11 @@ OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kern | |||
| ifeq ($(ENABLE_ZLIB),1) | ||||
| OBJS += kernel/fstdata.o | ||||
| endif | ||||
| ifeq ($(ENABLE_PLUGINS),1) | ||||
| ifeq ($(OS), MINGW) | ||||
| OBJS += libs/dlfcn-win32/dlfcn.o | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' | ||||
| kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' | ||||
|  | @ -724,7 +747,7 @@ yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS)) | |||
| endif | ||||
| 
 | ||||
| $(PROGRAM_PREFIX)yosys$(EXE): $(OBJS) | ||||
| 	$(P) $(LD) -o $(PROGRAM_PREFIX)yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS) | ||||
| 	$(P) $(LD) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) | ||||
| 
 | ||||
| libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) | ||||
| ifeq ($(OS), Darwin) | ||||
|  | @ -767,8 +790,8 @@ LDLIBS_NOVERIFIC = $(LDLIBS) | |||
| endif | ||||
| 
 | ||||
| $(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in | ||||
| 	$(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC)))#;' \
 | ||||
| 			-e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC))#;' \
 | ||||
| 	$(P) $(SED) -e 's#@CXXFLAGS@#$(subst -Ilibs/dlfcn-win32,,$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC))))#;' \
 | ||||
| 			-e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC) $(PLUGIN_LDLIBS))#;' \
 | ||||
| 			-e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config | ||||
| 	$(Q) chmod +x $(PROGRAM_PREFIX)yosys-config | ||||
| 
 | ||||
|  | @ -916,6 +939,12 @@ ifeq ($(ENABLE_PYOSYS),1) | |||
| 	$(INSTALL_SUDO) cp misc/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/ | ||||
| endif | ||||
| endif | ||||
| ifeq ($(ENABLE_PLUGINS),1) | ||||
| ifeq ($(OS), MINGW) | ||||
| 	$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) | ||||
| 	$(INSTALL_SUDO) cp libyosys_exe.a $(DESTDIR)$(LIBDIR)/ | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| uninstall: | ||||
| 	$(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR)/,$(notdir $(TARGETS))) | ||||
|  | @ -1040,12 +1069,10 @@ config-mxe: clean | |||
| 
 | ||||
| config-msys2-32: clean | ||||
| 	echo 'CONFIG := msys2-32' > Makefile.conf | ||||
| 	echo 'ENABLE_PLUGINS := 0' >> Makefile.conf | ||||
| 	echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf | ||||
| 
 | ||||
| config-msys2-64: clean | ||||
| 	echo 'CONFIG := msys2-64' > Makefile.conf | ||||
| 	echo 'ENABLE_PLUGINS := 0' >> Makefile.conf | ||||
| 	echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf | ||||
| 
 | ||||
| config-cygwin: clean | ||||
|  |  | |||
|  | @ -453,7 +453,6 @@ assert topmod in smt.modinfo | |||
| 
 | ||||
| if cexfile is not None: | ||||
|     if not got_topt: | ||||
|         assume_skipped = 0 | ||||
|         skip_steps = 0 | ||||
|         num_steps = 0 | ||||
| 
 | ||||
|  | @ -499,7 +498,6 @@ if aimfile is not None: | |||
|     latch_map = dict() | ||||
| 
 | ||||
|     if not got_topt: | ||||
|         assume_skipped = 0 | ||||
|         skip_steps = 0 | ||||
|         num_steps = 0 | ||||
| 
 | ||||
|  | @ -633,7 +631,6 @@ if aimfile is not None: | |||
| 
 | ||||
| if inywfile is not None: | ||||
|     if not got_topt: | ||||
|         assume_skipped = 0 | ||||
|         skip_steps = 0 | ||||
|         num_steps = 0 | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,6 +57,11 @@ USING_YOSYS_NAMESPACE | |||
| #include "edif_file.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef VERIFIC_LIBERTY_SUPPORT | ||||
| #include "synlib_file.h" | ||||
| #include "SynlibGroup.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "VerificStream.h" | ||||
| #include "FileSystem.h" | ||||
| 
 | ||||
|  | @ -2358,6 +2363,9 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par | |||
| #endif | ||||
| #ifdef VERIFIC_EDIF_SUPPORT | ||||
| 	edif_file::Reset(); | ||||
| #endif | ||||
| #ifdef VERIFIC_LIBERTY_SUPPORT | ||||
| 	synlib_file::Reset(); | ||||
| #endif | ||||
| 	Libset::Reset(); | ||||
| 	Message::Reset(); | ||||
|  | @ -2426,6 +2434,18 @@ struct VerificPass : public Pass { | |||
| 		log("Load the specified EDIF files into Verific.\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| #endif | ||||
| #ifdef VERIFIC_LIBERTY_SUPPORT | ||||
| 		log("    verific {-liberty} <liberty-file>..\n"); | ||||
| 		log("\n"); | ||||
| 		log("Load the specified Liberty files into Verific.\n"); | ||||
| 		log("Default library when -work is not present is one specified in liberty file.\n"); | ||||
| 		log("To use from SystemVerilog or VHDL use -L to specify liberty library."); | ||||
| 		log("\n"); | ||||
| 		log("    -lib\n"); | ||||
| 		log("        only create empty blackbox modules\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| #endif | ||||
| 		log("    verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009|\n"); | ||||
| 		log("                     -sv2012|-sv|-formal] <command-file>\n"); | ||||
|  | @ -2535,7 +2555,7 @@ struct VerificPass : public Pass { | |||
| 		log("\n"); | ||||
| 		log("  -cells\n"); | ||||
| 		log("    Import all cell definitions from Verific loaded libraries even if they are\n"); | ||||
| 		log("    unused in design. Useful with \"-edif\" option.\n"); | ||||
| 		log("    unused in design. Useful with \"-edif\" and \"-liberty\" option.\n"); | ||||
| 		log("\n"); | ||||
| 		log("  -chparam name value \n"); | ||||
| 		log("    Elaborate the specified top modules (all modules when -all given) using\n"); | ||||
|  | @ -2729,6 +2749,7 @@ struct VerificPass : public Pass { | |||
| 
 | ||||
| 		int argidx = 1; | ||||
| 		std::string work = "work"; | ||||
| 		bool is_work_set = false; | ||||
| 		veri_file::RegisterCallBackVerificStream(&verific_read_cb); | ||||
| 
 | ||||
| 		if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || | ||||
|  | @ -2813,6 +2834,7 @@ struct VerificPass : public Pass { | |||
| 		{ | ||||
| 			if (args[argidx] == "-work" && argidx+1 < GetSize(args)) { | ||||
| 				work = args[++argidx]; | ||||
| 				is_work_set = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-L" && argidx+1 < GetSize(args)) { | ||||
|  | @ -3001,6 +3023,42 @@ struct VerificPass : public Pass { | |||
| 			} | ||||
| 			goto check_error; | ||||
| 		} | ||||
| #endif | ||||
| #ifdef VERIFIC_LIBERTY_SUPPORT | ||||
| 		if (GetSize(args) > argidx && args[argidx] == "-liberty") { | ||||
| 			bool flag_lib = false; | ||||
| 			for (argidx++; argidx < GetSize(args); argidx++) { | ||||
| 				if (args[argidx] == "-lib") { | ||||
| 					flag_lib = true; | ||||
| 					continue; | ||||
| 				} | ||||
| 				if (args[argidx].compare(0, 1, "-") == 0) { | ||||
| 					cmd_error(args, argidx, "unknown option"); | ||||
| 					goto check_error; | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			while (argidx < GetSize(args)) { | ||||
| 				std::string filename = frontent_rewrite(args, argidx, tmp_files); | ||||
| 				if (!synlib_file::Read(filename.c_str(), is_work_set ? work.c_str() : nullptr)) | ||||
| 					log_cmd_error("Reading `%s' in LIBERTY mode failed.\n", filename.c_str()); | ||||
| 				SynlibLibrary *lib = synlib_file::GetLastLibraryAnalyzed(); | ||||
| 				if (lib && flag_lib) { | ||||
| 					MapIter mi ; | ||||
| 					Verific::Cell *c ; | ||||
| 					FOREACH_CELL_OF_LIBRARY(lib->GetLibrary(),mi,c) { | ||||
| 						MapIter ni ; | ||||
| 						Netlist *nl; | ||||
| 						FOREACH_NETLIST_OF_CELL(c, ni, nl) { | ||||
| 							if (nl) | ||||
| 								nl->MakeBlackBox(); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			goto check_error; | ||||
| 		} | ||||
| #endif | ||||
| 		if (argidx < GetSize(args) && args[argidx] == "-pp") | ||||
| 		{ | ||||
|  | @ -3293,6 +3351,9 @@ struct VerificPass : public Pass { | |||
| #endif | ||||
| #ifdef VERIFIC_EDIF_SUPPORT | ||||
| 			edif_file::Reset(); | ||||
| #endif | ||||
| #ifdef VERIFIC_LIBERTY_SUPPORT | ||||
| 			synlib_file::Reset(); | ||||
| #endif | ||||
| 			Libset::Reset(); | ||||
| 			Message::Reset(); | ||||
|  | @ -3427,6 +3488,14 @@ struct ReadPass : public Pass { | |||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| #endif | ||||
| 		log("    read {-liberty} <liberty-file>..\n"); | ||||
| 		log("\n"); | ||||
| 		log("Load the specified Liberty files.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -lib\n"); | ||||
| 		log("        only create empty blackbox modules\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("    read {-f|-F} <command-file>\n"); | ||||
| 		log("\n"); | ||||
| 		log("Load and execute the specified command file. (Requires Verific.)\n"); | ||||
|  | @ -3531,6 +3600,15 @@ struct ReadPass : public Pass { | |||
| 			return; | ||||
| 		} | ||||
| #endif | ||||
| 		if (args[1] == "-liberty") { | ||||
| 			if (use_verific) { | ||||
| 				args[0] = "verific"; | ||||
| 			} else { | ||||
| 				args[0] = "read_liberty"; | ||||
| 			} | ||||
| 			Pass::call(design, args); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (args[1] == "-f" || args[1] == "-F") { | ||||
| 			if (use_verific) { | ||||
| 				args[0] = "verific"; | ||||
|  |  | |||
|  | @ -609,6 +609,36 @@ RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, boo | |||
| 	return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len); | ||||
| } | ||||
| 
 | ||||
| RTLIL::Const RTLIL::const_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) | ||||
| { | ||||
| 	log_assert(arg2.size() == arg1.size()); | ||||
| 	if (arg3[0] == State::S0) | ||||
| 		return arg1; | ||||
| 	else if (arg3[0] == State::S1) | ||||
| 		return arg2; | ||||
| 
 | ||||
| 	RTLIL::Const ret = arg1; | ||||
| 	for (int i = 0; i < ret.size(); i++) | ||||
| 		if (ret[i] != arg2[i]) | ||||
| 			ret[i] = State::Sx; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| RTLIL::Const RTLIL::const_pmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) | ||||
| { | ||||
| 	if (arg3.is_fully_zero()) | ||||
| 		return arg1; | ||||
| 
 | ||||
| 	if (!arg3.is_onehot()) | ||||
| 		return RTLIL::Const(State::Sx, arg1.size()); | ||||
| 
 | ||||
| 	for (int i = 0; i < arg3.size(); i++) | ||||
| 		if (arg3[i] == State::S1) | ||||
| 			return RTLIL::Const(std::vector<RTLIL::State>(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size())); | ||||
| 
 | ||||
| 	log_abort(); // unreachable
 | ||||
| } | ||||
| 
 | ||||
| RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2) | ||||
| { | ||||
| 	std::vector<RTLIL::State> t = arg1.bits; | ||||
|  |  | |||
|  | @ -488,16 +488,10 @@ struct CellTypes | |||
| 
 | ||||
| 	static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr) | ||||
| 	{ | ||||
| 		if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) { | ||||
| 			RTLIL::Const ret = arg1; | ||||
| 			for (size_t i = 0; i < arg3.bits.size(); i++) | ||||
| 				if (arg3.bits[i] == RTLIL::State::S1) { | ||||
| 					std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size()); | ||||
| 					ret = RTLIL::Const(bits); | ||||
| 				} | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
| 		if (cell->type.in(ID($mux), ID($_MUX_))) | ||||
| 			return const_mux(arg1, arg2, arg3); | ||||
| 		if (cell->type == ID($pmux)) | ||||
| 			return const_pmux(arg1, arg2, arg3); | ||||
| 		if (cell->type == ID($_AOI3_)) | ||||
| 			return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1)); | ||||
| 		if (cell->type == ID($_OAI3_)) | ||||
|  |  | |||
|  | @ -78,7 +78,18 @@ uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); } | |||
| 
 | ||||
| uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); } | ||||
| 
 | ||||
| static void normalize_brackets(std::string &str) | ||||
| { | ||||
| 	for (auto &c : str) { | ||||
| 		if (c == '<') | ||||
| 			c = '['; | ||||
| 		else if (c == '>') | ||||
| 			c = ']'; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fstHandle FstData::getHandle(std::string name) {  | ||||
| 	normalize_brackets(name); | ||||
| 	if (name_to_handle.find(name) != name_to_handle.end()) | ||||
| 		return name_to_handle[name]; | ||||
| 	else  | ||||
|  | @ -120,6 +131,7 @@ void FstData::extractVarNames() | |||
| 				var.is_reg = (fstVarType)h->u.var.typ == FST_VT_VCD_REG; | ||||
| 				var.name = remove_spaces(h->u.var.name); | ||||
| 				var.scope = fst_scope_name; | ||||
| 				normalize_brackets(var.scope); | ||||
| 				var.width = h->u.var.length; | ||||
| 				vars.push_back(var); | ||||
| 				if (!var.is_alias) | ||||
|  | @ -134,35 +146,34 @@ void FstData::extractVarNames() | |||
| 				if (clean_name[0]=='\\') | ||||
| 					clean_name = clean_name.substr(1); | ||||
| 				size_t pos = clean_name.find_last_of("<"); | ||||
| 				if (pos != std::string::npos) { | ||||
| 				if (pos != std::string::npos && clean_name.back() == '>') { | ||||
| 					std::string mem_cell = clean_name.substr(0, pos); | ||||
| 					normalize_brackets(mem_cell); | ||||
| 					std::string addr = clean_name.substr(pos+1); | ||||
| 					addr.pop_back(); // remove closing bracket
 | ||||
| 					char *endptr; | ||||
| 					int mem_addr = strtol(addr.c_str(), &endptr, 16); | ||||
| 					if (*endptr) { | ||||
| 						log_warning("Error parsing memory address in : %s\n", clean_name.c_str()); | ||||
| 						log_debug("Error parsing memory address in : %s\n", clean_name.c_str()); | ||||
| 					} else { | ||||
| 						memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id; | ||||
| 						name_to_handle[stringf("%s.%s[%d]",var.scope.c_str(),mem_cell.c_str(),mem_addr)] = h->u.var.handle; | ||||
| 						continue; | ||||
| 					} | ||||
| 				} | ||||
| 				pos = clean_name.find_last_of("["); | ||||
| 				if (pos != std::string::npos) { | ||||
| 				if (pos != std::string::npos && clean_name.back() == ']') { | ||||
| 					std::string mem_cell = clean_name.substr(0, pos); | ||||
| 					normalize_brackets(mem_cell); | ||||
| 					std::string addr = clean_name.substr(pos+1); | ||||
| 					addr.pop_back(); // remove closing bracket
 | ||||
| 					char *endptr; | ||||
| 					int mem_addr = strtol(addr.c_str(), &endptr, 10); | ||||
| 					if (*endptr) { | ||||
| 						log_warning("Error parsing memory address in : %s\n", clean_name.c_str()); | ||||
| 						log_debug("Error parsing memory address in : %s\n", clean_name.c_str()); | ||||
| 					} else { | ||||
| 						memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id; | ||||
| 						name_to_handle[stringf("%s.%s[%d]",var.scope.c_str(),mem_cell.c_str(),mem_addr)] = h->u.var.handle; | ||||
| 						continue; | ||||
| 					} | ||||
| 				} | ||||
| 				normalize_brackets(clean_name); | ||||
| 				name_to_handle[var.scope+"."+clean_name] = h->u.var.handle; | ||||
| 				break; | ||||
| 			} | ||||
|  | @ -241,6 +252,7 @@ void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t sta | |||
| 		past_data = last_data; | ||||
| 		callback(last_time); | ||||
| 	} | ||||
| 	past_data = last_data; | ||||
| 	callback(end_time); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -393,6 +393,11 @@ void log_dump_val_worker(RTLIL::IdString v); | |||
| void log_dump_val_worker(RTLIL::SigSpec v); | ||||
| void log_dump_val_worker(RTLIL::State v); | ||||
| 
 | ||||
| template<typename K, typename T, typename OPS> static inline void log_dump_val_worker(dict<K, T, OPS> &v); | ||||
| template<typename K, typename OPS> static inline void log_dump_val_worker(pool<K, OPS> &v); | ||||
| template<typename K> static inline void log_dump_val_worker(std::vector<K> &v); | ||||
| template<typename T> static inline void log_dump_val_worker(T *ptr); | ||||
| 
 | ||||
| template<typename K, typename T, typename OPS> | ||||
| static inline void log_dump_val_worker(dict<K, T, OPS> &v) { | ||||
| 	log("{"); | ||||
|  |  | |||
|  | @ -500,6 +500,8 @@ namespace RTLIL | |||
| 	RTLIL::Const const_pos         (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); | ||||
| 	RTLIL::Const const_neg         (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); | ||||
| 
 | ||||
| 	RTLIL::Const const_mux         (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); | ||||
| 	RTLIL::Const const_pmux        (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); | ||||
| 	RTLIL::Const const_bmux        (const RTLIL::Const &arg1, const RTLIL::Const &arg2); | ||||
| 	RTLIL::Const const_demux       (const RTLIL::Const &arg1, const RTLIL::Const &arg2); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										820
									
								
								libs/dlfcn-win32/dlfcn.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										820
									
								
								libs/dlfcn-win32/dlfcn.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,820 @@ | |||
| /*
 | ||||
|  * dlfcn-win32 | ||||
|  * Copyright (c) 2007 Ramiro Polla | ||||
|  * Copyright (c) 2015 Tiancheng "Timothy" Gu | ||||
|  * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com> | ||||
|  * Copyright (c) 2020 Ralf Habacker <ralf.habacker@freenet.de> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #ifdef _DEBUG | ||||
| #define _CRTDBG_MAP_ALLOC | ||||
| #include <stdlib.h> | ||||
| #include <crtdbg.h> | ||||
| #endif | ||||
| #include <windows.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| /* Older versions do not have this type */ | ||||
| #if _WIN32_WINNT < 0x0500 | ||||
| typedef ULONG ULONG_PTR; | ||||
| #endif | ||||
| 
 | ||||
| /* Older SDK versions do not have these macros */ | ||||
| #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | ||||
| #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4 | ||||
| #endif | ||||
| #ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | ||||
| #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
| /* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ | ||||
| #pragma intrinsic( _ReturnAddress ) | ||||
| #else | ||||
| /* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */ | ||||
| #ifndef _ReturnAddress | ||||
| #define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) ) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef DLFCN_WIN32_SHARED | ||||
| #define DLFCN_WIN32_EXPORTS | ||||
| #endif | ||||
| #include "dlfcn.h" | ||||
| 
 | ||||
| #if defined( _MSC_VER ) && _MSC_VER >= 1300 | ||||
| /* https://docs.microsoft.com/en-us/cpp/cpp/noinline */ | ||||
| #define DLFCN_NOINLINE __declspec( noinline ) | ||||
| #elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) ) | ||||
| /* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */ | ||||
| #define DLFCN_NOINLINE __attribute__(( noinline )) | ||||
| #else | ||||
| #define DLFCN_NOINLINE | ||||
| #endif | ||||
| 
 | ||||
| /* Note:
 | ||||
|  * MSDN says these functions are not thread-safe. We make no efforts to have | ||||
|  * any kind of thread safety. | ||||
|  */ | ||||
| 
 | ||||
| typedef struct local_object { | ||||
|     HMODULE hModule; | ||||
|     struct local_object *previous; | ||||
|     struct local_object *next; | ||||
| } local_object; | ||||
| 
 | ||||
| static local_object first_object; | ||||
| 
 | ||||
| /* These functions implement a double linked list for the local objects. */ | ||||
| static local_object *local_search( HMODULE hModule ) | ||||
| { | ||||
|     local_object *pobject; | ||||
| 
 | ||||
|     if( hModule == NULL ) | ||||
|         return NULL; | ||||
| 
 | ||||
|     for( pobject = &first_object; pobject; pobject = pobject->next ) | ||||
|         if( pobject->hModule == hModule ) | ||||
|             return pobject; | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| static BOOL local_add( HMODULE hModule ) | ||||
| { | ||||
|     local_object *pobject; | ||||
|     local_object *nobject; | ||||
| 
 | ||||
|     if( hModule == NULL ) | ||||
|         return TRUE; | ||||
| 
 | ||||
|     pobject = local_search( hModule ); | ||||
| 
 | ||||
|     /* Do not add object again if it's already on the list */ | ||||
|     if( pobject != NULL ) | ||||
|         return TRUE; | ||||
| 
 | ||||
|     for( pobject = &first_object; pobject->next; pobject = pobject->next ); | ||||
| 
 | ||||
|     nobject = (local_object *) malloc( sizeof( local_object ) ); | ||||
| 
 | ||||
|     if( !nobject ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     pobject->next = nobject; | ||||
|     nobject->next = NULL; | ||||
|     nobject->previous = pobject; | ||||
|     nobject->hModule = hModule; | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| static void local_rem( HMODULE hModule ) | ||||
| { | ||||
|     local_object *pobject; | ||||
| 
 | ||||
|     if( hModule == NULL ) | ||||
|         return; | ||||
| 
 | ||||
|     pobject = local_search( hModule ); | ||||
| 
 | ||||
|     if( pobject == NULL ) | ||||
|         return; | ||||
| 
 | ||||
|     if( pobject->next ) | ||||
|         pobject->next->previous = pobject->previous; | ||||
|     if( pobject->previous ) | ||||
|         pobject->previous->next = pobject->next; | ||||
| 
 | ||||
|     free( pobject ); | ||||
| } | ||||
| 
 | ||||
| /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
 | ||||
|  * static buffer. | ||||
|  * MSDN says the buffer cannot be larger than 64K bytes, so we set it to | ||||
|  * the limit. | ||||
|  */ | ||||
| static char error_buffer[65535]; | ||||
| static BOOL error_occurred; | ||||
| 
 | ||||
| static void save_err_str( const char *str, DWORD dwMessageId ) | ||||
| { | ||||
|     DWORD ret; | ||||
|     size_t pos, len; | ||||
| 
 | ||||
|     len = strlen( str ); | ||||
|     if( len > sizeof( error_buffer ) - 5 ) | ||||
|         len = sizeof( error_buffer ) - 5; | ||||
| 
 | ||||
|     /* Format error message to:
 | ||||
|      * "<argument to function that failed>": <Windows localized error message> | ||||
|       */ | ||||
|     pos = 0; | ||||
|     error_buffer[pos++] = '"'; | ||||
|     memcpy( error_buffer + pos, str, len ); | ||||
|     pos += len; | ||||
|     error_buffer[pos++] = '"'; | ||||
|     error_buffer[pos++] = ':'; | ||||
|     error_buffer[pos++] = ' '; | ||||
| 
 | ||||
|     ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId, | ||||
|         MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), | ||||
|         error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL ); | ||||
|     pos += ret; | ||||
| 
 | ||||
|     /* When FormatMessageA() fails it returns zero and does not touch buffer
 | ||||
|      * so add trailing null byte */ | ||||
|     if( ret == 0 ) | ||||
|         error_buffer[pos] = '\0'; | ||||
| 
 | ||||
|     if( pos > 1 ) | ||||
|     { | ||||
|         /* POSIX says the string must not have trailing <newline> */ | ||||
|         if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) | ||||
|             error_buffer[pos-2] = '\0'; | ||||
|     } | ||||
| 
 | ||||
|     error_occurred = TRUE; | ||||
| } | ||||
| 
 | ||||
| static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) | ||||
| { | ||||
|     char ptr_buf[2 + 2 * sizeof( ptr ) + 1]; | ||||
|     char num; | ||||
|     size_t i; | ||||
| 
 | ||||
|     ptr_buf[0] = '0'; | ||||
|     ptr_buf[1] = 'x'; | ||||
| 
 | ||||
|     for( i = 0; i < 2 * sizeof( ptr ); i++ ) | ||||
|     { | ||||
|         num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF ); | ||||
|         ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); | ||||
|     } | ||||
| 
 | ||||
|     ptr_buf[2 + 2 * sizeof( ptr )] = 0; | ||||
| 
 | ||||
|     save_err_str( ptr_buf, dwMessageId ); | ||||
| } | ||||
| 
 | ||||
| static UINT MySetErrorMode( UINT uMode ) | ||||
| { | ||||
|     static BOOL (WINAPI *SetThreadErrorModePtr)(DWORD, DWORD *) = NULL; | ||||
|     static BOOL failed = FALSE; | ||||
|     HMODULE kernel32; | ||||
|     DWORD oldMode; | ||||
| 
 | ||||
|     if( !failed && SetThreadErrorModePtr == NULL ) | ||||
|     { | ||||
|         kernel32 = GetModuleHandleA( "Kernel32.dll" ); | ||||
|         if( kernel32 != NULL ) | ||||
|             SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (LPVOID) GetProcAddress( kernel32, "SetThreadErrorMode" ); | ||||
|         if( SetThreadErrorModePtr == NULL ) | ||||
|             failed = TRUE; | ||||
|     } | ||||
| 
 | ||||
|     if( !failed ) | ||||
|     { | ||||
|         if( !SetThreadErrorModePtr( uMode, &oldMode ) ) | ||||
|             return 0; | ||||
|         else | ||||
|             return oldMode; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return SetErrorMode( uMode ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static HMODULE MyGetModuleHandleFromAddress( const void *addr ) | ||||
| { | ||||
|     static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL; | ||||
|     static BOOL failed = FALSE; | ||||
|     HMODULE kernel32; | ||||
|     HMODULE hModule; | ||||
|     MEMORY_BASIC_INFORMATION info; | ||||
|     SIZE_T sLen; | ||||
| 
 | ||||
|     if( !failed && GetModuleHandleExAPtr == NULL ) | ||||
|     { | ||||
|         kernel32 = GetModuleHandleA( "Kernel32.dll" ); | ||||
|         if( kernel32 != NULL ) | ||||
|             GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (LPVOID) GetProcAddress( kernel32, "GetModuleHandleExA" ); | ||||
|         if( GetModuleHandleExAPtr == NULL ) | ||||
|             failed = TRUE; | ||||
|     } | ||||
| 
 | ||||
|     if( !failed ) | ||||
|     { | ||||
|         /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */ | ||||
|         if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)addr, &hModule ) ) | ||||
|             return NULL; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         /* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380
 | ||||
|          * The HMODULE of a DLL is the same value as the module's base address. | ||||
|          */ | ||||
|         sLen = VirtualQuery( addr, &info, sizeof( info ) ); | ||||
|         if( sLen != sizeof( info ) ) | ||||
|             return NULL; | ||||
|         hModule = (HMODULE) info.AllocationBase; | ||||
|     } | ||||
| 
 | ||||
|     return hModule; | ||||
| } | ||||
| 
 | ||||
| /* Load Psapi.dll at runtime, this avoids linking caveat */ | ||||
| static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) | ||||
| { | ||||
|     static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL; | ||||
|     static BOOL failed = FALSE; | ||||
|     UINT uMode; | ||||
|     HMODULE psapi; | ||||
| 
 | ||||
|     if( failed ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     if( EnumProcessModulesPtr == NULL ) | ||||
|     { | ||||
|         /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */ | ||||
|         psapi = GetModuleHandleA( "Kernel32.dll" ); | ||||
|         if( psapi != NULL ) | ||||
|             EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "K32EnumProcessModules" ); | ||||
| 
 | ||||
|         /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ | ||||
|         if( EnumProcessModulesPtr == NULL ) | ||||
|         { | ||||
|             /* Do not let Windows display the critical-error-handler message box */ | ||||
|             uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); | ||||
|             psapi = LoadLibraryA( "Psapi.dll" ); | ||||
|             if( psapi != NULL ) | ||||
|             { | ||||
|                 EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" ); | ||||
|                 if( EnumProcessModulesPtr == NULL ) | ||||
|                     FreeLibrary( psapi ); | ||||
|             } | ||||
|             MySetErrorMode( uMode ); | ||||
|         } | ||||
| 
 | ||||
|         if( EnumProcessModulesPtr == NULL ) | ||||
|         { | ||||
|             failed = TRUE; | ||||
|             return FALSE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); | ||||
| } | ||||
| 
 | ||||
| DLFCN_EXPORT | ||||
| void *dlopen( const char *file, int mode ) | ||||
| { | ||||
|     HMODULE hModule; | ||||
|     UINT uMode; | ||||
| 
 | ||||
|     error_occurred = FALSE; | ||||
| 
 | ||||
|     /* Do not let Windows display the critical-error-handler message box */ | ||||
|     uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); | ||||
| 
 | ||||
|     if( file == NULL ) | ||||
|     { | ||||
|         /* POSIX says that if the value of file is NULL, a handle on a global
 | ||||
|          * symbol object must be provided. That object must be able to access | ||||
|          * all symbols from the original program file, and any objects loaded | ||||
|          * with the RTLD_GLOBAL flag. | ||||
|          * The return value from GetModuleHandle( ) allows us to retrieve | ||||
|          * symbols only from the original program file. EnumProcessModules() is | ||||
|          * used to access symbols from other libraries. For objects loaded | ||||
|          * with the RTLD_LOCAL flag, we create our own list later on. They are | ||||
|          * excluded from EnumProcessModules() iteration. | ||||
|          */ | ||||
|         hModule = GetModuleHandle( NULL ); | ||||
| 
 | ||||
|         if( !hModule ) | ||||
|             save_err_str( "(null)", GetLastError( ) ); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         HANDLE hCurrentProc; | ||||
|         DWORD dwProcModsBefore, dwProcModsAfter; | ||||
|         char lpFileName[MAX_PATH]; | ||||
|         size_t i, len; | ||||
| 
 | ||||
|         len = strlen( file ); | ||||
| 
 | ||||
|         if( len >= sizeof( lpFileName ) ) | ||||
|         { | ||||
|             save_err_str( file, ERROR_FILENAME_EXCED_RANGE ); | ||||
|             hModule = NULL; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* MSDN says backslashes *must* be used instead of forward slashes. */ | ||||
|             for( i = 0; i < len; i++ ) | ||||
|             { | ||||
|                 if( file[i] == '/' ) | ||||
|                     lpFileName[i] = '\\'; | ||||
|                 else | ||||
|                     lpFileName[i] = file[i]; | ||||
|             } | ||||
|             lpFileName[len] = '\0'; | ||||
| 
 | ||||
|             hCurrentProc = GetCurrentProcess( ); | ||||
| 
 | ||||
|             if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 ) | ||||
|                 dwProcModsBefore = 0; | ||||
| 
 | ||||
|             /* POSIX says the search path is implementation-defined.
 | ||||
|              * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely | ||||
|              * to UNIX's search paths (start with system folders instead of current | ||||
|              * folder). | ||||
|              */ | ||||
|             hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); | ||||
| 
 | ||||
|             if( !hModule ) | ||||
|             { | ||||
|                 save_err_str( lpFileName, GetLastError( ) ); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) | ||||
|                     dwProcModsAfter = 0; | ||||
| 
 | ||||
|                 /* If the object was loaded with RTLD_LOCAL, add it to list of local
 | ||||
|                  * objects, so that its symbols cannot be retrieved even if the handle for | ||||
|                  * the original program file is passed. POSIX says that if the same | ||||
|                  * file is specified in multiple invocations, and any of them are | ||||
|                  * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the | ||||
|                  * symbols will remain global. If number of loaded modules was not | ||||
|                  * changed after calling LoadLibraryEx(), it means that library was | ||||
|                  * already loaded. | ||||
|                  */ | ||||
|                 if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter ) | ||||
|                 { | ||||
|                     if( !local_add( hModule ) ) | ||||
|                     { | ||||
|                         save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY ); | ||||
|                         FreeLibrary( hModule ); | ||||
|                         hModule = NULL; | ||||
|                     } | ||||
|                 } | ||||
|                 else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter ) | ||||
|                 { | ||||
|                     local_rem( hModule ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Return to previous state of the error-mode bit flags. */ | ||||
|     MySetErrorMode( uMode ); | ||||
| 
 | ||||
|     return (void *) hModule; | ||||
| } | ||||
| 
 | ||||
| DLFCN_EXPORT | ||||
| int dlclose( void *handle ) | ||||
| { | ||||
|     HMODULE hModule = (HMODULE) handle; | ||||
|     BOOL ret; | ||||
| 
 | ||||
|     error_occurred = FALSE; | ||||
| 
 | ||||
|     ret = FreeLibrary( hModule ); | ||||
| 
 | ||||
|     /* If the object was loaded with RTLD_LOCAL, remove it from list of local
 | ||||
|      * objects. | ||||
|      */ | ||||
|     if( ret ) | ||||
|         local_rem( hModule ); | ||||
|     else | ||||
|         save_err_ptr_str( handle, GetLastError( ) ); | ||||
| 
 | ||||
|     /* dlclose's return value in inverted in relation to FreeLibrary's. */ | ||||
|     ret = !ret; | ||||
| 
 | ||||
|     return (int) ret; | ||||
| } | ||||
| 
 | ||||
| DLFCN_NOINLINE /* Needed for _ReturnAddress() */ | ||||
| DLFCN_EXPORT | ||||
| void *dlsym( void *handle, const char *name ) | ||||
| { | ||||
|     FARPROC symbol; | ||||
|     HMODULE hCaller; | ||||
|     HMODULE hModule; | ||||
|     DWORD dwMessageId; | ||||
| 
 | ||||
|     error_occurred = FALSE; | ||||
| 
 | ||||
|     symbol = NULL; | ||||
|     hCaller = NULL; | ||||
|     hModule = GetModuleHandle( NULL ); | ||||
|     dwMessageId = 0; | ||||
| 
 | ||||
|     if( handle == RTLD_DEFAULT ) | ||||
|     { | ||||
|         /* The symbol lookup happens in the normal global scope; that is,
 | ||||
|          * a search for a symbol using this handle would find the same | ||||
|          * definition as a direct use of this symbol in the program code. | ||||
|          * So use same lookup procedure as when filename is NULL. | ||||
|          */ | ||||
|         handle = hModule; | ||||
|     } | ||||
|     else if( handle == RTLD_NEXT ) | ||||
|     { | ||||
|         /* Specifies the next object after this one that defines name.
 | ||||
|          * This one refers to the object containing the invocation of dlsym(). | ||||
|          * The next object is the one found upon the application of a load | ||||
|          * order symbol resolution algorithm. To get caller function of dlsym() | ||||
|          * use _ReturnAddress() intrinsic. To get HMODULE of caller function | ||||
|          * use MyGetModuleHandleFromAddress() which calls either standard | ||||
|          * GetModuleHandleExA() function or hack via VirtualQuery(). | ||||
|          */ | ||||
|         hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) ); | ||||
| 
 | ||||
|         if( hCaller == NULL ) | ||||
|         { | ||||
|             dwMessageId = ERROR_INVALID_PARAMETER; | ||||
|             goto end; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if( handle != RTLD_NEXT ) | ||||
|     { | ||||
|         symbol = GetProcAddress( (HMODULE) handle, name ); | ||||
| 
 | ||||
|         if( symbol != NULL ) | ||||
|             goto end; | ||||
|     } | ||||
| 
 | ||||
|     /* If the handle for the original program file is passed, also search
 | ||||
|      * in all globally loaded objects. | ||||
|      */ | ||||
| 
 | ||||
|     if( hModule == handle || handle == RTLD_NEXT ) | ||||
|     { | ||||
|         HANDLE hCurrentProc; | ||||
|         HMODULE *modules; | ||||
|         DWORD cbNeeded; | ||||
|         DWORD dwSize; | ||||
|         size_t i; | ||||
| 
 | ||||
|         hCurrentProc = GetCurrentProcess( ); | ||||
| 
 | ||||
|         /* GetModuleHandle( NULL ) only returns the current program file. So
 | ||||
|          * if we want to get ALL loaded module including those in linked DLLs, | ||||
|          * we have to use EnumProcessModules( ). | ||||
|          */ | ||||
|         if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) | ||||
|         { | ||||
|             modules = (HMODULE *)malloc( dwSize ); | ||||
|             if( modules ) | ||||
|             { | ||||
|                 if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) | ||||
|                 { | ||||
|                     for( i = 0; i < dwSize / sizeof( HMODULE ); i++ ) | ||||
|                     { | ||||
|                         if( handle == RTLD_NEXT && hCaller ) | ||||
|                         { | ||||
|                             /* Next modules can be used for RTLD_NEXT */ | ||||
|                             if( hCaller == modules[i] ) | ||||
|                                 hCaller = NULL; | ||||
|                             continue; | ||||
|                         } | ||||
|                         if( local_search( modules[i] ) ) | ||||
|                             continue; | ||||
|                         symbol = GetProcAddress( modules[i], name ); | ||||
|                         if( symbol != NULL ) | ||||
|                         { | ||||
|                             free( modules ); | ||||
|                             goto end; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
|                 free( modules ); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 dwMessageId = ERROR_NOT_ENOUGH_MEMORY; | ||||
|                 goto end; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| end: | ||||
|     if( symbol == NULL ) | ||||
|     { | ||||
|         if( !dwMessageId ) | ||||
|             dwMessageId = ERROR_PROC_NOT_FOUND; | ||||
|         save_err_str( name, dwMessageId ); | ||||
|     } | ||||
| 
 | ||||
|     return *(void **) (&symbol); | ||||
| } | ||||
| 
 | ||||
| DLFCN_EXPORT | ||||
| char *dlerror( void ) | ||||
| { | ||||
|     /* If this is the second consecutive call to dlerror, return NULL */ | ||||
|     if( !error_occurred ) | ||||
|         return NULL; | ||||
| 
 | ||||
|     /* POSIX says that invoking dlerror( ) a second time, immediately following
 | ||||
|      * a prior invocation, shall result in NULL being returned. | ||||
|      */ | ||||
|     error_occurred = FALSE; | ||||
| 
 | ||||
|     return error_buffer; | ||||
| } | ||||
| 
 | ||||
| /* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
 | ||||
|  * for details */ | ||||
| 
 | ||||
| /* Get specific image section */ | ||||
| static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size ) | ||||
| { | ||||
|     IMAGE_DOS_HEADER *dosHeader; | ||||
|     IMAGE_NT_HEADERS *ntHeaders; | ||||
|     IMAGE_OPTIONAL_HEADER *optionalHeader; | ||||
| 
 | ||||
|     dosHeader = (IMAGE_DOS_HEADER *) module; | ||||
| 
 | ||||
|     if( dosHeader->e_magic != IMAGE_DOS_SIGNATURE ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     ntHeaders = (IMAGE_NT_HEADERS *) ( (BYTE *) dosHeader + dosHeader->e_lfanew ); | ||||
| 
 | ||||
|     if( ntHeaders->Signature != IMAGE_NT_SIGNATURE ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     optionalHeader = &ntHeaders->OptionalHeader; | ||||
| 
 | ||||
|     if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     if( size != NULL ) | ||||
|         *size = optionalHeader->DataDirectory[index].Size; | ||||
| 
 | ||||
|     *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress ); | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| /* Return symbol name for a given address from export table */ | ||||
| static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, const void *addr, void **func_address ) | ||||
| { | ||||
|     DWORD i; | ||||
|     void *candidateAddr = NULL; | ||||
|     int candidateIndex = -1; | ||||
|     BYTE *base = (BYTE *) module; | ||||
|     DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions); | ||||
|     DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames); | ||||
|     USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals); | ||||
| 
 | ||||
|     for( i = 0; i < ied->NumberOfFunctions; i++ ) | ||||
|     { | ||||
|         if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) ) | ||||
|             continue; | ||||
| 
 | ||||
|         candidateAddr = (void *) ( base + functionAddressesOffsets[i] ); | ||||
|         candidateIndex = i; | ||||
|     } | ||||
| 
 | ||||
|     if( candidateIndex == -1 ) | ||||
|         return NULL; | ||||
| 
 | ||||
|     *func_address = candidateAddr; | ||||
| 
 | ||||
|     for( i = 0; i < ied->NumberOfNames; i++ ) | ||||
|     { | ||||
|         if( functionNameOrdinalsIndexes[i] == candidateIndex ) | ||||
|             return (const char *) ( base + functionNamesOffsets[i] ); | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| static BOOL is_valid_address( const void *addr ) | ||||
| { | ||||
|     MEMORY_BASIC_INFORMATION info; | ||||
|     SIZE_T result; | ||||
| 
 | ||||
|     if( addr == NULL ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     /* check valid pointer */ | ||||
|     result = VirtualQuery( addr, &info, sizeof( info ) ); | ||||
| 
 | ||||
|     if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| /* Return state if address points to an import thunk
 | ||||
|  * | ||||
|  * An import thunk is setup with a 'jmp' instruction followed by an | ||||
|  * absolute address (32bit) or relative offset (64bit) pointing into | ||||
|  * the import address table (iat), which is partially maintained by | ||||
|  * the runtime linker. | ||||
|  */ | ||||
| static BOOL is_import_thunk( const void *addr ) | ||||
| { | ||||
|     return *(short *) addr == 0x25ff ? TRUE : FALSE; | ||||
| } | ||||
| 
 | ||||
| /* Return adress from the import address table (iat),
 | ||||
|  * if the original address points to a thunk table entry. | ||||
|  */ | ||||
| static void *get_address_from_import_address_table( void *iat, DWORD iat_size, const void *addr ) | ||||
| { | ||||
|     BYTE *thkp = (BYTE *) addr; | ||||
|     /* Get offset from thunk table (after instruction 0xff 0x25)
 | ||||
|      *   4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 | ||||
|      */ | ||||
|     ULONG offset = *(ULONG *)( thkp + 2 ); | ||||
| #ifdef _WIN64 | ||||
|     /* On 64 bit the offset is relative
 | ||||
|      *      4018c8:   ff 25 4a 8a 00 00    jmpq    *0x8a4a(%rip)    # 40a318 <__imp_VirtualQuery> | ||||
|      * And can be also negative (MSVC in WDK) | ||||
|      *   100002f20:   ff 25 3a e1 ff ff    jmpq   *-0x1ec6(%rip)    # 0x100001060 | ||||
|      * So cast to signed LONG type | ||||
|      */ | ||||
|     BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset ); | ||||
| #else | ||||
|     /* On 32 bit the offset is absolute
 | ||||
|      *   4019b4:    ff 25 90 71 40 00    jmp    *0x40719 | ||||
|      */ | ||||
|     BYTE *ptr = (BYTE *) offset; | ||||
| #endif | ||||
| 
 | ||||
|     if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size ) | ||||
|         return NULL; | ||||
| 
 | ||||
|     return *(void **) ptr; | ||||
| } | ||||
| 
 | ||||
| /* Holds module filename */ | ||||
| static char module_filename[2*MAX_PATH]; | ||||
| 
 | ||||
| static BOOL fill_info( const void *addr, Dl_info *info ) | ||||
| { | ||||
|     HMODULE hModule; | ||||
|     DWORD dwSize; | ||||
|     IMAGE_EXPORT_DIRECTORY *ied; | ||||
|     void *funcAddress = NULL; | ||||
| 
 | ||||
|     /* Get module of the specified address */ | ||||
|     hModule = MyGetModuleHandleFromAddress( addr ); | ||||
| 
 | ||||
|     if( hModule == NULL ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) ); | ||||
| 
 | ||||
|     if( dwSize == 0 || dwSize == sizeof( module_filename ) ) | ||||
|         return FALSE; | ||||
| 
 | ||||
|     info->dli_fname = module_filename; | ||||
|     info->dli_fbase = (void *) hModule; | ||||
| 
 | ||||
|     /* Find function name and function address in module's export table */ | ||||
|     if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) ) | ||||
|         info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress ); | ||||
|     else | ||||
|         info->dli_sname = NULL; | ||||
| 
 | ||||
|     info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : (void *) addr; | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| DLFCN_EXPORT | ||||
| int dladdr( const void *addr, Dl_info *info ) | ||||
| { | ||||
|     if( info == NULL ) | ||||
|         return 0; | ||||
| 
 | ||||
|     if( !is_valid_address( addr ) ) | ||||
|         return 0; | ||||
| 
 | ||||
|     if( is_import_thunk( addr ) ) | ||||
|     { | ||||
|         void *iat; | ||||
|         DWORD iatSize; | ||||
|         HMODULE hModule; | ||||
| 
 | ||||
|         /* Get module of the import thunk address */ | ||||
|         hModule = MyGetModuleHandleFromAddress( addr ); | ||||
| 
 | ||||
|         if( hModule == NULL ) | ||||
|             return 0; | ||||
| 
 | ||||
|         if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) | ||||
|         { | ||||
|             /* Fallback for cases where the iat is not defined,
 | ||||
|              * for example i586-mingw32msvc-gcc */ | ||||
|             IMAGE_IMPORT_DESCRIPTOR *iid; | ||||
|             DWORD iidSize; | ||||
| 
 | ||||
|             if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) ) | ||||
|                 return 0; | ||||
| 
 | ||||
|             if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) | ||||
|                 return 0; | ||||
| 
 | ||||
|             iat = (void *)( (BYTE *) hModule + iid->FirstThunk ); | ||||
|             /* We assume that in this case iid and iat's are in linear order */ | ||||
|             iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); | ||||
|         } | ||||
| 
 | ||||
|         addr = get_address_from_import_address_table( iat, iatSize, addr ); | ||||
| 
 | ||||
|         if( !is_valid_address( addr ) ) | ||||
|             return 0; | ||||
|     } | ||||
| 
 | ||||
|     if( !fill_info( addr, info ) ) | ||||
|         return 0; | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| #ifdef DLFCN_WIN32_SHARED | ||||
| BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) | ||||
| { | ||||
|     (void) hinstDLL; | ||||
|     (void) fdwReason; | ||||
|     (void) lpvReserved; | ||||
|     return TRUE; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										94
									
								
								libs/dlfcn-win32/dlfcn.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								libs/dlfcn-win32/dlfcn.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | |||
| /*
 | ||||
|  * dlfcn-win32 | ||||
|  * Copyright (c) 2007 Ramiro Polla | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef DLFCN_H | ||||
| #define DLFCN_H | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #if defined(DLFCN_WIN32_SHARED) | ||||
| #if defined(DLFCN_WIN32_EXPORTS) | ||||
| #   define DLFCN_EXPORT __declspec(dllexport) | ||||
| #else | ||||
| #   define DLFCN_EXPORT __declspec(dllimport) | ||||
| #endif | ||||
| #else | ||||
| #   define DLFCN_EXPORT | ||||
| #endif | ||||
| 
 | ||||
| /* Relocations are performed when the object is loaded. */ | ||||
| #define RTLD_NOW    0 | ||||
| 
 | ||||
| /* Relocations are performed at an implementation-defined time.
 | ||||
|  * Windows API does not support lazy symbol resolving (when first reference | ||||
|  * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW. | ||||
|  */ | ||||
| #define RTLD_LAZY   RTLD_NOW | ||||
| 
 | ||||
| /* All symbols are available for relocation processing of other modules. */ | ||||
| #define RTLD_GLOBAL (1 << 1) | ||||
| 
 | ||||
| /* All symbols are not made available for relocation processing by other modules. */ | ||||
| #define RTLD_LOCAL  (1 << 2) | ||||
| 
 | ||||
| /* These two were added in The Open Group Base Specifications Issue 6.
 | ||||
|  * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. | ||||
|  */ | ||||
| 
 | ||||
| /* The symbol lookup happens in the normal global scope. */ | ||||
| #define RTLD_DEFAULT    ((void *)0) | ||||
| 
 | ||||
| /* Specifies the next object after this one that defines name. */ | ||||
| #define RTLD_NEXT       ((void *)-1) | ||||
| 
 | ||||
| /* Structure filled in by dladdr() */ | ||||
| typedef struct dl_info | ||||
| { | ||||
|    const char *dli_fname;  /* Filename of defining object (thread unsafe and reused on every call to dladdr) */ | ||||
|    void       *dli_fbase;  /* Load address of that object */ | ||||
|    const char *dli_sname;  /* Name of nearest lower symbol */ | ||||
|    void       *dli_saddr;  /* Exact value of nearest symbol */ | ||||
| } Dl_info; | ||||
| 
 | ||||
| /* Open a symbol table handle. */ | ||||
| DLFCN_EXPORT void *dlopen(const char *file, int mode); | ||||
| 
 | ||||
| /* Close a symbol table handle. */ | ||||
| DLFCN_EXPORT int dlclose(void *handle); | ||||
| 
 | ||||
| /* Get the address of a symbol from a symbol table handle. */ | ||||
| DLFCN_EXPORT void *dlsym(void *handle, const char *name); | ||||
| 
 | ||||
| /* Get diagnostic information. */ | ||||
| DLFCN_EXPORT char *dlerror(void); | ||||
| 
 | ||||
| /* Translate address to symbolic information (no POSIX standard) */ | ||||
| DLFCN_EXPORT int dladdr(const void *addr, Dl_info *info); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* DLFCN_H */ | ||||
|  | @ -3607,6 +3607,7 @@ static int fstReaderRecreateHierFile(struct fstReaderContext *xc) | |||
|             fflush(xc->f); | ||||
| #endif | ||||
|             zfd = dup(fileno(xc->f)); | ||||
| 	    lseek(zfd, ftell(xc->f), SEEK_SET); | ||||
|             zhandle = gzdopen(zfd, "rb"); | ||||
|             if (!zhandle) { | ||||
|                 close(zfd); | ||||
|  | @ -4272,6 +4273,7 @@ int fstReaderInit(struct fstReaderContext *xc) | |||
| #endif | ||||
| 
 | ||||
|         zfd = dup(fileno(xc->f)); | ||||
| 	lseek(zfd, ftell(xc->f), SEEK_SET); | ||||
|         zhandle = gzdopen(zfd, "rb"); | ||||
|         if (zhandle) { | ||||
|             for (offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) { | ||||
|  |  | |||
|  | @ -902,6 +902,11 @@ widening it to 1-bit, or removing the cell altogether. | |||
| This command replaces clocked flip-flops with generic $ff cells that use the | ||||
| implicit global clock. This is useful for formal verification of designs with | ||||
| multiple clocks. | ||||
| 
 | ||||
| This pass assumes negative hold time for the async FF inputs. For example when | ||||
| a reset deasserts with the clock edge, then the FF output will still drive the | ||||
| reset value in the next cycle regardless of the data-in value at the time of | ||||
| the clock edge. | ||||
| \end{lstlisting} | ||||
| 
 | ||||
| \section{clkbufmap -- insert clock buffers on clock networks} | ||||
|  | @ -1554,12 +1559,17 @@ after an optimization pass. | |||
|     -undef | ||||
|         enable modelling of undef states during equiv_induct. | ||||
| 
 | ||||
|     -nocheck | ||||
|         disable running check before and after the command under test. | ||||
| 
 | ||||
| The following commands are executed by this verification command: | ||||
| 
 | ||||
|     run_pass: | ||||
|         hierarchy -auto-top | ||||
|         design -save preopt | ||||
|         check -assert    (unless -nocheck) | ||||
|         [command] | ||||
|         check -assert    (unless -nocheck) | ||||
|         design -stash postopt | ||||
| 
 | ||||
|     prepare: | ||||
|  | @ -3122,6 +3132,12 @@ detected. | |||
|         call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit. | ||||
| 
 | ||||
| 
 | ||||
|     -cross | ||||
|         allow output ports on the gold module to match input ports on the | ||||
|         gate module. This is useful when the gold module contains additional | ||||
|         logic to drive some of the gate module inputs. | ||||
| 
 | ||||
| 
 | ||||
|     miter -assert [options] module [miter_name] | ||||
| 
 | ||||
| Creates a miter circuit for property checking. All input ports are kept, | ||||
|  | @ -3989,6 +4005,19 @@ the language version (and before file names) to set additional verilog defines. | |||
| Load the specified VHDL files. (Requires Verific.) | ||||
| 
 | ||||
| 
 | ||||
|     read {-edif} <edif-file>.. | ||||
| 
 | ||||
| Load the specified EDIF files. (Requires Verific.) | ||||
| 
 | ||||
| 
 | ||||
|     read {-liberty} <liberty-file>.. | ||||
| 
 | ||||
| Load the specified Liberty files. | ||||
| 
 | ||||
|     -lib | ||||
|         only create empty blackbox modules | ||||
| 
 | ||||
| 
 | ||||
|     read {-f|-F} <command-file> | ||||
| 
 | ||||
| Load and execute the specified command file. (Requires Verific.) | ||||
|  | @ -7926,6 +7955,20 @@ Like -sv, but define FORMAL instead of SYNTHESIS. | |||
| Load the specified VHDL files into Verific. | ||||
| 
 | ||||
| 
 | ||||
|     verific {-edif} <edif-file>.. | ||||
| 
 | ||||
| Load the specified EDIF files into Verific. | ||||
| 
 | ||||
| 
 | ||||
|     verific {-liberty} <liberty-file>.. | ||||
| 
 | ||||
| Load the specified Liberty files into Verific. | ||||
| Default library when -work is not present is one specified in liberty file. | ||||
| To use from SystemVerilog or VHDL use -L to specify liberty library. | ||||
|     -lib | ||||
|         only create empty blackbox modules | ||||
| 
 | ||||
| 
 | ||||
|     verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009| | ||||
|                      -sv2012|-sv|-formal] <command-file> | ||||
| 
 | ||||
|  | @ -8032,6 +8075,10 @@ Import options: | |||
|   -fullinit | ||||
|     Keep all register initializations, even those for non-FF registers. | ||||
| 
 | ||||
|   -cells | ||||
|     Import all cell definitions from Verific loaded libraries even if they are | ||||
|     unused in design. Useful with "-edif" and "-liberty" option. | ||||
| 
 | ||||
|   -chparam name value  | ||||
|     Elaborate the specified top modules (all modules when -all given) using | ||||
|     this parameter value. Modules on which this parameter does not exist will | ||||
|  |  | |||
|  | @ -1494,7 +1494,7 @@ skip_identity: | |||
| 			RTLIL::SigSpec input = assign_map(cell->getPort(ID::S)); | ||||
| 			RTLIL::SigSpec inA = assign_map(cell->getPort(ID::A)); | ||||
| 			RTLIL::SigSpec inB = assign_map(cell->getPort(ID::B)); | ||||
| 			if (input.is_fully_const()) | ||||
| 			if (input.is_fully_const() && (!keepdc || input.is_fully_def())) | ||||
| 				ACTION_DO(ID::Y, input.as_bool() ? cell->getPort(ID::B) : cell->getPort(ID::A)); | ||||
| 			else if (inA == inB) | ||||
| 				ACTION_DO(ID::Y, cell->getPort(ID::A)); | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 	bool flag_make_outcmp = false; | ||||
| 	bool flag_make_assert = false; | ||||
| 	bool flag_flatten = false; | ||||
| 	bool flag_cross = false; | ||||
| 
 | ||||
| 	log_header(design, "Executing MITER pass (creating miter circuit).\n"); | ||||
| 
 | ||||
|  | @ -57,6 +58,10 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 			flag_flatten = true; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (args[argidx] == "-cross") { | ||||
| 			flag_cross = true; | ||||
| 			continue; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	if (argidx+3 != args.size() || args[argidx].compare(0, 1, "-") == 0) | ||||
|  | @ -75,6 +80,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 
 | ||||
| 	RTLIL::Module *gold_module = design->module(gold_name); | ||||
| 	RTLIL::Module *gate_module = design->module(gate_name); | ||||
| 	pool<Wire*> gold_cross_ports; | ||||
| 
 | ||||
| 	for (auto gold_wire : gold_module->wires()) { | ||||
| 		if (gold_wire->port_id == 0) | ||||
|  | @ -82,12 +88,17 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 		RTLIL::Wire *gate_wire = gate_module->wire(gold_wire->name); | ||||
| 		if (gate_wire == nullptr) | ||||
| 			goto match_gold_port_error; | ||||
| 		if (gold_wire->width != gate_wire->width) | ||||
| 			goto match_gold_port_error; | ||||
| 		if (flag_cross && !gold_wire->port_input && gold_wire->port_output && | ||||
| 				gate_wire->port_input && !gate_wire->port_output) { | ||||
| 			gold_cross_ports.insert(gold_wire); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (gold_wire->port_input != gate_wire->port_input) | ||||
| 			goto match_gold_port_error; | ||||
| 		if (gold_wire->port_output != gate_wire->port_output) | ||||
| 			goto match_gold_port_error; | ||||
| 		if (gold_wire->width != gate_wire->width) | ||||
| 			goto match_gold_port_error; | ||||
| 		continue; | ||||
| 	match_gold_port_error: | ||||
| 		log_cmd_error("No matching port in gate module was found for %s!\n", gold_wire->name.c_str()); | ||||
|  | @ -99,12 +110,15 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 		RTLIL::Wire *gold_wire = gold_module->wire(gate_wire->name); | ||||
| 		if (gold_wire == nullptr) | ||||
| 			goto match_gate_port_error; | ||||
| 		if (gate_wire->width != gold_wire->width) | ||||
| 			goto match_gate_port_error; | ||||
| 		if (flag_cross && !gold_wire->port_input && gold_wire->port_output && | ||||
| 				gate_wire->port_input && !gate_wire->port_output) | ||||
| 			continue; | ||||
| 		if (gate_wire->port_input != gold_wire->port_input) | ||||
| 			goto match_gate_port_error; | ||||
| 		if (gate_wire->port_output != gold_wire->port_output) | ||||
| 			goto match_gate_port_error; | ||||
| 		if (gate_wire->width != gold_wire->width) | ||||
| 			goto match_gate_port_error; | ||||
| 		continue; | ||||
| 	match_gate_port_error: | ||||
| 		log_cmd_error("No matching port in gold module was found for %s!\n", gate_wire->name.c_str()); | ||||
|  | @ -123,6 +137,14 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: | |||
| 
 | ||||
| 	for (auto gold_wire : gold_module->wires()) | ||||
| 	{ | ||||
| 		if (gold_cross_ports.count(gold_wire)) | ||||
| 		{ | ||||
| 			RTLIL::Wire *w = miter_module->addWire("\\cross_" + RTLIL::unescape_id(gold_wire->name), gold_wire->width); | ||||
| 			gold_cell->setPort(gold_wire->name, w); | ||||
| 			gate_cell->setPort(gold_wire->name, w); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (gold_wire->port_input) | ||||
| 		{ | ||||
| 			RTLIL::Wire *w = miter_module->addWire("\\in_" + RTLIL::unescape_id(gold_wire->name), gold_wire->width); | ||||
|  | @ -384,6 +406,12 @@ struct MiterPass : public Pass { | |||
| 		log("        call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -cross\n"); | ||||
| 		log("        allow output ports on the gold module to match input ports on the\n"); | ||||
| 		log("        gate module. This is useful when the gold module contains additional\n"); | ||||
| 		log("        logic to drive some of the gate module inputs.\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("    miter -assert [options] module [miter_name]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Creates a miter circuit for property checking. All input ports are kept,\n"); | ||||
|  |  | |||
|  | @ -758,6 +758,7 @@ struct SatHelper | |||
| 		if (last_timestep == -2) | ||||
| 			log("  no model variables selected for display.\n"); | ||||
| 
 | ||||
| 		fprintf(f, "#%d\n", last_timestep+1); | ||||
| 		fclose(f); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -813,18 +813,6 @@ struct SimInstance | |||
| 			std::string v = shared->fst->valueOf(item.second); | ||||
| 			did_something |= set_state(item.first, Const::from_string(v)); | ||||
| 		} | ||||
| 		for (auto &it : ff_database) | ||||
| 		{ | ||||
| 			ff_state_t &ff = it.second; | ||||
| 			SigSpec dsig = it.second.data.sig_d; | ||||
| 			Const value = get_state(dsig); | ||||
| 			if (dsig.is_wire()) { | ||||
| 				ff.past_d = value; | ||||
| 				if (ff.data.has_aload) | ||||
| 					ff.past_ad = value; | ||||
| 				did_something |= true; | ||||
| 			} | ||||
| 		} | ||||
| 		for (auto cell : module->cells()) | ||||
| 		{ | ||||
| 			if (cell->is_mem_cell()) { | ||||
|  | @ -1019,6 +1007,16 @@ struct SimWorker : SimShared | |||
| 		top->update_ph3(); | ||||
| 	} | ||||
| 
 | ||||
| 	void initialize_stable_past() | ||||
| 	{ | ||||
| 		if (debug) | ||||
| 			log("\n-- ph1 (initialize) --\n"); | ||||
| 		top->update_ph1(); | ||||
| 		if (debug) | ||||
| 			log("\n-- ph3 (initialize) --\n"); | ||||
| 		top->update_ph3(); | ||||
| 	} | ||||
| 
 | ||||
| 	void set_inports(pool<IdString> ports, State value) | ||||
| 	{ | ||||
| 		for (auto portname : ports) | ||||
|  | @ -1191,6 +1189,7 @@ struct SimWorker : SimShared | |||
| 
 | ||||
| 				if (initial) { | ||||
| 					did_something |= top->setInitState(); | ||||
| 					initialize_stable_past(); | ||||
| 					initial = false; | ||||
| 				} | ||||
| 				if (did_something) | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ kernel/register.o: techlibs/common/simlib_help.inc techlibs/common/simcells_help | |||
| $(eval $(call add_share_file,share,techlibs/common/simlib.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/simcells.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/techmap.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/smtmap.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/pmux2mux.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/adff2dff.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/dff2ff.v)) | ||||
|  |  | |||
|  | @ -1279,14 +1279,9 @@ parameter WIDTH = 0; | |||
| 
 | ||||
| input [WIDTH-1:0] A, B; | ||||
| input S; | ||||
| output reg [WIDTH-1:0] Y; | ||||
| output [WIDTH-1:0] Y; | ||||
| 
 | ||||
| always @* begin | ||||
| 	if (S) | ||||
| 		Y = B; | ||||
| 	else | ||||
| 		Y = A; | ||||
| end | ||||
| assign Y = S ? B : A; | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										28
									
								
								techlibs/common/smtmap.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								techlibs/common/smtmap.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| (* techmap_celltype = "$pmux" *) | ||||
| module smt_pmux (A, B, S, Y); | ||||
| 	parameter WIDTH = 1; | ||||
| 	parameter S_WIDTH = 1; | ||||
| 
 | ||||
| 	(* force_downto *) | ||||
| 	input [WIDTH-1:0] A; | ||||
| 	(* force_downto *) | ||||
| 	input [WIDTH*S_WIDTH-1:0] B; | ||||
| 	(* force_downto *) | ||||
| 	input [S_WIDTH-1:0] S; | ||||
| 	(* force_downto *) | ||||
| 	output [WIDTH-1:0] Y; | ||||
| 
 | ||||
| 	(* force_downto *) | ||||
| 	wire [WIDTH-1:0] Y_B; | ||||
| 
 | ||||
| 	genvar i, j; | ||||
| 	generate | ||||
| 		(* force_downto *) | ||||
| 		wire [WIDTH*(S_WIDTH+1)-1:0] C; | ||||
| 
 | ||||
| 		assign C[WIDTH-1:0] = A; | ||||
| 		for (i = 0; i < S_WIDTH; i = i + 1) | ||||
| 			assign C[WIDTH*(i+2)-1:WIDTH*(i+1)] = S[i] ? B[WIDTH*(i+1)-1:WIDTH*i] : C[WIDTH*(i+1)-1:WIDTH*i]; | ||||
| 		assign Y = C[WIDTH*(S_WIDTH+1)-1:WIDTH*S_WIDTH]; | ||||
| 	endgenerate | ||||
| endmodule | ||||
|  | @ -3,7 +3,7 @@ set -eu | |||
| source ../gen-tests-makefile.sh | ||||
| echo "Generate FST for sim models" | ||||
| find tb/* -name tb*.v | while read name; do | ||||
|     test_name=$(basename -s .v $name) | ||||
|     test_name=$(basename $name .v) | ||||
|     echo "Test $test_name" | ||||
|     verilog_name=${test_name:3}.v | ||||
|     iverilog -o tb/$test_name.out $name $verilog_name | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue