mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-26 02:30:37 +00:00
Merge branch 'YosysHQ:main' into master
This commit is contained in:
commit
2df3a55221
96 changed files with 1950 additions and 1073 deletions
2
.github/actions/setup-build-env/action.yml
vendored
2
.github/actions/setup-build-env/action.yml
vendored
|
|
@ -8,7 +8,7 @@ runs:
|
|||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
|
||||
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
|
|
|
|||
9
.github/workflows/test-compile.yml
vendored
9
.github/workflows/test-compile.yml
vendored
|
|
@ -30,18 +30,15 @@ jobs:
|
|||
- ubuntu-latest
|
||||
compiler:
|
||||
# oldest supported
|
||||
- 'clang-14'
|
||||
- 'clang-10'
|
||||
- 'gcc-10'
|
||||
# newest, make sure to update maximum standard step to match
|
||||
- 'clang-18'
|
||||
- 'clang-19'
|
||||
- 'gcc-13'
|
||||
include:
|
||||
# macOS
|
||||
- os: macos-13
|
||||
compiler: 'clang'
|
||||
# oldest clang not available on ubuntu-latest
|
||||
- os: ubuntu-20.04
|
||||
compiler: 'clang-10'
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
|
|
@ -72,7 +69,7 @@ jobs:
|
|||
|
||||
# maximum standard, only on newest compilers
|
||||
- name: Build C++20
|
||||
if: ${{ matrix.compiler == 'clang-18' || matrix.compiler == 'gcc-13' }}
|
||||
if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-13' }}
|
||||
shell: bash
|
||||
run: |
|
||||
make config-$CC_SHORT
|
||||
|
|
|
|||
14
CHANGELOG
14
CHANGELOG
|
|
@ -2,9 +2,21 @@
|
|||
List of major changes and improvements between releases
|
||||
=======================================================
|
||||
|
||||
Yosys 0.48 .. Yosys 0.49-dev
|
||||
Yosys 0.49 .. Yosys 0.50-dev
|
||||
--------------------------
|
||||
|
||||
Yosys 0.48 .. Yosys 0.49
|
||||
--------------------------
|
||||
* Various
|
||||
- "$scopeinfo" cells are now part of JSON export by default.
|
||||
- Added option to specify hierarchical separator for "flatten".
|
||||
- Improved "wreduce" to handle more cases of operator size reduction.
|
||||
- Updated hashing interface, see docs/source/yosys_internals/hashing.rst
|
||||
for breaking API changes.
|
||||
|
||||
* New commands and options
|
||||
- Added "-noscopeinfo" option to "json" and "write_json" pass.
|
||||
|
||||
Yosys 0.47 .. Yosys 0.48
|
||||
--------------------------
|
||||
* Various
|
||||
|
|
|
|||
2
COPYING
2
COPYING
|
|
@ -1,6 +1,6 @@
|
|||
ISC License
|
||||
|
||||
Copyright (C) 2012 - 2020 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
|||
217
Makefile
217
Makefile
|
|
@ -2,9 +2,7 @@
|
|||
CONFIG := none
|
||||
# CONFIG := clang
|
||||
# CONFIG := gcc
|
||||
# CONFIG := afl-gcc
|
||||
# CONFIG := wasi
|
||||
# CONFIG := mxe
|
||||
# CONFIG := msys2-32
|
||||
# CONFIG := msys2-64
|
||||
|
||||
|
|
@ -155,7 +153,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.48+0
|
||||
YOSYS_VER := 0.49+1
|
||||
|
||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||
|
|
@ -171,7 +169,7 @@ endif
|
|||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
bumpversion:
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline aaa5347.. | wc -l`/;" Makefile
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 427b5a2.. | wc -l`/;" Makefile
|
||||
|
||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
||||
|
||||
|
|
@ -265,16 +263,6 @@ ifeq ($(DISABLE_ABC_THREADS),1)
|
|||
ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
|
||||
endif
|
||||
|
||||
else ifeq ($(CONFIG),afl-gcc)
|
||||
CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),cygwin)
|
||||
CXX = g++
|
||||
CXXFLAGS += -std=gnu++11 $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),wasi)
|
||||
ifeq ($(WASI_SDK),)
|
||||
CXX = clang++
|
||||
|
|
@ -302,18 +290,6 @@ LINK_ABC := 1
|
|||
DISABLE_ABC_THREADS := 1
|
||||
endif
|
||||
|
||||
else ifeq ($(CONFIG),mxe)
|
||||
PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
|
||||
CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -Wno-attributes
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s
|
||||
LIBS := $(filter-out -lrt,$(LIBS))
|
||||
ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||
# TODO: Try to solve pthread linking issue in more appropriate way
|
||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LINKFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
|
||||
EXE = .exe
|
||||
|
||||
else ifeq ($(CONFIG),msys2-32)
|
||||
CXX = i686-w64-mingw32-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
|
|
@ -340,7 +316,7 @@ ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
|||
LTOFLAGS =
|
||||
|
||||
else
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, mxe, msys2-32, msys2-64, none)
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, msys2-32, msys2-64, none)
|
||||
endif
|
||||
|
||||
|
||||
|
|
@ -392,9 +368,6 @@ ifeq ($(LINK_TERMCAP),1)
|
|||
LIBS += -ltermcap
|
||||
ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap"
|
||||
endif
|
||||
ifeq ($(CONFIG),mxe)
|
||||
LIBS += -ltermcap
|
||||
endif
|
||||
else
|
||||
ifeq ($(ENABLE_EDITLINE),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_EDITLINE
|
||||
|
|
@ -443,17 +416,12 @@ TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
|
|||
TCL_LIBS ?= -l$(TCL_VERSION)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG),mxe)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_TCL
|
||||
LIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
|
||||
else
|
||||
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
|
||||
LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS))
|
||||
ifneq (,$(findstring TCL_WITH_EXTERNAL_TOMMATH,$(CXXFLAGS)))
|
||||
LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libtommath || echo)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_GCOV),1)
|
||||
CXXFLAGS += --coverage
|
||||
|
|
@ -842,71 +810,101 @@ else
|
|||
ABCOPT=""
|
||||
endif
|
||||
|
||||
# When YOSYS_NOVERIFIC is set as a make variable, also export it to the
|
||||
# enviornment, so that `YOSYS_NOVERIFIC=1 make test` _and_
|
||||
# `make test YOSYS_NOVERIFIC=1` will run with verific disabled.
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
export YOSYS_NOVERIFIC
|
||||
# Tests that generate .mk with tests/gen-tests-makefile.sh
|
||||
MK_TEST_DIRS =
|
||||
MK_TEST_DIRS += tests/arch/anlogic
|
||||
MK_TEST_DIRS += tests/arch/ecp5
|
||||
MK_TEST_DIRS += tests/arch/efinix
|
||||
MK_TEST_DIRS += tests/arch/gatemate
|
||||
MK_TEST_DIRS += tests/arch/gowin
|
||||
MK_TEST_DIRS += tests/arch/ice40
|
||||
MK_TEST_DIRS += tests/arch/intel_alm
|
||||
MK_TEST_DIRS += tests/arch/machxo2
|
||||
MK_TEST_DIRS += tests/arch/microchip
|
||||
MK_TEST_DIRS += tests/arch/nanoxplore
|
||||
MK_TEST_DIRS += tests/arch/nexus
|
||||
MK_TEST_DIRS += tests/arch/quicklogic/pp3
|
||||
MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f
|
||||
MK_TEST_DIRS += tests/arch/xilinx
|
||||
MK_TEST_DIRS += tests/opt
|
||||
MK_TEST_DIRS += tests/sat
|
||||
MK_TEST_DIRS += tests/sim
|
||||
MK_TEST_DIRS += tests/svtypes
|
||||
MK_TEST_DIRS += tests/techmap
|
||||
MK_TEST_DIRS += tests/various
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifneq ($(YOSYS_NOVERIFIC),1)
|
||||
MK_TEST_DIRS += tests/verific
|
||||
endif
|
||||
endif
|
||||
MK_TEST_DIRS += tests/verilog
|
||||
|
||||
# Tests that don't generate .mk
|
||||
SH_TEST_DIRS =
|
||||
SH_TEST_DIRS += tests/simple
|
||||
SH_TEST_DIRS += tests/simple_abc9
|
||||
SH_TEST_DIRS += tests/hana
|
||||
SH_TEST_DIRS += tests/asicworld
|
||||
# SH_TEST_DIRS += tests/realmath
|
||||
SH_TEST_DIRS += tests/share
|
||||
SH_TEST_DIRS += tests/opt_share
|
||||
SH_TEST_DIRS += tests/fsm
|
||||
SH_TEST_DIRS += tests/memlib
|
||||
SH_TEST_DIRS += tests/bram
|
||||
SH_TEST_DIRS += tests/svinterfaces
|
||||
SH_TEST_DIRS += tests/xprop
|
||||
SH_TEST_DIRS += tests/select
|
||||
SH_TEST_DIRS += tests/proc
|
||||
SH_TEST_DIRS += tests/blif
|
||||
SH_TEST_DIRS += tests/arch
|
||||
SH_TEST_DIRS += tests/rpc
|
||||
SH_TEST_DIRS += tests/memfile
|
||||
SH_TEST_DIRS += tests/fmt
|
||||
SH_TEST_DIRS += tests/cxxrtl
|
||||
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
|
||||
SH_TEST_DIRS += tests/functional
|
||||
endif
|
||||
|
||||
test: $(TARGETS) $(EXTRA_TARGETS)
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
@echo
|
||||
@echo "Running tests without verific support due to YOSYS_NOVERIFIC=1"
|
||||
@echo
|
||||
else
|
||||
+cd tests/verific && bash run-test.sh $(SEEDOPT)
|
||||
endif
|
||||
endif
|
||||
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
|
||||
# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/opt_share && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/techmap && bash run-test.sh
|
||||
+cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
|
||||
+cd tests/memlib && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/bram && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/various && bash run-test.sh
|
||||
+cd tests/select && bash run-test.sh
|
||||
+cd tests/sat && bash run-test.sh
|
||||
+cd tests/sim && bash run-test.sh
|
||||
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/svtypes && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/proc && bash run-test.sh
|
||||
+cd tests/blif && bash run-test.sh
|
||||
+cd tests/opt && bash run-test.sh
|
||||
+cd tests/aiger && bash run-test.sh $(ABCOPT)
|
||||
+cd tests/arch && bash run-test.sh
|
||||
+cd tests/arch/ice40 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/xilinx && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/ecp5 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/machxo2 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/efinix && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/anlogic && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/gowin && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/nanoxplore && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/nexus && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/microchip && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/rpc && bash run-test.sh
|
||||
+cd tests/memfile && bash run-test.sh
|
||||
+cd tests/verilog && bash run-test.sh
|
||||
+cd tests/xprop && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/fmt && bash run-test.sh
|
||||
+cd tests/cxxrtl && bash run-test.sh
|
||||
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
|
||||
+cd tests/functional && bash run-test.sh
|
||||
endif
|
||||
# Tests that don't generate .mk and need special args
|
||||
SH_ABC_TEST_DIRS =
|
||||
SH_ABC_TEST_DIRS += tests/memories
|
||||
SH_ABC_TEST_DIRS += tests/aiger
|
||||
SH_ABC_TEST_DIRS += tests/alumacc
|
||||
|
||||
# seed-tests/ is a dummy string, not a directory
|
||||
.PHONY: seed-tests
|
||||
seed-tests: $(SH_TEST_DIRS:%=seed-tests/%)
|
||||
.PHONY: seed-tests/%
|
||||
seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd $* && bash run-test.sh $(SEEDOPT)
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
# abcopt-tests/ is a dummy string, not a directory
|
||||
.PHONY: abcopt-tests
|
||||
abcopt-tests: $(SH_ABC_TEST_DIRS:%=abcopt-tests/%)
|
||||
abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT)
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
# makefile-tests/ is a dummy string, not a directory
|
||||
.PHONY: makefile-tests
|
||||
makefile-tests: $(MK_TEST_DIRS:%=makefile-tests/%)
|
||||
# this target actually emits .mk files
|
||||
%.mk:
|
||||
+cd $(dir $*) && bash run-test.sh
|
||||
# this one spawns submake on each
|
||||
makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(MAKE) -C $* -f run-test.mk
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
test: makefile-tests abcopt-tests seed-tests
|
||||
@echo ""
|
||||
@echo " Passed \"make test\"."
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
@echo " Ran tests without verific support due to YOSYS_NOVERIFIC=1."
|
||||
endif
|
||||
endif
|
||||
@echo ""
|
||||
|
||||
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
|
||||
|
|
@ -1101,19 +1099,6 @@ vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
|
|||
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
|
||||
rm -f srcfiles.txt kernel/version.cc
|
||||
|
||||
ifeq ($(CONFIG),mxe)
|
||||
mxebin: $(TARGETS) $(EXTRA_TARGETS)
|
||||
rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
|
||||
mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
|
||||
cp -r $(PROGRAM_PREFIX)yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
cp -r $(PROGRAM_PREFIX)yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
endif
|
||||
echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
|
||||
echo -en 'Documentation at https://yosyshq.net/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
|
||||
zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
endif
|
||||
|
||||
config-clean: clean
|
||||
rm -f Makefile.conf
|
||||
|
||||
|
|
@ -1129,9 +1114,6 @@ config-gcc-static: clean
|
|||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
|
||||
config-afl-gcc: clean
|
||||
echo 'CONFIG := afl-gcc' > Makefile.conf
|
||||
|
||||
config-wasi: clean
|
||||
echo 'CONFIG := wasi' > Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
|
|
@ -1140,10 +1122,6 @@ config-wasi: clean
|
|||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
echo 'ENABLE_ZLIB := 0' >> Makefile.conf
|
||||
|
||||
config-mxe: clean
|
||||
echo 'CONFIG := mxe' > Makefile.conf
|
||||
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
|
||||
|
||||
config-msys2-32: clean
|
||||
echo 'CONFIG := msys2-32' > Makefile.conf
|
||||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||
|
|
@ -1152,9 +1130,6 @@ config-msys2-64: clean
|
|||
echo 'CONFIG := msys2-64' > Makefile.conf
|
||||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||
|
||||
config-cygwin: clean
|
||||
echo 'CONFIG := cygwin' > Makefile.conf
|
||||
|
||||
config-gcov: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
echo 'ENABLE_GCOV := 1' >> Makefile.conf
|
||||
|
|
@ -1183,5 +1158,5 @@ echo-cxx:
|
|||
-include kernel/*.d
|
||||
-include techlibs/*/*.d
|
||||
|
||||
.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc mxebin
|
||||
.PHONY: config-clean config-clang config-gcc config-gcc-static config-afl-gcc config-gprof config-sudo
|
||||
.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc
|
||||
.PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct Scheduler {
|
|||
struct Vertex {
|
||||
T *data;
|
||||
Vertex *prev, *next;
|
||||
pool<Vertex*, hash_ptr_ops> preds, succs;
|
||||
pool<Vertex*> preds, succs;
|
||||
|
||||
Vertex() : data(NULL), prev(this), next(this) {}
|
||||
Vertex(T *data) : data(data), prev(NULL), next(NULL) {}
|
||||
|
|
@ -300,10 +300,10 @@ struct FlowGraph {
|
|||
};
|
||||
|
||||
std::vector<Node*> nodes;
|
||||
dict<const RTLIL::Wire*, pool<Node*, hash_ptr_ops>> wire_comb_defs, wire_sync_defs, wire_uses;
|
||||
dict<Node*, pool<const RTLIL::Wire*>, hash_ptr_ops> node_comb_defs, node_sync_defs, node_uses;
|
||||
dict<const RTLIL::Wire*, pool<Node*>> wire_comb_defs, wire_sync_defs, wire_uses;
|
||||
dict<Node*, pool<const RTLIL::Wire*>> node_comb_defs, node_sync_defs, node_uses;
|
||||
dict<const RTLIL::Wire*, bool> wire_def_inlinable;
|
||||
dict<const RTLIL::Wire*, dict<Node*, bool, hash_ptr_ops>> wire_use_inlinable;
|
||||
dict<const RTLIL::Wire*, dict<Node*, bool>> wire_use_inlinable;
|
||||
dict<RTLIL::SigBit, bool> bit_has_state;
|
||||
|
||||
~FlowGraph()
|
||||
|
|
@ -365,7 +365,7 @@ struct FlowGraph {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool is_inlinable(const RTLIL::Wire *wire, const pool<Node*, hash_ptr_ops> &nodes) const
|
||||
bool is_inlinable(const RTLIL::Wire *wire, const pool<Node*> &nodes) const
|
||||
{
|
||||
// Can the wire be inlined, knowing that the given nodes are reachable?
|
||||
if (nodes.size() != 1)
|
||||
|
|
@ -3080,7 +3080,7 @@ struct CxxrtlWorker {
|
|||
// without feedback arcs can generally be evaluated in a single pass, i.e. it always requires only
|
||||
// a single delta cycle.
|
||||
Scheduler<FlowGraph::Node> scheduler;
|
||||
dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*, hash_ptr_ops> node_vertex_map;
|
||||
dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*> node_vertex_map;
|
||||
for (auto node : flow.nodes)
|
||||
node_vertex_map[node] = scheduler.add(node);
|
||||
for (auto node_comb_def : flow.node_comb_defs) {
|
||||
|
|
@ -3095,7 +3095,7 @@ struct CxxrtlWorker {
|
|||
|
||||
// Find out whether the order includes any feedback arcs.
|
||||
std::vector<FlowGraph::Node*> node_order;
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> evaluated_nodes;
|
||||
pool<FlowGraph::Node*> evaluated_nodes;
|
||||
pool<const RTLIL::Wire*> feedback_wires;
|
||||
for (auto vertex : scheduler.schedule()) {
|
||||
auto node = vertex->data;
|
||||
|
|
@ -3139,7 +3139,7 @@ struct CxxrtlWorker {
|
|||
}
|
||||
|
||||
// Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users.
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> worklist;
|
||||
pool<FlowGraph::Node*> worklist;
|
||||
for (auto node : flow.nodes) {
|
||||
if (node->type == FlowGraph::Node::Type::CELL_EVAL && !is_internal_cell(node->cell->type))
|
||||
worklist.insert(node); // node evaluates a submodule
|
||||
|
|
@ -3159,8 +3159,8 @@ struct CxxrtlWorker {
|
|||
worklist.insert(node); // node drives public wires
|
||||
}
|
||||
}
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*, hash_ptr_ops>> live_wires;
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> live_nodes;
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*>> live_wires;
|
||||
pool<FlowGraph::Node*> live_nodes;
|
||||
while (!worklist.empty()) {
|
||||
auto node = worklist.pop();
|
||||
live_nodes.insert(node);
|
||||
|
|
@ -3290,15 +3290,15 @@ struct CxxrtlWorker {
|
|||
|
||||
// Discover nodes reachable from primary outputs (i.e. outlines) up until primary inputs (i.e. members)
|
||||
// and collect reachable wire users.
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> worklist;
|
||||
pool<FlowGraph::Node*> worklist;
|
||||
for (auto node : flow.nodes) {
|
||||
if (flow.node_comb_defs.count(node))
|
||||
for (auto wire : flow.node_comb_defs[node])
|
||||
if (debug_wire_types[wire].is_outline())
|
||||
worklist.insert(node); // node drives outline
|
||||
}
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*, hash_ptr_ops>> debug_live_wires;
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> debug_live_nodes;
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*>> debug_live_wires;
|
||||
pool<FlowGraph::Node*> debug_live_nodes;
|
||||
while (!worklist.empty()) {
|
||||
auto node = worklist.pop();
|
||||
debug_live_nodes.insert(node);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ struct JsonWriter
|
|||
bool use_selection;
|
||||
bool aig_mode;
|
||||
bool compat_int_mode;
|
||||
bool scopeinfo_mode;
|
||||
|
||||
Design *design;
|
||||
Module *module;
|
||||
|
|
@ -43,9 +44,9 @@ struct JsonWriter
|
|||
dict<SigBit, string> sigids;
|
||||
pool<Aig> aig_models;
|
||||
|
||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) :
|
||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode, bool scopeinfo_mode) :
|
||||
f(f), use_selection(use_selection), aig_mode(aig_mode),
|
||||
compat_int_mode(compat_int_mode) { }
|
||||
compat_int_mode(compat_int_mode), scopeinfo_mode(scopeinfo_mode) { }
|
||||
|
||||
string get_string(string str)
|
||||
{
|
||||
|
|
@ -192,9 +193,7 @@ struct JsonWriter
|
|||
for (auto c : module->cells()) {
|
||||
if (use_selection && !module->selected(c))
|
||||
continue;
|
||||
// Eventually we will want to emit $scopeinfo, but currently this
|
||||
// will break JSON netlist consumers like nextpnr
|
||||
if (c->type == ID($scopeinfo))
|
||||
if (!scopeinfo_mode && c->type == ID($scopeinfo))
|
||||
continue;
|
||||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: {\n", get_name(c->name).c_str());
|
||||
|
|
@ -356,6 +355,9 @@ struct JsonBackend : public Backend {
|
|||
log(" -selected\n");
|
||||
log(" output only select module\n");
|
||||
log("\n");
|
||||
log(" -noscopeinfo\n");
|
||||
log(" don't include $scopeinfo cells in the output\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log("The general syntax of the JSON output created by this command is as follows:\n");
|
||||
log("\n");
|
||||
|
|
@ -601,6 +603,7 @@ struct JsonBackend : public Backend {
|
|||
bool aig_mode = false;
|
||||
bool compat_int_mode = false;
|
||||
bool use_selection = false;
|
||||
bool scopeinfo_mode = true;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
@ -617,13 +620,17 @@ struct JsonBackend : public Backend {
|
|||
use_selection = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noscopeinfo") {
|
||||
scopeinfo_mode = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log_header(design, "Executing JSON backend.\n");
|
||||
|
||||
JsonWriter json_writer(*f, use_selection, aig_mode, compat_int_mode);
|
||||
JsonWriter json_writer(*f, use_selection, aig_mode, compat_int_mode, scopeinfo_mode);
|
||||
json_writer.write_design(design);
|
||||
}
|
||||
} JsonBackend;
|
||||
|
|
@ -648,6 +655,9 @@ struct JsonPass : public Pass {
|
|||
log(" emit 32-bit or smaller fully-defined parameter values directly\n");
|
||||
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||
log("\n");
|
||||
log(" -noscopeinfo\n");
|
||||
log(" don't include $scopeinfo cells in the output\n");
|
||||
log("\n");
|
||||
log("See 'help write_json' for a description of the JSON format used.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
|
@ -656,6 +666,7 @@ struct JsonPass : public Pass {
|
|||
std::string filename;
|
||||
bool aig_mode = false;
|
||||
bool compat_int_mode = false;
|
||||
bool scopeinfo_mode = true;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
@ -672,6 +683,10 @@ struct JsonPass : public Pass {
|
|||
compat_int_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noscopeinfo") {
|
||||
scopeinfo_mode = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -693,7 +708,7 @@ struct JsonPass : public Pass {
|
|||
f = &buf;
|
||||
}
|
||||
|
||||
JsonWriter json_writer(*f, true, aig_mode, compat_int_mode);
|
||||
JsonWriter json_writer(*f, true, aig_mode, compat_int_mode, scopeinfo_mode);
|
||||
json_writer.write_design(design);
|
||||
|
||||
if (!empty) {
|
||||
|
|
|
|||
|
|
@ -1208,7 +1208,7 @@ class SmtOpts:
|
|||
def helpmsg(self):
|
||||
return """
|
||||
-s <solver>
|
||||
set SMT solver: z3, yices, boolector, bitwuzla, cvc4, mathsat, dummy
|
||||
set SMT solver: z3, yices, boolector, bitwuzla, cvc4, cvc5, mathsat, dummy
|
||||
default: yices
|
||||
|
||||
-S <opt>
|
||||
|
|
|
|||
|
|
@ -5,12 +5,35 @@ import os
|
|||
|
||||
project = 'YosysHQ Yosys'
|
||||
author = 'YosysHQ GmbH'
|
||||
copyright ='2024 YosysHQ GmbH'
|
||||
yosys_ver = "0.48"
|
||||
copyright ='2025 YosysHQ GmbH'
|
||||
yosys_ver = "0.49"
|
||||
|
||||
# select HTML theme
|
||||
html_theme = 'furo-ys'
|
||||
html_css_files = ['custom.css']
|
||||
html_theme_options: dict[str] = {
|
||||
"source_repository": "https://github.com/YosysHQ/yosys/",
|
||||
"source_branch": "main",
|
||||
"source_directory": "docs/source/",
|
||||
}
|
||||
|
||||
# try to fix the readthedocs detection
|
||||
html_context: dict[str] = {
|
||||
"READTHEDOCS": True,
|
||||
"display_github": True,
|
||||
"github_user": "YosysHQ",
|
||||
"github_repo": "yosys",
|
||||
"slug": "yosys",
|
||||
}
|
||||
|
||||
# override source_branch if not main
|
||||
git_slug = os.getenv("READTHEDOCS_VERSION_NAME")
|
||||
if git_slug not in [None, "latest", "stable"]:
|
||||
html_theme_options["source_branch"] = git_slug
|
||||
|
||||
# edit only works on branches, not tags
|
||||
if os.getenv("READTHEDOCS_VERSION_TYPE", "branch") != "branch":
|
||||
html_theme_options["top_of_page_buttons"] = ["view"]
|
||||
|
||||
# These folders are copied to the documentation's HTML output
|
||||
html_static_path = ['_static', "_images"]
|
||||
|
|
|
|||
|
|
@ -7,17 +7,6 @@ see :doc:`/introduction`. For a quick guide on how to get started using Yosys,
|
|||
check out :doc:`/getting_started/index`. For the complete list of commands
|
||||
available, go to :ref:`commandindex`.
|
||||
|
||||
.. note::
|
||||
|
||||
This documentation recently went through a major restructure. If you're
|
||||
looking for something from the previous version and can't find it here,
|
||||
please `let us know`_. Documentation from before the restructure can still
|
||||
be found by switching to `version 0.36`_ or earlier. Note that the previous
|
||||
theme does not include a version switcher.
|
||||
|
||||
.. _let us know: https://github.com/YosysHQ/yosys/issues/new/choose
|
||||
.. _version 0.36: https://yosyshq.readthedocs.io/projects/yosys/en/0.36/
|
||||
|
||||
.. todo:: look into command ref improvements
|
||||
|
||||
- Search bar with live drop down suggestions for matching on title /
|
||||
|
|
|
|||
166
docs/source/yosys_internals/hashing.rst
Normal file
166
docs/source/yosys_internals/hashing.rst
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
Hashing and associative data structures in Yosys
|
||||
------------------------------------------------
|
||||
|
||||
Container classes based on hashing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yosys uses ``dict<K, T>`` and ``pool<T>`` as main container classes.
|
||||
``dict<K, T>`` is essentially a replacement for ``std::unordered_map<K, T>``
|
||||
and ``pool<T>`` is a replacement for ``std::unordered_set<T>``.
|
||||
The main characteristics are:
|
||||
|
||||
* ``dict<K, T>`` and ``pool<T>`` are about 2x faster than the std containers
|
||||
(though this claim hasn't been verified for over 10 years)
|
||||
|
||||
* references to elements in a ``dict<K, T>`` or ``pool<T>`` are invalidated by
|
||||
insert and remove operations (similar to ``std::vector<T>`` on ``push_back()``).
|
||||
|
||||
* some iterators are invalidated by ``erase()``. specifically, iterators
|
||||
that have not passed the erased element yet are invalidated. (``erase()``
|
||||
itself returns valid iterator to the next element.)
|
||||
|
||||
* no iterators are invalidated by ``insert()``. elements are inserted at
|
||||
``begin()``. i.e. only a new iterator that starts at ``begin()`` will see the
|
||||
inserted elements.
|
||||
|
||||
* the method ``.count(key, iterator)`` is like ``.count(key)`` but only
|
||||
considers elements that can be reached via the iterator.
|
||||
|
||||
* iterators can be compared. ``it1 < it2`` means that the position of ``t2``
|
||||
can be reached via ``t1`` but not vice versa.
|
||||
|
||||
* the method ``.sort()`` can be used to sort the elements in the container
|
||||
the container stays sorted until elements are added or removed.
|
||||
|
||||
* ``dict<K, T>`` and ``pool<T>`` will have the same order of iteration across
|
||||
all compilers, standard libraries and architectures.
|
||||
|
||||
In addition to ``dict<K, T>`` and ``pool<T>`` there is also an ``idict<K>`` that
|
||||
creates a bijective map from ``K`` to the integers. For example:
|
||||
|
||||
::
|
||||
|
||||
idict<string, 42> si;
|
||||
log("%d\n", si("hello")); // will print 42
|
||||
log("%d\n", si("world")); // will print 43
|
||||
log("%d\n", si.at("world")); // will print 43
|
||||
log("%d\n", si.at("dummy")); // will throw exception
|
||||
log("%s\n", si[42].c_str())); // will print hello
|
||||
log("%s\n", si[43].c_str())); // will print world
|
||||
log("%s\n", si[44].c_str())); // will throw exception
|
||||
|
||||
It is not possible to remove elements from an idict.
|
||||
|
||||
Finally ``mfp<K>`` implements a merge-find set data structure (aka. disjoint-set
|
||||
or union-find) over the type ``K`` ("mfp" = merge-find-promote).
|
||||
|
||||
The hash function
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The hash function generally used in Yosys is the XOR version of DJB2:
|
||||
|
||||
::
|
||||
|
||||
state = ((state << 5) + state) ^ value
|
||||
|
||||
This is an old-school hash designed to hash ASCII characters. Yosys doesn't hash
|
||||
a lot of ASCII text, but it still happens to be a local optimum due to factors
|
||||
described later.
|
||||
|
||||
Hash function quality is multi-faceted and highly dependent on what is being
|
||||
hashed. Yosys isn't concerned by any cryptographic qualities, instead the goal
|
||||
is minimizing total hashing collision risk given the data patterns within Yosys.
|
||||
In general, a good hash function typically folds values into a state accumulator
|
||||
with a mathematical function that is fast to compute and has some beneficial
|
||||
properties. One of these is the avalanche property, which demands that a small
|
||||
change such as flipping a bit or incrementing by one in the input produces a
|
||||
large, unpredictable change in the output. Additionally, the bit independence
|
||||
criterion states that any pair of output bits should change independently when
|
||||
any single input bit is inverted. These properties are important for avoiding
|
||||
hash collision on data patterns like the hash of a sequence not colliding with
|
||||
its permutation, not losing from the state the information added by hashing
|
||||
preceding elements, etc.
|
||||
|
||||
DJB2 lacks these properties. Instead, since Yosys hashes large numbers of data
|
||||
structures composed of incrementing integer IDs, Yosys abuses the predictability
|
||||
of DJB2 to get lower hash collisions, with regular nature of the hashes
|
||||
surviving through the interaction with the "modulo prime" operations in the
|
||||
associative data structures. For example, some most common objects in Yosys are
|
||||
interned ``IdString``\ s of incrementing indices or ``SigBit``\ s with bit
|
||||
offsets into wire (represented by its unique ``IdString`` name) as the typical
|
||||
case. This is what makes DJB2 a local optimum. Additionally, the ADD version of
|
||||
DJB2 (like above but with addition instead of XOR) is used to this end for some
|
||||
types, abandoning the general pattern of folding values into a state value.
|
||||
|
||||
Making a type hashable
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's first take a look at the external interface on a simplified level.
|
||||
Generally, to get the hash for ``T obj``, you would call the utility function
|
||||
``run_hash<T>(const T& obj)``, corresponding to ``hash_ops<T>::hash(obj)``,
|
||||
the default implementation of which uses ``hash_ops<T>::hash_into(Hasher(), obj)``.
|
||||
``Hasher`` is the class actually implementing the hash function, hiding its
|
||||
initialized internal state, and passing it out on ``hash_t yield()`` with
|
||||
perhaps some finalization steps.
|
||||
|
||||
``hash_ops<T>`` is the star of the show. By default it pulls the ``Hasher h``
|
||||
through a ``Hasher T::hash_into(Hasher h)`` method. That's the method you have to
|
||||
implement to make a record (class or struct) type easily hashable with Yosys
|
||||
hashlib associative data structures.
|
||||
|
||||
``hash_ops<T>`` is specialized for built-in types like ``int`` or ``bool`` and
|
||||
treats pointers the same as integers, so it doesn't dereference pointers. Since
|
||||
many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index
|
||||
``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops<Wire*>``
|
||||
and others in ``kernel/hashlib.h`` that actually dereference the pointers and
|
||||
call ``hash_into`` on the instances pointed to.
|
||||
|
||||
``hash_ops<T>`` is also specialized for simple compound types like
|
||||
``std::pair<U>`` by calling hash_into in sequence on its members. For flexible
|
||||
size containers like ``std::vector<U>`` the size of the container is hashed
|
||||
first. That is also how implementing hashing for a custom record data type
|
||||
should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on
|
||||
the ``Hasher h`` you have received for each member in sequence and ``return
|
||||
h;``.
|
||||
|
||||
The ``hash_ops<T>::hash(obj)`` method is not indended to be called when
|
||||
context of implementing the hashing for a record or other compound type.
|
||||
When writing it, you should connect it to ``hash_ops<T>::hash_into(Hasher h)``
|
||||
as shown below. If you have a strong reason to do so, and you have
|
||||
to create a special implementation for top-level hashing, look at how
|
||||
``hash_ops<RTLIL::SigBit>::hash(...)`` is implemented in ``kernel/rtlil.h``.
|
||||
|
||||
Porting plugins from the legacy interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Previously, the interface to implement hashing on custom types was just
|
||||
``unsigned int T::hash() const``. This meant hashes for members were computed
|
||||
independently and then ad-hoc combined with the hash function with some xorshift
|
||||
operations thrown in to mix bits together somewhat. A plugin can stay compatible
|
||||
with both versions prior and after the break by implementing both interfaces
|
||||
based on the existance and value of `YS_HASHING_VERSION`.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: Example hash compatibility wrapper
|
||||
:name: hash_plugin_compat
|
||||
|
||||
#ifndef YS_HASHING_VERSION
|
||||
unsigned int T::hash() const {
|
||||
return mkhash(a, b);
|
||||
}
|
||||
#elif YS_HASHING_VERSION == 1
|
||||
Hasher T::hash_into(Hasher h) const {
|
||||
h.eat(a);
|
||||
h.eat(b);
|
||||
return h;
|
||||
}
|
||||
Hasher T::hash() const {
|
||||
Hasher h;
|
||||
h.eat(*this);
|
||||
return h;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported hashing interface"
|
||||
#endif
|
||||
|
||||
Feel free to contact Yosys maintainers with related issues.
|
||||
|
|
@ -39,3 +39,4 @@ as reference to implement a similar system in any language.
|
|||
extending_yosys/index
|
||||
techmap
|
||||
verilog
|
||||
hashing
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ struct ScopeinfoExamplePass : public Pass {
|
|||
|
||||
// Shuffle wires so this example produces more interesting outputs
|
||||
std::sort(wires.begin(), wires.end(), [](Wire *a, Wire *b) {
|
||||
return mkhash_xorshift(a->name.hash() * 0x2c9277b5) < mkhash_xorshift(b->name.hash() * 0x2c9277b5);
|
||||
return mkhash_xorshift(run_hash(a->name) * 0x2c9277b5) < mkhash_xorshift(run_hash(b->name) * 0x2c9277b5);
|
||||
});
|
||||
|
||||
ModuleHdlnameIndex index(module);
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@
|
|||
};
|
||||
# TODO: don't override src when ./abc is empty
|
||||
# which happens when the command used is `nix build` and not `nix build ?submodules=1`
|
||||
abc-verifier = pkgs.abc-verifier.overrideAttrs(x: y: {src = ./abc;});
|
||||
abc-verifier = pkgs.abc-verifier;
|
||||
yosys = pkgs.clangStdenv.mkDerivation {
|
||||
name = "yosys";
|
||||
src = ./. ;
|
||||
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git pkg-configUpstream llvmPackages.bintools ];
|
||||
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 zlib git pkg-configUpstream llvmPackages.bintools ];
|
||||
checkInputs = with pkgs; [ gtest ];
|
||||
propagatedBuildInputs = [ abc-verifier ];
|
||||
preConfigure = "make config-clang";
|
||||
checkTarget = "test";
|
||||
checkTarget = "unit-test";
|
||||
installPhase = ''
|
||||
make install PREFIX=$out ABCEXTERNAL=yosys-abc
|
||||
ln -s ${abc-verifier}/bin/abc $out/bin/yosys-abc
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
packages.default = yosys;
|
||||
defaultPackage = yosys;
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [ clang llvmPackages.bintools bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier ];
|
||||
buildInputs = with pkgs; [ clang llvmPackages.bintools gcc bison flex libffi tcl readline python3 zlib git gtest abc-verifier verilog boost python3Packages.boost ];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ namespace AST
|
|||
{
|
||||
// for dict<> and pool<>
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
// this nodes type
|
||||
AstNodeType type;
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ static const std::string verific_unescape(const char *value)
|
|||
}
|
||||
#endif
|
||||
|
||||
void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj, Netlist *nl)
|
||||
void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj, Netlist *nl, int wire_width_hint)
|
||||
{
|
||||
if (!obj)
|
||||
return;
|
||||
|
|
@ -433,10 +433,18 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
|
|||
auto type_range = nl->GetTypeRange(obj->Name());
|
||||
if (!type_range)
|
||||
return;
|
||||
if (type_range->IsTypeScalar()) {
|
||||
if (nl->IsFromVhdl() && type_range->IsTypeScalar()) {
|
||||
const long long bottom_bound = type_range->GetScalarRangeLeftBound();
|
||||
const long long top_bound = type_range->GetScalarRangeRightBound();
|
||||
const unsigned bit_width = type_range->NumElements();
|
||||
int bit_width = type_range->LeftRangeBound()+1;
|
||||
if (bit_width <= 0) { // VHDL null range
|
||||
if (wire_width_hint >= 0)
|
||||
bit_width = wire_width_hint;
|
||||
else
|
||||
bit_width = 64; //fallback, currently largest integer width that verific will allow (in vhdl2019 mode)
|
||||
} else {
|
||||
if (wire_width_hint >= 0) log_assert(bit_width == wire_width_hint);
|
||||
}
|
||||
RTLIL::Const bottom_const(bottom_bound, bit_width);
|
||||
RTLIL::Const top_const(top_bound, bit_width);
|
||||
if (bottom_bound < 0 || top_bound < 0) {
|
||||
|
|
@ -611,7 +619,7 @@ RTLIL::SigSpec VerificImporter::operatorInportCase(Instance *inst, const char *p
|
|||
}
|
||||
}
|
||||
|
||||
RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, hash_ptr_ops> *any_all_nets)
|
||||
RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*> *any_all_nets)
|
||||
{
|
||||
RTLIL::SigSpec sig;
|
||||
RTLIL::Wire *dummy_wire = NULL;
|
||||
|
|
@ -1456,7 +1464,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
log("Importing module %s.\n", RTLIL::id2cstr(module->name));
|
||||
}
|
||||
import_attributes(module->attributes, nl, nl);
|
||||
module->set_string_attribute(ID::hdlname, nl->CellBaseName());
|
||||
if (module->name.isPublic())
|
||||
module->set_string_attribute(ID::hdlname, nl->CellBaseName());
|
||||
module->set_string_attribute(ID(library), nl->Owner()->Owner()->Name());
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
if (nl->IsFromVhdl()) {
|
||||
|
|
@ -1499,7 +1508,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
log(" importing port %s.\n", port->Name());
|
||||
|
||||
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name()));
|
||||
import_attributes(wire->attributes, port, nl);
|
||||
import_attributes(wire->attributes, port, nl, 1);
|
||||
|
||||
wire->port_id = nl->IndexOf(port) + 1;
|
||||
|
||||
|
|
@ -1527,11 +1536,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
|
||||
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
|
||||
wire->upto = portbus->IsUp();
|
||||
import_attributes(wire->attributes, portbus, nl);
|
||||
import_attributes(wire->attributes, portbus, nl, portbus->Size());
|
||||
SetIter si ;
|
||||
Port *port ;
|
||||
FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
|
||||
import_attributes(wire->attributes, port->GetNet(), nl);
|
||||
import_attributes(wire->attributes, port->GetNet(), nl, portbus->Size());
|
||||
break;
|
||||
}
|
||||
bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN;
|
||||
|
|
@ -1568,9 +1577,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
|
||||
module->fixup_ports();
|
||||
|
||||
dict<Net*, char, hash_ptr_ops> init_nets;
|
||||
pool<Net*, hash_ptr_ops> anyconst_nets, anyseq_nets;
|
||||
pool<Net*, hash_ptr_ops> allconst_nets, allseq_nets;
|
||||
dict<Net*, char> init_nets;
|
||||
pool<Net*> anyconst_nets, anyseq_nets;
|
||||
pool<Net*> allconst_nets, allseq_nets;
|
||||
any_all_nets.clear();
|
||||
|
||||
FOREACH_NET_OF_NETLIST(nl, mi, net)
|
||||
|
|
@ -1693,7 +1702,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
|
||||
|
||||
RTLIL::Wire *wire = module->addWire(wire_name);
|
||||
import_attributes(wire->attributes, net, nl);
|
||||
import_attributes(wire->attributes, net, nl, 1);
|
||||
|
||||
net_map[net] = wire;
|
||||
}
|
||||
|
|
@ -1722,10 +1731,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
MapIter mibus;
|
||||
FOREACH_NET_OF_NETBUS(netbus, mibus, net) {
|
||||
if (net)
|
||||
import_attributes(wire->attributes, net, nl);
|
||||
import_attributes(wire->attributes, net, nl, netbus->Size());
|
||||
break;
|
||||
}
|
||||
import_attributes(wire->attributes, netbus, nl);
|
||||
import_attributes(wire->attributes, netbus, nl, netbus->Size());
|
||||
|
||||
RTLIL::Const initval = Const(State::Sx, GetSize(wire));
|
||||
bool initval_valid = false;
|
||||
|
|
@ -1833,10 +1842,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
module->connect(net_map_at(net), module->Anyseq(new_verific_id(net)));
|
||||
|
||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||
pool<Instance*, hash_ptr_ops> sva_asserts;
|
||||
pool<Instance*, hash_ptr_ops> sva_assumes;
|
||||
pool<Instance*, hash_ptr_ops> sva_covers;
|
||||
pool<Instance*, hash_ptr_ops> sva_triggers;
|
||||
pool<Instance*> sva_asserts;
|
||||
pool<Instance*> sva_assumes;
|
||||
pool<Instance*> sva_covers;
|
||||
pool<Instance*> sva_triggers;
|
||||
#endif
|
||||
|
||||
pool<RTLIL::Cell*> past_ffs;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ struct VerificImporter
|
|||
|
||||
std::map<Verific::Net*, RTLIL::SigBit> net_map;
|
||||
std::map<Verific::Net*, Verific::Net*> sva_posedge_map;
|
||||
pool<Verific::Net*, hash_ptr_ops> any_all_nets;
|
||||
pool<Verific::Net*> any_all_nets;
|
||||
|
||||
bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
|
||||
bool mode_autocover, mode_fullinit;
|
||||
|
|
@ -81,7 +81,7 @@ struct VerificImporter
|
|||
RTLIL::SigBit net_map_at(Verific::Net *net);
|
||||
|
||||
RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
|
||||
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr);
|
||||
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr, int wire_width_hint = -1);
|
||||
|
||||
RTLIL::SigBit netToSigBit(Verific::Net *net);
|
||||
RTLIL::SigSpec operatorInput(Verific::Instance *inst);
|
||||
|
|
@ -89,7 +89,7 @@ struct VerificImporter
|
|||
RTLIL::SigSpec operatorInput2(Verific::Instance *inst);
|
||||
RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname);
|
||||
RTLIL::SigSpec operatorInportCase(Verific::Instance *inst, const char *portname);
|
||||
RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr);
|
||||
RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*> *any_all_nets = nullptr);
|
||||
|
||||
bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name);
|
||||
bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name);
|
||||
|
|
|
|||
|
|
@ -1051,7 +1051,7 @@ struct VerificSvaImporter
|
|||
msg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile());
|
||||
}
|
||||
|
||||
dict<Net*, bool, hash_ptr_ops> check_expression_cache;
|
||||
dict<Net*, bool> check_expression_cache;
|
||||
|
||||
bool check_expression(Net *net, bool raise_error = false)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,57 +37,15 @@ And then executed using the following command:
|
|||
Yosys Data Structures
|
||||
---------------------
|
||||
|
||||
Here is a short list of data structures that you should make yourself familiar
|
||||
with before you write C++ code for Yosys. The following data structures are all
|
||||
defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used.
|
||||
1. Container classes based on hashing
|
||||
|
||||
1. Yosys Container Classes
|
||||
Yosys heavily relies on custom container data structures such as dict or pool
|
||||
defined in kernel/hashlib.h.
|
||||
dict<K, T> is essentially a replacement for std::unordered_map<K, T>
|
||||
and pool<T> is a replacement for std::unordered_set<T>. Please refer to
|
||||
docs/source/yosys_internals/hashing.rst for more information on those.
|
||||
|
||||
Yosys uses dict<K, T> and pool<T> as main container classes. dict<K, T> is
|
||||
essentially a replacement for std::unordered_map<K, T> and pool<T> is a
|
||||
replacement for std::unordered_set<T>. The main characteristics are:
|
||||
|
||||
- dict<K, T> and pool<T> are about 2x faster than the std containers
|
||||
|
||||
- references to elements in a dict<K, T> or pool<T> are invalidated by
|
||||
insert and remove operations (similar to std::vector<T> on push_back()).
|
||||
|
||||
- some iterators are invalidated by erase(). specifically, iterators
|
||||
that have not passed the erased element yet are invalidated. (erase()
|
||||
itself returns valid iterator to the next element.)
|
||||
|
||||
- no iterators are invalidated by insert(). elements are inserted at
|
||||
begin(). i.e. only a new iterator that starts at begin() will see the
|
||||
inserted elements.
|
||||
|
||||
- the method .count(key, iterator) is like .count(key) but only
|
||||
considers elements that can be reached via the iterator.
|
||||
|
||||
- iterators can be compared. it1 < it2 means that the position of t2
|
||||
can be reached via t1 but not vice versa.
|
||||
|
||||
- the method .sort() can be used to sort the elements in the container
|
||||
the container stays sorted until elements are added or removed.
|
||||
|
||||
- dict<K, T> and pool<T> will have the same order of iteration across
|
||||
all compilers, standard libraries and architectures.
|
||||
|
||||
In addition to dict<K, T> and pool<T> there is also an idict<K> that
|
||||
creates a bijective map from K to the integers. For example:
|
||||
|
||||
idict<string, 42> si;
|
||||
log("%d\n", si("hello")); // will print 42
|
||||
log("%d\n", si("world")); // will print 43
|
||||
log("%d\n", si.at("world")); // will print 43
|
||||
log("%d\n", si.at("dummy")); // will throw exception
|
||||
log("%s\n", si[42].c_str())); // will print hello
|
||||
log("%s\n", si[43].c_str())); // will print world
|
||||
log("%s\n", si[44].c_str())); // will throw exception
|
||||
|
||||
It is not possible to remove elements from an idict.
|
||||
|
||||
Finally mfp<K> implements a merge-find set data structure (aka. disjoint-set or
|
||||
union-find) over the type K ("mfp" = merge-find-promote).
|
||||
Otherwise, Yosys makes use of the following:
|
||||
|
||||
2. Standard STL data types
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ struct BitPatternPool
|
|||
int width;
|
||||
struct bits_t {
|
||||
std::vector<RTLIL::State> bitdata;
|
||||
mutable unsigned int cached_hash;
|
||||
mutable Hasher::hash_t cached_hash;
|
||||
bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
|
||||
RTLIL::State &operator[](int index) {
|
||||
return bitdata[index];
|
||||
|
|
@ -39,14 +39,15 @@ struct BitPatternPool
|
|||
return bitdata[index];
|
||||
}
|
||||
bool operator==(const bits_t &other) const {
|
||||
if (hash() != other.hash())
|
||||
if (run_hash(*this) != run_hash(other))
|
||||
return false;
|
||||
return bitdata == other.bitdata;
|
||||
}
|
||||
unsigned int hash() const {
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
if (!cached_hash)
|
||||
cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
|
||||
return cached_hash;
|
||||
cached_hash = run_hash(bitdata);
|
||||
h.eat(cached_hash);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
pool<bits_t> database;
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ bool AigNode::operator==(const AigNode &other) const
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned int AigNode::hash() const
|
||||
Hasher AigNode::hash_into(Hasher h) const
|
||||
{
|
||||
unsigned int h = mkhash_init;
|
||||
h = mkhash(portname.hash(), portbit);
|
||||
h = mkhash(h, inverter);
|
||||
h = mkhash(h, left_parent);
|
||||
h = mkhash(h, right_parent);
|
||||
h.eat(portname);
|
||||
h.eat(portbit);
|
||||
h.eat(inverter);
|
||||
h.eat(left_parent);
|
||||
h.eat(right_parent);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
|
@ -54,9 +54,10 @@ bool Aig::operator==(const Aig &other) const
|
|||
return name == other.name;
|
||||
}
|
||||
|
||||
unsigned int Aig::hash() const
|
||||
Hasher Aig::hash_into(Hasher h) const
|
||||
{
|
||||
return hash_ops<std::string>::hash(name);
|
||||
h.eat(name);
|
||||
return h;
|
||||
}
|
||||
|
||||
struct AigMaker
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ struct AigNode
|
|||
|
||||
AigNode();
|
||||
bool operator==(const AigNode &other) const;
|
||||
unsigned int hash() const;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
struct Aig
|
||||
|
|
@ -44,7 +44,7 @@ struct Aig
|
|||
Aig(Cell *cell);
|
||||
|
||||
bool operator==(const Aig &other) const;
|
||||
unsigned int hash() const;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -315,9 +315,6 @@ struct ConstEval
|
|||
Macc macc;
|
||||
macc.from_cell(cell);
|
||||
|
||||
if (!eval(macc.bit_ports, undef, cell))
|
||||
return false;
|
||||
|
||||
for (auto &port : macc.ports) {
|
||||
if (!eval(port.in_a, undef, cell))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/hashlib.h"
|
||||
#include "libs/sha1/sha1.h"
|
||||
#include "libs/cxxopts/include/cxxopts.hpp"
|
||||
#include <iostream>
|
||||
|
|
@ -282,6 +283,8 @@ int main(int argc, char **argv)
|
|||
("M,randomize-pointers", "will slightly randomize allocated pointer addresses. for debugging")
|
||||
("autoidx", "start counting autoidx up from <seed>, similar effect to --hash-seed",
|
||||
cxxopts::value<uint64_t>(), "<idx>")
|
||||
("hash-seed", "mix up hashing values with <seed>, for extreme optimization and testing",
|
||||
cxxopts::value<uint64_t>(), "<seed>")
|
||||
("A,abort", "will call abort() at the end of the script. for debugging")
|
||||
("x,experimental", "do not print warnings for the experimental <feature>",
|
||||
cxxopts::value<std::vector<std::string>>(), "<feature>")
|
||||
|
|
@ -437,6 +440,10 @@ int main(int argc, char **argv)
|
|||
int idx = result["autoidx"].as<uint64_t>();
|
||||
autoidx = idx;
|
||||
}
|
||||
if (result.count("hash-seed")) {
|
||||
int seed = result["hash-seed"].as<uint64_t>();
|
||||
Hasher::set_fudge((Hasher::hash_t)seed);
|
||||
}
|
||||
|
||||
if (log_errfile == NULL) {
|
||||
log_files.push_back(stdout);
|
||||
|
|
|
|||
|
|
@ -74,10 +74,8 @@ struct DriveBitWire
|
|||
return offset < other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash_add(wire->name.hash(), offset);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
|
||||
operator SigBit() const
|
||||
{
|
||||
|
|
@ -107,10 +105,8 @@ struct DriveBitPort
|
|||
return offset < other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -133,10 +129,7 @@ struct DriveBitMarker
|
|||
return offset < other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash_add(marker, offset);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -171,10 +164,7 @@ public:
|
|||
return multiple_ == other.multiple_;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return multiple_.hash();
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
struct DriveBit
|
||||
|
|
@ -362,35 +352,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
unsigned int inner = 0;
|
||||
switch (type_)
|
||||
{
|
||||
case DriveType::NONE:
|
||||
inner = 0;
|
||||
break;
|
||||
case DriveType::CONSTANT:
|
||||
inner = constant_;
|
||||
break;
|
||||
case DriveType::WIRE:
|
||||
inner = wire_.hash();
|
||||
break;
|
||||
case DriveType::PORT:
|
||||
inner = port_.hash();
|
||||
break;
|
||||
case DriveType::MARKER:
|
||||
inner = marker_.hash();
|
||||
break;
|
||||
case DriveType::MULTIPLE:
|
||||
inner = multiple_.hash();
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
break;
|
||||
}
|
||||
return mkhash((unsigned int)type_, inner);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
bool operator==(const DriveBit &other) const
|
||||
{
|
||||
|
|
@ -511,10 +473,7 @@ struct DriveChunkWire
|
|||
return offset < other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash_add(mkhash(wire->name.hash(), width), offset);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
explicit operator SigChunk() const
|
||||
{
|
||||
|
|
@ -572,10 +531,7 @@ struct DriveChunkPort
|
|||
return offset < other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -616,10 +572,7 @@ struct DriveChunkMarker
|
|||
return offset < other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash_add(mkhash(marker, width), offset);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
struct DriveChunkMultiple
|
||||
|
|
@ -659,10 +612,7 @@ public:
|
|||
return false; // TODO implement, canonicalize order
|
||||
}
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
return mkhash(width_, multiple_.hash());
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
|
||||
struct DriveChunk
|
||||
|
|
@ -913,35 +863,7 @@ public:
|
|||
bool try_append(DriveBit const &bit);
|
||||
bool try_append(DriveChunk const &chunk);
|
||||
|
||||
unsigned int hash() const
|
||||
{
|
||||
unsigned int inner = 0;
|
||||
switch (type_)
|
||||
{
|
||||
case DriveType::NONE:
|
||||
inner = 0;
|
||||
break;
|
||||
case DriveType::CONSTANT:
|
||||
inner = constant_.hash();
|
||||
break;
|
||||
case DriveType::WIRE:
|
||||
inner = wire_.hash();
|
||||
break;
|
||||
case DriveType::PORT:
|
||||
inner = port_.hash();
|
||||
break;
|
||||
case DriveType::MARKER:
|
||||
inner = marker_.hash();
|
||||
break;
|
||||
case DriveType::MULTIPLE:
|
||||
inner = multiple_.hash();
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
break;
|
||||
}
|
||||
return mkhash((unsigned int)type_, inner);
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
bool operator==(const DriveChunk &other) const
|
||||
{
|
||||
|
|
@ -1144,17 +1066,20 @@ public:
|
|||
DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); }
|
||||
DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); }
|
||||
|
||||
unsigned int hash() const {
|
||||
if (hash_ != 0) return hash_;
|
||||
|
||||
void updhash() const {
|
||||
if (hash_ != 0)
|
||||
return;
|
||||
pack();
|
||||
hash_ = hash_ops<std::vector<DriveChunk>>().hash(chunks_);
|
||||
hash_ = run_hash(chunks_);
|
||||
hash_ |= (hash_ == 0);
|
||||
return hash_;
|
||||
}
|
||||
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
|
||||
bool operator==(DriveSpec const &other) const {
|
||||
if (size() != other.size() || hash() != other.hash())
|
||||
updhash();
|
||||
other.updhash();
|
||||
if (size() != other.size() || hash_ != other.hash_)
|
||||
return false;
|
||||
return chunks() == other.chunks();
|
||||
}
|
||||
|
|
@ -1187,7 +1112,7 @@ private:
|
|||
bool operator==(const DriveBitId &other) const { return id == other.id; }
|
||||
bool operator!=(const DriveBitId &other) const { return id != other.id; }
|
||||
bool operator<(const DriveBitId &other) const { return id < other.id; }
|
||||
unsigned int hash() const { return id; }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
};
|
||||
// Essentially a dict<DriveBitId, pool<DriveBitId>> but using less memory
|
||||
// and fewer allocations
|
||||
|
|
@ -1333,6 +1258,131 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
inline Hasher DriveBitWire::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(wire->name);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveBitPort::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(cell->name);
|
||||
h.eat(port);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveBitMarker::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(marker);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveBitMultiple::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(multiple_);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveBit::hash_into(Hasher h) const
|
||||
{
|
||||
switch (type_) {
|
||||
case DriveType::NONE:
|
||||
h.eat(0);
|
||||
break;
|
||||
case DriveType::CONSTANT:
|
||||
h.eat(constant_);
|
||||
break;
|
||||
case DriveType::WIRE:
|
||||
h.eat(wire_);
|
||||
break;
|
||||
case DriveType::PORT:
|
||||
h.eat(port_);
|
||||
break;
|
||||
case DriveType::MARKER:
|
||||
h.eat(marker_);
|
||||
break;
|
||||
case DriveType::MULTIPLE:
|
||||
h.eat(multiple_);
|
||||
break;
|
||||
}
|
||||
h.eat(type_);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveChunkWire::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(wire->name);
|
||||
h.eat(width);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveChunkPort::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(cell->name);
|
||||
h.eat(port);
|
||||
h.eat(width);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveChunkMarker::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(marker);
|
||||
h.eat(width);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveChunkMultiple::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(width_);
|
||||
h.eat(multiple_);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveChunk::hash_into(Hasher h) const
|
||||
{
|
||||
switch (type_) {
|
||||
case DriveType::NONE:
|
||||
h.eat(0);
|
||||
break;
|
||||
case DriveType::CONSTANT:
|
||||
h.eat(constant_);
|
||||
break;
|
||||
case DriveType::WIRE:
|
||||
h.eat(wire_);
|
||||
break;
|
||||
case DriveType::PORT:
|
||||
h.eat(port_);
|
||||
break;
|
||||
case DriveType::MARKER:
|
||||
h.eat(marker_);
|
||||
break;
|
||||
case DriveType::MULTIPLE:
|
||||
h.eat(multiple_);
|
||||
break;
|
||||
}
|
||||
h.eat(type_);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriveSpec::hash_into(Hasher h) const
|
||||
{
|
||||
updhash();
|
||||
h.eat(hash_);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline Hasher DriverMap::DriveBitId::hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(id);
|
||||
return h;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ namespace Functional {
|
|||
// returns the data width of a bitvector sort, errors out for other sorts
|
||||
int data_width() const { return std::get<1>(_v).second; }
|
||||
bool operator==(Sort const& other) const { return _v == other._v; }
|
||||
unsigned int hash() const { return mkhash(_v); }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(_v); return h; }
|
||||
};
|
||||
class IR;
|
||||
class Factory;
|
||||
|
|
@ -225,8 +225,10 @@ namespace Functional {
|
|||
const RTLIL::Const &as_const() const { return std::get<RTLIL::Const>(_extra); }
|
||||
std::pair<IdString, IdString> as_idstring_pair() const { return std::get<std::pair<IdString, IdString>>(_extra); }
|
||||
int as_int() const { return std::get<int>(_extra); }
|
||||
int hash() const {
|
||||
return mkhash((unsigned int) _fn, mkhash(_extra));
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat((unsigned int) _fn);
|
||||
h.eat(_extra);
|
||||
return h;
|
||||
}
|
||||
bool operator==(NodeData const &other) const {
|
||||
return _fn == other._fn && _extra == other._extra;
|
||||
|
|
|
|||
432
kernel/hashlib.h
432
kernel/hashlib.h
|
|
@ -17,27 +17,52 @@
|
|||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <type_traits>
|
||||
#include <stdint.h>
|
||||
|
||||
#define YS_HASHING_VERSION 1
|
||||
|
||||
namespace hashlib {
|
||||
|
||||
/**
|
||||
* HASHING
|
||||
*
|
||||
* Also refer to docs/source/yosys_internals/hashing.rst
|
||||
*
|
||||
* The Hasher knows how to hash 32 and 64-bit integers. That's it.
|
||||
* In the future, it could be expanded to do vectors with SIMD.
|
||||
*
|
||||
* The Hasher doesn't know how to hash common standard containers
|
||||
* and compositions. However, hashlib provides centralized wrappers.
|
||||
*
|
||||
* Hashlib doesn't know how to hash silly Yosys-specific types.
|
||||
* Hashlib doesn't depend on Yosys and can be used standalone.
|
||||
* Please don't use hashlib standalone for new projects.
|
||||
* Never directly include kernel/hashlib.h in Yosys code.
|
||||
* Instead include kernel/yosys_common.h
|
||||
*
|
||||
* The hash_ops type is now always left to its default value, derived
|
||||
* from templated functions through SFINAE. Providing custom ops is
|
||||
* still supported.
|
||||
*
|
||||
* HASH TABLES
|
||||
*
|
||||
* We implement associative data structures with separate chaining.
|
||||
* Linked lists use integers into the indirection hashtable array
|
||||
* instead of pointers.
|
||||
*/
|
||||
|
||||
const int hashtable_size_trigger = 2;
|
||||
const int hashtable_size_factor = 3;
|
||||
|
||||
// The XOR version of DJB2
|
||||
inline unsigned int mkhash(unsigned int a, unsigned int b) {
|
||||
return ((a << 5) + a) ^ b;
|
||||
}
|
||||
namespace legacy {
|
||||
inline uint32_t djb2_add(uint32_t a, uint32_t b) {
|
||||
return ((a << 5) + a) + b;
|
||||
}
|
||||
};
|
||||
|
||||
// traditionally 5381 is used as starting value for the djb2 hash
|
||||
const unsigned int mkhash_init = 5381;
|
||||
|
||||
// The ADD version of DJB2
|
||||
// (use this version for cache locality in b)
|
||||
inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
|
||||
return ((a << 5) + a) + b;
|
||||
}
|
||||
template<typename T>
|
||||
struct hash_ops;
|
||||
|
||||
inline unsigned int mkhash_xorshift(unsigned int a) {
|
||||
if (sizeof(a) == 4) {
|
||||
|
|
@ -53,72 +78,113 @@ inline unsigned int mkhash_xorshift(unsigned int a) {
|
|||
return a;
|
||||
}
|
||||
|
||||
template<typename T> struct hash_ops {
|
||||
class HasherDJB32 {
|
||||
public:
|
||||
using hash_t = uint32_t;
|
||||
|
||||
HasherDJB32() {
|
||||
// traditionally 5381 is used as starting value for the djb2 hash
|
||||
state = 5381;
|
||||
}
|
||||
static void set_fudge(hash_t f) {
|
||||
fudge = f;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t state;
|
||||
static uint32_t fudge;
|
||||
// The XOR version of DJB2
|
||||
[[nodiscard]]
|
||||
static uint32_t djb2_xor(uint32_t a, uint32_t b) {
|
||||
uint32_t hash = ((a << 5) + a) ^ b;
|
||||
return hash;
|
||||
}
|
||||
public:
|
||||
void hash32(uint32_t i) {
|
||||
state = djb2_xor(i, state);
|
||||
state = mkhash_xorshift(fudge ^ state);
|
||||
return;
|
||||
}
|
||||
void hash64(uint64_t i) {
|
||||
state = djb2_xor((uint32_t)(i & 0xFFFFFFFFULL), state);
|
||||
state = djb2_xor((uint32_t)(i >> 32ULL), state);
|
||||
state = mkhash_xorshift(fudge ^ state);
|
||||
return;
|
||||
}
|
||||
[[nodiscard]]
|
||||
hash_t yield() {
|
||||
return (hash_t)state;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void eat(T&& t) {
|
||||
*this = hash_ops<std::remove_cv_t<std::remove_reference_t<T>>>::hash_into(std::forward<T>(t), *this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void eat(const T& t) {
|
||||
*this = hash_ops<T>::hash_into(t, *this);
|
||||
}
|
||||
|
||||
void commutative_eat(hash_t t) {
|
||||
state ^= t;
|
||||
}
|
||||
|
||||
void force(hash_t new_state) {
|
||||
state = new_state;
|
||||
}
|
||||
};
|
||||
|
||||
using Hasher = HasherDJB32;
|
||||
|
||||
// Boilerplate compressor for trivially implementing
|
||||
// top-level hash method with hash_into
|
||||
#define HASH_TOP_LOOP_FST [[nodiscard]] static inline Hasher hash
|
||||
#define HASH_TOP_LOOP_SND { \
|
||||
Hasher h; \
|
||||
h = hash_into(a, h); \
|
||||
return h; \
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct hash_ops {
|
||||
static inline bool cmp(const T &a, const T &b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(const T &a) {
|
||||
return a.hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct hash_int_ops {
|
||||
template<typename T>
|
||||
static inline bool cmp(T a, T b) {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_ops<bool> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(bool a) {
|
||||
return a ? 1 : 0;
|
||||
}
|
||||
};
|
||||
template<> struct hash_ops<int32_t> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(int32_t a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
template<> struct hash_ops<int64_t> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(int64_t a) {
|
||||
return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
|
||||
}
|
||||
};
|
||||
template<> struct hash_ops<uint32_t> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(uint32_t a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
template<> struct hash_ops<uint64_t> : hash_int_ops
|
||||
{
|
||||
static inline unsigned int hash(uint64_t a) {
|
||||
return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_ops<std::string> {
|
||||
static inline bool cmp(const std::string &a, const std::string &b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(const std::string &a) {
|
||||
unsigned int v = 0;
|
||||
for (auto c : a)
|
||||
v = mkhash(v, c);
|
||||
return v;
|
||||
[[nodiscard]] static inline Hasher hash_into(const T &a, Hasher h) {
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
static_assert(sizeof(T) <= sizeof(uint64_t));
|
||||
if (sizeof(T) == sizeof(uint64_t))
|
||||
h.hash64(a);
|
||||
else
|
||||
h.hash32(a);
|
||||
return h;
|
||||
} else if constexpr (std::is_enum_v<T>) {
|
||||
using u_type = std::underlying_type_t<T>;
|
||||
return hash_ops<u_type>::hash_into((u_type) a, h);
|
||||
} else if constexpr (std::is_pointer_v<T>) {
|
||||
return hash_ops<uintptr_t>::hash_into((uintptr_t) a, h);
|
||||
} else if constexpr (std::is_same_v<T, std::string>) {
|
||||
for (auto c : a)
|
||||
h.hash32(c);
|
||||
return h;
|
||||
} else {
|
||||
return a.hash_into(h);
|
||||
}
|
||||
}
|
||||
HASH_TOP_LOOP_FST (const T &a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
|
||||
static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::pair<P, Q> a) {
|
||||
return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
|
||||
[[nodiscard]] static inline Hasher hash_into(std::pair<P, Q> a, Hasher h) {
|
||||
h = hash_ops<P>::hash_into(a.first, h);
|
||||
h = hash_ops<Q>::hash_into(a.second, h);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::pair<P, Q> a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename... T> struct hash_ops<std::tuple<T...>> {
|
||||
|
|
@ -126,50 +192,66 @@ template<typename... T> struct hash_ops<std::tuple<T...>> {
|
|||
return a == b;
|
||||
}
|
||||
template<size_t I = 0>
|
||||
static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>) {
|
||||
return mkhash_init;
|
||||
static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(std::tuple<T...>, Hasher h) {
|
||||
return h;
|
||||
}
|
||||
template<size_t I = 0>
|
||||
static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) {
|
||||
static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(std::tuple<T...> a, Hasher h) {
|
||||
typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
|
||||
return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
|
||||
h = hash_into<I+1>(a, h);
|
||||
h = element_ops_t::hash_into(std::get<I>(a), h);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::tuple<T...> a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename T> struct hash_ops<std::vector<T>> {
|
||||
static inline bool cmp(std::vector<T> a, std::vector<T> b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::vector<T> a) {
|
||||
unsigned int h = mkhash_init;
|
||||
[[nodiscard]] static inline Hasher hash_into(std::vector<T> a, Hasher h) {
|
||||
h.eat((uint32_t)a.size());
|
||||
for (auto k : a)
|
||||
h = mkhash(h, hash_ops<T>::hash(k));
|
||||
h.eat(k);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::vector<T> a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename T, size_t N> struct hash_ops<std::array<T, N>> {
|
||||
static inline bool cmp(std::array<T, N> a, std::array<T, N> b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(std::array<T, N> a, Hasher h) {
|
||||
for (const auto& k : a)
|
||||
h = hash_ops<T>::hash_into(k, h);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::array<T, N> a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
struct hash_cstr_ops {
|
||||
static inline bool cmp(const char *a, const char *b) {
|
||||
for (int i = 0; a[i] || b[i]; i++)
|
||||
if (a[i] != b[i])
|
||||
return false;
|
||||
return true;
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
static inline unsigned int hash(const char *a) {
|
||||
unsigned int hash = mkhash_init;
|
||||
[[nodiscard]] static inline Hasher hash_into(const char *a, Hasher h) {
|
||||
while (*a)
|
||||
hash = mkhash(hash, *(a++));
|
||||
return hash;
|
||||
h.hash32(*(a++));
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (const char *a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template <> struct hash_ops<char*> : hash_cstr_ops {};
|
||||
|
||||
struct hash_ptr_ops {
|
||||
static inline bool cmp(const void *a, const void *b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(const void *a) {
|
||||
return (uintptr_t)a;
|
||||
[[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) {
|
||||
return hash_ops<uintptr_t>::hash_into((uintptr_t)a, h);
|
||||
}
|
||||
HASH_TOP_LOOP_FST (const void *a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
struct hash_obj_ops {
|
||||
|
|
@ -177,22 +259,42 @@ struct hash_obj_ops {
|
|||
return a == b;
|
||||
}
|
||||
template<typename T>
|
||||
static inline unsigned int hash(const T *a) {
|
||||
return a ? a->hash() : 0;
|
||||
[[nodiscard]] static inline Hasher hash_into(const T *a, Hasher h) {
|
||||
if (a)
|
||||
h = a->hash_into(h);
|
||||
else
|
||||
h.eat(0);
|
||||
return h;
|
||||
}
|
||||
template<typename T>
|
||||
HASH_TOP_LOOP_FST (const T *a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
/**
|
||||
* If you find yourself using this function, think hard
|
||||
* about if it's the right thing to do. Mixing finalized
|
||||
* hashes together with XORs or worse can destroy
|
||||
* desirable qualities of the hash function
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]]
|
||||
Hasher::hash_t run_hash(const T& obj) {
|
||||
return hash_ops<T>::hash(obj).yield();
|
||||
}
|
||||
|
||||
/** Refer to docs/source/yosys_internals/hashing.rst */
|
||||
template<typename T>
|
||||
[[nodiscard]]
|
||||
[[deprecated]]
|
||||
inline unsigned int mkhash(const T &v) {
|
||||
return hash_ops<T>().hash(v);
|
||||
return (unsigned int) run_hash<T>(v);
|
||||
}
|
||||
|
||||
template<> struct hash_ops<std::monostate> {
|
||||
static inline bool cmp(std::monostate a, std::monostate b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::monostate) {
|
||||
return mkhash_init;
|
||||
[[nodiscard]] static inline Hasher hash_into(std::monostate, Hasher h) {
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -200,9 +302,10 @@ template<typename... T> struct hash_ops<std::variant<T...>> {
|
|||
static inline bool cmp(std::variant<T...> a, std::variant<T...> b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::variant<T...> a) {
|
||||
unsigned int h = std::visit([](const auto &v) { return mkhash(v); }, a);
|
||||
return mkhash(a.index(), h);
|
||||
[[nodiscard]] static inline Hasher hash_into(std::variant<T...> a, Hasher h) {
|
||||
std::visit([& h](const auto &v) { h.eat(v); }, a);
|
||||
h.eat(a.index());
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -210,18 +313,19 @@ template<typename T> struct hash_ops<std::optional<T>> {
|
|||
static inline bool cmp(std::optional<T> a, std::optional<T> b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::optional<T> a) {
|
||||
[[nodiscard]] static inline Hasher hash_into(std::optional<T> a, Hasher h) {
|
||||
if(a.has_value())
|
||||
return mkhash(*a);
|
||||
h.eat(*a);
|
||||
else
|
||||
return 0;
|
||||
h.eat(0);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
inline int hashtable_size(int min_size)
|
||||
inline unsigned int hashtable_size(unsigned int min_size)
|
||||
{
|
||||
// Primes as generated by https://oeis.org/A175953
|
||||
static std::vector<int> zero_and_some_primes = {
|
||||
static std::vector<unsigned int> zero_and_some_primes = {
|
||||
0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
|
||||
853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
|
||||
12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
|
||||
|
|
@ -231,13 +335,13 @@ inline int hashtable_size(int min_size)
|
|||
25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
|
||||
121590311, 151987889, 189984863, 237481091, 296851369, 371064217,
|
||||
463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113,
|
||||
1769372713
|
||||
1769372713, 2211715897, 2764644887, 3455806139
|
||||
};
|
||||
|
||||
for (auto p : zero_and_some_primes)
|
||||
if (p >= min_size) return p;
|
||||
|
||||
if (sizeof(int) == 4)
|
||||
if (sizeof(unsigned int) == 4)
|
||||
throw std::length_error("hash table exceeded maximum size.\nDesign is likely too large for yosys to handle, if possible try not to flatten the design.");
|
||||
|
||||
for (auto p : zero_and_some_primes)
|
||||
|
|
@ -252,8 +356,7 @@ template<typename K, typename OPS = hash_ops<K>> class pool;
|
|||
template<typename K, typename OPS = hash_ops<K>> class mfp;
|
||||
|
||||
template<typename K, typename T, typename OPS>
|
||||
class dict
|
||||
{
|
||||
class dict {
|
||||
struct entry_t
|
||||
{
|
||||
std::pair<K, T> udata;
|
||||
|
|
@ -277,11 +380,11 @@ class dict
|
|||
}
|
||||
#endif
|
||||
|
||||
int do_hash(const K &key) const
|
||||
Hasher::hash_t do_hash(const K &key) const
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
Hasher::hash_t hash = 0;
|
||||
if (!hashtable.empty())
|
||||
hash = ops.hash(key) % (unsigned int)(hashtable.size());
|
||||
hash = ops.hash(key).yield() % (unsigned int)(hashtable.size());
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -292,13 +395,13 @@ class dict
|
|||
|
||||
for (int i = 0; i < int(entries.size()); i++) {
|
||||
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
|
||||
int hash = do_hash(entries[i].udata.first);
|
||||
Hasher::hash_t hash = do_hash(entries[i].udata.first);
|
||||
entries[i].next = hashtable[hash];
|
||||
hashtable[hash] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int do_erase(int index, int hash)
|
||||
int do_erase(int index, Hasher::hash_t hash)
|
||||
{
|
||||
do_assert(index < int(entries.size()));
|
||||
if (hashtable.empty() || index < 0)
|
||||
|
|
@ -321,7 +424,7 @@ class dict
|
|||
|
||||
if (index != back_idx)
|
||||
{
|
||||
int back_hash = do_hash(entries[back_idx].udata.first);
|
||||
Hasher::hash_t back_hash = do_hash(entries[back_idx].udata.first);
|
||||
|
||||
k = hashtable[back_hash];
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
|
|
@ -347,7 +450,7 @@ class dict
|
|||
return 1;
|
||||
}
|
||||
|
||||
int do_lookup(const K &key, int &hash) const
|
||||
int do_lookup(const K &key, Hasher::hash_t &hash) const
|
||||
{
|
||||
if (hashtable.empty())
|
||||
return -1;
|
||||
|
|
@ -367,7 +470,7 @@ class dict
|
|||
return index;
|
||||
}
|
||||
|
||||
int do_insert(const K &key, int &hash)
|
||||
int do_insert(const K &key, Hasher::hash_t &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.emplace_back(std::pair<K, T>(key, T()), -1);
|
||||
|
|
@ -380,7 +483,7 @@ class dict
|
|||
return entries.size() - 1;
|
||||
}
|
||||
|
||||
int do_insert(const std::pair<K, T> &value, int &hash)
|
||||
int do_insert(const std::pair<K, T> &value, Hasher::hash_t &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.emplace_back(value, -1);
|
||||
|
|
@ -393,7 +496,7 @@ class dict
|
|||
return entries.size() - 1;
|
||||
}
|
||||
|
||||
int do_insert(std::pair<K, T> &&rvalue, int &hash)
|
||||
int do_insert(std::pair<K, T> &&rvalue, Hasher::hash_t &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
auto key = rvalue.first;
|
||||
|
|
@ -505,7 +608,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> insert(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -515,7 +618,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> insert(const std::pair<K, T> &value)
|
||||
{
|
||||
int hash = do_hash(value.first);
|
||||
Hasher::hash_t hash = do_hash(value.first);
|
||||
int i = do_lookup(value.first, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -525,7 +628,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
|
||||
{
|
||||
int hash = do_hash(rvalue.first);
|
||||
Hasher::hash_t hash = do_hash(rvalue.first);
|
||||
int i = do_lookup(rvalue.first, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -535,7 +638,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> emplace(K const &key, T const &value)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -545,7 +648,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -555,7 +658,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> emplace(K &&rkey, T const &value)
|
||||
{
|
||||
int hash = do_hash(rkey);
|
||||
Hasher::hash_t hash = do_hash(rkey);
|
||||
int i = do_lookup(rkey, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -565,7 +668,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
|
||||
{
|
||||
int hash = do_hash(rkey);
|
||||
Hasher::hash_t hash = do_hash(rkey);
|
||||
int i = do_lookup(rkey, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -575,35 +678,35 @@ public:
|
|||
|
||||
int erase(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int index = do_lookup(key, hash);
|
||||
return do_erase(index, hash);
|
||||
}
|
||||
|
||||
iterator erase(iterator it)
|
||||
{
|
||||
int hash = do_hash(it->first);
|
||||
Hasher::hash_t hash = do_hash(it->first);
|
||||
do_erase(it.index, hash);
|
||||
return ++it;
|
||||
}
|
||||
|
||||
int count(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
int count(const K &key, const_iterator it) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 || i > it.index ? 0 : 1;
|
||||
}
|
||||
|
||||
iterator find(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
|
|
@ -612,7 +715,7 @@ public:
|
|||
|
||||
const_iterator find(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
|
|
@ -621,7 +724,7 @@ public:
|
|||
|
||||
T& at(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
throw std::out_of_range("dict::at()");
|
||||
|
|
@ -630,7 +733,7 @@ public:
|
|||
|
||||
const T& at(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
throw std::out_of_range("dict::at()");
|
||||
|
|
@ -639,7 +742,7 @@ public:
|
|||
|
||||
const T& at(const K &key, const T &defval) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return defval;
|
||||
|
|
@ -648,7 +751,7 @@ public:
|
|||
|
||||
T& operator[](const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
i = do_insert(std::pair<K, T>(key, T()), hash);
|
||||
|
|
@ -683,12 +786,14 @@ public:
|
|||
return !operator==(other);
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
for (auto &entry : entries) {
|
||||
h ^= hash_ops<K>::hash(entry.udata.first);
|
||||
h ^= hash_ops<T>::hash(entry.udata.second);
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
for (auto &it : entries) {
|
||||
Hasher entry_hash;
|
||||
entry_hash.eat(it.udata.first);
|
||||
entry_hash.eat(it.udata.second);
|
||||
h.commutative_eat(entry_hash.yield());
|
||||
}
|
||||
h.eat(entries.size());
|
||||
return h;
|
||||
}
|
||||
|
||||
|
|
@ -734,11 +839,11 @@ protected:
|
|||
}
|
||||
#endif
|
||||
|
||||
int do_hash(const K &key) const
|
||||
Hasher::hash_t do_hash(const K &key) const
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
Hasher::hash_t hash = 0;
|
||||
if (!hashtable.empty())
|
||||
hash = ops.hash(key) % (unsigned int)(hashtable.size());
|
||||
hash = ops.hash(key).yield() % (unsigned int)(hashtable.size());
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -749,13 +854,13 @@ protected:
|
|||
|
||||
for (int i = 0; i < int(entries.size()); i++) {
|
||||
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
|
||||
int hash = do_hash(entries[i].udata);
|
||||
Hasher::hash_t hash = do_hash(entries[i].udata);
|
||||
entries[i].next = hashtable[hash];
|
||||
hashtable[hash] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int do_erase(int index, int hash)
|
||||
int do_erase(int index, Hasher::hash_t hash)
|
||||
{
|
||||
do_assert(index < int(entries.size()));
|
||||
if (hashtable.empty() || index < 0)
|
||||
|
|
@ -776,7 +881,7 @@ protected:
|
|||
|
||||
if (index != back_idx)
|
||||
{
|
||||
int back_hash = do_hash(entries[back_idx].udata);
|
||||
Hasher::hash_t back_hash = do_hash(entries[back_idx].udata);
|
||||
|
||||
k = hashtable[back_hash];
|
||||
if (k == back_idx) {
|
||||
|
|
@ -800,7 +905,7 @@ protected:
|
|||
return 1;
|
||||
}
|
||||
|
||||
int do_lookup(const K &key, int &hash) const
|
||||
int do_lookup(const K &key, Hasher::hash_t &hash) const
|
||||
{
|
||||
if (hashtable.empty())
|
||||
return -1;
|
||||
|
|
@ -820,7 +925,7 @@ protected:
|
|||
return index;
|
||||
}
|
||||
|
||||
int do_insert(const K &value, int &hash)
|
||||
int do_insert(const K &value, Hasher::hash_t &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.emplace_back(value, -1);
|
||||
|
|
@ -833,7 +938,7 @@ protected:
|
|||
return entries.size() - 1;
|
||||
}
|
||||
|
||||
int do_insert(K &&rvalue, int &hash)
|
||||
int do_insert(K &&rvalue, Hasher::hash_t &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.emplace_back(std::forward<K>(rvalue), -1);
|
||||
|
|
@ -940,7 +1045,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> insert(const K &value)
|
||||
{
|
||||
int hash = do_hash(value);
|
||||
Hasher::hash_t hash = do_hash(value);
|
||||
int i = do_lookup(value, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -950,7 +1055,7 @@ public:
|
|||
|
||||
std::pair<iterator, bool> insert(K &&rvalue)
|
||||
{
|
||||
int hash = do_hash(rvalue);
|
||||
Hasher::hash_t hash = do_hash(rvalue);
|
||||
int i = do_lookup(rvalue, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
|
|
@ -966,35 +1071,35 @@ public:
|
|||
|
||||
int erase(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int index = do_lookup(key, hash);
|
||||
return do_erase(index, hash);
|
||||
}
|
||||
|
||||
iterator erase(iterator it)
|
||||
{
|
||||
int hash = do_hash(*it);
|
||||
Hasher::hash_t hash = do_hash(*it);
|
||||
do_erase(it.index, hash);
|
||||
return ++it;
|
||||
}
|
||||
|
||||
int count(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
int count(const K &key, const_iterator it) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 || i > it.index ? 0 : 1;
|
||||
}
|
||||
|
||||
iterator find(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
|
|
@ -1003,7 +1108,7 @@ public:
|
|||
|
||||
const_iterator find(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
|
|
@ -1012,7 +1117,7 @@ public:
|
|||
|
||||
bool operator[](const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
Hasher::hash_t hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i >= 0;
|
||||
}
|
||||
|
|
@ -1051,11 +1156,12 @@ public:
|
|||
return !operator==(other);
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
unsigned int hashval = mkhash_init;
|
||||
for (auto &it : entries)
|
||||
hashval ^= ops.hash(it.udata);
|
||||
return hashval;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
for (auto &it : entries) {
|
||||
h.commutative_eat(ops.hash(it.udata).yield());
|
||||
}
|
||||
h.eat(entries.size());
|
||||
return h;
|
||||
}
|
||||
|
||||
void reserve(size_t n) { entries.reserve(n); }
|
||||
|
|
@ -1105,7 +1211,7 @@ public:
|
|||
|
||||
int operator()(const K &key)
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
Hasher::hash_t hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
i = database.do_insert(key, hash);
|
||||
|
|
@ -1114,7 +1220,7 @@ public:
|
|||
|
||||
int at(const K &key) const
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
Hasher::hash_t hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
throw std::out_of_range("idict::at()");
|
||||
|
|
@ -1123,7 +1229,7 @@ public:
|
|||
|
||||
int at(const K &key, int defval) const
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
Hasher::hash_t hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return defval;
|
||||
|
|
@ -1132,7 +1238,7 @@ public:
|
|||
|
||||
int count(const K &key) const
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
Hasher::hash_t hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
return i < 0 ? 0 : 1;
|
||||
}
|
||||
|
|
@ -1176,7 +1282,7 @@ class mfp
|
|||
mutable std::vector<int> parents;
|
||||
|
||||
public:
|
||||
typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
|
||||
typedef typename idict<K, 0>::const_iterator const_iterator;
|
||||
|
||||
constexpr mfp()
|
||||
{
|
||||
|
|
|
|||
12
kernel/log.h
12
kernel/log.h
|
|
@ -363,13 +363,13 @@ 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, typename T> static inline void log_dump_val_worker(dict<K, T> &v);
|
||||
template<typename K> static inline void log_dump_val_worker(pool<K> &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) {
|
||||
template<typename K, typename T>
|
||||
static inline void log_dump_val_worker(dict<K, T> &v) {
|
||||
log("{");
|
||||
bool first = true;
|
||||
for (auto &it : v) {
|
||||
|
|
@ -382,8 +382,8 @@ static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
|
|||
log(" }");
|
||||
}
|
||||
|
||||
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(pool<K> &v) {
|
||||
log("{");
|
||||
bool first = true;
|
||||
for (auto &it : v) {
|
||||
|
|
|
|||
|
|
@ -30,14 +30,11 @@ struct Macc
|
|||
RTLIL::SigSpec in_a, in_b;
|
||||
bool is_signed, do_subtract;
|
||||
};
|
||||
|
||||
std::vector<port_t> ports;
|
||||
RTLIL::SigSpec bit_ports;
|
||||
|
||||
void optimize(int width)
|
||||
{
|
||||
std::vector<port_t> new_ports;
|
||||
RTLIL::SigSpec new_bit_ports;
|
||||
RTLIL::Const off(0, width);
|
||||
|
||||
for (auto &port : ports)
|
||||
|
|
@ -48,11 +45,6 @@ struct Macc
|
|||
if (GetSize(port.in_a) < GetSize(port.in_b))
|
||||
std::swap(port.in_a, port.in_b);
|
||||
|
||||
if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
|
||||
bit_ports.append(port.in_a);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) {
|
||||
RTLIL::Const v = port.in_a.as_const();
|
||||
if (GetSize(port.in_b))
|
||||
|
|
@ -79,12 +71,6 @@ struct Macc
|
|||
new_ports.push_back(port);
|
||||
}
|
||||
|
||||
for (auto &bit : bit_ports)
|
||||
if (bit == State::S1)
|
||||
off = const_add(off, RTLIL::Const(1, width), false, false, width);
|
||||
else if (bit != State::S0)
|
||||
new_bit_ports.append(bit);
|
||||
|
||||
if (off.as_bool()) {
|
||||
port_t port;
|
||||
port.in_a = off;
|
||||
|
|
@ -94,7 +80,6 @@ struct Macc
|
|||
}
|
||||
|
||||
new_ports.swap(ports);
|
||||
bit_ports = new_bit_ports;
|
||||
}
|
||||
|
||||
void from_cell(RTLIL::Cell *cell)
|
||||
|
|
@ -102,7 +87,6 @@ struct Macc
|
|||
RTLIL::SigSpec port_a = cell->getPort(ID::A);
|
||||
|
||||
ports.clear();
|
||||
bit_ports = cell->getPort(ID::B);
|
||||
|
||||
auto config_bits = cell->getParam(ID::CONFIG);
|
||||
int config_cursor = 0;
|
||||
|
|
@ -145,6 +129,9 @@ struct Macc
|
|||
ports.push_back(this_port);
|
||||
}
|
||||
|
||||
for (auto bit : cell->getPort(ID::B))
|
||||
ports.push_back(port_t{{bit}, {}, false, false});
|
||||
|
||||
log_assert(config_cursor == config_width);
|
||||
log_assert(port_a_cursor == GetSize(port_a));
|
||||
}
|
||||
|
|
@ -190,11 +177,11 @@ struct Macc
|
|||
}
|
||||
|
||||
cell->setPort(ID::A, port_a);
|
||||
cell->setPort(ID::B, bit_ports);
|
||||
cell->setPort(ID::B, {});
|
||||
cell->setParam(ID::CONFIG, config_bits);
|
||||
cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits));
|
||||
cell->setParam(ID::A_WIDTH, GetSize(port_a));
|
||||
cell->setParam(ID::B_WIDTH, GetSize(bit_ports));
|
||||
cell->setParam(ID::B_WIDTH, 0);
|
||||
}
|
||||
|
||||
bool eval(RTLIL::Const &result) const
|
||||
|
|
@ -219,19 +206,12 @@ struct Macc
|
|||
result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result));
|
||||
}
|
||||
|
||||
for (auto bit : bit_ports) {
|
||||
if (bit.wire)
|
||||
return false;
|
||||
result = const_add(result, bit.data, false, false, GetSize(result));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_simple_product()
|
||||
{
|
||||
return bit_ports.empty() &&
|
||||
ports.size() == 1 &&
|
||||
return ports.size() == 1 &&
|
||||
!ports[0].in_b.empty() &&
|
||||
!ports[0].do_subtract;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,11 @@ struct ModIndex : public RTLIL::Monitor
|
|||
return cell == other.cell && port == other.port && offset == other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(cell->name);
|
||||
h.eat(port);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -304,6 +307,7 @@ struct ModWalker
|
|||
RTLIL::Cell *cell;
|
||||
RTLIL::IdString port;
|
||||
int offset;
|
||||
PortBit(Cell* c, IdString p, int o) : cell(c), port(p), offset(o) {}
|
||||
|
||||
bool operator<(const PortBit &other) const {
|
||||
if (cell != other.cell)
|
||||
|
|
@ -317,8 +321,11 @@ struct ModWalker
|
|||
return cell == other.cell && port == other.port && offset == other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(cell->name);
|
||||
h.eat(port);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -355,7 +362,7 @@ struct ModWalker
|
|||
{
|
||||
for (int i = 0; i < int(bits.size()); i++)
|
||||
if (bits[i].wire != NULL) {
|
||||
PortBit pbit = { cell, port, i };
|
||||
PortBit pbit {cell, port, i};
|
||||
if (is_output) {
|
||||
signal_drivers[bits[i]].insert(pbit);
|
||||
cell_outputs[cell].insert(bits[i]);
|
||||
|
|
|
|||
|
|
@ -1221,7 +1221,7 @@ struct LicensePass : public Pass {
|
|||
log(" | |\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 - 2024 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | |\n");
|
||||
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
|
||||
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
bool RTLIL::IdString::destruct_guard_ok = false;
|
||||
RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
|
||||
std::vector<char*> RTLIL::IdString::global_id_storage_;
|
||||
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
|
||||
dict<char*, int> RTLIL::IdString::global_id_index_;
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
std::vector<int> RTLIL::IdString::global_refcount_storage_;
|
||||
std::vector<int> RTLIL::IdString::global_free_idx_list_;
|
||||
|
|
@ -4476,17 +4476,17 @@ void RTLIL::SigSpec::updhash() const
|
|||
cover("kernel.rtlil.sigspec.hash");
|
||||
that->pack();
|
||||
|
||||
that->hash_ = mkhash_init;
|
||||
Hasher h;
|
||||
for (auto &c : that->chunks_)
|
||||
if (c.wire == NULL) {
|
||||
for (auto &v : c.data)
|
||||
that->hash_ = mkhash(that->hash_, v);
|
||||
h.eat(v);
|
||||
} else {
|
||||
that->hash_ = mkhash(that->hash_, c.wire->name.index_);
|
||||
that->hash_ = mkhash(that->hash_, c.offset);
|
||||
that->hash_ = mkhash(that->hash_, c.width);
|
||||
h.eat(c.wire->name.index_);
|
||||
h.eat(c.offset);
|
||||
h.eat(c.width);
|
||||
}
|
||||
|
||||
that->hash_ = h.yield();
|
||||
if (that->hash_ == 0)
|
||||
that->hash_ = 1;
|
||||
}
|
||||
|
|
|
|||
691
kernel/rtlil.h
691
kernel/rtlil.h
|
|
@ -76,329 +76,357 @@ namespace RTLIL
|
|||
struct SyncRule;
|
||||
struct Process;
|
||||
struct Binding;
|
||||
struct IdString;
|
||||
|
||||
typedef std::pair<SigSpec, SigSpec> SigSig;
|
||||
};
|
||||
|
||||
struct IdString
|
||||
struct RTLIL::IdString
|
||||
{
|
||||
#undef YOSYS_XTRACE_GET_PUT
|
||||
#undef YOSYS_SORT_ID_FREE_LIST
|
||||
#undef YOSYS_USE_STICKY_IDS
|
||||
#undef YOSYS_NO_IDS_REFCNT
|
||||
|
||||
// the global id string cache
|
||||
|
||||
static bool destruct_guard_ok; // POD, will be initialized to zero
|
||||
static struct destruct_guard_t {
|
||||
destruct_guard_t() { destruct_guard_ok = true; }
|
||||
~destruct_guard_t() { destruct_guard_ok = false; }
|
||||
} destruct_guard;
|
||||
|
||||
static std::vector<char*> global_id_storage_;
|
||||
static dict<char*, int> global_id_index_;
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
static std::vector<int> global_refcount_storage_;
|
||||
static std::vector<int> global_free_idx_list_;
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_USE_STICKY_IDS
|
||||
static int last_created_idx_ptr_;
|
||||
static int last_created_idx_[8];
|
||||
#endif
|
||||
|
||||
static inline void xtrace_db_dump()
|
||||
{
|
||||
#undef YOSYS_XTRACE_GET_PUT
|
||||
#undef YOSYS_SORT_ID_FREE_LIST
|
||||
#undef YOSYS_USE_STICKY_IDS
|
||||
#undef YOSYS_NO_IDS_REFCNT
|
||||
|
||||
// the global id string cache
|
||||
|
||||
static bool destruct_guard_ok; // POD, will be initialized to zero
|
||||
static struct destruct_guard_t {
|
||||
destruct_guard_t() { destruct_guard_ok = true; }
|
||||
~destruct_guard_t() { destruct_guard_ok = false; }
|
||||
} destruct_guard;
|
||||
|
||||
static std::vector<char*> global_id_storage_;
|
||||
static dict<char*, int, hash_cstr_ops> global_id_index_;
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
static std::vector<int> global_refcount_storage_;
|
||||
static std::vector<int> global_free_idx_list_;
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
|
||||
{
|
||||
if (global_id_storage_.at(idx) == nullptr)
|
||||
log("#X# DB-DUMP index %d: FREE\n", idx);
|
||||
else
|
||||
log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void checkpoint()
|
||||
{
|
||||
#ifdef YOSYS_USE_STICKY_IDS
|
||||
static int last_created_idx_ptr_;
|
||||
static int last_created_idx_[8];
|
||||
last_created_idx_ptr_ = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (last_created_idx_[i])
|
||||
put_reference(last_created_idx_[i]);
|
||||
last_created_idx_[i] = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef YOSYS_SORT_ID_FREE_LIST
|
||||
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void xtrace_db_dump()
|
||||
{
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
|
||||
{
|
||||
if (global_id_storage_.at(idx) == nullptr)
|
||||
log("#X# DB-DUMP index %d: FREE\n", idx);
|
||||
else
|
||||
log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
static inline int get_reference(int idx)
|
||||
{
|
||||
if (idx) {
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
global_refcount_storage_[idx]++;
|
||||
#endif
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace)
|
||||
log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
#endif
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int get_reference(const char *p)
|
||||
{
|
||||
log_assert(destruct_guard_ok);
|
||||
|
||||
if (!p[0])
|
||||
return 0;
|
||||
|
||||
auto it = global_id_index_.find((char*)p);
|
||||
if (it != global_id_index_.end()) {
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
global_refcount_storage_.at(it->second)++;
|
||||
#endif
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace)
|
||||
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
|
||||
#endif
|
||||
return it->second;
|
||||
}
|
||||
|
||||
static inline void checkpoint()
|
||||
{
|
||||
#ifdef YOSYS_USE_STICKY_IDS
|
||||
last_created_idx_ptr_ = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (last_created_idx_[i])
|
||||
put_reference(last_created_idx_[i]);
|
||||
last_created_idx_[i] = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef YOSYS_SORT_ID_FREE_LIST
|
||||
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
|
||||
#endif
|
||||
}
|
||||
log_assert(p[0] == '$' || p[0] == '\\');
|
||||
log_assert(p[1] != 0);
|
||||
for (const char *c = p; *c; c++)
|
||||
if ((unsigned)*c <= (unsigned)' ')
|
||||
log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
|
||||
|
||||
static inline int get_reference(int idx)
|
||||
{
|
||||
if (idx) {
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
global_refcount_storage_[idx]++;
|
||||
#endif
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace)
|
||||
log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
#endif
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int get_reference(const char *p)
|
||||
{
|
||||
log_assert(destruct_guard_ok);
|
||||
|
||||
if (!p[0])
|
||||
return 0;
|
||||
|
||||
auto it = global_id_index_.find((char*)p);
|
||||
if (it != global_id_index_.end()) {
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
global_refcount_storage_.at(it->second)++;
|
||||
#endif
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace)
|
||||
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
|
||||
#endif
|
||||
return it->second;
|
||||
}
|
||||
|
||||
log_assert(p[0] == '$' || p[0] == '\\');
|
||||
log_assert(p[1] != 0);
|
||||
for (const char *c = p; *c; c++)
|
||||
if ((unsigned)*c <= (unsigned)' ')
|
||||
log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
|
||||
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
if (global_free_idx_list_.empty()) {
|
||||
if (global_id_storage_.empty()) {
|
||||
global_refcount_storage_.push_back(0);
|
||||
global_id_storage_.push_back((char*)"");
|
||||
global_id_index_[global_id_storage_.back()] = 0;
|
||||
}
|
||||
log_assert(global_id_storage_.size() < 0x40000000);
|
||||
global_free_idx_list_.push_back(global_id_storage_.size());
|
||||
global_id_storage_.push_back(nullptr);
|
||||
global_refcount_storage_.push_back(0);
|
||||
}
|
||||
|
||||
int idx = global_free_idx_list_.back();
|
||||
global_free_idx_list_.pop_back();
|
||||
global_id_storage_.at(idx) = strdup(p);
|
||||
global_id_index_[global_id_storage_.at(idx)] = idx;
|
||||
global_refcount_storage_.at(idx)++;
|
||||
#else
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
if (global_free_idx_list_.empty()) {
|
||||
if (global_id_storage_.empty()) {
|
||||
global_refcount_storage_.push_back(0);
|
||||
global_id_storage_.push_back((char*)"");
|
||||
global_id_index_[global_id_storage_.back()] = 0;
|
||||
}
|
||||
int idx = global_id_storage_.size();
|
||||
global_id_storage_.push_back(strdup(p));
|
||||
global_id_index_[global_id_storage_.back()] = idx;
|
||||
#endif
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# New IdString '%s' with index %d.\n", p, idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace)
|
||||
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_USE_STICKY_IDS
|
||||
// Avoid Create->Delete->Create pattern
|
||||
if (last_created_idx_[last_created_idx_ptr_])
|
||||
put_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||
last_created_idx_[last_created_idx_ptr_] = idx;
|
||||
get_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
|
||||
#endif
|
||||
|
||||
return idx;
|
||||
log_assert(global_id_storage_.size() < 0x40000000);
|
||||
global_free_idx_list_.push_back(global_id_storage_.size());
|
||||
global_id_storage_.push_back(nullptr);
|
||||
global_refcount_storage_.push_back(0);
|
||||
}
|
||||
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
static inline void put_reference(int idx)
|
||||
{
|
||||
// put_reference() may be called from destructors after the destructor of
|
||||
// global_refcount_storage_ has been run. in this case we simply do nothing.
|
||||
if (!destruct_guard_ok || !idx)
|
||||
return;
|
||||
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace) {
|
||||
log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
|
||||
int &refcount = global_refcount_storage_[idx];
|
||||
|
||||
if (--refcount > 0)
|
||||
return;
|
||||
|
||||
log_assert(refcount == 0);
|
||||
free_reference(idx);
|
||||
}
|
||||
static inline void free_reference(int idx)
|
||||
{
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
global_id_index_.erase(global_id_storage_.at(idx));
|
||||
free(global_id_storage_.at(idx));
|
||||
global_id_storage_.at(idx) = nullptr;
|
||||
global_free_idx_list_.push_back(idx);
|
||||
}
|
||||
int idx = global_free_idx_list_.back();
|
||||
global_free_idx_list_.pop_back();
|
||||
global_id_storage_.at(idx) = strdup(p);
|
||||
global_id_index_[global_id_storage_.at(idx)] = idx;
|
||||
global_refcount_storage_.at(idx)++;
|
||||
#else
|
||||
static inline void put_reference(int) { }
|
||||
if (global_id_storage_.empty()) {
|
||||
global_id_storage_.push_back((char*)"");
|
||||
global_id_index_[global_id_storage_.back()] = 0;
|
||||
}
|
||||
int idx = global_id_storage_.size();
|
||||
global_id_storage_.push_back(strdup(p));
|
||||
global_id_index_[global_id_storage_.back()] = idx;
|
||||
#endif
|
||||
|
||||
// the actual IdString object is just is a single int
|
||||
|
||||
int index_;
|
||||
|
||||
inline IdString() : index_(0) { }
|
||||
inline IdString(const char *str) : index_(get_reference(str)) { }
|
||||
inline IdString(const IdString &str) : index_(get_reference(str.index_)) { }
|
||||
inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }
|
||||
inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { }
|
||||
inline ~IdString() { put_reference(index_); }
|
||||
|
||||
inline void operator=(const IdString &rhs) {
|
||||
put_reference(index_);
|
||||
index_ = get_reference(rhs.index_);
|
||||
if (yosys_xtrace) {
|
||||
log("#X# New IdString '%s' with index %d.\n", p, idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
inline void operator=(const char *rhs) {
|
||||
IdString id(rhs);
|
||||
*this = id;
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace)
|
||||
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_USE_STICKY_IDS
|
||||
// Avoid Create->Delete->Create pattern
|
||||
if (last_created_idx_[last_created_idx_ptr_])
|
||||
put_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||
last_created_idx_[last_created_idx_ptr_] = idx;
|
||||
get_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
|
||||
#endif
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
#ifndef YOSYS_NO_IDS_REFCNT
|
||||
static inline void put_reference(int idx)
|
||||
{
|
||||
// put_reference() may be called from destructors after the destructor of
|
||||
// global_refcount_storage_ has been run. in this case we simply do nothing.
|
||||
if (!destruct_guard_ok || !idx)
|
||||
return;
|
||||
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace) {
|
||||
log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
|
||||
int &refcount = global_refcount_storage_[idx];
|
||||
|
||||
if (--refcount > 0)
|
||||
return;
|
||||
|
||||
log_assert(refcount == 0);
|
||||
free_reference(idx);
|
||||
}
|
||||
static inline void free_reference(int idx)
|
||||
{
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
inline void operator=(const std::string &rhs) {
|
||||
IdString id(rhs);
|
||||
*this = id;
|
||||
}
|
||||
|
||||
inline const char *c_str() const {
|
||||
return global_id_storage_.at(index_);
|
||||
}
|
||||
|
||||
inline std::string str() const {
|
||||
return std::string(global_id_storage_.at(index_));
|
||||
}
|
||||
|
||||
inline bool operator<(const IdString &rhs) const {
|
||||
return index_ < rhs.index_;
|
||||
}
|
||||
|
||||
inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }
|
||||
inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }
|
||||
|
||||
// The methods below are just convenience functions for better compatibility with std::string.
|
||||
|
||||
bool operator==(const std::string &rhs) const { return c_str() == rhs; }
|
||||
bool operator!=(const std::string &rhs) const { return c_str() != rhs; }
|
||||
|
||||
bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; }
|
||||
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
|
||||
|
||||
char operator[](size_t i) const {
|
||||
const char *p = c_str();
|
||||
#ifndef NDEBUG
|
||||
for (; i != 0; i--, p++)
|
||||
log_assert(*p != 0);
|
||||
return *p;
|
||||
global_id_index_.erase(global_id_storage_.at(idx));
|
||||
free(global_id_storage_.at(idx));
|
||||
global_id_storage_.at(idx) = nullptr;
|
||||
global_free_idx_list_.push_back(idx);
|
||||
}
|
||||
#else
|
||||
return *(p + i);
|
||||
static inline void put_reference(int) { }
|
||||
#endif
|
||||
|
||||
// the actual IdString object is just is a single int
|
||||
|
||||
int index_;
|
||||
|
||||
inline IdString() : index_(0) { }
|
||||
inline IdString(const char *str) : index_(get_reference(str)) { }
|
||||
inline IdString(const IdString &str) : index_(get_reference(str.index_)) { }
|
||||
inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }
|
||||
inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { }
|
||||
inline ~IdString() { put_reference(index_); }
|
||||
|
||||
inline void operator=(const IdString &rhs) {
|
||||
put_reference(index_);
|
||||
index_ = get_reference(rhs.index_);
|
||||
}
|
||||
|
||||
inline void operator=(const char *rhs) {
|
||||
IdString id(rhs);
|
||||
*this = id;
|
||||
}
|
||||
|
||||
inline void operator=(const std::string &rhs) {
|
||||
IdString id(rhs);
|
||||
*this = id;
|
||||
}
|
||||
|
||||
inline const char *c_str() const {
|
||||
return global_id_storage_.at(index_);
|
||||
}
|
||||
|
||||
inline std::string str() const {
|
||||
return std::string(global_id_storage_.at(index_));
|
||||
}
|
||||
|
||||
inline bool operator<(const IdString &rhs) const {
|
||||
return index_ < rhs.index_;
|
||||
}
|
||||
|
||||
inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }
|
||||
inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }
|
||||
|
||||
// The methods below are just convenience functions for better compatibility with std::string.
|
||||
|
||||
bool operator==(const std::string &rhs) const { return c_str() == rhs; }
|
||||
bool operator!=(const std::string &rhs) const { return c_str() != rhs; }
|
||||
|
||||
bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; }
|
||||
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
|
||||
|
||||
char operator[](size_t i) const {
|
||||
const char *p = c_str();
|
||||
#ifndef NDEBUG
|
||||
for (; i != 0; i--, p++)
|
||||
log_assert(*p != 0);
|
||||
return *p;
|
||||
#else
|
||||
return *(p + i);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
|
||||
if (len == std::string::npos || len >= strlen(c_str() + pos))
|
||||
return std::string(c_str() + pos);
|
||||
else
|
||||
return std::string(c_str() + pos, len);
|
||||
}
|
||||
|
||||
int compare(size_t pos, size_t len, const char* s) const {
|
||||
return strncmp(c_str()+pos, s, len);
|
||||
}
|
||||
|
||||
bool begins_with(const char* prefix) const {
|
||||
size_t len = strlen(prefix);
|
||||
if (size() < len) return false;
|
||||
return compare(0, len, prefix) == 0;
|
||||
}
|
||||
|
||||
bool ends_with(const char* suffix) const {
|
||||
size_t len = strlen(suffix);
|
||||
if (size() < len) return false;
|
||||
return compare(size()-len, len, suffix) == 0;
|
||||
}
|
||||
|
||||
bool contains(const char* str) const {
|
||||
return strstr(c_str(), str);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return strlen(c_str());
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return c_str()[0] == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
*this = IdString();
|
||||
}
|
||||
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { return hash_ops<int>::hash_into(index_, h); }
|
||||
|
||||
[[nodiscard]] Hasher hash_top() const {
|
||||
Hasher h;
|
||||
h.force((Hasher::hash_t) index_);
|
||||
return h;
|
||||
}
|
||||
|
||||
// The following is a helper key_compare class. Instead of for example std::set<Cell*>
|
||||
// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
|
||||
// set has an influence on the algorithm.
|
||||
|
||||
template<typename T> struct compare_ptr_by_name {
|
||||
bool operator()(const T *a, const T *b) const {
|
||||
return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);
|
||||
}
|
||||
|
||||
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
|
||||
if (len == std::string::npos || len >= strlen(c_str() + pos))
|
||||
return std::string(c_str() + pos);
|
||||
else
|
||||
return std::string(c_str() + pos, len);
|
||||
}
|
||||
|
||||
int compare(size_t pos, size_t len, const char* s) const {
|
||||
return strncmp(c_str()+pos, s, len);
|
||||
}
|
||||
|
||||
bool begins_with(const char* prefix) const {
|
||||
size_t len = strlen(prefix);
|
||||
if (size() < len) return false;
|
||||
return compare(0, len, prefix) == 0;
|
||||
}
|
||||
|
||||
bool ends_with(const char* suffix) const {
|
||||
size_t len = strlen(suffix);
|
||||
if (size() < len) return false;
|
||||
return compare(size()-len, len, suffix) == 0;
|
||||
}
|
||||
|
||||
bool contains(const char* str) const {
|
||||
return strstr(c_str(), str);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return strlen(c_str());
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return c_str()[0] == 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
*this = IdString();
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return index_;
|
||||
}
|
||||
|
||||
// The following is a helper key_compare class. Instead of for example std::set<Cell*>
|
||||
// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
|
||||
// set has an influence on the algorithm.
|
||||
|
||||
template<typename T> struct compare_ptr_by_name {
|
||||
bool operator()(const T *a, const T *b) const {
|
||||
return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);
|
||||
}
|
||||
};
|
||||
|
||||
// often one needs to check if a given IdString is part of a list (for example a list
|
||||
// of cell types). the following functions helps with that.
|
||||
|
||||
template<typename... Args>
|
||||
bool in(Args... args) const {
|
||||
// Credit: https://articles.emptycrate.com/2016/05/14/folds_in_cpp11_ish.html
|
||||
bool result = false;
|
||||
(void) std::initializer_list<int>{ (result = result || in(args), 0)... };
|
||||
return result;
|
||||
}
|
||||
|
||||
bool in(const IdString &rhs) const { return *this == rhs; }
|
||||
bool in(const char *rhs) const { return *this == rhs; }
|
||||
bool in(const std::string &rhs) const { return *this == rhs; }
|
||||
bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
|
||||
|
||||
bool isPublic() const { return begins_with("\\"); }
|
||||
};
|
||||
|
||||
// often one needs to check if a given IdString is part of a list (for example a list
|
||||
// of cell types). the following functions helps with that.
|
||||
template<typename... Args>
|
||||
bool in(Args... args) const {
|
||||
return (... || in(args));
|
||||
}
|
||||
|
||||
bool in(const IdString &rhs) const { return *this == rhs; }
|
||||
bool in(const char *rhs) const { return *this == rhs; }
|
||||
bool in(const std::string &rhs) const { return *this == rhs; }
|
||||
inline bool in(const pool<IdString> &rhs) const;
|
||||
inline bool in(const pool<IdString> &&rhs) const;
|
||||
|
||||
bool isPublic() const { return begins_with("\\"); }
|
||||
};
|
||||
|
||||
namespace hashlib {
|
||||
template <>
|
||||
struct hash_ops<RTLIL::IdString> {
|
||||
static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash(const RTLIL::IdString id) {
|
||||
return id.hash_top();
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString id, Hasher h) {
|
||||
return id.hash_into(h);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* How to not use these methods:
|
||||
* 1. if(celltype.in({...})) -> if(celltype.in(...))
|
||||
* 2. pool<IdString> p; ... a.in(p) -> (bool)p.count(a)
|
||||
*/
|
||||
[[deprecated]]
|
||||
inline bool RTLIL::IdString::in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
|
||||
[[deprecated]]
|
||||
inline bool RTLIL::IdString::in(const pool<IdString> &&rhs) const { return rhs.count(*this) != 0; }
|
||||
|
||||
namespace RTLIL {
|
||||
namespace ID {
|
||||
#define X(_id) extern IdString _id;
|
||||
#include "kernel/constids.inc"
|
||||
#undef X
|
||||
};
|
||||
|
||||
extern dict<std::string, std::string> constpad;
|
||||
|
||||
const pool<IdString> &builtin_ff_cell_types();
|
||||
|
|
@ -796,11 +824,10 @@ public:
|
|||
bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());
|
||||
}
|
||||
|
||||
inline unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
|
||||
for (State b : *this)
|
||||
h = mkhash(h, b);
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(size());
|
||||
for (auto b : *this)
|
||||
h.eat(b);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
|
@ -890,7 +917,23 @@ struct RTLIL::SigBit
|
|||
bool operator <(const RTLIL::SigBit &other) const;
|
||||
bool operator ==(const RTLIL::SigBit &other) const;
|
||||
bool operator !=(const RTLIL::SigBit &other) const;
|
||||
unsigned int hash() const;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const;
|
||||
[[nodiscard]] Hasher hash_top() const;
|
||||
};
|
||||
|
||||
namespace hashlib {
|
||||
template <>
|
||||
struct hash_ops<RTLIL::SigBit> {
|
||||
static inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash(const RTLIL::SigBit sb) {
|
||||
return sb.hash_top();
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(const RTLIL::SigBit sb, Hasher h) {
|
||||
return sb.hash_into(h);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpecIterator
|
||||
|
|
@ -931,7 +974,7 @@ struct RTLIL::SigSpec
|
|||
{
|
||||
private:
|
||||
int width_;
|
||||
unsigned long hash_;
|
||||
Hasher::hash_t hash_;
|
||||
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
|
||||
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
|
||||
|
||||
|
|
@ -972,11 +1015,6 @@ public:
|
|||
SigSpec(const std::set<RTLIL::SigBit> &bits);
|
||||
explicit SigSpec(bool bit);
|
||||
|
||||
size_t get_hash() const {
|
||||
if (!hash_) hash();
|
||||
return hash_;
|
||||
}
|
||||
|
||||
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
|
||||
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
|
||||
|
||||
|
|
@ -1083,7 +1121,7 @@ public:
|
|||
operator std::vector<RTLIL::SigBit>() const { return bits(); }
|
||||
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
|
||||
|
||||
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check(Module *mod = nullptr) const;
|
||||
|
|
@ -1124,8 +1162,8 @@ struct RTLIL::Selection
|
|||
|
||||
struct RTLIL::Monitor
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
Monitor() {
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
|
|
@ -1147,8 +1185,8 @@ struct define_map_t;
|
|||
|
||||
struct RTLIL::Design
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
pool<RTLIL::Monitor*> monitors;
|
||||
dict<std::string, std::string> scratchpad;
|
||||
|
|
@ -1252,8 +1290,8 @@ struct RTLIL::Design
|
|||
|
||||
struct RTLIL::Module : public RTLIL::AttrObject
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
protected:
|
||||
void add(RTLIL::Wire *wire);
|
||||
|
|
@ -1607,8 +1645,8 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
|
|||
|
||||
struct RTLIL::Wire : public RTLIL::AttrObject
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
protected:
|
||||
// use module->addWire() and module->remove() to create or destroy wires
|
||||
|
|
@ -1646,8 +1684,8 @@ inline int GetSize(RTLIL::Wire *wire) {
|
|||
|
||||
struct RTLIL::Memory : public RTLIL::AttrObject
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
Memory();
|
||||
|
||||
|
|
@ -1661,8 +1699,8 @@ struct RTLIL::Memory : public RTLIL::AttrObject
|
|||
|
||||
struct RTLIL::Cell : public RTLIL::AttrObject
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
protected:
|
||||
// use module->addCell() and module->remove() to create or destroy cells
|
||||
|
|
@ -1771,8 +1809,8 @@ struct RTLIL::SyncRule
|
|||
|
||||
struct RTLIL::Process : public RTLIL::AttrObject
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
protected:
|
||||
// use module->addProcess() and module->remove() to create or destroy processes
|
||||
|
|
@ -1816,10 +1854,25 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
|
|||
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
|
||||
}
|
||||
|
||||
inline unsigned int RTLIL::SigBit::hash() const {
|
||||
if (wire)
|
||||
return mkhash_add(wire->name.hash(), offset);
|
||||
return data;
|
||||
inline Hasher RTLIL::SigBit::hash_into(Hasher h) const {
|
||||
if (wire) {
|
||||
h.eat(offset);
|
||||
h.eat(wire->name);
|
||||
return h;
|
||||
}
|
||||
h.eat(data);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
inline Hasher RTLIL::SigBit::hash_top() const {
|
||||
Hasher h;
|
||||
if (wire) {
|
||||
h.force(hashlib::legacy::djb2_add(wire->name.index_, offset));
|
||||
return h;
|
||||
}
|
||||
h.force(data);
|
||||
return h;
|
||||
}
|
||||
|
||||
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
|
||||
|
|
|
|||
|
|
@ -743,7 +743,6 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
if (cell->type == ID($macc))
|
||||
{
|
||||
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
||||
std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
|
||||
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
|
||||
Macc macc;
|
||||
|
|
@ -785,12 +784,6 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetSize(b); i++) {
|
||||
std::vector<int> val(GetSize(y), ez->CONST_FALSE);
|
||||
val.at(0) = b.at(i);
|
||||
tmp = ez->vec_add(tmp, val);
|
||||
}
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
|
||||
|
|
|
|||
|
|
@ -169,8 +169,11 @@ public:
|
|||
return !(*this == other);
|
||||
}
|
||||
|
||||
int hash() const {
|
||||
return mkhash(scope_name.hash(), hash_ptr_ops::hash(target));
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const
|
||||
{
|
||||
h.eat(scope_name);
|
||||
h.eat(target);
|
||||
return h;
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
|
|
@ -322,7 +325,7 @@ struct ModuleItem {
|
|||
Cell *cell() const { return type == Type::Cell ? static_cast<Cell *>(ptr) : nullptr; }
|
||||
|
||||
bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; }
|
||||
unsigned int hash() const { return (uintptr_t)ptr; }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(ptr); return h; }
|
||||
};
|
||||
|
||||
static inline void log_dump_val_worker(typename IdTree<ModuleItem>::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); }
|
||||
|
|
@ -334,12 +337,14 @@ template<typename O>
|
|||
std::vector<IdString> parse_hdlname(const O* object)
|
||||
{
|
||||
std::vector<IdString> path;
|
||||
if (!object->name.isPublic())
|
||||
return path;
|
||||
for (auto const &item : object->get_hdlname_attribute())
|
||||
path.push_back("\\" + item);
|
||||
if (path.empty())
|
||||
if (path.empty() && object->name.isPublic())
|
||||
path.push_back(object->name);
|
||||
if (!path.empty() && !(object->name.isPublic() || object->name.begins_with("$paramod") || object->name.begins_with("$abstract"))) {
|
||||
path.pop_back();
|
||||
path.push_back(object->name);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
@ -348,17 +353,22 @@ std::pair<std::vector<IdString>, IdString> parse_scopename(const O* object)
|
|||
{
|
||||
std::vector<IdString> path;
|
||||
IdString trailing = object->name;
|
||||
if (object->name.isPublic()) {
|
||||
if (object->name.isPublic() || object->name.begins_with("$paramod") || object->name.begins_with("$abstract")) {
|
||||
for (auto const &item : object->get_hdlname_attribute())
|
||||
path.push_back("\\" + item);
|
||||
if (!path.empty()) {
|
||||
trailing = path.back();
|
||||
path.pop_back();
|
||||
}
|
||||
} else if (object->has_attribute(ID::hdlname)) {
|
||||
for (auto const &item : object->get_hdlname_attribute())
|
||||
path.push_back("\\" + item);
|
||||
if (!path.empty()) {
|
||||
path.pop_back();
|
||||
}
|
||||
} else {
|
||||
for (auto const &item : split_tokens(object->get_string_attribute(ID(scopename)), " "))
|
||||
path.push_back("\\" + item);
|
||||
|
||||
}
|
||||
return {path, trailing};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,11 @@ struct SigPool
|
|||
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
|
||||
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
|
||||
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
|
||||
unsigned int hash() const { return first->name.hash() + second; }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(first->name);
|
||||
h.eat(second);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
pool<bitDef_t> bits;
|
||||
|
|
@ -143,7 +147,11 @@ struct SigSet
|
|||
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
|
||||
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
|
||||
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
|
||||
unsigned int hash() const { return first->name.hash() + second; }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(first->name);
|
||||
h.eat(second);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
dict<bitDef_t, std::set<T, Compare>> bits;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ struct TimingInfo
|
|||
explicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {}
|
||||
bool operator==(const NameBit& nb) const { return nb.name == name && nb.offset == offset; }
|
||||
bool operator!=(const NameBit& nb) const { return !operator==(nb); }
|
||||
unsigned int hash() const { return mkhash_add(name.hash(), offset); }
|
||||
std::optional<SigBit> get_connection(RTLIL::Cell *cell) {
|
||||
if (!cell->hasPort(name))
|
||||
return {};
|
||||
|
|
@ -45,6 +44,11 @@ struct TimingInfo
|
|||
return {};
|
||||
return port[offset];
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(name);
|
||||
h.eat(offset);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
struct BitBit
|
||||
{
|
||||
|
|
@ -52,7 +56,11 @@ struct TimingInfo
|
|||
BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}
|
||||
BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {}
|
||||
bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; }
|
||||
unsigned int hash() const { return mkhash_add(first.hash(), second.hash()); }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(first);
|
||||
h.eat(second);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct ModuleTiming
|
||||
|
|
|
|||
|
|
@ -31,17 +31,17 @@ YOSYS_NAMESPACE_BEGIN
|
|||
// A map-like container, but you can save and restore the state
|
||||
// ------------------------------------------------
|
||||
|
||||
template<typename Key, typename T, typename OPS = hash_ops<Key>>
|
||||
template<typename Key, typename T>
|
||||
struct stackmap
|
||||
{
|
||||
private:
|
||||
std::vector<dict<Key, T*, OPS>> backup_state;
|
||||
dict<Key, T, OPS> current_state;
|
||||
std::vector<dict<Key, T*>> backup_state;
|
||||
dict<Key, T> current_state;
|
||||
static T empty_tuple;
|
||||
|
||||
public:
|
||||
stackmap() { }
|
||||
stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
|
||||
stackmap(const dict<Key, T> &other) : current_state(other) { }
|
||||
|
||||
template<typename Other>
|
||||
void operator=(const Other &other)
|
||||
|
|
@ -94,7 +94,7 @@ public:
|
|||
current_state.erase(k);
|
||||
}
|
||||
|
||||
const dict<Key, T, OPS> &stdmap()
|
||||
const dict<Key, T> &stdmap()
|
||||
{
|
||||
return current_state;
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ public:
|
|||
// A simple class for topological sorting
|
||||
// ------------------------------------------------
|
||||
|
||||
template <typename T, typename C = std::less<T>, typename OPS = hash_ops<T>> class TopoSort
|
||||
template <typename T, typename C = std::less<T>> class TopoSort
|
||||
{
|
||||
public:
|
||||
// We use this ordering of the edges in the adjacency matrix for
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ std::set<std::string> yosys_input_files, yosys_output_files;
|
|||
bool memhasher_active = false;
|
||||
uint32_t memhasher_rng = 123456;
|
||||
std::vector<void*> memhasher_store;
|
||||
uint32_t Hasher::fudge = 0;
|
||||
|
||||
std::string yosys_share_dirname;
|
||||
std::string yosys_abc_executable;
|
||||
|
|
@ -140,7 +141,7 @@ void yosys_banner()
|
|||
log("\n");
|
||||
log(" /----------------------------------------------------------------------------\\\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | Copyright (C) 2012 - 2024 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n");
|
||||
log(" \\----------------------------------------------------------------------------/\n");
|
||||
log(" %s\n", yosys_version_str);
|
||||
|
|
|
|||
|
|
@ -134,8 +134,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
// Note: All headers included in hashlib.h must be included
|
||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
|
||||
#ifdef HASHLIB_H
|
||||
# undef HASHLIB_H
|
||||
# include "kernel/hashlib.h"
|
||||
# error "You've probably included hashlib.h under two namespace paths. Bad idea."
|
||||
#else
|
||||
# include "kernel/hashlib.h"
|
||||
# undef HASHLIB_H
|
||||
|
|
@ -153,6 +152,15 @@ using std::get;
|
|||
using std::min;
|
||||
using std::max;
|
||||
|
||||
using hashlib::Hasher;
|
||||
using hashlib::run_hash;
|
||||
using hashlib::hash_ops;
|
||||
using hashlib::mkhash_xorshift;
|
||||
using hashlib::dict;
|
||||
using hashlib::idict;
|
||||
using hashlib::pool;
|
||||
using hashlib::mfp;
|
||||
|
||||
// A primitive shared string implementation that does not
|
||||
// move its .c_str() when the object is copied or moved.
|
||||
struct shared_str {
|
||||
|
|
@ -163,22 +171,12 @@ struct shared_str {
|
|||
const char *c_str() const { return content->c_str(); }
|
||||
const string &str() const { return *content; }
|
||||
bool operator==(const shared_str &other) const { return *content == *other.content; }
|
||||
unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(*content);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
using hashlib::mkhash;
|
||||
using hashlib::mkhash_init;
|
||||
using hashlib::mkhash_add;
|
||||
using hashlib::mkhash_xorshift;
|
||||
using hashlib::hash_ops;
|
||||
using hashlib::hash_cstr_ops;
|
||||
using hashlib::hash_ptr_ops;
|
||||
using hashlib::hash_obj_ops;
|
||||
using hashlib::dict;
|
||||
using hashlib::idict;
|
||||
using hashlib::pool;
|
||||
using hashlib::mfp;
|
||||
|
||||
namespace RTLIL {
|
||||
struct IdString;
|
||||
struct Const;
|
||||
|
|
@ -347,10 +345,6 @@ RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std:
|
|||
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
|
||||
namespace ID = RTLIL::ID;
|
||||
|
||||
namespace hashlib {
|
||||
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
|
||||
}
|
||||
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,10 @@ struct IdPath : public std::vector<RTLIL::IdString>
|
|||
bool has_address() const { int tmp; return get_address(tmp); };
|
||||
bool get_address(int &addr) const;
|
||||
|
||||
int hash() const { return hashlib::hash_ops<std::vector<RTLIL::IdString>>::hash(*this); }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(static_cast<const std::vector<RTLIL::IdString>&&>(*this));
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct WitnessHierarchyItem {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace json11 {
|
||||
|
|
|
|||
|
|
@ -855,7 +855,11 @@ class WClass:
|
|||
if self.hash_id != None:
|
||||
text += "\n\t\tunsigned int get_hash_py()"
|
||||
text += "\n\t\t{"
|
||||
text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";"
|
||||
suffix = f"->{self.hash_id}" if self.hash_id else f"->{self.hash_id}"
|
||||
if self.hash_id == "":
|
||||
text += f"\n\t\t\treturn run_hash(*(get_cpp_obj()));"
|
||||
else:
|
||||
text += f"\n\t\t\treturn run_hash(get_cpp_obj()->{self.hash_id});"
|
||||
text += "\n\t\t}"
|
||||
|
||||
text += "\n\t};\n"
|
||||
|
|
@ -956,7 +960,7 @@ class WClass:
|
|||
|
||||
sources = [
|
||||
Source("kernel/celltypes",[
|
||||
WClass("CellType", link_types.pointer, None, None, "type.hash()", True),
|
||||
WClass("CellType", link_types.pointer, None, None, "type", True),
|
||||
WClass("CellTypes", link_types.pointer, None, None, None, True)
|
||||
]
|
||||
),
|
||||
|
|
@ -970,23 +974,23 @@ sources = [
|
|||
]
|
||||
),
|
||||
Source("kernel/rtlil",[
|
||||
WClass("IdString", link_types.ref_copy, None, "str()", "hash()"),
|
||||
WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"),
|
||||
WClass("IdString", link_types.ref_copy, None, "str()", ""),
|
||||
WClass("Const", link_types.ref_copy, None, "as_string()", ""),
|
||||
WClass("AttrObject", link_types.ref_copy, None, None, None),
|
||||
WClass("Selection", link_types.ref_copy, None, None, None),
|
||||
WClass("Monitor", link_types.derive, None, None, None),
|
||||
WClass("CaseRule",link_types.ref_copy, None, None, None, True),
|
||||
WClass("SwitchRule",link_types.ref_copy, None, None, None, True),
|
||||
WClass("SyncRule", link_types.ref_copy, None, None, None, True),
|
||||
WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"),
|
||||
WClass("Process", link_types.ref_copy, None, "name.c_str()", "name"),
|
||||
WClass("SigChunk", link_types.ref_copy, None, None, None),
|
||||
WClass("SigBit", link_types.ref_copy, None, None, "hash()"),
|
||||
WClass("SigSpec", link_types.ref_copy, None, None, "hash()"),
|
||||
WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
|
||||
WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
|
||||
WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
|
||||
WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
|
||||
WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()")
|
||||
WClass("SigBit", link_types.ref_copy, None, None, ""),
|
||||
WClass("SigSpec", link_types.ref_copy, None, None, ""),
|
||||
WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
|
||||
WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
|
||||
WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
|
||||
WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
|
||||
WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "")
|
||||
]
|
||||
),
|
||||
#Source("kernel/satgen",[
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct DftTagWorker {
|
|||
bool operator<(const tag_set &other) const { return index < other.index; }
|
||||
bool operator==(const tag_set &other) const { return index == other.index; }
|
||||
|
||||
unsigned int hash() const { return hash_ops<int>::hash(index); }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(index); return h; }
|
||||
|
||||
bool empty() const { return index == 0; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,8 +52,10 @@ struct ExampleDtPass : public Pass
|
|||
return name == other.name && parameters == other.parameters;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return mkhash(name.hash(), parameters.hash());
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(name);
|
||||
h.eat(parameters);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/hashlib.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
|
|||
|
|
@ -70,13 +70,13 @@ struct GraphNode {
|
|||
|
||||
pool<IdString> names_;
|
||||
dict<int, uint8_t> tags_;
|
||||
pool<GraphNode*, hash_ptr_ops> upstream_;
|
||||
pool<GraphNode*, hash_ptr_ops> downstream_;
|
||||
pool<GraphNode*> upstream_;
|
||||
pool<GraphNode*> downstream_;
|
||||
|
||||
pool<IdString> &names() { return get()->names_; }
|
||||
dict<int, uint8_t> &tags() { return get()->tags_; }
|
||||
pool<GraphNode*, hash_ptr_ops> &upstream() { return get()->upstream_; }
|
||||
pool<GraphNode*, hash_ptr_ops> &downstream() { return get()->downstream_; }
|
||||
pool<GraphNode*> &upstream() { return get()->upstream_; }
|
||||
pool<GraphNode*> &downstream() { return get()->downstream_; }
|
||||
|
||||
uint8_t tag(int index) {
|
||||
return tags().at(index, 0);
|
||||
|
|
@ -154,8 +154,8 @@ struct Graph {
|
|||
nodes.push_back(n);
|
||||
n->index = GetSize(nodes);
|
||||
|
||||
pool<GraphNode*, hash_ptr_ops> new_upstream;
|
||||
pool<GraphNode*, hash_ptr_ops> new_downstream;
|
||||
pool<GraphNode*> new_upstream;
|
||||
pool<GraphNode*> new_downstream;
|
||||
|
||||
for (auto g : n->upstream()) {
|
||||
if (n != (g = g->get()))
|
||||
|
|
@ -302,7 +302,7 @@ struct Graph {
|
|||
}
|
||||
}
|
||||
|
||||
pool<GraphNode*, hash_ptr_ops> excluded;
|
||||
pool<GraphNode*> excluded;
|
||||
|
||||
for (auto grp : config.groups)
|
||||
{
|
||||
|
|
@ -348,7 +348,7 @@ struct Graph {
|
|||
excluded.insert(g->get());
|
||||
|
||||
dict<Cell*, GraphNode*> cell_nodes;
|
||||
dict<SigBit, pool<GraphNode*, hash_ptr_ops>> sig_users;
|
||||
dict<SigBit, pool<GraphNode*>> sig_users;
|
||||
|
||||
for (auto cell : module->selected_cells()) {
|
||||
auto g = new GraphNode;
|
||||
|
|
@ -483,8 +483,8 @@ struct Graph {
|
|||
|
||||
{
|
||||
header("Any nodes with identical connections");
|
||||
typedef pair<pool<GraphNode*, hash_ptr_ops>, pool<GraphNode*, hash_ptr_ops>> node_conn_t;
|
||||
dict<node_conn_t, pool<GraphNode*, hash_ptr_ops>> nodes_by_conn;
|
||||
typedef pair<pool<GraphNode*>, pool<GraphNode*>> node_conn_t;
|
||||
dict<node_conn_t, pool<GraphNode*>> nodes_by_conn;
|
||||
for (auto g : term ? term_nodes : nonterm_nodes) {
|
||||
auto &entry = nodes_by_conn[node_conn_t(g->upstream(), g->downstream())];
|
||||
for (auto n : entry)
|
||||
|
|
@ -506,8 +506,8 @@ struct Graph {
|
|||
|
||||
header("Sibblings with identical tags");
|
||||
for (auto g : nonterm_nodes) {
|
||||
auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
|
||||
dict<std::vector<int>, pool<GraphNode*, hash_ptr_ops>> nodes_by_tags;
|
||||
auto process_conns = [&](const pool<GraphNode*> &stream) {
|
||||
dict<std::vector<int>, pool<GraphNode*>> nodes_by_tags;
|
||||
for (auto n : stream) {
|
||||
if (n->terminal) continue;
|
||||
std::vector<int> key;
|
||||
|
|
@ -556,7 +556,7 @@ struct Graph {
|
|||
if (!term) {
|
||||
header("Sibblings with similar tags (strict)");
|
||||
for (auto g : nonterm_nodes) {
|
||||
auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
|
||||
auto process_conns = [&](const pool<GraphNode*> &stream) {
|
||||
std::vector<GraphNode*> nodes;
|
||||
for (auto n : stream)
|
||||
if (!n->terminal) nodes.push_back(n);
|
||||
|
|
@ -585,7 +585,7 @@ struct Graph {
|
|||
if (!term) {
|
||||
header("Sibblings with similar tags (non-strict)");
|
||||
for (auto g : nonterm_nodes) {
|
||||
auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
|
||||
auto process_conns = [&](const pool<GraphNode*> &stream) {
|
||||
std::vector<GraphNode*> nodes;
|
||||
for (auto n : stream)
|
||||
if (!n->terminal) nodes.push_back(n);
|
||||
|
|
@ -603,7 +603,7 @@ struct Graph {
|
|||
|
||||
{
|
||||
header("Any nodes with identical fan-in or fan-out");
|
||||
dict<pool<GraphNode*, hash_ptr_ops>, pool<GraphNode*, hash_ptr_ops>> nodes_by_conn[2];
|
||||
dict<pool<GraphNode*>, pool<GraphNode*>> nodes_by_conn[2];
|
||||
for (auto g : term ? term_nodes : nonterm_nodes) {
|
||||
auto &up_entry = nodes_by_conn[0][g->upstream()];
|
||||
auto &down_entry = nodes_by_conn[1][g->downstream()];
|
||||
|
|
@ -629,7 +629,7 @@ struct Graph {
|
|||
if (!term) {
|
||||
header("Sibblings with similar tags (lax)");
|
||||
for (auto g : nonterm_nodes) {
|
||||
auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
|
||||
auto process_conns = [&](const pool<GraphNode*> &stream) {
|
||||
std::vector<GraphNode*> nodes;
|
||||
for (auto n : stream)
|
||||
if (!n->terminal) nodes.push_back(n);
|
||||
|
|
@ -720,9 +720,9 @@ struct VizWorker
|
|||
fprintf(f, "digraph \"%s\" {\n", log_id(module));
|
||||
fprintf(f, " rankdir = LR;\n");
|
||||
|
||||
dict<GraphNode*, std::vector<std::vector<std::string>>, hash_ptr_ops> extra_lines;
|
||||
dict<GraphNode*, GraphNode*, hash_ptr_ops> bypass_nodes;
|
||||
pool<GraphNode*, hash_ptr_ops> bypass_candidates;
|
||||
dict<GraphNode*, std::vector<std::vector<std::string>>> extra_lines;
|
||||
dict<GraphNode*, GraphNode*> bypass_nodes;
|
||||
pool<GraphNode*> bypass_candidates;
|
||||
|
||||
auto bypass = [&](GraphNode *g, GraphNode *n) {
|
||||
log_assert(g->terminal);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@ struct EquivStructWorker
|
|||
parameters == other.parameters && port_sizes == other.port_sizes;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
h = mkhash(h, mkhash(type));
|
||||
h = mkhash(h, mkhash(parameters));
|
||||
h = mkhash(h, mkhash(connections));
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(type);
|
||||
h.eat(parameters);
|
||||
h.eat(port_sizes);
|
||||
h.eat(connections);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -377,6 +377,13 @@ static void extract_fsm(RTLIL::Wire *wire)
|
|||
fsm_cell->setPort(ID::CTRL_OUT, ctrl_out);
|
||||
fsm_cell->parameters[ID::NAME] = RTLIL::Const(wire->name.str());
|
||||
fsm_cell->attributes = wire->attributes;
|
||||
if(fsm_cell->attributes.count(ID::hdlname)) {
|
||||
auto hdlname = fsm_cell->get_hdlname_attribute();
|
||||
hdlname.pop_back();
|
||||
fsm_cell->set_hdlname_attribute(hdlname);
|
||||
fsm_cell->set_string_attribute(ID(scopename), fsm_cell->get_string_attribute(ID::hdlname));
|
||||
fsm_cell->attributes.erase(ID::hdlname);
|
||||
}
|
||||
fsm_data.copy_to_cell(fsm_cell);
|
||||
|
||||
// rename original state wire
|
||||
|
|
@ -385,6 +392,13 @@ static void extract_fsm(RTLIL::Wire *wire)
|
|||
wire->attributes.erase(ID::fsm_encoding);
|
||||
wire->name = stringf("$fsm$oldstate%s", wire->name.c_str());
|
||||
module->wires_[wire->name] = wire;
|
||||
if(wire->attributes.count(ID::hdlname)) {
|
||||
auto hdlname = wire->get_hdlname_attribute();
|
||||
hdlname.pop_back();
|
||||
wire->set_hdlname_attribute(hdlname);
|
||||
wire->set_string_attribute(ID(scopename), wire->get_string_attribute(ID::hdlname));
|
||||
wire->attributes.erase(ID::hdlname);
|
||||
}
|
||||
|
||||
// unconnect control outputs from old drivers
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/cost.h"
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ struct ThresholdHierarchyKeeping {
|
|||
}
|
||||
|
||||
if (size > threshold) {
|
||||
log("Keeping %s (estimated size above threshold: %llu > %llu).\n", log_id(module), size, threshold);
|
||||
log("Keeping %s (estimated size above threshold: %" PRIu64 " > %" PRIu64 ").\n", log_id(module), size, threshold);
|
||||
module->set_bool_attribute(ID::keep_hierarchy);
|
||||
size = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ struct ShareWorker
|
|||
|
||||
static int bits_macc(const Macc &m, int width)
|
||||
{
|
||||
int bits = GetSize(m.bit_ports);
|
||||
int bits = 0;
|
||||
for (auto &p : m.ports)
|
||||
bits += bits_macc_port(p, width);
|
||||
return bits;
|
||||
|
|
@ -1255,7 +1255,6 @@ struct ShareWorker
|
|||
qcsat.max_cell_count = 100;
|
||||
}
|
||||
|
||||
pool<RTLIL::Cell*> sat_cells;
|
||||
std::set<RTLIL::SigBit> bits_queue;
|
||||
|
||||
std::vector<int> cell_active, other_cell_active;
|
||||
|
|
@ -1298,8 +1297,8 @@ struct ShareWorker
|
|||
|
||||
qcsat.ez->assume(qcsat.ez->AND(sub1, sub2));
|
||||
|
||||
log(" Size of SAT problem: %d cells, %d variables, %d clauses\n",
|
||||
GetSize(sat_cells), qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses());
|
||||
log(" Size of SAT problem: %d variables, %d clauses\n",
|
||||
qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses());
|
||||
|
||||
if (qcsat.ez->solve(sat_model, sat_model_values)) {
|
||||
log(" According to the SAT solver this pair of cells can not be shared.\n");
|
||||
|
|
|
|||
|
|
@ -263,6 +263,19 @@ struct WreduceWorker
|
|||
}
|
||||
}
|
||||
|
||||
int reduced_opsize(const SigSpec &inp, bool signed_)
|
||||
{
|
||||
int size = GetSize(inp);
|
||||
if (signed_) {
|
||||
while (size >= 2 && inp[size - 1] == inp[size - 2])
|
||||
size--;
|
||||
} else {
|
||||
while (size >= 1 && inp[size - 1] == State::S0)
|
||||
size--;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void run_cell(Cell *cell)
|
||||
{
|
||||
bool did_something = false;
|
||||
|
|
@ -295,6 +308,45 @@ struct WreduceWorker
|
|||
bool port_a_signed = false;
|
||||
bool port_b_signed = false;
|
||||
|
||||
// For some operations if the output is no wider than either of the inputs
|
||||
// we are free to choose the signedness of the operands
|
||||
if (cell->type.in(ID($mul), ID($add), ID($sub)) &&
|
||||
max_port_a_size == GetSize(sig) &&
|
||||
max_port_b_size == GetSize(sig)) {
|
||||
SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)), sig_b = mi.sigmap(cell->getPort(ID::B));
|
||||
|
||||
// Remove top bits from sig_a and sig_b which are not visible on the output
|
||||
sig_a.extend_u0(max_port_a_size);
|
||||
sig_b.extend_u0(max_port_b_size);
|
||||
|
||||
int signed_cost, unsigned_cost;
|
||||
if (cell->type == ID($mul)) {
|
||||
signed_cost = reduced_opsize(sig_a, true) * reduced_opsize(sig_b, true);
|
||||
unsigned_cost = reduced_opsize(sig_a, false) * reduced_opsize(sig_b, false);
|
||||
} else {
|
||||
signed_cost = max(reduced_opsize(sig_a, true), reduced_opsize(sig_b, true));
|
||||
unsigned_cost = max(reduced_opsize(sig_a, false), reduced_opsize(sig_b, false));
|
||||
}
|
||||
|
||||
if (!port_a_signed && !port_b_signed && signed_cost < unsigned_cost) {
|
||||
log("Converting cell %s.%s (%s) from unsigned to signed.\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type));
|
||||
cell->setParam(ID::A_SIGNED, 1);
|
||||
cell->setParam(ID::B_SIGNED, 1);
|
||||
port_a_signed = true;
|
||||
port_b_signed = true;
|
||||
did_something = true;
|
||||
} else if (port_a_signed && port_b_signed && unsigned_cost < signed_cost) {
|
||||
log("Converting cell %s.%s (%s) from signed to unsigned.\n",
|
||||
log_id(module), log_id(cell), log_id(cell->type));
|
||||
cell->setParam(ID::A_SIGNED, 0);
|
||||
cell->setParam(ID::B_SIGNED, 0);
|
||||
port_a_signed = false;
|
||||
port_b_signed = false;
|
||||
did_something = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_port_a_size >= 0 && cell->type != ID($shiftx))
|
||||
run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
|
||||
|
||||
|
|
|
|||
|
|
@ -127,11 +127,10 @@ struct proc_dlatch_db_t
|
|||
return signal == other.signal && match == other.match && children == other.children;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
mkhash(h, signal.hash());
|
||||
mkhash(h, match.hash());
|
||||
for (auto i : children) mkhash(h, i);
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
h.eat(signal);
|
||||
h.eat(match);
|
||||
h.eat(children);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ struct SigSnippets
|
|||
|
||||
struct SnippetSwCache
|
||||
{
|
||||
dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache;
|
||||
dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
|
||||
dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>> full_case_bits_cache;
|
||||
dict<RTLIL::SwitchRule*, pool<int>> cache;
|
||||
const SigSnippets *snippets;
|
||||
int current_snippet;
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRul
|
|||
return swcache.full_case_bits_cache.at(sw);
|
||||
}
|
||||
|
||||
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
|
||||
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool> &swpara,
|
||||
RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
|
||||
{
|
||||
RTLIL::SigSpec result = defval;
|
||||
|
|
@ -421,7 +421,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
|
|||
swcache.snippets = &sigsnip;
|
||||
swcache.insert(&proc->root_case);
|
||||
|
||||
dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> swpara;
|
||||
dict<RTLIL::SwitchRule*, bool> swpara;
|
||||
|
||||
int cnt = 0;
|
||||
for (int idx : sigsnip.snippets)
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ struct coverdb_t
|
|||
|
||||
struct mutate_queue_t
|
||||
{
|
||||
pool<mutate_t*, hash_ptr_ops> db;
|
||||
pool<mutate_t*> db;
|
||||
|
||||
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
|
||||
mutate_t *m = nullptr;
|
||||
|
|
|
|||
|
|
@ -46,9 +46,11 @@ struct IdBit {
|
|||
|
||||
bool operator==(const IdBit &other) const { return name == other.name && bit == other.bit; };
|
||||
bool operator!=(const IdBit &other) const { return name != other.name || bit != other.bit; };
|
||||
unsigned hash() const
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const
|
||||
{
|
||||
return mkhash_add(name.hash(), bit);
|
||||
h.eat(name);
|
||||
h.eat(bit);
|
||||
return h;
|
||||
}
|
||||
|
||||
IdString name;
|
||||
|
|
@ -62,9 +64,11 @@ struct InvBit {
|
|||
|
||||
bool operator==(const InvBit &other) const { return bit == other.bit && inverted == other.inverted; };
|
||||
bool operator!=(const InvBit &other) const { return bit != other.bit || inverted != other.inverted; };
|
||||
unsigned hash() const
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const
|
||||
{
|
||||
return mkhash(bit.hash(), inverted);
|
||||
h.eat(bit);
|
||||
h.eat(inverted);
|
||||
return h;
|
||||
}
|
||||
|
||||
IdBit bit;
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ struct SimInstance
|
|||
pool<SigBit> dirty_bits;
|
||||
pool<Cell*> dirty_cells;
|
||||
pool<IdString> dirty_memories;
|
||||
pool<SimInstance*, hash_ptr_ops> dirty_children;
|
||||
pool<SimInstance*> dirty_children;
|
||||
|
||||
struct ff_state_t
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1411,6 +1411,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
|||
module->connect(conn);
|
||||
}
|
||||
|
||||
cell_stats.sort();
|
||||
for (auto &it : cell_stats)
|
||||
log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
|
||||
int in_wires = 0, out_wires = 0;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ struct AlumaccWorker
|
|||
|
||||
dict<RTLIL::SigBit, int> bit_users;
|
||||
dict<RTLIL::SigSpec, maccnode_t*> sig_macc;
|
||||
dict<RTLIL::SigSig, pool<alunode_t*, hash_ptr_ops>> sig_alu;
|
||||
dict<RTLIL::SigSig, pool<alunode_t*>> sig_alu;
|
||||
int macc_counter, alu_counter;
|
||||
|
||||
AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module)
|
||||
|
|
@ -226,7 +226,7 @@ struct AlumaccWorker
|
|||
{
|
||||
while (1)
|
||||
{
|
||||
pool<maccnode_t*, hash_ptr_ops> delete_nodes;
|
||||
pool<maccnode_t*> delete_nodes;
|
||||
|
||||
for (auto &it : sig_macc)
|
||||
{
|
||||
|
|
@ -278,12 +278,12 @@ struct AlumaccWorker
|
|||
|
||||
void macc_to_alu()
|
||||
{
|
||||
pool<maccnode_t*, hash_ptr_ops> delete_nodes;
|
||||
pool<maccnode_t*> delete_nodes;
|
||||
|
||||
for (auto &it : sig_macc)
|
||||
{
|
||||
auto n = it.second;
|
||||
RTLIL::SigSpec A, B, C = n->macc.bit_ports;
|
||||
RTLIL::SigSpec A, B, C;
|
||||
bool a_signed = false, b_signed = false;
|
||||
bool subtract_b = false;
|
||||
alunode_t *alunode;
|
||||
|
|
|
|||
|
|
@ -233,10 +233,9 @@ struct ClockgatePass : public Pass {
|
|||
SigBit ce_bit;
|
||||
bool pol_clk;
|
||||
bool pol_ce;
|
||||
unsigned int hash() const {
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce);
|
||||
unsigned int h = mkhash_init;
|
||||
h = mkhash(h, hash_ops<decltype(t)>::hash(t));
|
||||
h.eat(t);
|
||||
return h;
|
||||
}
|
||||
bool operator==(const ClkNetInfo& other) const {
|
||||
|
|
|
|||
|
|
@ -28,22 +28,22 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
IdString concat_name(RTLIL::Cell *cell, IdString object_name)
|
||||
IdString concat_name(RTLIL::Cell *cell, IdString object_name, const std::string &separator = ".")
|
||||
{
|
||||
if (object_name[0] == '\\')
|
||||
return stringf("%s.%s", cell->name.c_str(), object_name.c_str() + 1);
|
||||
return stringf("%s%s%s", cell->name.c_str(), separator.c_str(), object_name.c_str() + 1);
|
||||
else {
|
||||
std::string object_name_str = object_name.str();
|
||||
if (object_name_str.substr(0, 8) == "$flatten")
|
||||
object_name_str.erase(0, 8);
|
||||
return stringf("$flatten%s.%s", cell->name.c_str(), object_name_str.c_str());
|
||||
return stringf("$flatten%s%s%s", cell->name.c_str(), separator.c_str(), object_name_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
IdString map_name(RTLIL::Cell *cell, T *object)
|
||||
IdString map_name(RTLIL::Cell *cell, T *object, const std::string &separator = ".")
|
||||
{
|
||||
return cell->module->uniquify(concat_name(cell, object->name));
|
||||
return cell->module->uniquify(concat_name(cell, object->name, separator));
|
||||
}
|
||||
|
||||
void map_sigspec(const dict<RTLIL::Wire*, RTLIL::Wire*> &map, RTLIL::SigSpec &sig, RTLIL::Module *into = nullptr)
|
||||
|
|
@ -60,6 +60,7 @@ struct FlattenWorker
|
|||
bool ignore_wb = false;
|
||||
bool create_scopeinfo = true;
|
||||
bool create_scopename = false;
|
||||
std::string separator = ".";
|
||||
|
||||
template<class T>
|
||||
void map_attributes(RTLIL::Cell *cell, T *object, IdString orig_object_name)
|
||||
|
|
@ -107,13 +108,13 @@ struct FlattenWorker
|
|||
}
|
||||
}
|
||||
|
||||
void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells)
|
||||
void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells, const std::string &separator)
|
||||
{
|
||||
// Copy the contents of the flattened cell
|
||||
|
||||
dict<IdString, IdString> memory_map;
|
||||
for (auto &tpl_memory_it : tpl->memories) {
|
||||
RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second), tpl_memory_it.second);
|
||||
RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second, separator), tpl_memory_it.second);
|
||||
map_attributes(cell, new_memory, tpl_memory_it.second->name);
|
||||
memory_map[tpl_memory_it.first] = new_memory->name;
|
||||
design->select(module, new_memory);
|
||||
|
|
@ -127,7 +128,7 @@ struct FlattenWorker
|
|||
|
||||
RTLIL::Wire *new_wire = nullptr;
|
||||
if (tpl_wire->name[0] == '\\') {
|
||||
RTLIL::Wire *hier_wire = module->wire(concat_name(cell, tpl_wire->name));
|
||||
RTLIL::Wire *hier_wire = module->wire(concat_name(cell, tpl_wire->name, separator));
|
||||
if (hier_wire != nullptr && hier_wire->get_bool_attribute(ID::hierconn)) {
|
||||
hier_wire->attributes.erase(ID::hierconn);
|
||||
if (GetSize(hier_wire) < GetSize(tpl_wire)) {
|
||||
|
|
@ -139,7 +140,7 @@ struct FlattenWorker
|
|||
}
|
||||
}
|
||||
if (new_wire == nullptr) {
|
||||
new_wire = module->addWire(map_name(cell, tpl_wire), tpl_wire);
|
||||
new_wire = module->addWire(map_name(cell, tpl_wire, separator), tpl_wire);
|
||||
new_wire->port_input = new_wire->port_output = false;
|
||||
new_wire->port_id = false;
|
||||
}
|
||||
|
|
@ -150,7 +151,7 @@ struct FlattenWorker
|
|||
}
|
||||
|
||||
for (auto &tpl_proc_it : tpl->processes) {
|
||||
RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second), tpl_proc_it.second);
|
||||
RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second, separator), tpl_proc_it.second);
|
||||
map_attributes(cell, new_proc, tpl_proc_it.second->name);
|
||||
for (auto new_proc_sync : new_proc->syncs)
|
||||
for (auto &memwr_action : new_proc_sync->mem_write_actions)
|
||||
|
|
@ -161,14 +162,14 @@ struct FlattenWorker
|
|||
}
|
||||
|
||||
for (auto tpl_cell : tpl->cells()) {
|
||||
RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell), tpl_cell);
|
||||
RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell, separator), tpl_cell);
|
||||
map_attributes(cell, new_cell, tpl_cell->name);
|
||||
if (new_cell->has_memid()) {
|
||||
IdString memid = new_cell->getParam(ID::MEMID).decode_string();
|
||||
new_cell->setParam(ID::MEMID, Const(memory_map.at(memid).str()));
|
||||
} else if (new_cell->is_mem_cell()) {
|
||||
IdString memid = new_cell->getParam(ID::MEMID).decode_string();
|
||||
new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid).str()));
|
||||
new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid, separator).str()));
|
||||
}
|
||||
auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); };
|
||||
new_cell->rewrite_sigspecs(rewriter);
|
||||
|
|
@ -279,7 +280,7 @@ struct FlattenWorker
|
|||
module->rename(scopeinfo, cell_name);
|
||||
}
|
||||
|
||||
void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool<RTLIL::Module*> &used_modules)
|
||||
void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool<RTLIL::Module*> &used_modules, const std::string &separator)
|
||||
{
|
||||
if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
|
||||
return;
|
||||
|
|
@ -308,7 +309,7 @@ struct FlattenWorker
|
|||
// If a design is fully selected and has a top module defined, topological sorting ensures that all cells
|
||||
// added during flattening are black boxes, and flattening is finished in one pass. However, when flattening
|
||||
// individual modules, this isn't the case, and the newly added cells might have to be flattened further.
|
||||
flatten_cell(design, module, cell, tpl, sigmap, worklist);
|
||||
flatten_cell(design, module, cell, tpl, sigmap, worklist, separator);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -345,6 +346,9 @@ struct FlattenPass : public Pass {
|
|||
log(" with a public name the enclosing scope can be found via their\n");
|
||||
log(" 'hdlname' attribute.\n");
|
||||
log("\n");
|
||||
log(" -separator <char>\n");
|
||||
log(" Use this separator char instead of '.' when concatenating design levels.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
|
|
@ -353,6 +357,9 @@ struct FlattenPass : public Pass {
|
|||
|
||||
FlattenWorker worker;
|
||||
|
||||
if (design->scratchpad.count("flatten.separator"))
|
||||
worker.separator = design->scratchpad_get_string("flatten.separator");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-wb") {
|
||||
|
|
@ -367,6 +374,10 @@ struct FlattenPass : public Pass {
|
|||
worker.create_scopename = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-separator" && argidx + 1 < args.size()) {
|
||||
worker.separator = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -401,7 +412,7 @@ struct FlattenPass : public Pass {
|
|||
log_error("Cannot flatten a design containing recursive instantiations.\n");
|
||||
|
||||
for (auto module : topo_modules.sorted)
|
||||
worker.flatten_module(design, module, used_modules);
|
||||
worker.flatten_module(design, module, used_modules, worker.separator);
|
||||
|
||||
if (top != nullptr)
|
||||
for (auto module : design->modules().to_vector())
|
||||
|
|
|
|||
|
|
@ -250,9 +250,11 @@ struct FlowGraph
|
|||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
unsigned int hash() const
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const
|
||||
{
|
||||
return hash_ops<pair<RTLIL::SigBit, int>>::hash({node, is_bottom});
|
||||
std::pair<RTLIL::SigBit, int> p = {node, is_bottom};
|
||||
h.eat(p);
|
||||
return h;
|
||||
}
|
||||
|
||||
static NodePrime top(RTLIL::SigBit node)
|
||||
|
|
|
|||
|
|
@ -286,19 +286,23 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
|
|||
log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b),
|
||||
GetSize(port.in_a), GetSize(port.in_b), port.is_signed ? "signed" : "unsigned");
|
||||
|
||||
if (GetSize(macc.bit_ports) != 0)
|
||||
log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), GetSize(macc.bit_ports));
|
||||
|
||||
if (unmap)
|
||||
{
|
||||
typedef std::pair<RTLIL::SigSpec, bool> summand_t;
|
||||
std::vector<summand_t> summands;
|
||||
|
||||
RTLIL::SigSpec bit_ports;
|
||||
|
||||
for (auto &port : macc.ports) {
|
||||
summand_t this_summand;
|
||||
if (GetSize(port.in_b)) {
|
||||
this_summand.first = module->addWire(NEW_ID, width);
|
||||
module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed);
|
||||
} else if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
|
||||
// Mimic old 'bit_ports' treatment in case it's relevant for performance,
|
||||
// i.e. defer single-bit summands to be the last ones
|
||||
bit_ports.append(port.in_a);
|
||||
continue;
|
||||
} else if (GetSize(port.in_a) != width) {
|
||||
this_summand.first = module->addWire(NEW_ID, width);
|
||||
module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed);
|
||||
|
|
@ -309,7 +313,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
|
|||
summands.push_back(this_summand);
|
||||
}
|
||||
|
||||
for (auto &bit : macc.bit_ports)
|
||||
for (auto &bit : bit_ports)
|
||||
summands.push_back(summand_t(bit, false));
|
||||
|
||||
if (GetSize(summands) == 0)
|
||||
|
|
@ -346,14 +350,20 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
|
|||
else
|
||||
{
|
||||
MaccmapWorker worker(module, width);
|
||||
RTLIL::SigSpec bit_ports;
|
||||
|
||||
for (auto &port : macc.ports)
|
||||
if (GetSize(port.in_b) == 0)
|
||||
for (auto &port : macc.ports) {
|
||||
// Mimic old 'bit_ports' treatment in case it's relevant for performance,
|
||||
// i.e. defer single-bit summands to be the last ones
|
||||
if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract)
|
||||
bit_ports.append(port.in_a);
|
||||
else if (GetSize(port.in_b) == 0)
|
||||
worker.add(port.in_a, port.is_signed, port.do_subtract);
|
||||
else
|
||||
worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract);
|
||||
}
|
||||
|
||||
for (auto &bit : macc.bit_ports)
|
||||
for (auto bit : bit_ports)
|
||||
worker.add(bit, 0);
|
||||
|
||||
module->connect(cell->getPort(ID::Y), worker.synth());
|
||||
|
|
|
|||
|
|
@ -201,18 +201,19 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
this_port.do_subtract = xorshift32(2) == 1;
|
||||
macc.ports.push_back(this_port);
|
||||
}
|
||||
|
||||
wire = module->addWire(ID::B);
|
||||
wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
|
||||
wire->port_input = true;
|
||||
macc.bit_ports = wire;
|
||||
// Macc::to_cell sets the input ports
|
||||
macc.to_cell(cell);
|
||||
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = width;
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
|
||||
macc.to_cell(cell);
|
||||
// override the B input (macc helpers always sets an empty vector)
|
||||
wire = module->addWire(ID::B);
|
||||
wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::B, wire);
|
||||
}
|
||||
|
||||
if (cell_type == ID($lut))
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass {
|
|||
DspConfig(const DspConfig &ref) = default;
|
||||
DspConfig(DspConfig &&ref) = default;
|
||||
|
||||
unsigned int hash() const { return connections.hash(); }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(connections); return h; }
|
||||
|
||||
bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
def generate(filename):
|
||||
with open(filename, "w") as f:
|
||||
f.write("// **AUTOGENERATED FILE** **DO NOT EDIT**\n")
|
||||
f.write(f"// Generated by {sys.argv[0]} at {datetime.now(timezone.utc)}\n")
|
||||
f.write(f"// Generated by {sys.argv[0]}\n")
|
||||
|
||||
f.write("`timescale 1ns /10ps\n")
|
||||
for a_width in [1,2,4,9,18,36]:
|
||||
|
|
|
|||
50
tests/alumacc/macc_b_port_compat.ys
Normal file
50
tests/alumacc/macc_b_port_compat.ys
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# We don't set the B port on $macc cells anymore,
|
||||
# test compatibility with older RTLIL files which can
|
||||
# have the B port populated
|
||||
|
||||
read_verilog <<EOF
|
||||
module gold(input signed [2:0] a1, input signed [2:0] b1,
|
||||
input [1:0] a2, input [3:0] b2, input c, input d, output signed [3:0] y);
|
||||
wire signed [3:0] ab1;
|
||||
assign ab1 = a1 * b1;
|
||||
assign y = ab1 + a2*b2 + c + d + 1;
|
||||
endmodule
|
||||
EOF
|
||||
prep
|
||||
|
||||
# test the model for $macc including the retired B parameter
|
||||
# matches the gold module
|
||||
read_rtlil <<EOF
|
||||
attribute \src "<<EOF:1.1-4.10"
|
||||
module \gate
|
||||
wire width 3 input 1 signed \a1
|
||||
wire width 2 input 3 \a2
|
||||
wire width 3 input 2 signed \b1
|
||||
wire width 4 input 4 \b2
|
||||
wire input 5 \c
|
||||
wire input 6 \d
|
||||
wire width 4 output 7 signed \y
|
||||
|
||||
cell $macc $1
|
||||
parameter \A_WIDTH 12
|
||||
parameter \B_WIDTH 3
|
||||
parameter \CONFIG 20'01010000011011010011
|
||||
parameter \CONFIG_WIDTH 20
|
||||
parameter \Y_WIDTH 4
|
||||
connect \A { \a2 \b2 \b1 \a1 }
|
||||
connect \B { \d \c 1'1 }
|
||||
connect \Y \y
|
||||
end
|
||||
end
|
||||
EOF
|
||||
|
||||
design -save gold_gate
|
||||
equiv_make gold gate equiv
|
||||
equiv_induct equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
design -load gold_gate
|
||||
maccmap gate
|
||||
equiv_make gold gate equiv
|
||||
equiv_induct equiv
|
||||
equiv_status -assert equiv
|
||||
6
tests/alumacc/run-test.sh
Normal file
6
tests/alumacc/run-test.sh
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
for x in *.ys; do
|
||||
echo "Running $x.."
|
||||
../../yosys -ql ${x%.ys}.log $x
|
||||
done
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
set -eu
|
||||
python3 mem_gen.py
|
||||
source ../../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash
|
||||
generate_mk --yosys-scripts --bash
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ YOSYS_BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../ >/dev/null 2>&1 && pwd)
|
|||
|
||||
# $ generate_target target_name test_command
|
||||
generate_target() {
|
||||
target_name=$1
|
||||
target_name=$(basename $PWD)-$1
|
||||
test_command=$2
|
||||
echo "all: $target_name"
|
||||
echo ".PHONY: $target_name"
|
||||
|
|
@ -105,7 +105,6 @@ generate_tests() {
|
|||
fi
|
||||
}
|
||||
|
||||
run_tests() {
|
||||
generate_mk() {
|
||||
generate_tests "$@" > run-test.mk
|
||||
exec ${MAKE:-make} -f run-test.mk
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts
|
||||
generate_mk --yosys-scripts
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts
|
||||
generate_mk --yosys-scripts
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ find tb/* -name tb*.v | while read name; do
|
|||
iverilog -o tb/$test_name.out $name $verilog_name
|
||||
./tb/$test_name.out -fst
|
||||
done
|
||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --prove-sv
|
||||
generate_mk --yosys-scripts --prove-sv
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --tcl-scripts --bash --yosys-args "-e 'select out of bounds'"
|
||||
generate_mk --yosys-scripts --tcl-scripts --bash --yosys-args "-e 'select out of bounds'"
|
||||
|
|
|
|||
38
tests/various/json_scopeinfo.ys
Normal file
38
tests/various/json_scopeinfo.ys
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
read_verilog <<EOT
|
||||
module top(input in, output out);
|
||||
wire [1:0] w1, w2;
|
||||
f1_test u1 (.in(in), .out(w1[0]));
|
||||
f2_test u2 (.in(w1), .out(w2));
|
||||
f3_test u3 (.in(w2[0]), .out(out));
|
||||
endmodule
|
||||
|
||||
module f1_test(input in, output out);
|
||||
assign out = in;
|
||||
endmodule
|
||||
|
||||
module f2_test(input [1:0] in, output [1:0] out);
|
||||
assign out[0] = in[0];
|
||||
assign out[1] = in[1];
|
||||
endmodule
|
||||
|
||||
module f3_test(input in, output [1:0] out);
|
||||
assign out[0] = in;
|
||||
assign out[1] = in;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
hierarchy -top top
|
||||
flatten -scopename
|
||||
prep
|
||||
|
||||
write_json json_scopeinfo.out
|
||||
!grep -qF '$scopeinfo' json_scopeinfo.out
|
||||
|
||||
write_json -noscopeinfo json_scopeinfo.out
|
||||
!grep -qvF '$scopeinfo' json_scopeinfo.out
|
||||
|
||||
json -o json_scopeinfo.out
|
||||
!grep -qF '$scopeinfo' json_scopeinfo.out
|
||||
|
||||
json -noscopeinfo -o json_scopeinfo.out
|
||||
!grep -qvF '$scopeinfo' json_scopeinfo.out
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash
|
||||
generate_mk --yosys-scripts --bash
|
||||
|
|
|
|||
22
tests/various/wreduce2.ys
Normal file
22
tests/various/wreduce2.ys
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
parameter awidth = 6;
|
||||
parameter bwidth = 8;
|
||||
parameter ywidth = 14;
|
||||
|
||||
input [awidth-1:0] a;
|
||||
input [bwidth-1:0] b;
|
||||
output [ywidth-1:0] y;
|
||||
|
||||
wire [ywidth-1:0] aext = {{(ywidth-awidth){a[awidth-1]}}, a};
|
||||
wire [ywidth-1:0] bext = {{(ywidth-bwidth){b[bwidth-1]}}, b};
|
||||
|
||||
assign y = aext*bext;
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
opt_clean
|
||||
wreduce
|
||||
select -assert-count 1 t:$mul
|
||||
select -assert-count 1 t:$mul r:A_SIGNED=1 r:B_SIGNED=1 %i %i
|
||||
select -assert-count 1 t:$mul r:A_WIDTH=6 r:B_WIDTH=8 %i %i
|
||||
45
tests/verific/bounds.sv
Normal file
45
tests/verific/bounds.sv
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
typedef enum {IDLE, RUN, STOP} state_t;
|
||||
|
||||
typedef struct {
|
||||
logic [7:0] field1;
|
||||
int field2;
|
||||
} my_struct_t;
|
||||
|
||||
// Submodule to handle the interface ports
|
||||
module submodule (
|
||||
my_ifc i_ifc,
|
||||
my_ifc o_ifc
|
||||
);
|
||||
// Connect the interface signals
|
||||
assign o_ifc.data = i_ifc.data;
|
||||
endmodule
|
||||
|
||||
module test (
|
||||
input i_a,
|
||||
output o_a,
|
||||
input [0:0] i_b,
|
||||
output [0:0] o_b,
|
||||
input [3:0] i_c,
|
||||
output [3:0] o_c,
|
||||
input logic i_d,
|
||||
output logic o_d,
|
||||
input bit [7:0] i_e,
|
||||
output bit [7:0] o_e,
|
||||
input int i_f,
|
||||
output int o_f,
|
||||
input state_t i_h,
|
||||
output state_t o_h,
|
||||
input my_struct_t i_i,
|
||||
output my_struct_t o_i
|
||||
);
|
||||
|
||||
assign o_a = i_a;
|
||||
assign o_b = i_b;
|
||||
assign o_c = i_c;
|
||||
assign o_d = i_d;
|
||||
assign o_e = i_e;
|
||||
assign o_f = i_f;
|
||||
assign o_h = i_h;
|
||||
assign o_i = i_i;
|
||||
|
||||
endmodule
|
||||
|
|
@ -2,17 +2,108 @@ library IEEE;
|
|||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.NUMERIC_STD.ALL;
|
||||
|
||||
entity work is
|
||||
entity test is
|
||||
Port (
|
||||
a : in INTEGER range -5 to 10;
|
||||
b : out INTEGER range -6 to 11
|
||||
);
|
||||
end entity work;
|
||||
-- BIT type
|
||||
bit_in : in BIT;
|
||||
bit_out : out BIT;
|
||||
|
||||
architecture Behavioral of work is
|
||||
-- BIT_VECTOR type
|
||||
bit_vector_in : in BIT_VECTOR(3 downto 0);
|
||||
bit_vector_out : out BIT_VECTOR(3 downto 0);
|
||||
|
||||
-- BIT_VECTOR type with to index
|
||||
bit_vector_in_to : in BIT_VECTOR(0 to 3);
|
||||
bit_vector_out_to : out BIT_VECTOR(0 to 3);
|
||||
|
||||
-- STD_ULOGIC type
|
||||
std_ulogic_in : in STD_ULOGIC;
|
||||
std_ulogic_out : out STD_ULOGIC;
|
||||
|
||||
-- STD_ULOGIC_VECTOR type
|
||||
std_ulogic_vector_in : in STD_ULOGIC_VECTOR(3 downto 0);
|
||||
std_ulogic_vector_out : out STD_ULOGIC_VECTOR(3 downto 0);
|
||||
|
||||
-- STD_ULOGIC_VECTOR type with to index
|
||||
std_ulogic_vector_in_to : in STD_ULOGIC_VECTOR(0 to 3);
|
||||
std_ulogic_vector_out_to : out STD_ULOGIC_VECTOR(0 to 3);
|
||||
|
||||
-- STD_LOGIC type
|
||||
std_logic_in : in STD_LOGIC;
|
||||
std_logic_out : out STD_LOGIC;
|
||||
|
||||
-- STD_LOGIC_VECTOR type
|
||||
std_logic_vector_in : in STD_LOGIC_VECTOR(3 downto 0);
|
||||
std_logic_vector_out : out STD_LOGIC_VECTOR(3 downto 0);
|
||||
|
||||
-- STD_LOGIC_VECTOR type with to index
|
||||
std_logic_vector_in_to : in STD_LOGIC_VECTOR(0 to 3);
|
||||
std_logic_vector_out_to : out STD_LOGIC_VECTOR(0 to 3);
|
||||
|
||||
-- SIGNED type
|
||||
signed_in : in SIGNED(3 downto 0);
|
||||
signed_out : out SIGNED(3 downto 0);
|
||||
|
||||
-- SIGNED type with to index
|
||||
signed_in_to : in SIGNED(0 to 3);
|
||||
signed_out_to : out SIGNED(0 to 3);
|
||||
|
||||
-- UNSIGNED type
|
||||
unsigned_in : in UNSIGNED(3 downto 0);
|
||||
unsigned_out : out UNSIGNED(3 downto 0);
|
||||
|
||||
-- UNSIGNED type with to index
|
||||
unsigned_in_to : in UNSIGNED(0 to 3);
|
||||
unsigned_out_to : out UNSIGNED(0 to 3);
|
||||
|
||||
-- INTEGER type without range
|
||||
integer_in : in INTEGER;
|
||||
integer_out : out INTEGER;
|
||||
|
||||
-- INTEGER type with range
|
||||
integer_with_range_in : in INTEGER range -5 to 10;
|
||||
integer_with_range_out : out INTEGER range -6 to 10;
|
||||
|
||||
-- INTEGER type with single value range
|
||||
integer_single_value_in : in INTEGER range 5 to 5;
|
||||
integer_single_value_out : out INTEGER range 5 to 5;
|
||||
|
||||
-- INTEGER type with null range
|
||||
integer_null_range_in : in INTEGER range 7 to -1;
|
||||
integer_null_range_out : out INTEGER range 0 to -1;
|
||||
|
||||
-- NATURAL type
|
||||
natural_in : in NATURAL;
|
||||
natural_out : out NATURAL;
|
||||
|
||||
-- POSITIVE type
|
||||
positive_in : in POSITIVE;
|
||||
positive_out : out POSITIVE
|
||||
);
|
||||
end entity test;
|
||||
|
||||
architecture Behavioral of test is
|
||||
signal integer_with_range : INTEGER range -1 to 100;
|
||||
begin
|
||||
process(a)
|
||||
begin
|
||||
b <= a;
|
||||
end process;
|
||||
bit_out <= bit_in;
|
||||
bit_vector_out <= bit_vector_in;
|
||||
bit_vector_out_to <= bit_vector_in_to;
|
||||
std_ulogic_out <= std_ulogic_in;
|
||||
std_ulogic_vector_out <= std_ulogic_vector_in;
|
||||
std_ulogic_vector_out_to <= std_ulogic_vector_in_to;
|
||||
std_logic_out <= std_logic_in;
|
||||
std_logic_vector_out <= std_logic_vector_in;
|
||||
std_logic_vector_out_to <= std_logic_vector_in_to;
|
||||
signed_out <= signed_in;
|
||||
signed_out_to <= signed_in_to;
|
||||
unsigned_out <= unsigned_in;
|
||||
unsigned_out_to <= unsigned_in_to;
|
||||
integer_with_range_out <= integer_with_range_in;
|
||||
integer_out <= integer_in;
|
||||
integer_single_value_out <= integer_single_value_in;
|
||||
integer_null_range_out <= integer_null_range_in;
|
||||
natural_out <= natural_in;
|
||||
positive_out <= positive_in;
|
||||
|
||||
integer_with_range <= 42;
|
||||
end architecture Behavioral;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,168 @@
|
|||
read -vhdl bounds.vhd
|
||||
verific -import work
|
||||
select -assert-count 1 a:bottom_bound=5'bs11011
|
||||
select -assert-count 1 a:top_bound=5'bs01010
|
||||
select -assert-count 1 a:bottom_bound=5'bs11010
|
||||
select -assert-count 1 a:top_bound=5'bs01011
|
||||
hierarchy -top test
|
||||
|
||||
# bit: not a scalar type
|
||||
select -assert-count 0 w:bit_in a:bottom_bound %i
|
||||
select -assert-count 0 w:bit_in a:top_bound %i
|
||||
select -assert-count 0 w:bit_out a:bottom_bound %i
|
||||
select -assert-count 0 w:bit_out a:top_bound %i
|
||||
|
||||
# bit_vector: not a scalar type
|
||||
select -assert-count 0 w:bit_vector_in a:bottom_bound %i
|
||||
select -assert-count 0 w:bit_vector_in a:top_bound %i
|
||||
select -assert-count 0 w:bit_vector_out a:bottom_bound %i
|
||||
select -assert-count 0 w:bit_vector_out a:top_bound %i
|
||||
|
||||
# bit_vector with to index: not a scalar type
|
||||
select -assert-count 0 w:bit_vector_in_to a:bottom_bound %i
|
||||
select -assert-count 0 w:bit_vector_in_to a:top_bound %i
|
||||
select -assert-count 0 w:bit_vector_out_to a:bottom_bound %i
|
||||
select -assert-count 0 w:bit_vector_out_to a:top_bound %i
|
||||
|
||||
# std_ulogic: not a scalar type
|
||||
select -assert-count 0 w:std_ulogic_in a:bottom_bound %i
|
||||
select -assert-count 0 w:std_ulogic_in a:top_bound %i
|
||||
select -assert-count 0 w:std_ulogic_out a:bottom_bound %i
|
||||
select -assert-count 0 w:std_ulogic_out a:top_bound %i
|
||||
|
||||
# std_ulogic_vector: not a scalar type
|
||||
select -assert-count 0 w:std_ulogic_vector_in a:bottom_bound %i
|
||||
select -assert-count 0 w:std_ulogic_vector_in a:top_bound %i
|
||||
select -assert-count 0 w:std_ulogic_vector_out a:bottom_bound %i
|
||||
select -assert-count 0 w:std_ulogic_vector_out a:top_bound %i
|
||||
|
||||
# std_ulogic_vector with to index: not a scalar type
|
||||
select -assert-count 0 w:std_ulogic_vector_in_to a:bottom_bound %i
|
||||
select -assert-count 0 w:std_ulogic_vector_in_to a:top_bound %i
|
||||
select -assert-count 0 w:std_ulogic_vector_out_to a:bottom_bound %i
|
||||
select -assert-count 0 w:std_ulogic_vector_out_to a:top_bound %i
|
||||
|
||||
# std_logic: not a scalar type
|
||||
select -assert-count 0 w:std_logic_in a:bottom_bound %i
|
||||
select -assert-count 0 w:std_logic_in a:top_bound %i
|
||||
select -assert-count 0 w:std_logic_out a:bottom_bound %i
|
||||
select -assert-count 0 w:std_logic_out a:top_bound %i
|
||||
|
||||
# std_logic_vector: not a scalar type
|
||||
select -assert-count 0 w:std_logic_vector_in a:bottom_bound %i
|
||||
select -assert-count 0 w:std_logic_vector_in a:top_bound %i
|
||||
select -assert-count 0 w:std_logic_vector_out a:bottom_bound %i
|
||||
select -assert-count 0 w:std_logic_vector_out a:top_bound %i
|
||||
|
||||
# std_logic_vector with to index: not a scalar type
|
||||
select -assert-count 0 w:std_logic_vector_in_to a:bottom_bound %i
|
||||
select -assert-count 0 w:std_logic_vector_in_to a:top_bound %i
|
||||
select -assert-count 0 w:std_logic_vector_out_to a:bottom_bound %i
|
||||
select -assert-count 0 w:std_logic_vector_out_to a:top_bound %i
|
||||
|
||||
# signed: not a scalar type
|
||||
select -assert-count 0 w:signed_in a:bottom_bound %i
|
||||
select -assert-count 0 w:signed_in a:top_bound %i
|
||||
select -assert-count 0 w:signed_out a:bottom_bound %i
|
||||
select -assert-count 0 w:signed_out a:top_bound %i
|
||||
|
||||
# signed with to index: not a scalar type
|
||||
select -assert-count 0 w:signed_in_to a:bottom_bound %i
|
||||
select -assert-count 0 w:signed_in_to a:top_bound %i
|
||||
select -assert-count 0 w:signed_out_to a:bottom_bound %i
|
||||
select -assert-count 0 w:signed_out_to a:top_bound %i
|
||||
|
||||
# unsigned: not a scalar type
|
||||
select -assert-count 0 w:unsigned_in a:bottom_bound %i
|
||||
select -assert-count 0 w:unsigned_in a:top_bound %i
|
||||
select -assert-count 0 w:unsigned_out a:bottom_bound %i
|
||||
select -assert-count 0 w:unsigned_out a:top_bound %i
|
||||
|
||||
# unsigned with to index: not a scalar type
|
||||
select -assert-count 0 w:unsigned_in_to a:bottom_bound %i
|
||||
select -assert-count 0 w:unsigned_in_to a:top_bound %i
|
||||
select -assert-count 0 w:unsigned_out_to a:bottom_bound %i
|
||||
select -assert-count 0 w:unsigned_out_to a:top_bound %i
|
||||
|
||||
# integer: scalar type
|
||||
select -assert-count 1 w:integer_in a:bottom_bound=32'b10000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:integer_in a:top_bound=32'b01111111111111111111111111111111 %i
|
||||
select -assert-count 1 w:integer_out a:bottom_bound=32'b10000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:integer_out a:top_bound=32'b01111111111111111111111111111111 %i
|
||||
|
||||
# integer with range: scalar type
|
||||
select -assert-count 1 w:integer_with_range_in a:bottom_bound=5'bs11011 %i
|
||||
select -assert-count 1 w:integer_with_range_in a:top_bound=5'bs01010 %i
|
||||
select -assert-count 1 w:integer_with_range_out a:bottom_bound=5'bs11010 %i
|
||||
select -assert-count 1 w:integer_with_range_out a:top_bound=5'bs01010 %i
|
||||
|
||||
# integer with single value range: scalar type
|
||||
select -assert-count 1 w:integer_single_value_in a:bottom_bound=3'bs101 %i
|
||||
select -assert-count 1 w:integer_single_value_in a:top_bound=3'bs101 %i
|
||||
select -assert-count 1 w:integer_single_value_out a:bottom_bound=3'bs101 %i
|
||||
select -assert-count 1 w:integer_single_value_out a:top_bound=3'bs101 %i
|
||||
|
||||
# integer with null range: scalar type
|
||||
select -assert-count 1 w:integer_null_range_in a:bottom_bound=4'bs0111 %i
|
||||
select -assert-count 1 w:integer_null_range_in a:top_bound=4'bs1111 %i
|
||||
select -assert-count 1 w:integer_null_range_out a:bottom_bound=1'bs0 %i
|
||||
select -assert-count 1 w:integer_null_range_out a:top_bound=1'bs1 %i
|
||||
|
||||
# natural: scalar type
|
||||
select -assert-count 1 w:natural_in a:bottom_bound=31'b0000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:natural_in a:top_bound=31'b1111111111111111111111111111111 %i
|
||||
select -assert-count 1 w:natural_out a:bottom_bound=31'b0000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:natural_out a:top_bound=31'b1111111111111111111111111111111 %i
|
||||
|
||||
# positive: scalar type
|
||||
select -assert-count 1 w:positive_in a:bottom_bound=31'b0000000000000000000000000000001 %i
|
||||
select -assert-count 1 w:positive_in a:top_bound=31'b1111111111111111111111111111111 %i
|
||||
select -assert-count 1 w:positive_out a:bottom_bound=31'b0000000000000000000000000000001 %i
|
||||
select -assert-count 1 w:positive_out a:top_bound=31'b1111111111111111111111111111111 %i
|
||||
|
||||
|
||||
design -reset
|
||||
read -vhdl2019 bounds.vhd
|
||||
hierarchy -top test
|
||||
|
||||
## integer size changed in VHDL 2019
|
||||
# integer: scalar type
|
||||
select -assert-count 1 w:integer_in a:bottom_bound=64'b1000000000000000000000000000000000000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:integer_in a:top_bound=64'b0111111111111111111111111111111111111111111111111111111111111111 %i
|
||||
select -assert-count 1 w:integer_out a:bottom_bound=64'b1000000000000000000000000000000000000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:integer_out a:top_bound=64'b0111111111111111111111111111111111111111111111111111111111111111 %i
|
||||
|
||||
# natural: scalar type
|
||||
select -assert-count 1 w:natural_in a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:natural_in a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i
|
||||
select -assert-count 1 w:natural_out a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000000 %i
|
||||
select -assert-count 1 w:natural_out a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i
|
||||
|
||||
# positive: scalar type
|
||||
select -assert-count 1 w:positive_in a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000001 %i
|
||||
select -assert-count 1 w:positive_in a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i
|
||||
select -assert-count 1 w:positive_out a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000001 %i
|
||||
select -assert-count 1 w:positive_out a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i
|
||||
|
||||
## ranged integer sizes should be unaffected
|
||||
# integer with range: scalar type
|
||||
select -assert-count 1 w:integer_with_range_in a:bottom_bound=5'bs11011 %i
|
||||
select -assert-count 1 w:integer_with_range_in a:top_bound=5'bs01010 %i
|
||||
select -assert-count 1 w:integer_with_range_out a:bottom_bound=5'bs11010 %i
|
||||
select -assert-count 1 w:integer_with_range_out a:top_bound=5'bs01010 %i
|
||||
|
||||
# integer with single value range: scalar type
|
||||
select -assert-count 1 w:integer_single_value_in a:bottom_bound=3'bs101 %i
|
||||
select -assert-count 1 w:integer_single_value_in a:top_bound=3'bs101 %i
|
||||
select -assert-count 1 w:integer_single_value_out a:bottom_bound=3'bs101 %i
|
||||
select -assert-count 1 w:integer_single_value_out a:top_bound=3'bs101 %i
|
||||
|
||||
# integer with null range: scalar type
|
||||
select -assert-count 1 w:integer_null_range_in a:bottom_bound=4'bs0111 %i
|
||||
select -assert-count 1 w:integer_null_range_in a:top_bound=4'bs1111 %i
|
||||
select -assert-count 1 w:integer_null_range_out a:bottom_bound=1'bs0 %i
|
||||
select -assert-count 1 w:integer_null_range_out a:top_bound=1'bs1 %i
|
||||
|
||||
|
||||
design -reset
|
||||
read -sv bounds.sv
|
||||
hierarchy -top test
|
||||
|
||||
## bounds should not be generated for SV
|
||||
select -assert-count none a:bottom_bound
|
||||
select -assert-count none a:top_bound
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash
|
||||
generate_mk --yosys-scripts --bash
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
source ../gen-tests-makefile.sh
|
||||
run_tests --yosys-scripts --bash
|
||||
generate_mk --yosys-scripts --bash
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue