mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-07 01:54:10 +00:00
Merge branch 'YosysHQ:master' into master
This commit is contained in:
commit
15d41041d8
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…
Reference in a new issue